Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

start-stop-daemon.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /* This utility was added to the Kannel source tree for the benefit of
00058  * those distributions that aren't Debian.  It is used by kannel-init.d
00059  * to start and stop the run_kannel_box daemon. 
00060  * It was copied from the dpkg 1.6.11 source tree on 21 March 2000.
00061  * If that was very long ago, refreshing the copy would be a good idea,
00062  * in case bugs were fixed.
00063  * Richard Braakman
00064  */
00065 
00066 /*
00067  * A rewrite of the original Debian's start-stop-daemon Perl script
00068  * in C (faster - it is executed many times during system startup).
00069  *
00070  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
00071  * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
00072  * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
00073  * freely for any purpose.  Changes by Christian Schwarz
00074  * <schwarz@monet.m.isar.de>, to make output conform to the Debian
00075  * Console Message Standard, also placed in public domain.  Minor
00076  * changes by Klee Dienes <klee@debian.org>, also placed in the Public
00077  * Domain.
00078  *
00079  * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
00080  * and --make-pidfile options, placed in public domain aswell.
00081  */
00082 
00083 #include "gw-config.h"
00084 
00085 #if defined(linux)
00086 #define OSLinux
00087 #elif defined(__GNU__)
00088 #define OSHURD
00089 #elif defined(SunOS)
00090 #elif defined(__CYGWIN__)
00091 #elif defined(__FreeBSD__) || defined(__APPLE__)
00092 #define FreeBSD
00093 #else
00094 #error Unknown architecture - cannot build start-stop-daemon
00095 #endif
00096 
00097 #ifdef HAVE_HURH_H
00098 #include <hurd.h>
00099 #endif
00100 #ifdef HAVE_PS_H
00101 #include <ps.h>
00102 #endif
00103 
00104 #include <errno.h>
00105 #include <stdio.h>
00106 #include <stdlib.h>
00107 #include <string.h>
00108 #include <stdarg.h>
00109 #include <signal.h>
00110 #include <sys/stat.h>
00111 #include <dirent.h>
00112 #include <unistd.h>
00113 #if HAVE_GETOPT_H
00114 #include <getopt.h>
00115 #endif
00116 #include <unistd.h>
00117 #include <pwd.h>
00118 #include <grp.h>
00119 #include <sys/ioctl.h>
00120 #include <sys/types.h>
00121 #include <sys/termios.h>
00122 #include <fcntl.h>
00123 
00124 /*Solaris needs to be told how
00125 to talk to it's proc filesystem*/
00126 #define _STRUCTURED_PROC 1
00127 #ifdef SunOS
00128 #include <sys/procfs.h>
00129 #endif
00130 
00131 
00132 #ifdef HAVE_ERROR_H
00133 #include <error.h>
00134 #endif
00135 #ifdef HURD_IHASH_H
00136 #include <hurd/ihash.h>
00137 #endif
00138 
00139 static int testmode = 0;
00140 static int quietmode = 0;
00141 static int exitnodo = 1;
00142 static int start = 0;
00143 static int stop = 0;
00144 static int background = 0;
00145 static int mpidfile = 0;
00146 static int signal_nr = 15;
00147 static const char *signal_str = NULL;
00148 static int user_id = -1;
00149 static int runas_uid = -1;
00150 static int runas_gid = -1;
00151 static const char *userspec = NULL;
00152 static char *changeuser = NULL;
00153 static char *changegroup = NULL;
00154 static char *changeroot = NULL;
00155 static const char *cmdname = NULL;
00156 static char *execname = NULL;
00157 static char *startas = NULL;
00158 static const char *pidfile = NULL;
00159 static const char *progname = "";
00160 
00161 static struct stat exec_stat;
00162 #if defined(OSHURD)
00163 static struct ps_context *context;
00164 static struct proc_stat_list *procset;
00165 #endif
00166 
00167 
00168 struct pid_list {
00169     struct pid_list *next;
00170     int pid;
00171 };
00172 
00173 static struct pid_list *found = NULL;
00174 static struct pid_list *killed = NULL;
00175 
00176 static void *xmalloc(int size);
00177 static void push(struct pid_list **list, int pid);
00178 static void do_help(void);
00179 static void parse_options(int argc, char * const *argv);
00180 #if defined(OSLinux) || defined(OSHURD) || defined(SunOS) || defined(FreeBSD)
00181 static int pid_is_user(int pid, int uid);
00182 static int pid_is_cmd(int pid, const char *name);
00183 #endif
00184 static void check(int pid);
00185 static void do_pidfile(const char *name);
00186 static int do_stop(void);
00187 #if defined(OSLinux)
00188 static int pid_is_exec(int pid, const struct stat *esb);
00189 #endif
00190 #if defined(OSHURD)
00191 static void do_psinit(void);
00192 #endif
00193 
00194 
00195 #ifdef __GNUC__
00196 static void fatal(const char *format, ...)
00197     __attribute__((noreturn, format(printf, 1, 2)));
00198 static void badusage(const char *msg)
00199     __attribute__((noreturn));
00200 #else
00201 static void fatal(const char *format, ...);
00202 static void badusage(const char *msg);
00203 #endif
00204 
00205 static void
00206 fatal(const char *format, ...)
00207 {
00208     va_list arglist;
00209 
00210     fprintf(stderr, "%s: ", progname);
00211     va_start(arglist, format);
00212     vfprintf(stderr, format, arglist);
00213     va_end(arglist);
00214     putc('\n', stderr);
00215     exit(2);
00216 }
00217 
00218 
00219 static void *
00220 xmalloc(int size)
00221 {
00222     void *ptr;
00223 
00224     ptr = malloc(size);
00225     if (ptr)
00226         return ptr;
00227     fatal("malloc(%d) failed", size);
00228 }
00229 
00230 
00231 static void
00232 push(struct pid_list **list, int pid)
00233 {
00234     struct pid_list *p;
00235 
00236     p = xmalloc(sizeof(*p));
00237     p->next = *list;
00238     p->pid = pid;
00239     *list = p;
00240 }
00241 
00242 
00243 static void
00244 do_help(void)
00245 {
00246 
00247 /*Print the help for systems that have getopt long*/
00248 
00249 #ifndef SunOS     /*Solaris doesn't*/
00250 
00251     printf("\
00252 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
00253 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
00254 GW_VERSION "\n\
00255 \n\
00256 Usage:\n\
00257   start-stop-daemon -S|--start options ... -- arguments ...\n\
00258   start-stop-daemon -K|--stop options ...\n\
00259   start-stop-daemon -H|--help\n\
00260   start-stop-daemon -V|--version\n\
00261 \n\
00262 Options (at least one of --exec|--pidfile|--user is required):\n\
00263   -x|--exec <executable>        program to start/check if it is running\n\
00264   -p|--pidfile <pid-file>       pid file to check\n\
00265   -c|--chuid <name|uid[:group|gid]>\n\
00266         change to this user/group before starting process\n\
00267   -u|--user <username>|<uid>    stop processes owned by this user\n\
00268   -n|--name <process-name>      stop processes with this name\n\
00269   -s|--signal <signal>          signal to send (default TERM)\n\
00270   -a|--startas <pathname>       program to start (default is <executable>)\n\
00271   -b|--background               force the process to detach\n\
00272   -m|--make-pidfile             create the pidfile before starting\n\
00273   -t|--test                     test mode, don't do anything\n\
00274   -o|--oknodo                   exit status 0 (not 1) if nothing done\n\
00275   -q|--quiet                    be more quiet\n\
00276   -v|--verbose                  be more verbose\n\
00277 \n\
00278 Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = trouble\n");
00279 
00280 #else /* Deal with systems that don't have getopt long, like Solaris*/
00281 
00282     printf("\
00283 start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\
00284 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
00285 GW_VERSION "\n\
00286 \n\
00287 Usage:\n\
00288   start-stop-daemon -S options ... -- arguments ...\n\
00289   start-stop-daemon -K options ...\n\
00290   start-stop-daemon -H\n\
00291   start-stop-daemon -V\n\
00292 \n\
00293 Options (at least one of --exec|--pidfile|--user is required):\n\
00294   -x <executable>               program to start/check if it is running\n\
00295   -p <pid-file>                 pid file to check\n\
00296   -c <name|uid[:group|gid]>     change to this user/group before starting process\n\
00297   -u <username>|<uid>           stop processes owned by this user\n\
00298   -n <process-name>             stop processes with this name\n\
00299   -s <signal>                   signal to send (default TERM)\n\
00300   -a <pathname>                 program to start (default is <executable>)\n\
00301   -b                            force the process to detach\n\
00302   -m                            create the pidfile before starting\n\
00303   -t                            test mode, don't do anything\n\
00304   -o                            exit status 0 (not 1) if nothing done\n\
00305   -q                            be more quiet\n\
00306   -v                            be more verbose\n\
00307 \n\
00308 Exit status:  0 = done  1 = nothing done (=> 0 if -o)  2 = trouble\n");
00309 #endif   /*No more OS ( getopt ) specific stuff this function... */
00310 }
00311 
00312 
00313 static void
00314 badusage(const char *msg)
00315 {
00316     if (msg)
00317         fprintf(stderr, "%s: %s\n", progname, msg);
00318 
00319     #ifndef SunOS
00320     fprintf(stderr, "Try `%s --help' for more information.\n", progname);
00321     #else
00322     fprintf(stderr, "Try `%s -H' for more information.\n", progname);
00323     #endif
00324 
00325     exit(2);
00326 }
00327 
00328 struct sigpair {
00329     const char *name;
00330     int signal;
00331 };
00332 
00333 static const struct sigpair siglist[] = {
00334     { "ABRT", SIGABRT },
00335     { "ALRM", SIGALRM },
00336     { "FPE", SIGFPE },
00337     { "HUP", SIGHUP },
00338     { "ILL", SIGILL },
00339     { "INT", SIGINT },
00340     { "KILL", SIGKILL },
00341     { "PIPE", SIGPIPE },
00342     { "QUIT", SIGQUIT },
00343     { "SEGV", SIGSEGV },
00344     { "TERM", SIGTERM },
00345     { "USR1", SIGUSR1 },
00346     { "USR2", SIGUSR2 },
00347     { "CHLD", SIGCHLD },
00348     { "CONT", SIGCONT },
00349     { "STOP", SIGSTOP },
00350     { "TSTP", SIGTSTP },
00351     { "TTIN", SIGTTIN },
00352     { "TTOU", SIGTTOU }
00353 };
00354 static int sigcount = sizeof (siglist) / sizeof (siglist[0]);
00355 
00356 static int parse_signal (const char *signal_str, int *signal_nr)
00357 {
00358     int i;
00359     for (i = 0; i < sigcount; i++) {
00360         if (strcmp (signal_str, siglist[i].name) == 0) {
00361             *signal_nr = siglist[i].signal;
00362             return 0;
00363         }
00364     }
00365     return -1;
00366 }
00367 
00368 static void
00369 parse_options(int argc, char * const *argv)
00370 {
00371 
00372 #if HAVE_GETOPT_LONG
00373     static struct option longopts[] = {
00374         { "help",     0, NULL, 'H'},
00375         { "stop",     0, NULL, 'K'},
00376         { "start",    0, NULL, 'S'},
00377         { "version",      0, NULL, 'V'},
00378         { "startas",      1, NULL, 'a'},
00379         { "name",     1, NULL, 'n'},
00380         { "oknodo",   0, NULL, 'o'},
00381         { "pidfile",      1, NULL, 'p'},
00382         { "quiet",    0, NULL, 'q'},
00383         { "signal",   1, NULL, 's'},
00384         { "test",     0, NULL, 't'},
00385         { "user",     1, NULL, 'u'},
00386         { "chroot",   1, NULL, 'r'},
00387         { "verbose",      0, NULL, 'v'},
00388         { "exec",     1, NULL, 'x'},
00389         { "chuid",    1, NULL, 'c'},
00390         { "background",   0, NULL, 'b'},
00391         { "make-pidfile", 0, NULL, 'm'},
00392         { NULL,     0, NULL, 0}
00393     };
00394 #endif
00395     int c;
00396 
00397     for (;;) {
00398 #if HAVE_GETOPT_LONG
00399         c = getopt_long(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm",
00400                 longopts, (int *) 0);
00401 #else
00402         c = getopt(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm");
00403 #endif
00404         if (c == -1)
00405             break;
00406         switch (c) {
00407         case 'H':  /* --help */
00408             do_help();
00409             exit(0);
00410         case 'K':  /* --stop */
00411             stop = 1;
00412             break;
00413         case 'S':  /* --start */
00414             start = 1;
00415             break;
00416         case 'V':  /* --version */
00417             printf("start-stop-daemon " GW_VERSION "\n");
00418             exit(0);
00419         case 'a':  /* --startas <pathname> */
00420             startas = optarg;
00421             break;
00422         case 'n':  /* --name <process-name> */
00423             cmdname = optarg;
00424             break;
00425         case 'o':  /* --oknodo */
00426             exitnodo = 0;
00427             break;
00428         case 'p':  /* --pidfile <pid-file> */
00429             pidfile = optarg;
00430             break;
00431         case 'q':  /* --quiet */
00432             quietmode = 1;
00433             break;
00434         case 's':  /* --signal <signal> */
00435             signal_str = optarg;
00436             break;
00437         case 't':  /* --test */
00438             testmode = 1;
00439             break;
00440         case 'u':  /* --user <username>|<uid> */
00441             userspec = optarg;
00442             break;
00443         case 'v':  /* --verbose */
00444             quietmode = -1;
00445             break;
00446         case 'x':  /* --exec <executable> */
00447             execname = optarg;
00448             break;
00449         case 'c':  /* --chuid <username>|<uid> */
00450             /* we copy the string just in case we need the
00451              * argument later. */
00452             changeuser = strdup(optarg);
00453             changeuser = strtok(changeuser, ":");
00454             changegroup = strtok(NULL, ":");
00455             break;
00456         case 'r':  /* --chroot /new/root */
00457             changeroot = optarg;
00458             break;
00459         case 'b':  /* --background */
00460             background = 1;
00461             break;
00462         case 'm':  /* --make-pidfile */
00463             mpidfile = 1;
00464             break;
00465         default:
00466             badusage(NULL);  /* message printed by getopt */
00467         }
00468     }
00469 
00470     if (signal_str != NULL) {
00471         if (sscanf (signal_str, "%d", &signal_nr) != 1) {
00472             if (parse_signal (signal_str, &signal_nr) != 0) {
00473                 badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)");
00474             }
00475         }   
00476     }
00477 
00478     if (start == stop)
00479         #ifndef SunOS
00480         badusage("need one of --start or --stop");
00481         #else
00482         badusage("need one of -S (start) or -K (stop)");
00483         #endif
00484 
00485     if (!execname && !pidfile && !userspec)
00486         badusage("need at least one of --exec, --pidfile or --user");
00487 
00488     if (!startas)
00489         startas = execname;
00490 
00491     if (start && !startas)
00492         badusage("--start needs --exec or --startas");
00493 
00494     if (mpidfile && pidfile == NULL)
00495         badusage("--make-pidfile is only relevant with --pidfile");
00496 
00497     if (background && !start)
00498         badusage("--background is only relevant with --start");
00499 
00500 }
00501 
00502 #if defined(OSLinux)
00503 static int
00504 pid_is_exec(int pid, const struct stat *esb)
00505 {
00506     struct stat sb;
00507     char buf[32];
00508 
00509     sprintf(buf, "/proc/%d/exe", pid);
00510     if (stat(buf, &sb) != 0)
00511         return 0;
00512     return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
00513 }
00514 
00515 
00516 static int
00517 pid_is_user(int pid, int uid)
00518 {
00519     struct stat sb;
00520     char buf[32];
00521 
00522     sprintf(buf, "/proc/%d", pid);
00523     if (stat(buf, &sb) != 0)
00524         return 0;
00525     return ((int) sb.st_uid == uid);
00526 }
00527 
00528 
00529 static int
00530 pid_is_cmd(int pid, const char *name)
00531 {
00532     char buf[32];
00533     FILE *f;
00534     int c;
00535 
00536     sprintf(buf, "/proc/%d/stat", pid);
00537     f = fopen(buf, "r");
00538     if (!f)
00539         return 0;
00540     while ((c = getc(f)) != EOF && c != '(')
00541         ;
00542     if (c != '(') {
00543         fclose(f);
00544         return 0;
00545     }
00546     /* this hopefully handles command names containing ')' */
00547     while ((c = getc(f)) != EOF && c == *name)
00548         name++;
00549     fclose(f);
00550     return (c == ')' && *name == '\0');
00551 }
00552 #endif /* OSLinux */
00553 
00554 #if defined(OSHURD)
00555 static int
00556 pid_is_user(int pid, int uid)
00557 {
00558    struct stat sb;
00559    char buf[32];
00560    struct proc_stat *pstat;
00561 
00562    sprintf(buf, "/proc/%d", pid);
00563    if (stat(buf, &sb) != 0)
00564        return 0;
00565    return (sb.st_uid == uid);
00566    pstat = proc_stat_list_pid_proc_stat (procset, pid);
00567    if (pstat == NULL)
00568        fatal ("Error getting process information: NULL proc_stat struct");
00569    proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID);
00570    return (pstat->owner_uid == uid);
00571 }
00572 
00573 static int
00574 pid_is_cmd(int pid, const char *name)
00575 {
00576    struct proc_stat *pstat;
00577    pstat = proc_stat_list_pid_proc_stat (procset, pid);
00578    if (pstat == NULL)
00579        fatal ("Error getting process information: NULL proc_stat struct");
00580    proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS);
00581    return (!strcmp (name, pstat->args));
00582 }
00583 #endif /* OSHURD */
00584 
00585 #if defined(SunOS)
00586 /*
00587 Lots of lovely system dependant functions for Solaris.  I used to like the
00588 idea of proc, but now I'm not so sure.  It feels to much like a kludge.
00589 */
00590 
00591 /*
00592 pid_is_user, takes the pid and a uid, normally ours, but can be someone
00593 elses, to allow you to identify the process' owner. returns zero on success,
00594 and either true or the uid of the owner on failure (this may be undefined,
00595 or I may be misremembering.
00596 */
00597 static int
00598 pid_is_user(int pid, int uid)
00599 {
00600    struct stat sb;
00601    char buf[32];
00602 
00603    sprintf(buf, "/proc/%d", pid);
00604    if (stat(buf, &sb) != 0)
00605       return 0; /*I can stat it so it seems to be mine...*/
00606    return ((int) sb.st_uid == uid);
00607 }
00608 
00609 /*
00610 pid_is_cmd, takes a pid, and a string representing the process' (supposed)
00611 name.  Compares the process' supposed name with the name reported by the
00612 system.  Returns zero on failure, and nonzero on success.
00613 */
00614 static int
00615 pid_is_cmd(int pid, const char *name)
00616 {
00617    char buf[32];
00618    FILE *f;
00619    psinfo_t pid_info;
00620 
00621    sprintf(buf, "/proc/%d/psinfo", pid);
00622    f = fopen(buf, "r");
00623    if (!f)
00624       return 0;
00625    fread(&pid_info,sizeof(psinfo_t),1,f);
00626    return (!strcmp(name,pid_info.pr_fname));
00627 }
00628 #endif /*SunOS*/
00629 
00630 #ifdef FreeBSD
00631 static int pid_is_user(int pid, int uid)
00632 {
00633  struct stat sb;
00634  char buf[32];
00635 
00636  sprintf(buf, "/proc/%d", pid);
00637  if (stat(buf, &sb) != 0)
00638   return 0;
00639  return ((int) sb.st_uid == uid);
00640 }
00641 
00642 static int
00643 pid_is_cmd(int pid, const char *name)
00644 {
00645     char buf[32];
00646     FILE *f;
00647     int c;
00648 
00649     sprintf(buf, "/proc/%d/stat", pid);
00650     f = fopen(buf, "r");
00651     if (!f)
00652         return 0;
00653     while ((c = getc(f)) != EOF && c != '(')
00654         ;
00655     if (c != '(') {
00656         fclose(f);
00657         return 0;
00658     }
00659     /* this hopefully handles command names containing ')' */
00660     while ((c = getc(f)) != EOF && c == *name)
00661         name++;
00662     fclose(f);
00663     return (c == ')' && *name == '\0');
00664 }
00665 #endif /*FreeBSD*/
00666 
00667 static void
00668 check(int pid)
00669 {
00670 #if defined(OSLinux)
00671     if (execname && !pid_is_exec(pid, &exec_stat))
00672         return;
00673 #elif defined(OSHURD)
00674     /* I will try this to see if it works */
00675     if (execname && !pid_is_cmd(pid, execname))
00676         return;
00677 #endif
00678     if (userspec && !pid_is_user(pid, user_id))
00679         return;
00680     if (cmdname && !pid_is_cmd(pid, cmdname))
00681         return;
00682     push(&found, pid);
00683 }
00684 
00685 
00686 static void
00687 do_pidfile(const char *name)
00688 {
00689     FILE *f;
00690     int pid;
00691 
00692     f = fopen(name, "r");
00693     if (f) {
00694         if (fscanf(f, "%d", &pid) == 1)
00695             check(pid);
00696         fclose(f);
00697     }
00698 }
00699 
00700 /* WTA: this  needs to be an autoconf check for /proc/pid existance.
00701  */
00702 #if defined(OSLinux) || defined (SunOS) || defined(FreeBSD)
00703 static void
00704 do_procinit(void)
00705 {
00706     DIR *procdir;
00707     struct dirent *entry;
00708     int foundany, pid;
00709 
00710     procdir = opendir("/proc");
00711     if (!procdir)
00712         fatal("opendir /proc: %s", strerror(errno));
00713 
00714     foundany = 0;
00715     while ((entry = readdir(procdir)) != NULL) {
00716         if (sscanf(entry->d_name, "%d", &pid) != 1)
00717             continue;
00718         foundany++;
00719         check(pid);
00720     }
00721     closedir(procdir);
00722     if (!foundany)
00723         fatal("nothing in /proc - not mounted?");
00724 }
00725 #endif /* OSLinux */
00726 
00727 
00728 #if defined(OSHURD)
00729 error_t
00730 check_all (void *ptr)
00731 {
00732    struct proc_stat *pstat = ptr;
00733 
00734    check (pstat->pid);
00735    return (0);
00736 }
00737 
00738 static void
00739 do_psinit(void)
00740    error_t err;
00741 
00742    err = ps_context_create (getproc (), &context);
00743    if (err)
00744        error (1, err, "ps_context_create");
00745 
00746    err = proc_stat_list_create (context, &procset);
00747    if (err)
00748        error (1, err, "proc_stat_list_create");
00749 
00750    err = proc_stat_list_add_all (procset, 0, 0);
00751    if (err)
00752        error (1, err, "proc_stat_list_add_all");
00753 
00754    /* Check all pids */
00755    ihash_iterate (context->procs, check_all);
00756 }
00757 #endif /* OSHURD */
00758 
00759 /* return 1 on failure */
00760 static int
00761 do_stop(void)
00762 {
00763     char what[1024];
00764     struct pid_list *p;
00765     int retval = 0;
00766 
00767     if (cmdname)
00768         strcpy(what, cmdname);
00769     else if (execname)
00770         strcpy(what, execname);
00771     else if (pidfile)
00772         sprintf(what, "process in pidfile `%s'", pidfile);
00773     else if (userspec)
00774         sprintf(what, "process(es) owned by `%s'", userspec);
00775     else
00776         fatal("internal error, please report");
00777 
00778     if (!found) {
00779         if (quietmode <= 0)
00780             printf("No %s found running; none killed.\n", what);
00781         exit(exitnodo);
00782     }
00783     for (p = found; p; p = p->next) {
00784         if (testmode)
00785             printf("Would send signal %d to %d.\n",
00786                    signal_nr, p->pid);
00787         else if (kill(p->pid, signal_nr) == 0)
00788             push(&killed, p->pid);
00789         else {
00790             printf("%s: warning: failed to kill %d: %s\n",
00791                    progname, p->pid, strerror(errno));
00792             retval += exitnodo;
00793         }
00794     }
00795     if (quietmode < 0 && killed) {
00796         printf("Stopped %s (pid", what);
00797         for (p = killed; p; p = p->next)
00798             printf(" %d", p->pid);
00799         printf(").\n");
00800     }
00801     return retval;
00802 }
00803 
00804 
00805 int
00806 main(int argc, char **argv)
00807 {
00808     progname = argv[0];
00809 
00810     parse_options(argc, argv);
00811     argc -= optind;
00812     argv += optind;
00813 
00814     if (execname && stat(execname, &exec_stat))
00815         fatal("stat %s: %s", execname, strerror(errno));
00816 
00817     if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
00818         struct passwd *pw;
00819 
00820         pw = getpwnam(userspec);
00821         if (!pw)
00822             fatal("user `%s' not found\n", userspec);
00823 
00824         user_id = pw->pw_uid;
00825     }
00826     
00827     if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
00828         struct group *gr = getgrnam(changegroup);
00829         if (!gr)
00830             fatal("group `%s' not found\n", changegroup);
00831         runas_gid = gr->gr_gid;
00832     }
00833     if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
00834         struct passwd *pw = getpwnam(changeuser);
00835         if (!pw)
00836             fatal("user `%s' not found\n", changeuser);
00837         runas_uid = pw->pw_uid;
00838         if (changegroup == NULL) { /* pass the default group of this user */
00839             changegroup = ""; /* just empty */
00840             runas_gid = pw->pw_gid;
00841         }
00842     }
00843 
00844     if (pidfile)
00845         do_pidfile(pidfile);
00846     else
00847         do_procinit();
00848 
00849     if (stop) {
00850         int i = do_stop();
00851         if (i) {
00852             if (quietmode <= 0)
00853                 printf("%d pids were not killed\n", i);
00854             exit(1);
00855         }
00856         exit(0);
00857     }
00858 
00859     if (found) {
00860         if (quietmode <= 0)
00861             printf("%s already running.\n", execname);
00862         exit(exitnodo);
00863     }
00864     if (testmode) {
00865         printf("Would start %s ", startas);
00866         while (argc-- > 0)
00867             printf("%s ", *argv++);
00868         if (changeuser != NULL) {
00869             printf(" (as user %s[%d]", changeuser, runas_uid);
00870             if (changegroup != NULL)
00871                 printf(", and group %s[%d])", changegroup, runas_gid);
00872             else
00873                 printf(")");
00874         }
00875         if (changeroot != NULL)
00876             printf(" in directory %s", changeroot);
00877         printf(".\n");
00878         exit(0);
00879     }
00880     if (quietmode < 0)
00881         printf("Starting %s...\n", startas);
00882     *--argv = startas;
00883     if (changeroot != NULL) {
00884         if (chdir(changeroot) < 0)
00885             fatal("Unable to chdir() to %s", changeroot);
00886         if (chroot(changeroot) < 0)
00887             fatal("Unable to chroot() to %s", changeroot);
00888     }
00889     if (changeuser != NULL) {
00890         if (setgid(runas_gid))
00891             fatal("Unable to set gid to %d", runas_gid);
00892         if (initgroups(changeuser, runas_gid))
00893             fatal("Unable to set initgroups() with gid %d", runas_gid);
00894         if (setuid(runas_uid))
00895             fatal("Unable to set uid to %s", changeuser);
00896     }
00897     
00898     if (background) { /* ok, we need to detach this process */
00899         int i, fd;
00900         if (quietmode < 0)
00901             printf("Detatching to start %s...", startas);
00902         i = fork();
00903         if (i<0) {
00904             fatal("Unable to fork.\n");
00905         }
00906         if (i) { /* parent */
00907             if (quietmode < 0)
00908                 printf("done.\n");
00909             exit(0);
00910         }
00911          /* child continues here */
00912          /* now close all extra fds */
00913         for (i=getdtablesize()-1; i>=0; --i) close(i);
00914          /* change tty */
00915         fd = open("/dev/tty", O_RDWR);
00916         ioctl(fd, TIOCNOTTY, 0);
00917         close(fd);
00918         chdir("/");
00919         umask(022); /* set a default for dumb programs */
00920 #ifndef FreeBSD
00921         setpgrp();  /* set the process group */
00922 #else
00923         setpgrp(0, runas_gid);  /* set the process group */
00924 #endif
00925         fd=open("/dev/null", O_RDWR); /* stdin */
00926         dup(fd); /* stdout */
00927         dup(fd); /* stderr */
00928     }
00929     if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
00930         FILE *pidf = fopen(pidfile, "w");
00931         pid_t pidt = getpid();
00932         if (pidf == NULL)
00933             fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
00934                 strerror(errno));
00935         fprintf(pidf, "%d\n", (int)pidt);
00936         fclose(pidf);
00937     }
00938     execv(startas, argv);
00939     fatal("Unable to start %s: %s", startas, strerror(errno));
00940 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.