migration from private to rsa
[external/sysvinit.git] / contrib / start-stop-daemon.c
1 /*
2  * A rewrite of the original Debian's start-stop-daemon Perl script
3  * in C (faster - it is executed many times during system startup).
4  *
5  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
6  * public domain.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <signal.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <unistd.h>
18 #include <getopt.h>
19 #include <pwd.h>
20
21 #define VERSION "version 0.3, 1996-06-05"
22
23 static int testmode = 0;
24 static int quietmode = 0;
25 static int exitnodo = 1;
26 static int start = 0;
27 static int stop = 0;
28 static int signal_nr = 15;
29 static int user_id = -1;
30 static const char *userspec = NULL;
31 static const char *cmdname = NULL;
32 static char *execname = NULL;
33 static char *startas = NULL;
34 static const char *pidfile = NULL;
35 static const char *progname = "";
36
37 static struct stat exec_stat;
38
39 struct pid_list {
40         struct pid_list *next;
41         int pid;
42 };
43
44 static struct pid_list *found = NULL;
45 static struct pid_list *killed = NULL;
46
47 static void *xmalloc(int size);
48 static void push(struct pid_list **list, int pid);
49 static void do_help(void);
50 static void parse_options(int argc, char * const *argv);
51 static int pid_is_exec(int pid, const struct stat *esb);
52 static int pid_is_user(int pid, int uid);
53 static int pid_is_cmd(int pid, const char *name);
54 static void check(int pid);
55 static void do_pidfile(const char *name);
56 static void do_procfs(void);
57 static void do_stop(void);
58
59 #ifdef __GNUC__
60 static void fatal(const char *format, ...)
61         __attribute__((noreturn, format(printf, 1, 2)));
62 static void badusage(const char *msg)
63         __attribute__((noreturn));
64 #else
65 static void fatal(const char *format, ...);
66 static void badusage(const char *msg);
67 #endif
68
69 static void
70 fatal(const char *format, ...)
71 {
72         va_list arglist;
73
74         fprintf(stderr, "%s: ", progname);
75         va_start(arglist, format);
76         vfprintf(stderr, format, arglist);
77         va_end(arglist);
78         putc('\n', stderr);
79         exit(2);
80 }
81
82
83 static void *
84 xmalloc(int size)
85 {
86         void *ptr;
87
88         ptr = malloc(size);
89         if (ptr)
90                 return ptr;
91         fatal("malloc(%d) failed", size);
92 }
93
94
95 static void
96 push(struct pid_list **list, int pid)
97 {
98         struct pid_list *p;
99
100         p = xmalloc(sizeof(*p));
101         p->next = *list;
102         p->pid = pid;
103         *list = p;
104 }
105
106
107 static void
108 do_help(void)
109 {
110         printf("\
111 start-stop-daemon for Debian Linux - small and fast C version written by\n\
112 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
113 VERSION "\n\
114 \n\
115 Usage:
116     start-stop-daemon -S|--start options ... -- arguments ...\n\
117     start-stop-daemon -K|--stop options ...\n\
118     start-stop-daemon -H|--help\n\
119     start-stop-daemon -V|--version\n\
120 \n\
121 Options (at least one of --exec|--pidfile|--user is required):
122     -x|--exec <executable>       program to start/check if it is running\n\
123     -p|--pidfile <pid-file>      pid file to check\n\
124     -u|--user <username>|<uid>   stop this user's processes\n\
125     -n|--name <process-name>     stop processes with this name\n\
126     -s|--signal <signal>         signal to send (default 15)\n\
127     -a|--startas <pathname>      program to start (default <executable>)\n\
128     -t|--test                    test mode, don't do anything\n\
129     -o|--oknodo                  exit status 0 (not 1) if nothing done\n\
130     -q|--quiet  |  -v, --verbose\n\
131 \n\
132 Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = trouble\n");
133 }
134
135
136 static void
137 badusage(const char *msg)
138 {
139         if (msg && *msg)
140                 fprintf(stderr, "%s: %s\n", progname, msg);
141         fprintf(stderr, "Try `%s --help' for more information.\n", progname);
142         exit(2);
143 }
144
145
146 static void
147 parse_options(int argc, char * const *argv)
148 {
149         static struct option longopts[] = {
150                 { "help",       0, NULL, 'H'},
151                 { "stop",       0, NULL, 'K'},
152                 { "start",      0, NULL, 'S'},
153                 { "version",    0, NULL, 'V'},
154                 { "startas",    1, NULL, 'a'},
155                 { "name",       1, NULL, 'n'},
156                 { "oknodo",     0, NULL, 'o'},
157                 { "pidfile",    1, NULL, 'p'},
158                 { "quiet",      0, NULL, 'q'},
159                 { "signal",     1, NULL, 's'},
160                 { "test",       0, NULL, 't'},
161                 { "user",       1, NULL, 'u'},
162                 { "verbose",    0, NULL, 'v'},
163                 { "exec",       1, NULL, 'x'},
164                 { NULL,         0, NULL, 0}
165         };
166         int c;
167
168         for (;;) {
169                 c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
170                                 longopts, (int *) 0);
171                 if (c == -1)
172                         break;
173                 switch (c) {
174                 case 'H':  /* --help */
175                         do_help();
176                         exit(0);
177                 case 'K':  /* --stop */
178                         stop = 1;
179                         break;
180                 case 'S':  /* --start */
181                         start = 1;
182                         break;
183                 case 'V':  /* --version */
184                         printf("start-stop-daemon " VERSION "\n");
185                         exit(0);
186                 case 'a':  /* --startas <pathname> */
187                         startas = optarg;
188                         break;
189                 case 'n':  /* --name <process-name> */
190                         cmdname = optarg;
191                         break;
192                 case 'o':  /* --oknodo */
193                         exitnodo = 0;
194                         break;
195                 case 'p':  /* --pidfile <pid-file> */
196                         pidfile = optarg;
197                         break;
198                 case 'q':  /* --quiet */
199                         quietmode = 1;
200                         break;
201                 case 's':  /* --signal <signal> */
202                         if (sscanf(optarg, "%d", &signal_nr) != 1)
203                                 badusage("--signal takes a numeric argument");
204                         break;
205                 case 't':  /* --test */
206                         testmode = 1;
207                         break;
208                 case 'u':  /* --user <username>|<uid> */
209                         userspec = optarg;
210                         break;
211                 case 'v':  /* --verbose */
212                         quietmode = -1;
213                         break;
214                 case 'x':  /* --exec <executable> */
215                         execname = optarg;
216                         break;
217                 default:
218                         badusage("");  /* message printed by getopt */
219                 }
220         }
221
222         if (start == stop)
223                 badusage("need one of --start or --stop");
224
225         if (!execname && !pidfile && !userspec)
226                 badusage("need at least one of --exec, --pidfile or --user");
227
228         if (!startas)
229                 startas = execname;
230
231         if (start && !startas)
232                 badusage("--start needs --exec or --startas");
233 }
234
235
236 static int
237 pid_is_exec(int pid, const struct stat *esb)
238 {
239         struct stat sb;
240         char buf[32];
241
242         sprintf(buf, "/proc/%d/exe", pid);
243         if (stat(buf, &sb) != 0)
244                 return 0;
245         return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
246 }
247
248
249 static int
250 pid_is_user(int pid, int uid)
251 {
252         struct stat sb;
253         char buf[32];
254
255         sprintf(buf, "/proc/%d", pid);
256         if (stat(buf, &sb) != 0)
257                 return 0;
258         return (sb.st_uid == uid);
259 }
260
261
262 static int
263 pid_is_cmd(int pid, const char *name)
264 {
265         char buf[32];
266         FILE *f;
267         int c;
268
269         sprintf(buf, "/proc/%d/stat", pid);
270         f = fopen(buf, "r");
271         if (!f)
272                 return 0;
273         while ((c = getc(f)) != EOF && c != '(')
274                 ;
275         if (c != '(') {
276                 fclose(f);
277                 return 0;
278         }
279         /* this hopefully handles command names containing ')' */
280         while ((c = getc(f)) != EOF && c == *name)
281                 name++;
282         fclose(f);
283         return (c == ')' && *name == '\0');
284 }
285
286
287 static void
288 check(int pid)
289 {
290         if (execname && !pid_is_exec(pid, &exec_stat))
291                 return;
292         if (userspec && !pid_is_user(pid, user_id))
293                 return;
294         if (cmdname && !pid_is_cmd(pid, cmdname))
295                 return;
296         push(&found, pid);
297 }
298
299
300 static void
301 do_pidfile(const char *name)
302 {
303         FILE *f;
304         int pid;
305
306         f = fopen(name, "r");
307         if (f) {
308                 if (fscanf(f, "%d", &pid) == 1)
309                         check(pid);
310                 fclose(f);
311         }
312 }
313
314
315 static void
316 do_procfs(void)
317 {
318         DIR *procdir;
319         struct dirent *entry;
320         int foundany, pid;
321
322         procdir = opendir("/proc");
323         if (!procdir)
324                 fatal("opendir /proc: %s", strerror(errno));
325
326         foundany = 0;
327         while ((entry = readdir(procdir)) != NULL) {
328                 if (sscanf(entry->d_name, "%d", &pid) != 1)
329                         continue;
330                 foundany++;
331                 check(pid);
332         }
333         closedir(procdir);
334         if (!foundany)
335                 fatal("nothing in /proc - not mounted?");
336 }
337
338
339 static void
340 do_stop(void)
341 {
342         char what[1024];
343         struct pid_list *p;
344
345         if (cmdname)
346                 strcpy(what, cmdname);
347         else if (execname)
348                 strcpy(what, execname);
349         else if (pidfile)
350                 sprintf(what, "process in pidfile `%s'", pidfile);
351         else if (userspec)
352                 sprintf(what, "process(es) owned by `%s'", userspec);
353         else
354                 fatal("internal error, please report");
355
356         if (!found) {
357                 if (quietmode <= 0)
358                         printf("no %s found; none killed.\n", what);
359                 exit(exitnodo);
360         }
361         for (p = found; p; p = p->next) {
362                 if (testmode)
363                         printf("would send signal %d to %d.\n",
364                                signal_nr, p->pid);
365                 else if (kill(p->pid, signal_nr) == 0)
366                         push(&killed, p->pid);
367                 else
368                         printf("%s: warning: failed to kill %d: %s\n",
369                                progname, p->pid, strerror(errno));
370         }
371         if (quietmode < 0 && killed) {
372                 printf("stopped %s (pid", what);
373                 for (p = killed; p; p = p->next)
374                         printf(" %d", p->pid);
375                 printf(").\n");
376         }
377 }
378
379
380 int
381 main(int argc, char **argv)
382 {
383         progname = argv[0];
384
385         parse_options(argc, argv);
386         argc -= optind;
387         argv += optind;
388
389         if (execname && stat(execname, &exec_stat))
390                 fatal("stat %s: %s", execname, strerror(errno));
391
392         if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
393                 struct passwd *pw;
394
395                 pw = getpwnam(userspec);
396                 if (!pw)
397                         fatal("user `%s' not found\n", userspec);
398
399                 user_id = pw->pw_uid;
400         }
401
402         if (pidfile)
403                 do_pidfile(pidfile);
404         else
405                 do_procfs();
406
407         if (stop) {
408                 do_stop();
409                 exit(0);
410         }
411
412         if (found) {
413                 if (quietmode <= 0)
414                         printf("%s already running.\n", execname);
415                 exit(exitnodo);
416         }
417         if (testmode) {
418                 printf("would start %s ", startas);
419                 while (argc-- > 0)
420                         printf("%s ", *argv++);
421                 printf(".\n");
422                 exit(0);
423         }
424         if (quietmode < 0)
425                 printf("starting %s ...\n", startas);
426         *--argv = startas;
427         execv(startas, argv);
428         fatal("unable to start %s: %s", startas, strerror(errno));
429 }
430