initial checkin
[util-vserver.git] / util-vserver / src / vkill.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
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.
8 //  
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.
13 //  
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.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 #include "compat.h"
23
24 #include "vserver.h"
25 #include "linuxvirtual.h"
26
27 #include <getopt.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/resource.h>
36 #include <sys/wait.h>
37
38 #define VERSION_COPYRIGHT_DISCLAIMER
39
40 #define CMD_HELP        0x8000
41 #define CMD_VERSION     0x8001
42
43 #define WRITE_MSG(FD,X)         (void)(write(FD,X,sizeof(X)-1))
44 #define WRITE_STR(FD,X)         writeStr(FD,X)
45
46 static struct option const
47 CMDLINE_OPTIONS[] = {
48   { "help",     no_argument,  0, CMD_HELP },
49   { "version",  no_argument,  0, CMD_VERSION },
50   { 0,0,0,0 }
51 };
52
53 struct Arguments
54 {
55     xid_t               ctx;
56     int                 sig;
57 };
58
59 static char const * const SIGNALS[] = {
60   // 0      1      2          3       4       5       6       7
61   "UNUSED", "HUP", "INT",     "QUIT", "ILL",  "TRAP", "ABRT", "UNUSED",
62   "FPE",    "KILL", "USR1",   "SEGV", "USR2", "PIPE", "ALRM", "TERM",
63   "STKFLT", "CHLD", "CONT",   "STOP", "TSTP", "TTIN", "TTOU", "IO",
64   "XCPU",   "XFSZ", "VTALRM", "PROF", "WINCH",
65   0,
66 };
67
68 inline static void UNUSED
69 writeStr(int fd, char const *cmd)
70 {
71   (void)write(fd, cmd, strlen(cmd));
72 }
73
74 static void
75 showHelp(int fd, char const *cmd, int res)
76 {
77   WRITE_MSG(fd, "Usage:  ");
78   WRITE_STR(fd, cmd);
79   WRITE_MSG(fd,
80             " [-c <ctx>] [-s <signal>] [--] <pid>*\n"
81             "Please report bugs to " PACKAGE_BUGREPORT "\n");
82   exit(res);
83 }
84
85 static void
86 showVersion()
87 {
88   WRITE_MSG(1,
89             "vkill " VERSION " -- sends signals to processes within other contexts\n"
90             "This program is part of " PACKAGE_STRING "\n\n"
91             "Copyright (C) 2003 Enrico Scholz\n"
92             VERSION_COPYRIGHT_DISCLAIMER);
93   exit(0);
94 }
95
96 static int
97 str2sig(char const *str)
98 {
99   char  *errptr;
100   int   res = strtol(str, &errptr, 10);
101   
102   if (*errptr!='\0') res=-1;
103   if (res==-1 && strncmp(str,"SIG",3)==0) str+=3;
104   if (res==-1) {
105     char const * const  *ptr = SIGNALS;
106     for (;*ptr!=0; ++ptr) {
107       if (strcmp(*ptr,str)!=0) continue;
108       res = ptr-SIGNALS;
109       break;
110     }
111   }
112
113   return res;
114 }
115
116 #if defined(VC_ENABLE_API_LEGACY)
117 inline static ALWAYSINLINE int
118 kill_wrapper_legacy(xid_t UNUSED ctx, char const *proc, int UNUSED sig)
119 {
120   pid_t         pid = fork();
121   if (pid==-1) {
122     perror("fork()");
123     exit(1);
124   }
125   else if (pid==0) {
126     int         status;
127     int         res;
128     while ((res=wait4(pid, &status, 0,0))==-1 &&
129            (errno==EAGAIN || errno==EINTR)) {}
130
131     return (res==0 && WIFEXITED(status) && WEXITSTATUS(status)) ? 0 : 1;
132   }
133
134   execl(LEGACYDIR "/vkill", "legacy/vkill", proc, (void *)(0));
135   perror("execl()");
136   exit(1);
137 }
138
139 static int
140 kill_wrapper(xid_t ctx, char const *pid, int sig)
141 {
142   //printf("kill_wrapper(%u, %s, %i)\n", ctx, pid, sig);
143   if (vc_ctx_kill(ctx,atoi(pid),sig)==-1) {
144     int         err = errno;
145     if (vc_get_version(VC_CAT_COMPAT)==-1)
146       return kill_wrapper_legacy(ctx, pid, sig);
147     else {
148       errno = err;
149       perror("vc_ctx_kill()");
150       return 1;
151     }
152   }
153   
154   return 0;
155 }
156 #else // VC_ENABLE_API_LEGACY
157 inline static int
158 kill_wrapper(xid_t ctx, char const *pid, int sig)
159 {
160   if (vc_ctx_kill(ctx,atoi(pid),sig)==-1) {
161     perror("vc_ctx_kill()");
162     return 1;
163   }
164   return 0;
165 }
166 #endif
167
168
169 int main(int argc, char *argv[])
170 {
171   int                   fail = 0;
172   struct Arguments      args = {
173     .ctx = VC_NOCTX,
174     .sig = SIGTERM,
175   };
176   
177   while (1) {
178     int         c = getopt_long(argc, argv, "c:s:", CMDLINE_OPTIONS, 0);
179     if (c==-1) break;
180
181     switch (c) {
182       case CMD_HELP     :  showHelp(1, argv[0], 0);
183       case CMD_VERSION  :  showVersion();
184       case 'c'          :  args.ctx = atoi(optarg);    break;
185       case 's'          :  args.sig = str2sig(optarg); break;
186       default           :
187         WRITE_MSG(2, "Try '");
188         WRITE_STR(2, argv[0]);
189         WRITE_MSG(2, " --help\" for more information.\n");
190         return EXIT_FAILURE;
191         break;
192     }
193   }
194
195   if (args.sig==-1) {
196     WRITE_MSG(2, "Invalid signal specified\n");
197     return EXIT_FAILURE;
198   }
199
200   if (args.ctx==VC_NOCTX && optind==argc) {
201     WRITE_MSG(2, "No pid specified\n");
202     return EXIT_FAILURE;
203   }
204
205   if (optind==argc)
206     fail += kill_wrapper(args.ctx, "0", args.sig);
207   else for (;optind<argc;++optind)
208     fail += kill_wrapper(args.ctx, argv[optind], args.sig);
209
210   return fail==0 ? EXIT_SUCCESS : EXIT_FAILURE;
211 }
212
213 #ifdef TESTSUITE
214 void
215 vkill_test()
216 {
217   assert(str2sig("0") ==0 );
218   assert(str2sig("1") ==1 );
219   assert(str2sig("10")==10);
220   assert(str2sig("SIGHUP")==1);
221   assert(str2sig("HUP")   ==1);
222   assert(str2sig("SIGCHLD")==17);
223   assert(str2sig("CHLD")   ==17);
224   assert(str2sig("x")==-1);
225   assert(str2sig("1 0")==-1);
226
227   return 0;
228 }
229 #endif