📄 run_kannel_box.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #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>static char *progname; /* The name of this program (for error messages) */static char **box_arglist;static int min_restart_delay = 60; /* in seconds */static pid_t child_box; /* used in main_loop, available to signal handlers */static char *pidfile; /* The name of the pidfile to use. NULL if no pidfile */static int use_extra_args = 1; /* Add "extra_arguments" list to argv? *//* Extra arguments to pass to the box */static char *extra_arguments[] = { "-v", "4", /* Minimal output on stderr, goes to /dev/null anyway */};#define NUM_EXTRA ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments)))static void print_usage(FILE *stream){ fprintf(stream, "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]\n", progname);}/* Create the argument list to pass to the box process, and put it * in the box_arglist global variable. This is also the right place * to add any standard arguments that we want to pass. */static void build_box_arglist(char *boxfile, int argc, char **argv){ int i; char **argp; if (box_arglist) { free(box_arglist); } /* one for the boxfile name itself, one for each extra argument, * one for each normal argument, and one for the terminating NULL */ box_arglist = malloc((1 + NUM_EXTRA + argc + 1) * sizeof(*box_arglist)); if (!box_arglist) { fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno)); exit(1); } /* Have argp walk down box_arglist and set each argument. */ argp = box_arglist; *argp++ = boxfile; if (use_extra_args) { for (i = 0; i < NUM_EXTRA; i++) { *argp++ = extra_arguments[i]; } } for (i = 0; i < argc; i++) { *argp++ = argv[i]; } *argp++ = (char *)NULL;}static void write_pidfile(void){ int fd; FILE *f; if (!pidfile) return; fd = open(pidfile, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT, 0644); if (fd < 0) { fprintf(stderr, "%s: open: %s: %s\n", progname, pidfile, strerror(errno)); exit(1); } f = fdopen(fd, "w"); if (!f) { fprintf(stderr, "%s: fdopen: %s\n", progname, strerror(errno)); exit(1); } fprintf(f, "%ld\n", (long)getpid()); if (fclose(f) < 0) { fprintf(stderr, "%s: writing %s: %s\n", progname, pidfile, strerror(errno)); exit(1); }}static void remove_pidfile(void){ if (!pidfile) return; unlink(pidfile);}/* Set 0 (stdin) to /dev/null, and 1 and 2 (stdout and stderr) to /dev/full * if it's available and /dev/null otherwise. */static void rebind_standard_streams(void){ int devnullfd; int devfullfd; devnullfd = open("/dev/null", O_RDONLY); if (devnullfd < 0) { fprintf(stderr, "%s: cannot open /dev/null: %s\n", progname, strerror(errno)); exit(2); } devfullfd = open("/dev/full", O_WRONLY); if (devfullfd < 0) { devfullfd = devnullfd; } /* Alert: The dup on stderr is done last, so that the error message * works regardless of which dup fails. */ if (dup2(devnullfd, 0) < 0 || dup2(devfullfd, 1) < 0 || dup2(devfullfd, 2) < 0) { fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno)); exit(1); }}/* Some code to determine the highest possible file descriptor number, * so that we can close them all. */static int open_max(void){#ifdef OPEN_MAX return OPEN_MAX;#else int max; max = sysconf(_SC_OPEN_MAX); if (max <= 0) { return 1024; /* guess */ } return max;#endif}/* Close all file descriptors other than 0, 1, and 2. */static void close_extra_files(void){ int max = open_max(); int fd; for (fd = 3; fd < max; fd++) { close(fd); }}/* We received a signal that we should pass on to the child box. * We ignore it ourselves. */static void signal_transfer(int signum){ if (child_box > 0) { kill(child_box, signum); }}/* We received a signal that we should pass on to the child box, * and then die from ourselves. It has to be a signal that * terminates the process as its default action! */static void signal_transfer_and_die(int signum){ /* First send it to the child process */ if (child_box > 0) { kill(child_box, signum); } /* Prepare to die. Normally the atexit handler would take care * of this when we exit(), but we're going to die from a signal. */ remove_pidfile(); /* Then send it to self. First set the default handler, to * avoid catching the signal with this handler again. This * is not a race, because it doesn't matter if we die from * the signal we're going to send or from a different one. */ signal(signum, SIG_DFL); kill(getpid(), signum);}static void setup_signals(void){ signal(SIGHUP, &signal_transfer); signal(SIGINT, &signal_transfer_and_die); signal(SIGQUIT, &signal_transfer_and_die); signal(SIGTERM, &signal_transfer_and_die); signal(SIGUSR1, &signal_transfer); signal(SIGUSR2, &signal_transfer);}/* Fork off a box process and loop indefinitely, forking a new one * every time it dies. */static int main_loop(char *boxfile){ time_t next_fork = 0; /* We can't report any errors here, because we are running * as a daemon and we have no logfile of our own. So we * exit with errno as the exit code, to offer a minimal clue. */ for (;;) { /* Make sure we don't fork in an endless loop if something * is drastically wrong. This code limits it to one * per minute (or whatever min_restart_delay is set to). */ time_t this_time = time(NULL); if (this_time <= next_fork) { sleep(next_fork - this_time); } next_fork = this_time + min_restart_delay; child_box = fork(); if (child_box < 0) { return errno; } if (child_box == 0) { /* child. exec the box */ execvp(boxfile, box_arglist); exit(127); } while (waitpid(child_box, (int *)NULL, 0) != child_box) { if (errno == ECHILD) { /* Something went wrong... we don't know what, * but we do know that our child does not * exist. So restart it. */ break; } if (errno == EINTR) { continue; } /* Something weird happened. */ return errno; } }}int main(int argc, char *argv[]){ int i; char *boxfile = NULL; pid_t childpid; progname = argv[0]; if (argc == 1) { print_usage(stderr); exit(2); } /* Parse the options meant for the wrapper, and get the name of * the box to wrap. */ for (i = 1; i < argc && !boxfile; i++) { if (strcmp(argv[i], "--pidfile") == 0) { if (i+1 >= argc) { fprintf(stderr, "Missing argument for option %s\n", argv[i]); exit(2); } pidfile = argv[i+1]; i++; } else if (strcmp(argv[i], "--min-delay") == 0) { if (i+1 >= argc) { fprintf(stderr, "Missing argument for option %s", argv[i]); exit(2); } min_restart_delay = atoi(argv[i+1]); i++; } else if (strcmp(argv[i], "--no-extra-args") == 0) { use_extra_args = 0; } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option %s\n", argv[i]); exit(2); } else { boxfile = argv[i]; } } /* Check if we have everything */ if (!boxfile) { print_usage(stderr); exit(2); } /* The remaining arguments should be passed to the box */ build_box_arglist(boxfile, argc - i, argv + i); /* Ready to rock. Begin daemonization. */ /* Fork a child process and have the parent exit. * This makes us run in the background. */ childpid = fork(); if (childpid < 0) { fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); exit(1); } if (childpid != 0) { exit(0); /* parent exits immediately */ } /* The child continues here. Now call setsid() to disconnect * from our terminal and from the parent's session and process * group. */ if (setsid() < 0) { fprintf(stderr, "%s: setsid: %s\n", progname, strerror(errno)); exit(1); } /* Change to the root directory, so that we don't keep a * file descriptor open on an unknown directory. */ if (chdir("/") < 0) { fprintf(stderr, "%s: chdir to root: %s\n", progname, strerror(errno)); exit(1); } atexit(remove_pidfile); write_pidfile(); /* Set the umask to a known value, rather than inheriting * an unknown one. */ umask(077); /* Leave file descriptors 0, 1, and 2 pointing to harmless * places, and close all other file descriptors. */ rebind_standard_streams(); close_extra_files(); setup_signals(); return main_loop(boxfile);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -