Kannel: Open Source WAP and SMS gateway  svn-r5335
start-stop-daemon.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /* This utility was added to the Kannel source tree for the benefit of
58  * those distributions that aren't Debian. It is used by kannel-init.d
59  * to start and stop the run_kannel_box daemon.
60  * It was copied from the dpkg 1.6.11 source tree on 21 March 2000.
61  * If that was very long ago, refreshing the copy would be a good idea,
62  * in case bugs were fixed.
63  * Richard Braakman
64  */
65 
66 /*
67  * A rewrite of the original Debian's start-stop-daemon Perl script
68  * in C (faster - it is executed many times during system startup).
69  *
70  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
71  * public domain. Based conceptually on start-stop-daemon.pl, by Ian
72  * Jackson <ijackson@gnu.ai.mit.edu>. May be used and distributed
73  * freely for any purpose. Changes by Christian Schwarz
74  * <schwarz@monet.m.isar.de>, to make output conform to the Debian
75  * Console Message Standard, also placed in public domain. Minor
76  * changes by Klee Dienes <klee@debian.org>, also placed in the Public
77  * Domain.
78  *
79  * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
80  * and --make-pidfile options, placed in public domain aswell.
81  */
82 
83 #include "gw-config.h"
84 
85 #if defined(linux)
86 #define OSLinux
87 #elif defined(__GNU__)
88 #define OSHURD
89 #elif defined(SunOS)
90 #elif defined(__CYGWIN__)
91 #elif defined(__FreeBSD__) || defined(__APPLE__)
92 #define FreeBSD
93 #else
94 #error Unknown architecture - cannot build start-stop-daemon
95 #endif
96 
97 #ifdef HAVE_HURH_H
98 #include <hurd.h>
99 #endif
100 #ifdef HAVE_PS_H
101 #include <ps.h>
102 #endif
103 
104 #include <errno.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <stdarg.h>
109 #include <signal.h>
110 #include <sys/stat.h>
111 #include <dirent.h>
112 #include <unistd.h>
113 #if HAVE_GETOPT_H
114 #include <getopt.h>
115 #endif
116 #include <unistd.h>
117 #include <pwd.h>
118 #include <grp.h>
119 #include <sys/ioctl.h>
120 #include <sys/types.h>
121 #include <sys/termios.h>
122 #include <fcntl.h>
123 
124 /*Solaris needs to be told how
125 to talk to it's proc filesystem*/
126 #define _STRUCTURED_PROC 1
127 #ifdef SunOS
128 #include <sys/procfs.h>
129 #endif
130 
131 
132 #ifdef HAVE_ERROR_H
133 #include <error.h>
134 #endif
135 #ifdef HURD_IHASH_H
136 #include <hurd/ihash.h>
137 #endif
138 
139 static int testmode = 0;
140 static int quietmode = 0;
141 static int exitnodo = 1;
142 static int start = 0;
143 static int stop = 0;
144 static int background = 0;
145 static int mpidfile = 0;
146 static int signal_nr = 15;
147 static const char *signal_str = NULL;
148 static int user_id = -1;
149 static int runas_uid = -1;
150 static int runas_gid = -1;
151 static const char *userspec = NULL;
152 static char *changeuser = NULL;
153 static char *changegroup = NULL;
154 static char *changeroot = NULL;
155 static const char *cmdname = NULL;
156 static char *execname = NULL;
157 static char *startas = NULL;
158 static const char *pidfile = NULL;
159 static const char *progname = "";
160 
161 static struct stat exec_stat;
162 #if defined(OSHURD)
163 static struct ps_context *context;
164 static struct proc_stat_list *procset;
165 #endif
166 
167 
168 struct pid_list {
169  struct pid_list *next;
170  int pid;
171 };
172 
173 static struct pid_list *found = NULL;
174 static struct pid_list *killed = NULL;
175 
176 static void *xmalloc(int size);
177 static void push(struct pid_list **list, int pid);
178 static void do_help(void);
179 static void parse_options(int argc, char * const *argv);
180 #if defined(OSLinux) || defined(OSHURD) || defined(SunOS) || defined(FreeBSD)
181 static int pid_is_user(int pid, int uid);
182 static int pid_is_cmd(int pid, const char *name);
183 #endif
184 static void check(int pid);
185 static void do_pidfile(const char *name);
186 static int do_stop(void);
187 #if defined(OSLinux)
188 static int pid_is_exec(int pid, const struct stat *esb);
189 #endif
190 #if defined(OSHURD)
191 static void do_psinit(void);
192 #endif
193 
194 
195 #ifdef __GNUC__
196 static void fatal(const char *format, ...)
197  __attribute__((noreturn, format(printf, 1, 2)));
198 static void badusage(const char *msg)
199  __attribute__((noreturn));
200 #else
201 static void fatal(const char *format, ...);
202 static void badusage(const char *msg);
203 #endif
204 
205 static void
206 fatal(const char *format, ...)
207 {
208  va_list arglist;
209 
210  fprintf(stderr, "%s: ", progname);
211  va_start(arglist, format);
212  vfprintf(stderr, format, arglist);
213  va_end(arglist);
214  putc('\n', stderr);
215  exit(2);
216 }
217 
218 
219 static void *
221 {
222  void *ptr;
223 
224  ptr = malloc(size);
225  if (ptr)
226  return ptr;
227  fatal("malloc(%d) failed", size);
228 }
229 
230 
231 static void
232 push(struct pid_list **list, int pid)
233 {
234  struct pid_list *p;
235 
236  p = xmalloc(sizeof(*p));
237  p->next = *list;
238  p->pid = pid;
239  *list = p;
240 }
241 
242 
243 static void
244 do_help(void)
245 {
246 
247 /*Print the help for systems that have getopt long*/
248 
249 #ifndef SunOS /*Solaris doesn't*/
250 
251  printf("\
252 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
253 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
254 GW_VERSION "\n\
255 \n\
256 Usage:\n\
257  start-stop-daemon -S|--start options ... -- arguments ...\n\
258  start-stop-daemon -K|--stop options ...\n\
259  start-stop-daemon -H|--help\n\
260  start-stop-daemon -V|--version\n\
261 \n\
262 Options (at least one of --exec|--pidfile|--user is required):\n\
263  -x|--exec <executable> program to start/check if it is running\n\
264  -p|--pidfile <pid-file> pid file to check\n\
265  -c|--chuid <name|uid[:group|gid]>\n\
266  change to this user/group before starting process\n\
267  -u|--user <username>|<uid> stop processes owned by this user\n\
268  -n|--name <process-name> stop processes with this name\n\
269  -s|--signal <signal> signal to send (default TERM)\n\
270  -a|--startas <pathname> program to start (default is <executable>)\n\
271  -b|--background force the process to detach\n\
272  -m|--make-pidfile create the pidfile before starting\n\
273  -t|--test test mode, don't do anything\n\
274  -o|--oknodo exit status 0 (not 1) if nothing done\n\
275  -q|--quiet be more quiet\n\
276  -v|--verbose be more verbose\n\
277 \n\
278 Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n");
279 
280 #else /* Deal with systems that don't have getopt long, like Solaris*/
281 
282  printf("\
283 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
284 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
285 GW_VERSION "\n\
286 \n\
287 Usage:\n\
288  start-stop-daemon -S options ... -- arguments ...\n\
289  start-stop-daemon -K options ...\n\
290  start-stop-daemon -H\n\
291  start-stop-daemon -V\n\
292 \n\
293 Options (at least one of --exec|--pidfile|--user is required):\n\
294  -x <executable> program to start/check if it is running\n\
295  -p <pid-file> pid file to check\n\
296  -c <name|uid[:group|gid]> change to this user/group before starting process\n\
297  -u <username>|<uid> stop processes owned by this user\n\
298  -n <process-name> stop processes with this name\n\
299  -s <signal> signal to send (default TERM)\n\
300  -a <pathname> program to start (default is <executable>)\n\
301  -b force the process to detach\n\
302  -m create the pidfile before starting\n\
303  -t test mode, don't do anything\n\
304  -o exit status 0 (not 1) if nothing done\n\
305  -q be more quiet\n\
306  -v be more verbose\n\
307 \n\
308 Exit status: 0 = done 1 = nothing done (=> 0 if -o) 2 = trouble\n");
309 #endif /*No more OS ( getopt ) specific stuff this function... */
310 }
311 
312 
313 static void
314 badusage(const char *msg)
315 {
316  if (msg)
317  fprintf(stderr, "%s: %s\n", progname, msg);
318 
319  #ifndef SunOS
320  fprintf(stderr, "Try `%s --help' for more information.\n", progname);
321  #else
322  fprintf(stderr, "Try `%s -H' for more information.\n", progname);
323  #endif
324 
325  exit(2);
326 }
327 
328 struct sigpair {
329  const char *name;
330  int signal;
331 };
332 
333 static const struct sigpair siglist[] = {
334  { "ABRT", SIGABRT },
335  { "ALRM", SIGALRM },
336  { "FPE", SIGFPE },
337  { "HUP", SIGHUP },
338  { "ILL", SIGILL },
339  { "INT", SIGINT },
340  { "KILL", SIGKILL },
341  { "PIPE", SIGPIPE },
342  { "QUIT", SIGQUIT },
343  { "SEGV", SIGSEGV },
344  { "TERM", SIGTERM },
345  { "USR1", SIGUSR1 },
346  { "USR2", SIGUSR2 },
347  { "CHLD", SIGCHLD },
348  { "CONT", SIGCONT },
349  { "STOP", SIGSTOP },
350  { "TSTP", SIGTSTP },
351  { "TTIN", SIGTTIN },
352  { "TTOU", SIGTTOU }
353 };
354 static int sigcount = sizeof (siglist) / sizeof (siglist[0]);
355 
356 static int parse_signal (const char *signal_str, int *signal_nr)
357 {
358  int i;
359  for (i = 0; i < sigcount; i++) {
360  if (strcmp (signal_str, siglist[i].name) == 0) {
361  *signal_nr = siglist[i].signal;
362  return 0;
363  }
364  }
365  return -1;
366 }
367 
368 static void
369 parse_options(int argc, char * const *argv)
370 {
371 
372 #if HAVE_GETOPT_LONG
373  static struct option longopts[] = {
374  { "help", 0, NULL, 'H'},
375  { "stop", 0, NULL, 'K'},
376  { "start", 0, NULL, 'S'},
377  { "version", 0, NULL, 'V'},
378  { "startas", 1, NULL, 'a'},
379  { "name", 1, NULL, 'n'},
380  { "oknodo", 0, NULL, 'o'},
381  { "pidfile", 1, NULL, 'p'},
382  { "quiet", 0, NULL, 'q'},
383  { "signal", 1, NULL, 's'},
384  { "test", 0, NULL, 't'},
385  { "user", 1, NULL, 'u'},
386  { "chroot", 1, NULL, 'r'},
387  { "verbose", 0, NULL, 'v'},
388  { "exec", 1, NULL, 'x'},
389  { "chuid", 1, NULL, 'c'},
390  { "background", 0, NULL, 'b'},
391  { "make-pidfile", 0, NULL, 'm'},
392  { NULL, 0, NULL, 0}
393  };
394 #endif
395  int c;
396 
397  for (;;) {
398 #if HAVE_GETOPT_LONG
399  c = getopt_long(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm",
400  longopts, (int *) 0);
401 #else
402  c = getopt(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm");
403 #endif
404  if (c == -1)
405  break;
406  switch (c) {
407  case 'H': /* --help */
408  do_help();
409  exit(0);
410  case 'K': /* --stop */
411  stop = 1;
412  break;
413  case 'S': /* --start */
414  start = 1;
415  break;
416  case 'V': /* --version */
417  printf("start-stop-daemon " GW_VERSION "\n");
418  exit(0);
419  case 'a': /* --startas <pathname> */
420  startas = optarg;
421  break;
422  case 'n': /* --name <process-name> */
423  cmdname = optarg;
424  break;
425  case 'o': /* --oknodo */
426  exitnodo = 0;
427  break;
428  case 'p': /* --pidfile <pid-file> */
429  pidfile = optarg;
430  break;
431  case 'q': /* --quiet */
432  quietmode = 1;
433  break;
434  case 's': /* --signal <signal> */
435  signal_str = optarg;
436  break;
437  case 't': /* --test */
438  testmode = 1;
439  break;
440  case 'u': /* --user <username>|<uid> */
441  userspec = optarg;
442  break;
443  case 'v': /* --verbose */
444  quietmode = -1;
445  break;
446  case 'x': /* --exec <executable> */
447  execname = optarg;
448  break;
449  case 'c': /* --chuid <username>|<uid> */
450  /* we copy the string just in case we need the
451  * argument later. */
453  changeuser = strtok(changeuser, ":");
454  changegroup = strtok(NULL, ":");
455  break;
456  case 'r': /* --chroot /new/root */
457  changeroot = optarg;
458  break;
459  case 'b': /* --background */
460  background = 1;
461  break;
462  case 'm': /* --make-pidfile */
463  mpidfile = 1;
464  break;
465  default:
466  badusage(NULL); /* message printed by getopt */
467  }
468  }
469 
470  if (signal_str != NULL) {
471  if (sscanf (signal_str, "%d", &signal_nr) != 1) {
472  if (parse_signal (signal_str, &signal_nr) != 0) {
473  badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)");
474  }
475  }
476  }
477 
478  if (start == stop)
479  #ifndef SunOS
480  badusage("need one of --start or --stop");
481  #else
482  badusage("need one of -S (start) or -K (stop)");
483  #endif
484 
485  if (!execname && !pidfile && !userspec)
486  badusage("need at least one of --exec, --pidfile or --user");
487 
488  if (!startas)
489  startas = execname;
490 
491  if (start && !startas)
492  badusage("--start needs --exec or --startas");
493 
494  if (mpidfile && pidfile == NULL)
495  badusage("--make-pidfile is only relevant with --pidfile");
496 
497  if (background && !start)
498  badusage("--background is only relevant with --start");
499 
500 }
501 
502 #if defined(OSLinux)
503 static int
504 pid_is_exec(int pid, const struct stat *esb)
505 {
506  struct stat sb;
507  char buf[32];
508 
509  sprintf(buf, "/proc/%d/exe", pid);
510  if (stat(buf, &sb) != 0)
511  return 0;
512  return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
513 }
514 
515 
516 static int
517 pid_is_user(int pid, int uid)
518 {
519  struct stat sb;
520  char buf[32];
521 
522  sprintf(buf, "/proc/%d", pid);
523  if (stat(buf, &sb) != 0)
524  return 0;
525  return ((int) sb.st_uid == uid);
526 }
527 
528 
529 static int
530 pid_is_cmd(int pid, const char *name)
531 {
532  char buf[32];
533  FILE *f;
534  int c;
535 
536  sprintf(buf, "/proc/%d/stat", pid);
537  f = fopen(buf, "r");
538  if (!f)
539  return 0;
540  while ((c = getc(f)) != EOF && c != '(')
541  ;
542  if (c != '(') {
543  fclose(f);
544  return 0;
545  }
546  /* this hopefully handles command names containing ')' */
547  while ((c = getc(f)) != EOF && c == *name)
548  name++;
549  fclose(f);
550  return (c == ')' && *name == '\0');
551 }
552 #endif /* OSLinux */
553 
554 #if defined(OSHURD)
555 static int
556 pid_is_user(int pid, int uid)
557 {
558  struct stat sb;
559  char buf[32];
560  struct proc_stat *pstat;
561 
562  sprintf(buf, "/proc/%d", pid);
563  if (stat(buf, &sb) != 0)
564  return 0;
565  return (sb.st_uid == uid);
566  pstat = proc_stat_list_pid_proc_stat (procset, pid);
567  if (pstat == NULL)
568  fatal ("Error getting process information: NULL proc_stat struct");
569  proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID);
570  return (pstat->owner_uid == uid);
571 }
572 
573 static int
574 pid_is_cmd(int pid, const char *name)
575 {
576  struct proc_stat *pstat;
577  pstat = proc_stat_list_pid_proc_stat (procset, pid);
578  if (pstat == NULL)
579  fatal ("Error getting process information: NULL proc_stat struct");
580  proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS);
581  return (!strcmp (name, pstat->args));
582 }
583 #endif /* OSHURD */
584 
585 #if defined(SunOS)
586 /*
587 Lots of lovely system dependant functions for Solaris. I used to like the
588 idea of proc, but now I'm not so sure. It feels to much like a kludge.
589 */
590 
591 /*
592 pid_is_user, takes the pid and a uid, normally ours, but can be someone
593 elses, to allow you to identify the process' owner. returns zero on success,
594 and either true or the uid of the owner on failure (this may be undefined,
595 or I may be misremembering.
596 */
597 static int
598 pid_is_user(int pid, int uid)
599 {
600  struct stat sb;
601  char buf[32];
602 
603  sprintf(buf, "/proc/%d", pid);
604  if (stat(buf, &sb) != 0)
605  return 0; /*I can stat it so it seems to be mine...*/
606  return ((int) sb.st_uid == uid);
607 }
608 
609 /*
610 pid_is_cmd, takes a pid, and a string representing the process' (supposed)
611 name. Compares the process' supposed name with the name reported by the
612 system. Returns zero on failure, and nonzero on success.
613 */
614 static int
615 pid_is_cmd(int pid, const char *name)
616 {
617  char buf[32];
618  FILE *f;
619  psinfo_t pid_info;
620 
621  sprintf(buf, "/proc/%d/psinfo", pid);
622  f = fopen(buf, "r");
623  if (!f)
624  return 0;
625  fread(&pid_info,sizeof(psinfo_t),1,f);
626  return (!strcmp(name,pid_info.pr_fname));
627 }
628 #endif /*SunOS*/
629 
630 #ifdef FreeBSD
631 static int pid_is_user(int pid, int uid)
632 {
633  struct stat sb;
634  char buf[32];
635 
636  sprintf(buf, "/proc/%d", pid);
637  if (stat(buf, &sb) != 0)
638  return 0;
639  return ((int) sb.st_uid == uid);
640 }
641 
642 static int
643 pid_is_cmd(int pid, const char *name)
644 {
645  char buf[32];
646  FILE *f;
647  int c;
648 
649  sprintf(buf, "/proc/%d/stat", pid);
650  f = fopen(buf, "r");
651  if (!f)
652  return 0;
653  while ((c = getc(f)) != EOF && c != '(')
654  ;
655  if (c != '(') {
656  fclose(f);
657  return 0;
658  }
659  /* this hopefully handles command names containing ')' */
660  while ((c = getc(f)) != EOF && c == *name)
661  name++;
662  fclose(f);
663  return (c == ')' && *name == '\0');
664 }
665 #endif /*FreeBSD*/
666 
667 static void
668 check(int pid)
669 {
670 #if defined(OSLinux)
671  if (execname && !pid_is_exec(pid, &exec_stat))
672  return;
673 #elif defined(OSHURD)
674  /* I will try this to see if it works */
675  if (execname && !pid_is_cmd(pid, execname))
676  return;
677 #endif
678  if (userspec && !pid_is_user(pid, user_id))
679  return;
680  if (cmdname && !pid_is_cmd(pid, cmdname))
681  return;
682  push(&found, pid);
683 }
684 
685 
686 static void
687 do_pidfile(const char *name)
688 {
689  FILE *f;
690  int pid;
691 
692  f = fopen(name, "r");
693  if (f) {
694  if (fscanf(f, "%d", &pid) == 1)
695  check(pid);
696  fclose(f);
697  }
698 }
699 
700 /* WTA: this needs to be an autoconf check for /proc/pid existance.
701  */
702 #if defined(OSLinux) || defined (SunOS) || defined(FreeBSD)
703 static void
704 do_procinit(void)
705 {
706  DIR *procdir;
707  struct dirent *entry;
708  int foundany, pid;
709 
710  procdir = opendir("/proc");
711  if (!procdir)
712  fatal("opendir /proc: %s", strerror(errno));
713 
714  foundany = 0;
715  while ((entry = readdir(procdir)) != NULL) {
716  if (sscanf(entry->d_name, "%d", &pid) != 1)
717  continue;
718  foundany++;
719  check(pid);
720  }
721  closedir(procdir);
722  if (!foundany)
723  fatal("nothing in /proc - not mounted?");
724 }
725 #endif /* OSLinux */
726 
727 
728 #if defined(OSHURD)
729 error_t
730 check_all (void *ptr)
731 {
732  struct proc_stat *pstat = ptr;
733 
734  check (pstat->pid);
735  return (0);
736 }
737 
738 static void
739 do_psinit(void)
740  error_t err;
741 
742  err = ps_context_create (getproc (), &context);
743  if (err)
744  error (1, err, "ps_context_create");
745 
746  err = proc_stat_list_create (context, &procset);
747  if (err)
748  error (1, err, "proc_stat_list_create");
749 
750  err = proc_stat_list_add_all (procset, 0, 0);
751  if (err)
752  error (1, err, "proc_stat_list_add_all");
753 
754  /* Check all pids */
755  ihash_iterate (context->procs, check_all);
756 }
757 #endif /* OSHURD */
758 
759 /* return 1 on failure */
760 static int
761 do_stop(void)
762 {
763  char what[1024];
764  struct pid_list *p;
765  int retval = 0;
766 
767  if (cmdname)
768  strcpy(what, cmdname);
769  else if (execname)
770  strcpy(what, execname);
771  else if (pidfile)
772  sprintf(what, "process in pidfile `%s'", pidfile);
773  else if (userspec)
774  sprintf(what, "process(es) owned by `%s'", userspec);
775  else
776  fatal("internal error, please report");
777 
778  if (!found) {
779  if (quietmode <= 0)
780  printf("No %s found running; none killed.\n", what);
781  exit(exitnodo);
782  }
783  for (p = found; p; p = p->next) {
784  if (testmode)
785  printf("Would send signal %d to %d.\n",
786  signal_nr, p->pid);
787  else if (kill(p->pid, signal_nr) == 0)
788  push(&killed, p->pid);
789  else {
790  printf("%s: warning: failed to kill %d: %s\n",
791  progname, p->pid, strerror(errno));
792  retval += exitnodo;
793  }
794  }
795  if (quietmode < 0 && killed) {
796  printf("Stopped %s (pid", what);
797  for (p = killed; p; p = p->next)
798  printf(" %d", p->pid);
799  printf(").\n");
800  }
801  return retval;
802 }
803 
804 
805 int
806 main(int argc, char **argv)
807 {
808  progname = argv[0];
809 
810  parse_options(argc, argv);
811  argc -= optind;
812  argv += optind;
813 
814  if (execname && stat(execname, &exec_stat))
815  fatal("stat %s: %s", execname, strerror(errno));
816 
817  if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
818  struct passwd *pw;
819 
820  pw = getpwnam(userspec);
821  if (!pw)
822  fatal("user `%s' not found\n", userspec);
823 
824  user_id = pw->pw_uid;
825  }
826 
827  if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
828  struct group *gr = getgrnam(changegroup);
829  if (!gr)
830  fatal("group `%s' not found\n", changegroup);
831  runas_gid = gr->gr_gid;
832  }
833  if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
834  struct passwd *pw = getpwnam(changeuser);
835  if (!pw)
836  fatal("user `%s' not found\n", changeuser);
837  runas_uid = pw->pw_uid;
838  if (changegroup == NULL) { /* pass the default group of this user */
839  changegroup = ""; /* just empty */
840  runas_gid = pw->pw_gid;
841  }
842  }
843 
844  if (pidfile)
846  else
847  do_procinit();
848 
849  if (stop) {
850  int i = do_stop();
851  if (i) {
852  if (quietmode <= 0)
853  printf("%d pids were not killed\n", i);
854  exit(1);
855  }
856  exit(0);
857  }
858 
859  if (found) {
860  if (quietmode <= 0)
861  printf("%s already running.\n", execname);
862  exit(exitnodo);
863  }
864  if (testmode) {
865  printf("Would start %s ", startas);
866  while (argc-- > 0)
867  printf("%s ", *argv++);
868  if (changeuser != NULL) {
869  printf(" (as user %s[%d]", changeuser, runas_uid);
870  if (changegroup != NULL)
871  printf(", and group %s[%d])", changegroup, runas_gid);
872  else
873  printf(")");
874  }
875  if (changeroot != NULL)
876  printf(" in directory %s", changeroot);
877  printf(".\n");
878  exit(0);
879  }
880  if (quietmode < 0)
881  printf("Starting %s...\n", startas);
882  *--argv = startas;
883  if (changeroot != NULL) {
884  if (chdir(changeroot) < 0)
885  fatal("Unable to chdir() to %s", changeroot);
886  if (chroot(changeroot) < 0)
887  fatal("Unable to chroot() to %s", changeroot);
888  }
889  if (changeuser != NULL) {
890  if (setgid(runas_gid))
891  fatal("Unable to set gid to %d", runas_gid);
892  if (initgroups(changeuser, runas_gid))
893  fatal("Unable to set initgroups() with gid %d", runas_gid);
894  if (setuid(runas_uid))
895  fatal("Unable to set uid to %s", changeuser);
896  }
897 
898  if (background) { /* ok, we need to detach this process */
899  int i, fd;
900  if (quietmode < 0)
901  printf("Detatching to start %s...", startas);
902  i = fork();
903  if (i<0) {
904  fatal("Unable to fork.\n");
905  }
906  if (i) { /* parent */
907  if (quietmode < 0)
908  printf("done.\n");
909  exit(0);
910  }
911  /* child continues here */
912  /* now close all extra fds */
913  for (i=getdtablesize()-1; i>=0; --i) close(i);
914  /* change tty */
915  fd = open("/dev/tty", O_RDWR);
916  ioctl(fd, TIOCNOTTY, 0);
917  close(fd);
918  chdir("/");
919  umask(022); /* set a default for dumb programs */
920 #ifdef DARWIN
921  setpgrp(); /* set the process group */
922 #else
923 #ifndef FreeBSD
924  setpgrp(); /* set the process group */
925 #else
926  setpgrp(0, runas_gid); /* set the process group */
927 #endif
928 #endif
929 
930  fd=open("/dev/null", O_RDWR); /* stdin */
931  dup(fd); /* stdout */
932  dup(fd); /* stderr */
933  }
934  if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
935  FILE *pidf = fopen(pidfile, "w");
936  pid_t pidt = getpid();
937  if (pidf == NULL)
938  fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
939  strerror(errno));
940  fprintf(pidf, "%d\n", (int)pidt);
941  fclose(pidf);
942  }
943  execv(startas, argv);
944  fatal("Unable to start %s: %s", startas, strerror(errno));
945 }
static char * startas
void error(int err, const char *fmt,...)
Definition: log.c:648
static char * changegroup
int size
Definition: wsasm.c:84
static const char * signal_str
static int sigcount
static struct stat exec_stat
static const char * progname
Definition: parse.c:65
static const char * pidfile
static void push(struct pid_list **list, int pid)
int optind
Definition: attgetopt.c:80
static void do_pidfile(const char *name)
static char * changeuser
void * malloc(YYSIZE_T)
static struct pid_list * found
static struct pid_list * killed
static void parse_options(int argc, char *const *argv)
static void badusage(const char *msg)
static int mpidfile
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
static int runas_uid
#define strdup(p)
Definition: gwmem.h:195
static int exitnodo
static int quietmode
static const struct sigpair siglist[]
const char * name
static int stop
static int runas_gid
struct pid_list * next
char * name
Definition: smsc_cimd2.c:212
static void do_help(void)
static const char * cmdname
static int do_stop(void)
unsigned char * option
Definition: test_cimd2.c:1000
static void * xmalloc(int size)
static char * changeroot
int main(int argc, char **argv)
char * optarg
Definition: attgetopt.c:82
static int background
static int testmode
static int user_id
static int parse_signal(const char *signal_str, int *signal_nr)
static char * execname
static const char * userspec
static int signal_nr
static void fatal(const char *format,...)
static void check(int pid)
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int start
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.