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