From 58c696e88cfeb6d97d836b9f328d683b0e187d65 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 2 Dec 2003 17:20:39 +0000 Subject: Initial Import --- src/Makefile | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 8 ++ src/getjail.c | 69 ++++++++++ src/getjail.h | 35 +++++ src/jails.8 | 26 ++++ src/jails.c | 157 +++++++++++++++++++++++ src/killjail.8 | 68 ++++++++++ src/killjail.c | 387 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1107 insertions(+) create mode 100644 src/Makefile create mode 100644 src/Makefile.am create mode 100644 src/getjail.c create mode 100644 src/getjail.h create mode 100644 src/jails.8 create mode 100644 src/jails.c create mode 100644 src/killjail.8 create mode 100644 src/killjail.c (limited to 'src') diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..7b914d5 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,357 @@ +# Makefile.in generated automatically by automake 1.5 from Makefile.am. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. + +prefix = /usr/local +exec_prefix = ${prefix} + +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +libexecdir = ${exec_prefix}/libexec +datadir = ${prefix}/share +sysconfdir = ${prefix}/etc +sharedstatedir = ${prefix}/com +localstatedir = ${prefix}/var +libdir = ${exec_prefix}/lib +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include +pkgdatadir = $(datadir)/jailutils +pkglibdir = $(libdir)/jailutils +pkgincludedir = $(includedir)/jailutils +top_builddir = .. + +ACLOCAL = ${SHELL} /usr/work/src/jailutils/missing --run aclocal +AUTOCONF = ${SHELL} /usr/work/src/jailutils/missing --run autoconf +AUTOMAKE = ${SHELL} /usr/work/src/jailutils/missing --run automake +AUTOHEADER = ${SHELL} /usr/work/src/jailutils/missing --run autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL} +INSTALL_HEADER = $(INSTALL_DATA) +transform = s,x,x, +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AMTAR = ${SHELL} /usr/work/src/jailutils/missing --run tar +AWK = nawk +CC = gcc +DEPDIR = .deps +EXEEXT = +INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s +OBJEXT = o +PACKAGE = jailutils +VERSION = 0.5.4 +am__include = include +am__quote = +install_sh = /usr/work/src/jailutils/install-sh + +sbin_PROGRAMS = killjail jails +killjail_SOURCES = killjail.c getjail.c getjail.h +killjail_LDADD = -lkvm +jails_SOURCES = jails.c getjail.c getjail.h +jails_LDADD = -lkvm +man_MANS = killjail.8 jails.8 +EXTRA_DIST = $(man_MANS) +subdir = src +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +sbin_PROGRAMS = killjail$(EXEEXT) jails$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am_jails_OBJECTS = jails.$(OBJEXT) getjail.$(OBJEXT) +jails_OBJECTS = $(am_jails_OBJECTS) +jails_DEPENDENCIES = +jails_LDFLAGS = +am_killjail_OBJECTS = killjail.$(OBJEXT) getjail.$(OBJEXT) +killjail_OBJECTS = $(am_killjail_OBJECTS) +killjail_DEPENDENCIES = +killjail_LDFLAGS = + +DEFS = -DHAVE_CONFIG_H +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = +LDFLAGS = +LIBS = -lkvm +depcomp = $(SHELL) $(top_srcdir)/depcomp +DEP_FILES = $(DEPDIR)/getjail.Po $(DEPDIR)/jails.Po \ + $(DEPDIR)/killjail.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = -g -O2 +DIST_SOURCES = $(jails_SOURCES) $(killjail_SOURCES) + +NROFF = nroff +MANS = $(man_MANS) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(jails_SOURCES) $(killjail_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && \ + CONFIG_HEADERS= CONFIG_LINKS= \ + CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +jails$(EXEEXT): $(jails_OBJECTS) $(jails_DEPENDENCIES) + @rm -f jails$(EXEEXT) + $(LINK) $(jails_LDFLAGS) $(jails_OBJECTS) $(jails_LDADD) $(LIBS) +killjail$(EXEEXT): $(killjail_OBJECTS) $(killjail_DEPENDENCIES) + @rm -f killjail$(EXEEXT) + $(LINK) $(killjail_LDFLAGS) $(killjail_OBJECTS) $(killjail_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +include $(DEPDIR)/getjail.Po +include $(DEPDIR)/jails.Po +include $(DEPDIR)/killjail.Po + +distclean-depend: + -rm -rf $(DEPDIR) + +.c.o: + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$< + +.c.obj: + source='$<' object='$@' libtool=no \ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \ + $(CCDEPMODE) $(depcomp) \ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = depmode=gcc +uninstall-info-am: + +man8dir = $(mandir)/man8 +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +GTAGS: + here=`CDPATH=: && cd $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + $(mkinstalldirs) "$(distdir)/$$dir"; \ + fi; \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-sbinPROGRAMS + +install-info: install-info-am + +install-man: install-man8 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-man uninstall-sbinPROGRAMS + +uninstall-man: uninstall-man8 + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-sbinPROGRAMS distclean distclean-compile distclean-depend \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-man8 install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-man uninstall-man8 \ + uninstall-sbinPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..8dc8d62 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,8 @@ +sbin_PROGRAMS = killjail jails +killjail_SOURCES = killjail.c getjail.c getjail.h +killjail_LDADD = -lkvm +jails_SOURCES = jails.c getjail.c getjail.h +jails_LDADD = -lkvm +man_MANS = killjail.8 jails.8 +EXTRA_DIST = $(man_MANS) + diff --git a/src/getjail.c b/src/getjail.c new file mode 100644 index 0000000..9106557 --- /dev/null +++ b/src/getjail.c @@ -0,0 +1,69 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +*/ + +#include +#include +#include +#include "getjail.h" + +#define PROC_STATUS_PATH "/proc/%d/status" + +int getpidjail(pid_t pid, char* buff) +{ + int fd; + size_t bytes; + off_t off; + + /* Format the file name */ + if(snprintf(buff, JAIL_BUFF_SIZE, PROC_STATUS_PATH, pid)) + { + /* Open the file */ + if((fd = open(buff, O_RDONLY)) >= 0) + { + /* Seek to the last bit */ + off = lseek(fd, SEEK_END, 0); + + if(off != -1) + { + off -= JAIL_BUFF_SIZE; + if(off < 0) off = 0; + lseek(fd, SEEK_SET, off); + + if((bytes = read(fd, buff, JAIL_BUFF_SIZE - 1)) > 0) + { + /* Okay now jailname should be the last token */ + while(isspace(buff[bytes - 1])) + bytes--; + + buff[bytes] = 0; + + while(!isspace(buff[bytes - 1])) + bytes--; + + memmove(buff, buff + bytes, JAIL_BUFF_SIZE - bytes); + return 0; + + } + } + } + } + + return -1; +} diff --git a/src/getjail.h b/src/getjail.h new file mode 100644 index 0000000..5e58542 --- /dev/null +++ b/src/getjail.h @@ -0,0 +1,35 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +*/ + +#ifndef _GETJAIL_H_ +#define _GETJAIL_H_ + + + +#include +#include + +#define JAIL_BUFF_SIZE MAXHOSTNAMELEN + 2 + +int getpidjail(pid_t pid, char* buff); + + + +#endif /* _GETJAIL_H_ */ diff --git a/src/jails.8 b/src/jails.8 new file mode 100644 index 0000000..11de04f --- /dev/null +++ b/src/jails.8 @@ -0,0 +1,26 @@ +.\" Process this file with +.\" groff -man -Tascii jails.8 +.\" +.TH JAILS 8 "May 2002" FreeBSD "User Manual" +.SH NAME +.B jails +\- list all jails running on a system +.SH SYNOPSIS +.B jails + +.SH DESCRIPTION +The +.B jails +command will print a list of all the various jails running +on your system. The hostnames of those jails are printed. +The list is not ordered. + +.SH BUGS +I'm sure they're out there. + +.SH AUTHOR +Nate Nielsen + +.SH "SEE ALSO" +.BR jail (8), +.BR jailer (8) diff --git a/src/jails.c b/src/jails.c new file mode 100644 index 0000000..9c99743 --- /dev/null +++ b/src/jails.c @@ -0,0 +1,157 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// CHANGES +// 0.5.1 kvm_openfiles call uses /dev/null so non root users can use +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "getjail.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +static int listJails(); +static void usage(); + +int main(int argc, char* argv[]) +{ + /* Nice main :) */ + return listJails() >= 0 ? 0 : 1; +} + + +int listJails() +{ + kvm_t *kd; + struct kinfo_proc* kp; + char errbuf[_POSIX2_LINE_MAX]; + char jailName[JAIL_BUFF_SIZE]; + int nentries, i; + + + char* jails = NULL; /* jail list buffer */ + size_t nextJail = 0; /* current write positon */ + size_t endJails = 0; /* size of buffer */ + int numJails = 0; /* return value */ + + + /* Open kernel interface */ + kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, + O_RDONLY, errbuf); + if(kd == 0) + errx(1, "%s", errbuf); + + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "%s", kvm_geterr(kd)); + + + /* Okay now loop through and look for the jails */ + for(i = 0; i < nentries; i++) + { + pid_t pid; + +#if __FreeBSD_version > 500000 + + /* Check the flags first */ + if(!(kp[i].ki_flag & P_JAILED)) + continue; + + pid = kp[i].ki_pid; + +#else + + /* Check the flags first */ + if(!(kp[i].kp_proc.p_flag & P_JAILED)) + continue; + + pid = kp[i].kp_proc.p_pid; + +#endif + + /* Get this processes jail name */ + if(getpidjail(pid, jailName) < 0) + continue; + + if(jails) + { + char* j; + + /* See if that jail name was already taken */ + for(j = jails; *j != NULL; j += strlen(j) + 1) + { + if(!strcmp(jailName, j)) + break; + } + + /* Can't do this in loop above */ + if(*j) + continue; + } + + + /* Okay we got a jail name */ + + + /* Allocate if necessary enough space for it */ + if(nextJail + strlen(jailName) + 2 > endJails) + { + endJails += (JAIL_BUFF_SIZE * 0x2); + jails = (char*)realloc(jails, endJails); + if(!jails) + errx(1, "out of memory"); + } + + + /* Put the jail name in the buffer */ + strcpy(jails + nextJail, jailName); + nextJail += strlen(jailName) + 1; + jails[nextJail] = 0; + numJails++; + + /* And print it */ + fprintf(stdout, "%s\n", jailName); + } + + kvm_close(kd); + + return numJails; +} + +static void usage() +{ + fprintf(stderr, "usage: jails\n"); + exit(2); +} + diff --git a/src/killjail.8 b/src/killjail.8 new file mode 100644 index 0000000..b0f73b0 --- /dev/null +++ b/src/killjail.8 @@ -0,0 +1,68 @@ +.\" Process this file with +.\" groff -man -Tascii killjail.8 +.\" +.TH KILLJAIL 8 "May 2002" FreeBSD "User Manual" +.SH NAME +.B killjail +\- stop or restart a jail +.SH SYNOPSIS +.B killjail +[ +.B -h +| +.B -r +] [ +.B -t +.I timeout +] [ +.B -fq +] +.I jailname ... +.SH DESCRIPTION +.B killjail +can either send signals to a +.BR jailer (8) +process to manage the shutdown or restart of a jail or it can kill all +the processes in a jail on it's own. + +When no options are given the jail is shutdown as follows: +.IP 1. 3 +A stop request (SIGTERM) is sent to the +.BR jailer (8) +process for the jail if there is one. This initiates an orderly shutdown. +.IP 2. 3 +Any remaining processes are killed with a SIGTERM. +.IP 3. 3 +If the +.B -f +option is specified, send a SIGKILL to any remaining processes. + +.SH OPTIONS +.IP -f +Force jail to shutdown sending a SIGKILL as a last resort. +.IP -h +Sends a halt request to a jail (SIGQUIT). The jail must have a +.BR jailer (8) +process running inside it. The +.BR jailer (8) +process remains running within the jail, but all other jailed +processes are shutdown in and orderly fashion. +.IP -q +Supress warnings. +.IP -r +Sends a restart request to a jail (SIGHUP). The jail must have a +.BR jailer (8) +process running inside it. +.IP "-t timeout" +The timeout in seconds to wait between steps 1, 2 and 3 above. Defaults to 3. + +.SH BUGS +I'm sure they're out there. Let me know. + +.SH AUTHOR +Nate Nielsen + +.SH "SEE ALSO" +.BR jail (8), +.BR jailer (8), +.BR kill (1) diff --git a/src/killjail.c b/src/killjail.c new file mode 100644 index 0000000..2b4eb7d --- /dev/null +++ b/src/killjail.c @@ -0,0 +1,387 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// CHANGES +// 0.5.1 kvm_openfiles uses /dev/null +// +// 0.5.3 +// Added quiet option +// Added force option +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "getjail.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +/* The big long stop process */ +static int stopJail(char* jailName, int force); + +/* Signals the jailer for various requests */ +static int signalJail(char* jailName, int signal); + +static void killProcesses(pid_t* pids, int signal); +static int getJailProcesses(const char* jailName, pid_t* pidJailer, pid_t** pids); + +static void usage(); + + +/* The timeout to wait between kills */ +#define DEFAULT_TIMEOUT 10 +int g_timeout = DEFAULT_TIMEOUT; + +/* To find the jailer process look for this command */ +#define JAILER_COMMAND "jailer" + +/* Supress warnings */ +int g_quiet = 0; + +int main(int argc, char* argv[]) +{ + /* If this gets set then only signal jailer, no kill */ + int signal = 0; + int ch = 0; + int force = 0; + int ret = 0; + + while((ch = getopt(argc, argv, "fhqrt:")) != -1) + { + switch(ch) + { + /* Force jail to shutdown */ + case 'f': + force = 1; + break; + + case 'q': + g_quiet = 1; + break; + + /* Send halt request to jailer */ + case 'h': + signal = SIGQUIT; + break; + + /* Send restart request to jailer */ + case 'r': + signal = SIGHUP; + break; + + /* Timeout to use between kills */ + case 't': + g_timeout = atoi(optarg); + if(g_timeout <= 0) + errx(1, "invalid timeout argument: %s", optarg); + break; + + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + /* Make sure we have a jailName */ + if(argc == 0) + usage(); + + /* For each jail */ + while(argc > 0) + { + /* If a signal option was set above then signal, + otherwise kill */ + if(signal == 0) + { + if(stopJail(*argv, force) != 0) + ret = 1; + } + else + { + if(force) + errx(1, "-f option incompatible with -r or -h"); + + if(signalJail(*argv, signal) != 0) + ret = 1; + } + + argc--; + argv++; + } + + return ret; +} + + +int signalJail(char* jailName, int signal) +{ + pid_t jailerPid = 0; + + /* Only ask for jailer pid */ + getJailProcesses(jailName, &jailerPid, NULL); + + if(jailerPid == 0) + { + warnx("%s: jailer not running in jail", jailName); + return 1; + } + + if(kill(jailerPid, signal) < 0) + err(1, "%s: couldn't signal jailer", jailName); + + return 0; +} + + +int stopJail(char* jailName, int force) +{ + pid_t jailerPid = 0; + pid_t* jailProcesses = NULL; + int pass = 0; + int timeout = 0; + int ret = 0; + + /* + * Multiple passes are used to do different things. + * Each time the jails processes are listed. + */ + while(ret == 0 && + getJailProcesses(jailName, &jailerPid, &jailProcesses)) + { + + if(timeout > 0) + { + sleep(1); + timeout--; + } + + else + { + + switch(pass) + { + + /* First pass is killing the jailer */ + case 0: + + if(jailerPid == 0) + { + /* No jailer */ + if(!g_quiet) + warnx("%s: jailer not running in jail", jailName); + } + + else + { + if(kill(jailerPid, SIGTERM) < 0 && errno != ESRCH) + err(1, "%s: couldn't signal jailer:", jailName); + + else + timeout = g_timeout; + } + + break; + + + /* Okay now quit all processes in jail */ + case 1: + + /* If we get here, jailer looks like it's irresponsive */ + if(jailerPid != 0 && !g_quiet) + warnx("%s: jailer (pid %d) won't quit. terminating jail...", jailName, jailerPid); + + + killProcesses(jailProcesses, SIGTERM); + timeout = g_timeout; + break; + + + /* Okay now we force kill the processes if necessary */ + case 2: + + if(force) + { + /* If we get here, jailer looks like it's really irresponsive */ + if(!g_quiet) + warnx("%s: jail won't stop. forcing jail termination...", jailName); + + killProcesses(jailProcesses, SIGKILL); + timeout = g_timeout; + } + + break; + + + /* And if that didn't do it, well then give up */ + case 3: + + if(!g_quiet) + warnx("%s: couldn't stop jail, processes wouldn't die", jailName); + + ret = 1; + break; + + } + + pass++; + } + + if(jailProcesses) + free(jailProcesses); + + } + + if(pass == 0) + { + if(!g_quiet) + warnx("%s: jail not running", jailName); + + ret = 1; + } + + return ret; +} + +void killProcesses(pid_t* pids, int signal) +{ + /* Note that we assume pids is null terminated + this is what getJailProcesses returns */ + + while(*pids) + { + if(kill(*pids, signal) < 0) + { + /* We ignore missing process errors */ + if(errno != ESRCH) + err(1, "couldn't kill process: %d", *pids); + } + + pids++; + } +} + +int getJailProcesses(const char* jailName, pid_t* pidJailer, pid_t** pids) +{ + kvm_t *kd; + struct kinfo_proc* kp; + char errbuf[_POSIX2_LINE_MAX]; + char pidJail[JAIL_BUFF_SIZE]; + int nentries, i, j; + + /* Open the kernel interface */ + kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, + O_RDONLY, errbuf); + if(kd == 0) + errx(1, "%s", errbuf); + + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "%s", kvm_geterr(kd)); + + /* Allocate memory */ + if(pids) + { + if((*pids = (pid_t*)malloc((nentries + 1) * sizeof(pid_t))) == NULL) + err(1, "out of memory"); + } + + /* Okay now loop and look at each process' jail */ + for(i = 0, j = 0; i < nentries; i++) + { + pid_t pid; + +#if __FreeBSD_version > 500000 + + /* Check the flags first */ + if(!(kp[i].ki_flag & P_JAILED)) + continue; + + pid = kp[i].ki_pid; + +#else + + /* Check the flags first */ + if(!(kp[i].kp_proc.p_flag & P_JAILED)) + continue; + + pid = kp[i].kp_proc.p_pid; + +#endif + + /* Now actually get the jail name */ + if(getpidjail(pid, pidJail) < 0) + continue; + + if(strcmp(pidJail, jailName)) + continue; + + /* Copy the PID over */ + if(pids) + (*pids)[j++] = pid; + + /* If it's the jailer then copy that */ + if(pidJailer) + { +#if __FreeBSD_version > 500000 + if(strstr(kp[i].ki_comm, JAILER_COMMAND)) +#else + if(strstr(kp[i].kp_proc.p_comm, JAILER_COMMAND)) +#endif + *pidJailer = pid; + } + + } + + /* Null terminate pids array */ + if(pids) + (*pids)[j] = 0; + + kvm_close(kd); + + return j == 0 ? 0 : 1; +} + + + +static void usage() +{ + fprintf(stderr, "usage: killjail [ -h | -r ] [ -t timeout ] [ -qf ] jailname ...\n"); + exit(2); +} + -- cgit v1.2.3