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

run_kannel_box.c File Reference

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

Include dependency graph for run_kannel_box.c:

Include dependency graph

Go to the source code of this file.

Defines

#define NUM_EXTRA   ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments)))

Functions

void print_usage (FILE *stream)
void build_box_arglist (char *boxfile, int argc, char **argv)
void write_pidfile (void)
void remove_pidfile (void)
void rebind_standard_streams (void)
int open_max (void)
void close_extra_files (void)
void signal_transfer (int signum)
void signal_transfer_and_die (int signum)
void setup_signals (void)
int main_loop (char *boxfile)
int main (int argc, char *argv[])

Variables

char * progname
char ** box_arglist
int min_restart_delay = 60
pid_t child_box
char * pidfile
int use_extra_args = 1
char * extra_arguments []


Define Documentation

#define NUM_EXTRA   ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments)))
 

Definition at line 84 of file run_kannel_box.c.

Referenced by build_box_arglist().


Function Documentation

void build_box_arglist char *  boxfile,
int  argc,
char **  argv
[static]
 

Definition at line 96 of file run_kannel_box.c.

References box_arglist, extra_arguments, free, malloc, NUM_EXTRA, and progname.

Referenced by main().

00097 {
00098     int i;
00099     char **argp;
00100 
00101     if (box_arglist) {
00102         free(box_arglist);
00103     }
00104 
00105     /* one for the boxfile name itself, one for each extra argument,
00106      * one for each normal argument, and one for the terminating NULL */
00107     box_arglist = malloc((1 + NUM_EXTRA + argc + 1) * sizeof(*box_arglist));
00108     if (!box_arglist) {
00109         fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
00110         exit(1);
00111     }
00112 
00113     /* Have argp walk down box_arglist and set each argument. */
00114     argp = box_arglist;
00115 
00116     *argp++ = boxfile;
00117         if (use_extra_args) {
00118         for (i = 0; i < NUM_EXTRA; i++) {
00119             *argp++ = extra_arguments[i];
00120         }
00121     }
00122     for (i = 0; i < argc; i++) {
00123         *argp++ = argv[i];
00124     }
00125     *argp++ = (char *)NULL;
00126 }

void close_extra_files void   )  [static]
 

Definition at line 209 of file run_kannel_box.c.

References open_max().

Referenced by main().

00210 {
00211     int max = open_max();
00212     int fd;
00213 
00214     for (fd = 3; fd < max; fd++) {
00215         close(fd);
00216     }
00217 }

Here is the call graph for this function:

int main int  argc,
char *  argv[]
 

Definition at line 307 of file run_kannel_box.c.

References build_box_arglist(), close_extra_files(), main_loop(), min_restart_delay, pidfile, print_usage(), progname, rebind_standard_streams(), remove_pidfile(), setup_signals(), use_extra_args, and write_pidfile().

00308 {
00309     int i;
00310     char *boxfile = NULL;
00311     pid_t childpid;
00312 
00313     progname = argv[0];
00314 
00315     if (argc == 1) {
00316         print_usage(stderr);
00317         exit(2);
00318     }
00319 
00320     /* Parse the options meant for the wrapper, and get the name of
00321      * the box to wrap. */
00322     for (i = 1; i < argc && !boxfile; i++) {
00323         if (strcmp(argv[i], "--pidfile") == 0) {
00324             if (i+1 >= argc) {
00325                 fprintf(stderr, "Missing argument for option %s\n", argv[i]);
00326                 exit(2);
00327             }
00328             pidfile = argv[i+1];
00329             i++;
00330         } else if (strcmp(argv[i], "--min-delay") == 0) {
00331             if (i+1 >= argc) {
00332                 fprintf(stderr, "Missing argument for option %s", argv[i]);
00333                 exit(2);
00334             }
00335             min_restart_delay = atoi(argv[i+1]);
00336             i++;
00337         } else if (strcmp(argv[i], "--no-extra-args") == 0) {
00338                 use_extra_args = 0;
00339         } else if (argv[i][0] == '-') {
00340             fprintf(stderr, "Unknown option %s\n", argv[i]);
00341             exit(2);
00342         } else {
00343             boxfile = argv[i];
00344         }
00345     }
00346 
00347     /* Check if we have everything */
00348     if (!boxfile) {
00349         print_usage(stderr);
00350         exit(2);
00351     }
00352 
00353     /* The remaining arguments should be passed to the box */
00354     build_box_arglist(boxfile, argc - i, argv + i);
00355 
00356     /* Ready to rock.  Begin daemonization. */
00357 
00358     /* Fork a child process and have the parent exit.
00359          * This makes us run in the background. */
00360     childpid = fork();
00361     if (childpid < 0) {
00362         fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
00363         exit(1);
00364     }
00365     if (childpid != 0) {
00366         exit(0); /* parent exits immediately */
00367     }
00368     
00369     /* The child continues here.  Now call setsid() to disconnect
00370      * from our terminal and from the parent's session and process
00371      * group. */
00372     if (setsid() < 0) {
00373         fprintf(stderr, "%s: setsid: %s\n", progname, strerror(errno));
00374         exit(1);
00375     }
00376 
00377     /* Change to the root directory, so that we don't keep a
00378      * file descriptor open on an unknown directory. */
00379     if (chdir("/") < 0) {
00380         fprintf(stderr, "%s: chdir to root: %s\n", progname, strerror(errno));
00381         exit(1);
00382     }
00383 
00384     atexit(remove_pidfile);
00385     write_pidfile();
00386 
00387     /* Set the umask to a known value, rather than inheriting
00388      * an unknown one. */
00389     umask(077);
00390 
00391     /* Leave file descriptors 0, 1, and 2 pointing to harmless
00392      * places, and close all other file descriptors. */
00393     rebind_standard_streams();
00394     close_extra_files();
00395 
00396     setup_signals();
00397     return main_loop(boxfile);
00398 }

Here is the call graph for this function:

int main_loop char *  boxfile  )  [static]
 

Definition at line 262 of file run_kannel_box.c.

References box_arglist, and child_box.

00263 {
00264     time_t next_fork = 0;
00265 
00266     /* We can't report any errors here, because we are running
00267      * as a daemon and we have no logfile of our own.  So we
00268      * exit with errno as the exit code, to offer a minimal clue. */
00269 
00270     for (;;) {
00271 
00272         /* Make sure we don't fork in an endless loop if something
00273          * is drastically wrong.  This code limits it to one
00274          * per minute (or whatever min_restart_delay is set to). */
00275         time_t this_time = time(NULL);
00276         if (this_time <= next_fork) {
00277             sleep(next_fork - this_time);
00278         }
00279         next_fork = this_time + min_restart_delay;
00280 
00281         child_box = fork();
00282         if (child_box < 0) {
00283             return errno;
00284         }
00285         if (child_box == 0) {
00286             /* child.  exec the box */
00287             execvp(boxfile, box_arglist);
00288             exit(127);
00289         }
00290         
00291         while (waitpid(child_box, (int *)NULL, 0) != child_box) {
00292             if (errno == ECHILD) {
00293                 /* Something went wrong... we don't know what,
00294                  * but we do know that our child does not
00295                  * exist.  So restart it. */
00296                 break;
00297             }
00298             if (errno == EINTR) {
00299                 continue;
00300             }
00301             /* Something weird happened. */
00302             return errno;
00303         }
00304     }
00305 }

int open_max void   )  [static]
 

Definition at line 193 of file run_kannel_box.c.

Referenced by close_extra_files().

00194 {
00195 #ifdef OPEN_MAX
00196     return OPEN_MAX;
00197 #else
00198     int max;
00199 
00200     max = sysconf(_SC_OPEN_MAX);
00201     if (max <= 0) {
00202         return 1024;  /* guess */
00203     }
00204     return max;
00205 #endif
00206 }

void print_usage FILE *  stream  )  [static]
 

Definition at line 86 of file run_kannel_box.c.

References progname.

Referenced by main().

00087 {
00088     fprintf(stream,
00089         "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]\n",
00090         progname);
00091 }

void rebind_standard_streams void   )  [static]
 

Definition at line 165 of file run_kannel_box.c.

References progname.

Referenced by main().

00166 {
00167     int devnullfd;
00168     int devfullfd;
00169 
00170     devnullfd = open("/dev/null", O_RDONLY);
00171     if (devnullfd < 0) {
00172         fprintf(stderr, "%s: cannot open /dev/null: %s\n",
00173             progname, strerror(errno));
00174         exit(2);
00175     }
00176     devfullfd = open("/dev/full", O_WRONLY);
00177     if (devfullfd < 0) {
00178         devfullfd = devnullfd;
00179     }
00180 
00181     /* Alert: The dup on stderr is done last, so that the error message
00182      * works regardless of which dup fails. */
00183     if (dup2(devnullfd, 0) < 0 ||
00184         dup2(devfullfd, 1) < 0 ||
00185         dup2(devfullfd, 2) < 0) {
00186         fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno));
00187         exit(1);
00188     }
00189 }

void remove_pidfile void   )  [static]
 

Definition at line 155 of file run_kannel_box.c.

References pidfile.

Referenced by main(), and signal_transfer_and_die().

00156 {
00157     if (!pidfile)
00158         return;
00159 
00160     unlink(pidfile);
00161 }

void setup_signals void   )  [static]
 

Definition at line 250 of file run_kannel_box.c.

References signal_transfer(), and signal_transfer_and_die().

Referenced by main().

00251 {
00252     signal(SIGHUP, &signal_transfer);
00253     signal(SIGINT, &signal_transfer_and_die);
00254     signal(SIGQUIT, &signal_transfer_and_die);
00255     signal(SIGTERM, &signal_transfer_and_die);
00256     signal(SIGUSR1, &signal_transfer);
00257     signal(SIGUSR2, &signal_transfer);
00258 }

Here is the call graph for this function:

void signal_transfer int  signum  )  [static]
 

Definition at line 221 of file run_kannel_box.c.

References child_box.

Referenced by setup_signals().

00222 {
00223     if (child_box > 0) {
00224         kill(child_box, signum);
00225     }
00226 }

void signal_transfer_and_die int  signum  )  [static]
 

Definition at line 231 of file run_kannel_box.c.

References child_box, and remove_pidfile().

Referenced by setup_signals().

00232 {
00233     /* First send it to the child process */
00234     if (child_box > 0) {
00235         kill(child_box, signum);
00236     }
00237 
00238     /* Prepare to die.  Normally the atexit handler would take care
00239      * of this when we exit(), but we're going to die from a signal. */
00240     remove_pidfile();
00241 
00242     /* Then send it to self.  First set the default handler, to
00243      * avoid catching the signal with this handler again.  This
00244      * is not a race, because it doesn't matter if we die from
00245      * the signal we're going to send or from a different one.  */
00246     signal(signum, SIG_DFL);
00247     kill(getpid(), signum);
00248 }

Here is the call graph for this function:

void write_pidfile void   )  [static]
 

Definition at line 128 of file run_kannel_box.c.

References pidfile, and progname.

Referenced by main().

00129 {
00130     int fd;
00131     FILE *f;
00132 
00133     if (!pidfile)
00134         return;
00135 
00136     fd = open(pidfile, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT, 0644);
00137     if (fd < 0) {
00138         fprintf(stderr, "%s: open: %s: %s\n", progname, pidfile, strerror(errno));
00139         exit(1);
00140     }
00141 
00142     f = fdopen(fd, "w");
00143     if (!f) {
00144         fprintf(stderr, "%s: fdopen: %s\n", progname, strerror(errno));
00145         exit(1);
00146     }
00147 
00148     fprintf(f, "%ld\n", (long)getpid());
00149     if (fclose(f) < 0) {
00150         fprintf(stderr, "%s: writing %s: %s\n", progname, pidfile, strerror(errno));
00151         exit(1);
00152     }
00153 }


Variable Documentation

char** box_arglist [static]
 

Definition at line 74 of file run_kannel_box.c.

Referenced by build_box_arglist(), and main_loop().

pid_t child_box [static]
 

Definition at line 76 of file run_kannel_box.c.

Referenced by main_loop(), signal_transfer(), and signal_transfer_and_die().

char* extra_arguments[] [static]
 

Initial value:

 {
    "-v", "4",   
}

Definition at line 81 of file run_kannel_box.c.

Referenced by build_box_arglist().

int min_restart_delay = 60 [static]
 

Definition at line 75 of file run_kannel_box.c.

Referenced by main().

char* pidfile [static]
 

Definition at line 77 of file run_kannel_box.c.

Referenced by main(), remove_pidfile(), and write_pidfile().

char* progname [static]
 

Definition at line 73 of file run_kannel_box.c.

int use_extra_args = 1 [static]
 

Definition at line 78 of file run_kannel_box.c.

Referenced by main().

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