00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #include <stdio.h>
00058 #include <stddef.h>
00059 #include <stdlib.h>
00060 #include <limits.h>
00061
00062 #include <unistd.h>
00063 #include <errno.h>
00064 #include <string.h>
00065 #include <time.h>
00066
00067 #include <sys/types.h>
00068 #include <sys/stat.h>
00069 #include <sys/wait.h>
00070 #include <fcntl.h>
00071 #include <signal.h>
00072
00073 static char *progname;
00074 static char **box_arglist;
00075 static int min_restart_delay = 60;
00076 static pid_t child_box;
00077 static char *pidfile;
00078 static int use_extra_args = 1;
00079
00080
00081 static char *extra_arguments[] = {
00082 "-v", "4",
00083 };
00084 #define NUM_EXTRA ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments)))
00085
00086 static void print_usage(FILE *stream)
00087 {
00088 fprintf(stream,
00089 "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]\n",
00090 progname);
00091 }
00092
00093
00094
00095
00096 static void build_box_arglist(char *boxfile, int argc, char **argv)
00097 {
00098 int i;
00099 char **argp;
00100
00101 if (box_arglist) {
00102 free(box_arglist);
00103 }
00104
00105
00106
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
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 }
00127
00128 static void write_pidfile(void)
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 }
00154
00155 static void remove_pidfile(void)
00156 {
00157 if (!pidfile)
00158 return;
00159
00160 unlink(pidfile);
00161 }
00162
00163
00164
00165 static void rebind_standard_streams(void)
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
00182
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 }
00190
00191
00192
00193 static int open_max(void)
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;
00203 }
00204 return max;
00205 #endif
00206 }
00207
00208
00209 static void close_extra_files(void)
00210 {
00211 int max = open_max();
00212 int fd;
00213
00214 for (fd = 3; fd < max; fd++) {
00215 close(fd);
00216 }
00217 }
00218
00219
00220
00221 static void signal_transfer(int signum)
00222 {
00223 if (child_box > 0) {
00224 kill(child_box, signum);
00225 }
00226 }
00227
00228
00229
00230
00231 static void signal_transfer_and_die(int signum)
00232 {
00233
00234 if (child_box > 0) {
00235 kill(child_box, signum);
00236 }
00237
00238
00239
00240 remove_pidfile();
00241
00242
00243
00244
00245
00246 signal(signum, SIG_DFL);
00247 kill(getpid(), signum);
00248 }
00249
00250 static void setup_signals(void)
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 }
00259
00260
00261
00262 static int main_loop(char *boxfile)
00263 {
00264 time_t next_fork = 0;
00265
00266
00267
00268
00269
00270 for (;;) {
00271
00272
00273
00274
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
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
00294
00295
00296 break;
00297 }
00298 if (errno == EINTR) {
00299 continue;
00300 }
00301
00302 return errno;
00303 }
00304 }
00305 }
00306
00307 int main(int argc, char *argv[])
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
00321
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
00348 if (!boxfile) {
00349 print_usage(stderr);
00350 exit(2);
00351 }
00352
00353
00354 build_box_arglist(boxfile, argc - i, argv + i);
00355
00356
00357
00358
00359
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);
00367 }
00368
00369
00370
00371
00372 if (setsid() < 0) {
00373 fprintf(stderr, "%s: setsid: %s\n", progname, strerror(errno));
00374 exit(1);
00375 }
00376
00377
00378
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
00388
00389 umask(077);
00390
00391
00392
00393 rebind_standard_streams();
00394 close_extra_files();
00395
00396 setup_signals();
00397 return main_loop(boxfile);
00398 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.