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

start-stop-daemon.c File Reference

#include "gw-config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <pwd.h>
#include <grp.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/termios.h>
#include <fcntl.h>

Include dependency graph for start-stop-daemon.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  pid_list
struct  sigpair

Defines

#define _STRUCTURED_PROC   1

Functions

void * xmalloc (int size)
void push (struct pid_list **list, int pid)
void do_help (void)
void parse_options (int argc, char *const *argv)
void check (int pid)
void do_pidfile (const char *name)
int do_stop (void)
void fatal (const char *format,...)
void badusage (const char *msg)
int parse_signal (const char *signal_str, int *signal_nr)
int main (int argc, char **argv)

Variables

int testmode = 0
int quietmode = 0
int exitnodo = 1
int start = 0
int stop = 0
int background = 0
int mpidfile = 0
int signal_nr = 15
const char * signal_str = NULL
int user_id = -1
int runas_uid = -1
int runas_gid = -1
const char * userspec = NULL
char * changeuser = NULL
char * changegroup = NULL
char * changeroot = NULL
const char * cmdname = NULL
char * execname = NULL
char * startas = NULL
const char * pidfile = NULL
const char * progname = ""
stat exec_stat
pid_listfound = NULL
pid_listkilled = NULL
const struct sigpair siglist []
int sigcount = sizeof (siglist) / sizeof (siglist[0])


Define Documentation

#define _STRUCTURED_PROC   1
 

Definition at line 126 of file start-stop-daemon.c.


Function Documentation

void badusage const char *  msg  )  [static]
 

Definition at line 314 of file start-stop-daemon.c.

References progname.

Referenced by parse_options().

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 }

void check int  pid  )  [static]
 

Definition at line 668 of file start-stop-daemon.c.

References cmdname, exec_stat, execname, found, push(), user_id, and userspec.

Referenced by do_pidfile().

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 }

Here is the call graph for this function:

void do_help void   )  [static]
 

Definition at line 244 of file start-stop-daemon.c.

References GW_VERSION.

Referenced by parse_options().

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 }

void do_pidfile const char *  name  )  [static]
 

Definition at line 687 of file start-stop-daemon.c.

References check(), and name.

Referenced by main().

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 }

Here is the call graph for this function:

int do_stop void   )  [static]
 

Definition at line 761 of file start-stop-daemon.c.

References cmdname, execname, exitnodo, fatal(), killed, pid_list::next, pid_list::pid, pidfile, progname, push(), quietmode, signal_nr, and userspec.

Referenced by main().

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 }

Here is the call graph for this function:

void fatal const char *  format,
  ...
[static]
 

Definition at line 206 of file start-stop-daemon.c.

References progname.

Referenced by do_stop(), main(), and xmalloc().

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 }

int main int  argc,
char **  argv
 

Definition at line 806 of file start-stop-daemon.c.

References changegroup, changeroot, changeuser, do_pidfile(), do_stop(), exec_stat, execname, exitnodo, fatal(), mpidfile, parse_options(), pidfile, progname, quietmode, runas_gid, runas_uid, startas, user_id, and userspec.

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 }

Here is the call graph for this function:

void parse_options int  argc,
char *const *  argv
[static]
 

Definition at line 369 of file start-stop-daemon.c.

References background, badusage(), changegroup, changeroot, changeuser, cmdname, do_help(), execname, exitnodo, getopt(), GW_VERSION, mpidfile, optarg, option, parse_signal(), pidfile, quietmode, signal_nr, signal_str, start, startas, stop, testmode, and userspec.

Referenced by main().

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 }

Here is the call graph for this function:

int parse_signal const char *  signal_str,
int *  signal_nr
[static]
 

Definition at line 356 of file start-stop-daemon.c.

References name, siglist, sigpair::signal, signal_nr, and signal_str.

Referenced by parse_options().

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 }

void push struct pid_list **  list,
int  pid
[static]
 

Definition at line 232 of file start-stop-daemon.c.

References pid_list::next, pid_list::pid, and xmalloc().

Referenced by check(), and do_stop().

00233 {
00234     struct pid_list *p;
00235 
00236     p = xmalloc(sizeof(*p));
00237     p->next = *list;
00238     p->pid = pid;
00239     *list = p;
00240 }

Here is the call graph for this function:

void * xmalloc int  size  )  [static]
 

Definition at line 220 of file start-stop-daemon.c.

References fatal(), malloc, and size.

Referenced by push().

00221 {
00222     void *ptr;
00223 
00224     ptr = malloc(size);
00225     if (ptr)
00226         return ptr;
00227     fatal("malloc(%d) failed", size);
00228 }

Here is the call graph for this function:


Variable Documentation

int background = 0 [static]
 

Definition at line 144 of file start-stop-daemon.c.

Referenced by parse_options().

char* changegroup = NULL [static]
 

Definition at line 153 of file start-stop-daemon.c.

Referenced by main(), and parse_options().

char* changeroot = NULL [static]
 

Definition at line 154 of file start-stop-daemon.c.

Referenced by main(), and parse_options().

char* changeuser = NULL [static]
 

Definition at line 152 of file start-stop-daemon.c.

Referenced by main(), and parse_options().

const char* cmdname = NULL [static]
 

Definition at line 155 of file start-stop-daemon.c.

Referenced by check(), do_stop(), and parse_options().

struct stat exec_stat [static]
 

Definition at line 161 of file start-stop-daemon.c.

Referenced by check(), and main().

char* execname = NULL [static]
 

Definition at line 156 of file start-stop-daemon.c.

Referenced by check(), do_stop(), main(), and parse_options().

int exitnodo = 1 [static]
 

Definition at line 141 of file start-stop-daemon.c.

Referenced by do_stop(), main(), and parse_options().

struct pid_list* found = NULL [static]
 

Definition at line 173 of file start-stop-daemon.c.

Referenced by check().

struct pid_list* killed = NULL [static]
 

Definition at line 174 of file start-stop-daemon.c.

Referenced by do_stop().

int mpidfile = 0 [static]
 

Definition at line 145 of file start-stop-daemon.c.

Referenced by main(), and parse_options().

const char* pidfile = NULL [static]
 

Definition at line 158 of file start-stop-daemon.c.

Referenced by do_stop(), main(), and parse_options().

const char* progname = "" [static]
 

Definition at line 159 of file start-stop-daemon.c.

int quietmode = 0 [static]
 

Definition at line 140 of file start-stop-daemon.c.

Referenced by do_stop(), main(), and parse_options().

int runas_gid = -1 [static]
 

Definition at line 150 of file start-stop-daemon.c.

Referenced by main().

int runas_uid = -1 [static]
 

Definition at line 149 of file start-stop-daemon.c.

Referenced by main().

int sigcount = sizeof (siglist) / sizeof (siglist[0]) [static]
 

Definition at line 354 of file start-stop-daemon.c.

const struct sigpair siglist[] [static]
 

Initial value:

 {
    { "ABRT", SIGABRT },
    { "ALRM", SIGALRM },
    { "FPE", SIGFPE },
    { "HUP", SIGHUP },
    { "ILL", SIGILL },
    { "INT", SIGINT },
    { "KILL", SIGKILL },
    { "PIPE", SIGPIPE },
    { "QUIT", SIGQUIT },
    { "SEGV", SIGSEGV },
    { "TERM", SIGTERM },
    { "USR1", SIGUSR1 },
    { "USR2", SIGUSR2 },
    { "CHLD", SIGCHLD },
    { "CONT", SIGCONT },
    { "STOP", SIGSTOP },
    { "TSTP", SIGTSTP },
    { "TTIN", SIGTTIN },
    { "TTOU", SIGTTOU }
}

Definition at line 333 of file start-stop-daemon.c.

Referenced by parse_signal().

int signal_nr = 15 [static]
 

Definition at line 146 of file start-stop-daemon.c.

Referenced by do_stop(), parse_options(), and parse_signal().

const char* signal_str = NULL [static]
 

Definition at line 147 of file start-stop-daemon.c.

Referenced by parse_options(), and parse_signal().

int start = 0 [static]
 

Definition at line 142 of file start-stop-daemon.c.

Referenced by parse_options().

char* startas = NULL [static]
 

Definition at line 157 of file start-stop-daemon.c.

Referenced by main(), and parse_options().

int stop = 0 [static]
 

Definition at line 143 of file start-stop-daemon.c.

Referenced by parse_options().

int testmode = 0 [static]
 

Definition at line 139 of file start-stop-daemon.c.

Referenced by parse_options().

int user_id = -1 [static]
 

Definition at line 148 of file start-stop-daemon.c.

Referenced by check(), and main().

const char* userspec = NULL [static]
 

Definition at line 151 of file start-stop-daemon.c.

Referenced by check(), do_stop(), main(), and parse_options().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.