run_kannel_box.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:8k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. #include <stdio.h>
  2. #include <stddef.h>
  3. #include <stdlib.h>
  4. #include <limits.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <time.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/wait.h>
  12. #include <fcntl.h>
  13. #include <signal.h>
  14. static char *progname;  /* The name of this program (for error messages) */
  15. static char **box_arglist;
  16. static int min_restart_delay = 60; /* in seconds */
  17. static pid_t child_box; /* used in main_loop, available to signal handlers */
  18. static char *pidfile; /* The name of the pidfile to use.  NULL if no pidfile */
  19. static int use_extra_args = 1; /* Add "extra_arguments" list to argv? */
  20. /* Extra arguments to pass to the box */
  21. static char *extra_arguments[] = {
  22. "-v", "4",   /* Minimal output on stderr, goes to /dev/null anyway */
  23. };
  24. #define NUM_EXTRA ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments)))
  25. static void print_usage(FILE *stream)
  26. {
  27. fprintf(stream,
  28. "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]n",
  29. progname);
  30. }
  31. /* Create the argument list to pass to the box process, and put it
  32.  * in the box_arglist global variable.  This is also the right place
  33.  * to add any standard arguments that we want to pass. */
  34. static void build_box_arglist(char *boxfile, int argc, char **argv)
  35. {
  36. int i;
  37. char **argp;
  38. if (box_arglist) {
  39. free(box_arglist);
  40. }
  41. /* one for the boxfile name itself, one for each extra argument,
  42.  * one for each normal argument, and one for the terminating NULL */
  43. box_arglist = malloc((1 + NUM_EXTRA + argc + 1) * sizeof(*box_arglist));
  44. if (!box_arglist) {
  45. fprintf(stderr, "%s: malloc: %sn", progname, strerror(errno));
  46. exit(1);
  47. }
  48. /* Have argp walk down box_arglist and set each argument. */
  49. argp = box_arglist;
  50. *argp++ = boxfile;
  51.      if (use_extra_args) {
  52. for (i = 0; i < NUM_EXTRA; i++) {
  53. *argp++ = extra_arguments[i];
  54. }
  55. }
  56. for (i = 0; i < argc; i++) {
  57. *argp++ = argv[i];
  58. }
  59. *argp++ = (char *)NULL;
  60. }
  61. static void write_pidfile(void)
  62. {
  63. int fd;
  64. FILE *f;
  65. if (!pidfile)
  66. return;
  67. fd = open(pidfile, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT, 0644);
  68. if (fd < 0) {
  69. fprintf(stderr, "%s: open: %s: %sn", progname, pidfile, strerror(errno));
  70. exit(1);
  71. }
  72. f = fdopen(fd, "w");
  73. if (!f) {
  74. fprintf(stderr, "%s: fdopen: %sn", progname, strerror(errno));
  75. exit(1);
  76. }
  77. fprintf(f, "%ldn", (long)getpid());
  78. if (fclose(f) < 0) {
  79. fprintf(stderr, "%s: writing %s: %sn", progname, pidfile, strerror(errno));
  80. exit(1);
  81. }
  82. }
  83. static void remove_pidfile(void)
  84. {
  85. if (!pidfile)
  86. return;
  87. unlink(pidfile);
  88. }
  89. /* Set 0 (stdin) to /dev/null, and 1 and 2 (stdout and stderr) to /dev/full
  90.  * if it's available and /dev/null otherwise. */
  91. static void rebind_standard_streams(void)
  92. {
  93. int devnullfd;
  94. int devfullfd;
  95. devnullfd = open("/dev/null", O_RDONLY);
  96. if (devnullfd < 0) {
  97. fprintf(stderr, "%s: cannot open /dev/null: %sn",
  98. progname, strerror(errno));
  99. exit(2);
  100. }
  101. devfullfd = open("/dev/full", O_WRONLY);
  102. if (devfullfd < 0) {
  103. devfullfd = devnullfd;
  104. }
  105. /* Alert: The dup on stderr is done last, so that the error message
  106.  * works regardless of which dup fails. */
  107. if (dup2(devnullfd, 0) < 0 ||
  108.     dup2(devfullfd, 1) < 0 ||
  109.     dup2(devfullfd, 2) < 0) {
  110. fprintf(stderr, "%s: dup2: %sn", progname, strerror(errno));
  111. exit(1);
  112. }
  113. }
  114. /* Some code to determine the highest possible file descriptor number,
  115.  * so that we can close them all.  */
  116. static int open_max(void)
  117. {
  118. #ifdef OPEN_MAX
  119. return OPEN_MAX;
  120. #else
  121. int max;
  122. max = sysconf(_SC_OPEN_MAX);
  123. if (max <= 0) {
  124. return 1024;  /* guess */
  125. }
  126. return max;
  127. #endif
  128. }
  129. /* Close all file descriptors other than 0, 1, and 2. */
  130. static void close_extra_files(void)
  131. {
  132. int max = open_max();
  133. int fd;
  134. for (fd = 3; fd < max; fd++) {
  135. close(fd);
  136. }
  137. }
  138. /* We received a signal that we should pass on to the child box.
  139.  * We ignore it ourselves. */
  140. static void signal_transfer(int signum)
  141. {
  142. if (child_box > 0) {
  143. kill(child_box, signum);
  144. }
  145. }
  146. /* We received a signal that we should pass on to the child box,
  147.  * and then die from ourselves.  It has to be a signal that
  148.  * terminates the process as its default action! */
  149. static void signal_transfer_and_die(int signum)
  150. {
  151. /* First send it to the child process */
  152. if (child_box > 0) {
  153. kill(child_box, signum);
  154. }
  155. /* Prepare to die.  Normally the atexit handler would take care
  156.  * of this when we exit(), but we're going to die from a signal. */
  157. remove_pidfile();
  158. /* Then send it to self.  First set the default handler, to
  159.  * avoid catching the signal with this handler again.  This
  160.  * is not a race, because it doesn't matter if we die from
  161.  * the signal we're going to send or from a different one.  */
  162. signal(signum, SIG_DFL);
  163. kill(getpid(), signum);
  164. }
  165. static void setup_signals(void)
  166. {
  167. signal(SIGHUP, &signal_transfer);
  168. signal(SIGINT, &signal_transfer_and_die);
  169. signal(SIGQUIT, &signal_transfer_and_die);
  170. signal(SIGTERM, &signal_transfer_and_die);
  171. signal(SIGUSR1, &signal_transfer);
  172. signal(SIGUSR2, &signal_transfer);
  173. }
  174. /* Fork off a box process and loop indefinitely, forking a new one
  175.  * every time it dies. */
  176. static int main_loop(char *boxfile)
  177. {
  178. time_t next_fork = 0;
  179. /* We can't report any errors here, because we are running
  180.  * as a daemon and we have no logfile of our own.  So we
  181.  * exit with errno as the exit code, to offer a minimal clue. */
  182. for (;;) {
  183. /* Make sure we don't fork in an endless loop if something
  184.  * is drastically wrong.  This code limits it to one
  185.  * per minute (or whatever min_restart_delay is set to). */
  186. time_t this_time = time(NULL);
  187. if (this_time <= next_fork) {
  188. sleep(next_fork - this_time);
  189. }
  190. next_fork = this_time + min_restart_delay;
  191. child_box = fork();
  192. if (child_box < 0) {
  193. return errno;
  194. }
  195. if (child_box == 0) {
  196. /* child.  exec the box */
  197. execvp(boxfile, box_arglist);
  198. exit(127);
  199. }
  200. while (waitpid(child_box, (int *)NULL, 0) != child_box) {
  201. if (errno == ECHILD) {
  202. /* Something went wrong... we don't know what,
  203.  * but we do know that our child does not
  204.  * exist.  So restart it. */
  205. break;
  206. }
  207. if (errno == EINTR) {
  208. continue;
  209. }
  210. /* Something weird happened. */
  211. return errno;
  212. }
  213. }
  214. }
  215. int main(int argc, char *argv[])
  216. {
  217. int i;
  218. char *boxfile = NULL;
  219. pid_t childpid;
  220. progname = argv[0];
  221. if (argc == 1) {
  222. print_usage(stderr);
  223. exit(2);
  224. }
  225. /* Parse the options meant for the wrapper, and get the name of
  226.  * the box to wrap. */
  227. for (i = 1; i < argc && !boxfile; i++) {
  228. if (strcmp(argv[i], "--pidfile") == 0) {
  229. if (i+1 >= argc) {
  230. fprintf(stderr, "Missing argument for option %sn", argv[i]);
  231. exit(2);
  232. }
  233. pidfile = argv[i+1];
  234. i++;
  235. } else if (strcmp(argv[i], "--min-delay") == 0) {
  236. if (i+1 >= argc) {
  237. fprintf(stderr, "Missing argument for option %s", argv[i]);
  238. exit(2);
  239. }
  240. min_restart_delay = atoi(argv[i+1]);
  241. i++;
  242. } else if (strcmp(argv[i], "--no-extra-args") == 0) {
  243.      use_extra_args = 0;
  244. } else if (argv[i][0] == '-') {
  245. fprintf(stderr, "Unknown option %sn", argv[i]);
  246. exit(2);
  247. } else {
  248. boxfile = argv[i];
  249. }
  250. }
  251. /* Check if we have everything */
  252. if (!boxfile) {
  253. print_usage(stderr);
  254. exit(2);
  255. }
  256. /* The remaining arguments should be passed to the box */
  257. build_box_arglist(boxfile, argc - i, argv + i);
  258. /* Ready to rock.  Begin daemonization. */
  259. /* Fork a child process and have the parent exit.
  260.          * This makes us run in the background. */
  261. childpid = fork();
  262. if (childpid < 0) {
  263. fprintf(stderr, "%s: fork: %sn", progname, strerror(errno));
  264. exit(1);
  265. }
  266. if (childpid != 0) {
  267. exit(0); /* parent exits immediately */
  268. }
  269. /* The child continues here.  Now call setsid() to disconnect
  270.  * from our terminal and from the parent's session and process
  271.  * group. */
  272. if (setsid() < 0) {
  273. fprintf(stderr, "%s: setsid: %sn", progname, strerror(errno));
  274. exit(1);
  275. }
  276. /* Change to the root directory, so that we don't keep a
  277.  * file descriptor open on an unknown directory. */
  278. if (chdir("/") < 0) {
  279. fprintf(stderr, "%s: chdir to root: %sn", progname, strerror(errno));
  280. exit(1);
  281. }
  282. atexit(remove_pidfile);
  283. write_pidfile();
  284. /* Set the umask to a known value, rather than inheriting
  285.  * an unknown one. */
  286. umask(077);
  287. /* Leave file descriptors 0, 1, and 2 pointing to harmless
  288.  * places, and close all other file descriptors. */
  289. rebind_standard_streams();
  290. close_extra_files();
  291. setup_signals();
  292. return main_loop(boxfile);
  293. }