Kannel: Open Source WAP and SMS gateway  svn-r5335
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>

Go to the source code of this file.

Macros

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

Functions

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

Variables

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

Macro Definition Documentation

◆ NUM_EXTRA

#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

◆ build_box_arglist()

static 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, progname, and use_extra_args.

Referenced by main().

97 {
98  int i;
99  char **argp;
100 
101  if (box_arglist) {
102  free(box_arglist);
103  }
104 
105  /* one for the boxfile name itself, one for each extra argument,
106  * one for each normal argument, and one for the terminating NULL */
107  box_arglist = malloc((1 + NUM_EXTRA + argc + 1) * sizeof(*box_arglist));
108  if (!box_arglist) {
109  fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
110  exit(1);
111  }
112 
113  /* Have argp walk down box_arglist and set each argument. */
114  argp = box_arglist;
115 
116  *argp++ = boxfile;
117  if (use_extra_args) {
118  for (i = 0; i < NUM_EXTRA; i++) {
119  *argp++ = extra_arguments[i];
120  }
121  }
122  for (i = 0; i < argc; i++) {
123  *argp++ = argv[i];
124  }
125  *argp++ = (char *)NULL;
126 }
void * malloc(YYSIZE_T)
#define NUM_EXTRA
static char * extra_arguments[]
static char ** box_arglist
static char * progname
void free(void *)
static int use_extra_args

◆ close_extra_files()

static void close_extra_files ( void  )
static

Definition at line 209 of file run_kannel_box.c.

References open_max().

Referenced by main().

210 {
211  int max = open_max();
212  int fd;
213 
214  for (fd = 3; fd < max; fd++) {
215  close(fd);
216  }
217 }
static int open_max(void)

◆ main()

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().

308 {
309  int i;
310  char *boxfile = NULL;
311  pid_t childpid;
312 
313  progname = argv[0];
314 
315  if (argc == 1) {
316  print_usage(stderr);
317  exit(2);
318  }
319 
320  /* Parse the options meant for the wrapper, and get the name of
321  * the box to wrap. */
322  for (i = 1; i < argc && !boxfile; i++) {
323  if (strcmp(argv[i], "--pidfile") == 0) {
324  if (i+1 >= argc) {
325  fprintf(stderr, "Missing argument for option %s\n", argv[i]);
326  exit(2);
327  }
328  pidfile = argv[i+1];
329  i++;
330  } else if (strcmp(argv[i], "--min-delay") == 0) {
331  if (i+1 >= argc) {
332  fprintf(stderr, "Missing argument for option %s", argv[i]);
333  exit(2);
334  }
335  min_restart_delay = atoi(argv[i+1]);
336  i++;
337  } else if (strcmp(argv[i], "--no-extra-args") == 0) {
338  use_extra_args = 0;
339  } else if (argv[i][0] == '-') {
340  fprintf(stderr, "Unknown option %s\n", argv[i]);
341  exit(2);
342  } else {
343  boxfile = argv[i];
344  }
345  }
346 
347  /* Check if we have everything */
348  if (!boxfile) {
349  print_usage(stderr);
350  exit(2);
351  }
352 
353  /* The remaining arguments should be passed to the box */
354  build_box_arglist(boxfile, argc - i, argv + i);
355 
356  /* Ready to rock. Begin daemonization. */
357 
358  /* Fork a child process and have the parent exit.
359  * This makes us run in the background. */
360  childpid = fork();
361  if (childpid < 0) {
362  fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
363  exit(1);
364  }
365  if (childpid != 0) {
366  exit(0); /* parent exits immediately */
367  }
368 
369  /* The child continues here. Now call setsid() to disconnect
370  * from our terminal and from the parent's session and process
371  * group. */
372  if (setsid() < 0) {
373  fprintf(stderr, "%s: setsid: %s\n", progname, strerror(errno));
374  exit(1);
375  }
376 
377  /* Change to the root directory, so that we don't keep a
378  * file descriptor open on an unknown directory. */
379  if (chdir("/") < 0) {
380  fprintf(stderr, "%s: chdir to root: %s\n", progname, strerror(errno));
381  exit(1);
382  }
383 
384  atexit(remove_pidfile);
385  write_pidfile();
386 
387  /* Set the umask to a known value, rather than inheriting
388  * an unknown one. */
389  umask(077);
390 
391  /* Leave file descriptors 0, 1, and 2 pointing to harmless
392  * places, and close all other file descriptors. */
395 
396  setup_signals();
397  return main_loop(boxfile);
398 }
static void rebind_standard_streams(void)
static void remove_pidfile(void)
static char * pidfile
static void setup_signals(void)
static int main_loop(char *boxfile)
static char * progname
static void close_extra_files(void)
static int use_extra_args
static void print_usage(FILE *stream)
static void write_pidfile(void)
static void build_box_arglist(char *boxfile, int argc, char **argv)
static int min_restart_delay

◆ main_loop()

static int main_loop ( char *  boxfile)
static

Definition at line 262 of file run_kannel_box.c.

References box_arglist, child_box, and min_restart_delay.

Referenced by main().

263 {
264  time_t next_fork = 0;
265 
266  /* We can't report any errors here, because we are running
267  * as a daemon and we have no logfile of our own. So we
268  * exit with errno as the exit code, to offer a minimal clue. */
269 
270  for (;;) {
271 
272  /* Make sure we don't fork in an endless loop if something
273  * is drastically wrong. This code limits it to one
274  * per minute (or whatever min_restart_delay is set to). */
275  time_t this_time = time(NULL);
276  if (this_time <= next_fork) {
277  sleep(next_fork - this_time);
278  }
279  next_fork = this_time + min_restart_delay;
280 
281  child_box = fork();
282  if (child_box < 0) {
283  return errno;
284  }
285  if (child_box == 0) {
286  /* child. exec the box */
287  execvp(boxfile, box_arglist);
288  exit(127);
289  }
290 
291  while (waitpid(child_box, (int *)NULL, 0) != child_box) {
292  if (errno == ECHILD) {
293  /* Something went wrong... we don't know what,
294  * but we do know that our child does not
295  * exist. So restart it. */
296  break;
297  }
298  if (errno == EINTR) {
299  continue;
300  }
301  /* Something weird happened. */
302  return errno;
303  }
304  }
305 }
static pid_t child_box
static char ** box_arglist
static int min_restart_delay

◆ open_max()

static int open_max ( void  )
static

Definition at line 193 of file run_kannel_box.c.

Referenced by close_extra_files().

194 {
195 #ifdef OPEN_MAX
196  return OPEN_MAX;
197 #else
198  int max;
199 
200  max = sysconf(_SC_OPEN_MAX);
201  if (max <= 0) {
202  return 1024; /* guess */
203  }
204  return max;
205 #endif
206 }

◆ print_usage()

static void print_usage ( FILE *  stream)
static

Definition at line 86 of file run_kannel_box.c.

References progname.

Referenced by main().

87 {
88  fprintf(stream,
89  "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]\n",
90  progname);
91 }
static char * progname

◆ rebind_standard_streams()

static void rebind_standard_streams ( void  )
static

Definition at line 165 of file run_kannel_box.c.

References progname.

Referenced by main().

166 {
167  int devnullfd;
168  int devfullfd;
169 
170  devnullfd = open("/dev/null", O_RDONLY);
171  if (devnullfd < 0) {
172  fprintf(stderr, "%s: cannot open /dev/null: %s\n",
173  progname, strerror(errno));
174  exit(2);
175  }
176  devfullfd = open("/dev/full", O_WRONLY);
177  if (devfullfd < 0) {
178  devfullfd = devnullfd;
179  }
180 
181  /* Alert: The dup on stderr is done last, so that the error message
182  * works regardless of which dup fails. */
183  if (dup2(devnullfd, 0) < 0 ||
184  dup2(devfullfd, 1) < 0 ||
185  dup2(devfullfd, 2) < 0) {
186  fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno));
187  exit(1);
188  }
189 }
static char * progname

◆ remove_pidfile()

static 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().

156 {
157  if (!pidfile)
158  return;
159 
160  unlink(pidfile);
161 }
static char * pidfile

◆ setup_signals()

static 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().

251 {
252  signal(SIGHUP, &signal_transfer);
253  signal(SIGINT, &signal_transfer_and_die);
254  signal(SIGQUIT, &signal_transfer_and_die);
255  signal(SIGTERM, &signal_transfer_and_die);
256  signal(SIGUSR1, &signal_transfer);
257  signal(SIGUSR2, &signal_transfer);
258 }
static void signal_transfer(int signum)
static void signal_transfer_and_die(int signum)

◆ signal_transfer()

static void signal_transfer ( int  signum)
static

Definition at line 221 of file run_kannel_box.c.

References child_box.

Referenced by setup_signals().

222 {
223  if (child_box > 0) {
224  kill(child_box, signum);
225  }
226 }
static pid_t child_box

◆ signal_transfer_and_die()

static 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().

232 {
233  /* First send it to the child process */
234  if (child_box > 0) {
235  kill(child_box, signum);
236  }
237 
238  /* Prepare to die. Normally the atexit handler would take care
239  * of this when we exit(), but we're going to die from a signal. */
240  remove_pidfile();
241 
242  /* Then send it to self. First set the default handler, to
243  * avoid catching the signal with this handler again. This
244  * is not a race, because it doesn't matter if we die from
245  * the signal we're going to send or from a different one. */
246  signal(signum, SIG_DFL);
247  kill(getpid(), signum);
248 }
static void remove_pidfile(void)
static pid_t child_box

◆ write_pidfile()

static void write_pidfile ( void  )
static

Definition at line 128 of file run_kannel_box.c.

References pidfile, and progname.

Referenced by main().

129 {
130  int fd;
131  FILE *f;
132 
133  if (!pidfile)
134  return;
135 
136  fd = open(pidfile, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT, 0644);
137  if (fd < 0) {
138  fprintf(stderr, "%s: open: %s: %s\n", progname, pidfile, strerror(errno));
139  exit(1);
140  }
141 
142  f = fdopen(fd, "w");
143  if (!f) {
144  fprintf(stderr, "%s: fdopen: %s\n", progname, strerror(errno));
145  exit(1);
146  }
147 
148  fprintf(f, "%ld\n", (long)getpid());
149  if (fclose(f) < 0) {
150  fprintf(stderr, "%s: writing %s: %s\n", progname, pidfile, strerror(errno));
151  exit(1);
152  }
153 }
static char * pidfile
static char * progname

Variable Documentation

◆ box_arglist

char** box_arglist
static

Definition at line 74 of file run_kannel_box.c.

Referenced by build_box_arglist(), and main_loop().

◆ child_box

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().

◆ extra_arguments

char* extra_arguments[]
static
Initial value:
= {
"-v", "4",
}

Definition at line 81 of file run_kannel_box.c.

Referenced by build_box_arglist().

◆ min_restart_delay

int min_restart_delay = 60
static

Definition at line 75 of file run_kannel_box.c.

Referenced by main(), and main_loop().

◆ pidfile

char* pidfile
static

Definition at line 77 of file run_kannel_box.c.

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

◆ progname

char* progname
static

◆ use_extra_args

int use_extra_args = 1
static

Definition at line 78 of file run_kannel_box.c.

Referenced by build_box_arglist(), and main().

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