3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "wrappers-vserver.h"
27 #include "stack-start.h"
37 # define CLONE_NEWNS 0x00020000
41 # define MNT_DETACH 0x000000002
46 # define DPRINTF(...) printf(__VA_ARGS__)
48 # define DPRINTF(...) (void)0
52 enum { tpUNSET, tpCTX, tpPID } type;
55 unsigned int interval;
62 static struct option const
64 { "help", no_argument, 0, 'h' },
65 { "version", no_argument, 0, 'v' },
66 { "all", no_argument, 0, 'a' },
67 { "ctx", required_argument, 0, 'c' },
68 { "pid", required_argument, 0, 'p' },
69 { "interval", required_argument, 0, 'i' },
70 { "shutdown", no_argument, 0, 's' },
74 int wrapper_exit_code = 1;
77 showHelp(int fd, char const *cmd, int res)
79 WRITE_MSG(fd, "Usage: ");
82 " (-c|--ctx <ctx>)|(-p|--pid <pid>) [-i|--interval <msec>] [-a|--all]\n"
83 " [-s|--shutdown] [--] <signal> [<sec> <signal>]*\n\n"
84 "Please report bugs to " PACKAGE_BUGREPORT "\n");
92 "ctx-kill " VERSION " -- kills processes in foreign contexts\n"
93 "This program is part of " PACKAGE_STRING "\n\n"
94 "Copyright (C) 2003 Enrico Scholz\n"
95 VERSION_COPYRIGHT_DISCLAIMER);
100 iterateThroughProc(void (*fn)(pid_t pid, void *data),
101 struct ArgInfo const * const args,
109 dir = opendir("/proc");
117 while ((d=readdir(dir))!=0) {
118 pid_t pid = atoi(d->d_name);
119 if (pid==0 || // not a /proc/<pid>/ entry
120 (args->omit_init && pid==1) ||
121 getpgid(pid)==grp) // our own process-group
132 doKillAllSingle(pid_t pid, void *sig_ptr_v)
134 register int const * const sig_ptr = sig_ptr_v;
136 DPRINTF("sending signal '%u' to process '%u'\n",
142 getRemainingProcCountProc(pid_t UNUSED pid, void *cnt_v)
144 register size_t * const cnt = cnt_v;
150 getRemainingProcCount(struct ArgInfo const * const args)
153 iterateThroughProc(&getRemainingProcCountProc, args, &cnt);
159 doKillAll(struct ArgInfo const * const args)
162 pid_t init_pid = vc_X_getinitpid(0);
164 signal(SIGSTOP, SIG_IGN);
166 while (i<args->argc) {
167 int sig = atoi(args->argv[i]);
168 time_t next_time = time(0);
172 next_time += atoi(args->argv[i]);
174 iterateThroughProc(&doKillAllSingle, args, &sig);
175 if (init_pid!=-1 && init_pid>1 && init_pid!=getpid())
178 while (time(0)<next_time && getRemainingProcCount(args)>0)
179 usleep(args->interval * 1000);
184 if (args->shutdown && getRemainingProcCount(args)>0) {
185 WRITE_MSG(2, "There are processes which could not be killed\n");
192 doKillSingle(struct ArgInfo const * const args)
196 while (i<args->argc) {
197 int sig = atoi(args->argv[i]);
198 time_t next_time = time(0);
202 next_time += atoi(args->argv[i]);
204 DPRINTF("sending signal '%u' to process '%u'\n",
206 kill(args->pid, sig);
207 while (time(0)<next_time &&
208 (getpgid(args->pid)!=-1 || errno!=ESRCH))
210 usleep(args->interval * 1000);
217 childFunc(void *args_v)
219 struct ArgInfo * args = args_v;
221 Emount("none", "/mnt", "tmpfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, "size=4k");
223 Emkdir("proc", 0600);
225 Epivot_root(".", "old");
227 Eumount2("old", MNT_DETACH);
228 Emkdir("old/foo",0600);
229 Emount("none", "/proc", "proc", 0, 0);
231 // TODO: drop additional capabilities?
233 // TODO: it may be be better for ctx-shutdown to:
234 // * generate ctx with S_CTX_INFO_INIT
236 Evc_new_s_context(args->ctx, ~0, S_CTX_INFO_LOCK|S_CTX_INFO_SCHED);
238 switch (args->type) {
239 case tpCTX : doKillAll(args); break;
240 case tpPID : doKillSingle(args); break;
241 default : assert(false); return 1;
248 determineContext(pid_t pid)
259 Evc_new_s_context(1, ~0, S_CTX_INFO_LOCK|S_CTX_INFO_SCHED);
260 res = vc_X_getctx(pid);
261 Ewrite(fd[1], &res, sizeof res);
267 if (Eread(fd[0], &res, sizeof res)!=sizeof(res)) {
268 WRITE_MSG(2, "internal communication error while determining ctx\n");
273 WRITE_MSG(2, "can not determine contex for given pid\n");
280 int main(int argc, char *argv[])
285 struct ArgInfo args = {
292 int c = getopt_long(argc, argv, "hvsac:p:i:", CMDLINE_OPTIONS, 0);
296 case 'h' : showHelp(1, argv[0], 0);
297 case 'v' : showVersion();
300 args.ctx = atoi(optarg);
304 args.pid = atoi(optarg);
306 case 'i' : args.interval = atoi(optarg); break;
307 case 's' : args.shutdown = true; break;
308 case 'a' : args.omit_init = false; break;
310 WRITE_MSG(2, "Try '");
311 WRITE_STR(2, argv[0]);
312 WRITE_MSG(2, " --help\" for more information.\n");
318 if (args.type==tpUNSET){
319 WRITE_MSG(2, "Please specify a context or a pid\n");
324 WRITE_MSG(2, "No signal specified\n");
328 if (args.type==tpPID)
329 args.ctx = determineContext(args.pid);
332 WRITE_MSG(2, "Can not operate in ctx 0\n");
336 args.argc = argc-optind;
337 args.argv = argv+optind;
339 // TODO: args.argv verification (only integers)
341 if (args.argc%2 != 1) {
342 WRITE_MSG(2, "Wrong count of '<signal> [<pause> <signal>]*' arguments specified.\n");
346 pid = Eclone(childFunc, STACK_START(buf), CLONE_NEWNS|SIGCHLD, &args);
347 p = Ewait4(pid, &status, 0,0);
349 if (WIFEXITED(status)) return WEXITSTATUS(status);
350 if (WIFSIGNALED(status)) return kill(getpid(), WTERMSIG(status));