00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifdef WITHIN_PANDA
00016 #include "dtoolbase.h"
00017 #endif
00018
00019 #include <getopt.h>
00020 #include <stdio.h>
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <sys/types.h>
00025 #include <sys/wait.h>
00026 #include <sys/stat.h>
00027 #include <fcntl.h>
00028 #include <time.h>
00029 #include <signal.h>
00030 #include <stdlib.h>
00031 #include <assert.h>
00032 #include <pwd.h>
00033 #include <grp.h>
00034
00035 #ifdef HAVE_LIBCURL
00036 #include <curl/curl.h>
00037 #endif
00038
00039
00040
00041
00042 #define MAX_WAITTERM_SEC 10
00043
00044 char **params = NULL;
00045 char *logfile_name = NULL;
00046 char *pidfile_name = NULL;
00047 int dont_fork = 0;
00048 char *watchdog_url = NULL;
00049 int watchdog_start_sec = 0;
00050 int watchdog_cycle_sec = 0;
00051 int watchdog_timeout_sec = 0;
00052 char *startup_username = NULL;
00053 char *startup_groupname = NULL;
00054 char *startup_chdir = NULL;
00055 int logfile_fd = -1;
00056 int stop_on_terminate = 0;
00057 int stop_always = 0;
00058 char *respawn_script = NULL;
00059 int respawn_count_time = 0;
00060
00061
00062 int respawn_delay_time = 5;
00063
00064
00065
00066
00067 int spam_respawn_count = 5;
00068 int spam_respawn_time = 60;
00069 int spam_restart_delay_time = 600;
00070
00071
00072
00073 pid_t child_pid = 0;
00074 pid_t watchdog_pid = 0;
00075
00076 #define TIME_BUFFER_SIZE 128
00077
00078
00079
00080 typedef struct respawn_record_struct {
00081 time_t _time;
00082 struct respawn_record_struct *_next;
00083 } respawn_record;
00084
00085 respawn_record *respawns = NULL;
00086
00087 int
00088 record_respawn(time_t now) {
00089
00090
00091
00092 respawn_record *rec;
00093 respawn_record *next;
00094 int count;
00095
00096 if (respawn_count_time <= 0) {
00097
00098 return 0;
00099 }
00100
00101 rec = (respawn_record *)malloc(sizeof(respawn_record));
00102 rec->_time = now;
00103 rec->_next = respawns;
00104 respawns = rec;
00105
00106
00107
00108
00109 count = 0;
00110 while (rec->_next != NULL &&
00111 (now - rec->_time) <= respawn_count_time) {
00112 rec = rec->_next;
00113 count++;
00114 }
00115
00116
00117 next = rec->_next;
00118 rec->_next = NULL;
00119 while (next != NULL) {
00120 rec = next;
00121 next = rec->_next;
00122 free(rec);
00123 }
00124
00125 return count;
00126 }
00127
00128 void
00129 invoke_respawn_script(time_t now) {
00130 char buffer[32];
00131 char *new_command;
00132 int new_command_length;
00133
00134
00135
00136 if (respawn_count_time <= 0) {
00137
00138
00139 system(respawn_script);
00140
00141 } else {
00142
00143
00144 sprintf(buffer, " %d", record_respawn(now));
00145 new_command_length = strlen(respawn_script) + strlen(buffer);
00146 new_command = (char *)malloc(new_command_length + 1);
00147 strcpy(new_command, respawn_script);
00148 strcat(new_command, buffer);
00149 assert(strlen(new_command) == new_command_length);
00150
00151 system(new_command);
00152
00153 free(new_command);
00154 }
00155 }
00156
00157
00158
00159 size_t
00160 watchdog_bitbucket(void *ptr, size_t size, size_t nmemb, void *userdata) {
00161 return size * nmemb;
00162 }
00163
00164
00165
00166 pid_t
00167 waitpid_timeout(pid_t child_pid, int *status_ptr, int timeout_ms) {
00168 pid_t result;
00169 struct timeval now, tv;
00170 int now_ms, start_ms, elapsed_ms;
00171
00172 gettimeofday(&now, NULL);
00173 start_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
00174
00175 result = waitpid(child_pid, status_ptr, WNOHANG);
00176 while (result == 0) {
00177 gettimeofday(&now, NULL);
00178 now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
00179 elapsed_ms = now_ms - start_ms;
00180
00181 if (elapsed_ms > timeout_ms) {
00182
00183 return 0;
00184 }
00185
00186
00187 tv.tv_sec = 0;
00188 tv.tv_usec = 1;
00189 select(0, NULL, NULL, NULL, &tv);
00190 result = waitpid(child_pid, status_ptr, WNOHANG);
00191 }
00192 if (result == -1) {
00193 perror("waitpid");
00194 }
00195
00196 return result;
00197 }
00198
00199
00200
00201
00202
00203
00204 int
00205 do_watchdog(int *status_ptr) {
00206 #ifndef HAVE_LIBCURL
00207 fprintf(stderr, "Cannot watchdog; no libcurl available.\n");
00208 return 0;
00209 #else
00210
00211 CURL *curl;
00212 CURLcode res;
00213 char error_buffer[CURL_ERROR_SIZE];
00214 pid_t wresult;
00215
00216
00217 wresult = waitpid_timeout(child_pid, status_ptr, watchdog_start_sec * 1000);
00218 if (wresult == child_pid) {
00219
00220 return 0;
00221 }
00222
00223 curl = curl_easy_init();
00224 if (!curl) {
00225 fprintf(stderr, "Cannot watchdog; curl failed to init.\n");
00226 return 0;
00227 }
00228
00229 curl_easy_setopt(curl, CURLOPT_URL, watchdog_url);
00230
00231 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, watchdog_timeout_sec * 1000);
00232 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, watchdog_bitbucket);
00233 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
00234 curl_easy_setopt(curl, CURLOPT_USERAGENT, "autorestart");
00235 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
00236 curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
00237 curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
00238
00239 res = curl_easy_perform(curl);
00240 while (res == 0) {
00241
00242
00243 long http_response = 0;
00244 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response);
00245 if ((http_response / 100) != 2) {
00246
00247
00248 fprintf(stderr, "%s returned %ld\n", watchdog_url, http_response);
00249 break;
00250 }
00251
00252 wresult = waitpid_timeout(child_pid, status_ptr, watchdog_cycle_sec * 1000);
00253 if (wresult == child_pid) {
00254
00255 return 0;
00256 }
00257
00258 res = curl_easy_perform(curl);
00259 }
00260
00261 curl_easy_cleanup(curl);
00262
00263
00264 if (res != 0) {
00265 fprintf(stderr, "Failed to contact %s: %s\n", watchdog_url, error_buffer);
00266 }
00267
00268
00269 kill(child_pid, SIGTERM);
00270
00271 pid_t result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000);
00272 if (result != child_pid) {
00273 if (result == -1) {
00274 perror("waitpid");
00275 } else {
00276
00277 fprintf(stderr, "Force-killing child process\n");
00278 kill(child_pid, SIGKILL);
00279 result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000);
00280 if (result == -1) {
00281 perror("waitpid");
00282 }
00283 }
00284 }
00285
00286
00287 return 1;
00288 #endif
00289 }
00290
00291 void
00292 exec_process() {
00293
00294 char **p;
00295 for (p = params; *p != NULL; ++p) {
00296 fprintf(stderr, "%s ", *p);
00297 }
00298 fprintf(stderr, "\n");
00299 execvp(params[0], params);
00300 fprintf(stderr, "Cannot exec %s: %s\n", params[0], strerror(errno));
00301
00302
00303
00304 exit(0);
00305 }
00306
00307 int
00308 spawn_process() {
00309
00310
00311
00312
00313 pid_t wresult;
00314 int status;
00315 int error_exit;
00316
00317 child_pid = fork();
00318 if (child_pid < 0) {
00319
00320 perror("fork");
00321 return 0;
00322 }
00323
00324 if (child_pid == 0) {
00325
00326 fprintf(stderr, "Child pid is %d.\n", getpid());
00327 exec_process();
00328
00329 exit(1);
00330 }
00331
00332
00333
00334 error_exit = 0;
00335
00336 if (watchdog_url != NULL) {
00337
00338
00339 error_exit = do_watchdog(&status);
00340
00341 } else {
00342
00343
00344 wresult = waitpid(child_pid, &status, 0);
00345 if (wresult < 0) {
00346 perror("waitpid");
00347 return 0;
00348 }
00349 }
00350
00351
00352
00353 child_pid = 0;
00354
00355 if (error_exit) {
00356
00357 return 1;
00358
00359 } else if (WIFSIGNALED(status)) {
00360 int signal = WTERMSIG(status);
00361 fprintf(stderr, "\nprocess caught signal %d.\n\n", signal);
00362
00363
00364 return !stop_on_terminate || (signal != SIGTERM && signal != SIGKILL);
00365
00366 } else {
00367 int exit_status = WEXITSTATUS(status);
00368 fprintf(stderr, "\nprocess exited with status %d.\n\n", WEXITSTATUS(status));
00369
00370 return !stop_on_terminate || (exit_status != 0);
00371 }
00372 }
00373
00374 void
00375 sigterm_handler() {
00376 pid_t wresult;
00377 int status;
00378 time_t now;
00379 char time_buffer[TIME_BUFFER_SIZE];
00380
00381 now = time(NULL);
00382 strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now));
00383
00384 fprintf(stderr, "\nsigterm caught at %s; shutting down.\n", time_buffer);
00385 if (child_pid == 0) {
00386 fprintf(stderr, "no child process.\n\n");
00387
00388 } else {
00389 kill(child_pid, SIGTERM);
00390
00391 wresult = waitpid(child_pid, &status, 0);
00392 if (wresult < 0) {
00393 perror("waitpid");
00394 } else {
00395 fprintf(stderr, "child process terminated.\n\n");
00396 }
00397 }
00398 exit(1);
00399 }
00400
00401 void
00402 sighup_handler() {
00403 time_t now;
00404 char time_buffer[TIME_BUFFER_SIZE];
00405
00406 now = time(NULL);
00407 strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now));
00408
00409 fprintf(stderr, "\nsighup caught at %s.\n", time_buffer);
00410 if (child_pid == 0) {
00411 fprintf(stderr, "no child process.\n\n");
00412
00413 } else {
00414 kill(child_pid, SIGHUP);
00415 }
00416 }
00417
00418 void
00419 sigalarm_handler() {
00420 fprintf(stderr, "sleep epoch was complete.\n");
00421 }
00422
00423 void
00424 do_autorestart() {
00425 char time_buffer[TIME_BUFFER_SIZE];
00426 time_t now;
00427 time_t *spam_respawn = NULL;
00428 int sri, num_sri;
00429 struct sigaction sa;
00430
00431 if (spam_respawn_count > 1) {
00432 spam_respawn = (time_t *)malloc(sizeof(time_t) * spam_respawn_count);
00433 }
00434
00435
00436 setpgid(0, 0);
00437
00438
00439 sa.sa_handler = sigterm_handler;
00440 sigemptyset(&sa.sa_mask);
00441 sa.sa_flags = 0;
00442 if (sigaction(SIGTERM, &sa, NULL) < 0) {
00443 perror("sigaction");
00444 }
00445
00446
00447
00448 sa.sa_handler = sighup_handler;
00449 sigemptyset(&sa.sa_mask);
00450 sa.sa_flags = 0;
00451 if (sigaction(SIGHUP, &sa, NULL) < 0) {
00452 perror("sigaction");
00453 }
00454
00455 if (logfile_fd >= 0) {
00456
00457 dup2(logfile_fd, STDOUT_FILENO);
00458 dup2(logfile_fd, STDERR_FILENO);
00459 close(logfile_fd);
00460 }
00461
00462
00463 close(STDIN_FILENO);
00464
00465 now = time(NULL);
00466 strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now));
00467 fprintf(stderr, "autorestart begun at %s.\n", time_buffer);
00468
00469 if (pidfile_name != NULL) {
00470 unlink(pidfile_name);
00471 FILE *pidfile = fopen(pidfile_name, "w");
00472 if (pidfile == NULL) {
00473 fprintf(stderr, "Could not write pidfile %s\n", pidfile_name);
00474 } else {
00475 fprintf(pidfile, "%d\n", getpid());
00476 fclose(pidfile);
00477 }
00478 }
00479
00480 sri = 1;
00481 num_sri = 1;
00482 if (spam_respawn_count > 1) {
00483 spam_respawn[1] = now;
00484 }
00485
00486 while (spawn_process()) {
00487 now = time(NULL);
00488
00489 if (respawn_script != NULL) {
00490 invoke_respawn_script(now);
00491 }
00492
00493 if (respawn_delay_time) {
00494 sleep(respawn_delay_time);
00495 }
00496
00497
00498 if (spam_respawn_count > 1) {
00499 sri = (sri + 1) % spam_respawn_count;
00500 spam_respawn[sri] = now;
00501 if (num_sri < spam_respawn_count) {
00502 num_sri++;
00503 } else {
00504 time_t last = spam_respawn[(sri + 1) % spam_respawn_count];
00505 if (now - last < spam_respawn_time)
00506 {
00507 if(!spam_restart_delay_time)
00508 {
00509 fprintf(stderr, "respawning too fast, giving up.\n");
00510 break;
00511 }
00512 else
00513 {
00514 num_sri = 1;
00515 fprintf(stderr, "respawning too fast, will sleep for %d seconds.\n", spam_restart_delay_time);
00516 signal (SIGALRM, sigalarm_handler);
00517 alarm(spam_restart_delay_time);
00518 pause();
00519 signal (SIGALRM, SIG_IGN);
00520 }
00521 }
00522 }
00523 }
00524
00525 if (stop_always) {
00526 fprintf(stderr, "instructed to not autorestart, exiting.\n");
00527 break;
00528 }
00529
00530 strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now));
00531 fprintf(stderr, "respawning at %s.\n", time_buffer);
00532 }
00533
00534 now = time(NULL);
00535 strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now));
00536 fprintf(stderr, "autorestart terminated at %s.\n", time_buffer);
00537 exit(0);
00538 }
00539
00540 void
00541 double_fork() {
00542 pid_t child, grandchild, wresult;
00543 int status;
00544
00545
00546
00547 child = fork();
00548 if (child < 0) {
00549
00550 perror("fork");
00551 exit(1);
00552 }
00553
00554 if (child == 0) {
00555
00556 grandchild = fork();
00557 if (grandchild < 0) {
00558 perror("fork");
00559 exit(1);
00560 }
00561
00562 if (grandchild == 0) {
00563
00564 do_autorestart();
00565
00566 exit(1);
00567 }
00568
00569
00570 fprintf(stderr, "Spawned, monitoring pid is %d.\n", grandchild);
00571 exit(0);
00572 }
00573
00574
00575 wresult = waitpid(child, &status, 0);
00576 if (wresult < 0) {
00577 perror("waitpid");
00578 exit(1);
00579 }
00580
00581 if (!WIFEXITED(status)) {
00582 if (WIFSIGNALED(status)) {
00583 fprintf(stderr, "child caught signal %d unexpectedly.\n", WTERMSIG(status));
00584 } else {
00585 fprintf(stderr, "child exited with status %d.\n", WEXITSTATUS(status));
00586 }
00587 exit(1);
00588 }
00589 }
00590
00591 void
00592 usage() {
00593 fprintf(stderr,
00594 "\n"
00595 "autorestart [opts] program [args . . . ]\n"
00596 "autorestart -h\n\n");
00597 }
00598
00599 void
00600 help() {
00601 usage();
00602 fprintf(stderr,
00603 "This program is used to run a program as a background task and\n"
00604 "automatically restart it should it terminate for any reason other\n"
00605 "than normal exit or explicit user kill.\n\n"
00606
00607 "If the program exits with a status of 0, indicating successful\n"
00608 "completion, it is not restarted.\n\n"
00609
00610 "If the program is terminated via a TERM or KILL signal (e.g. via\n"
00611 "kill [pid] or kill -9 [pid]), it is assumed the user meant for the\n"
00612 "process to stop, and it is not restarted.\n\n"
00613
00614 "Options:\n\n"
00615
00616 " -l logfilename\n"
00617 " Route stdout and stderr from the child process into the indicated\n"
00618 " log file.\n\n"
00619
00620 " -p pidfilename\n"
00621 " Write the pid of the monitoring process to the indicated pidfile.\n\n"
00622 " -f\n"
00623 " Don't fork autorestart itself; run it as a foreground process. \n"
00624 " (Normally, autorestart forks itself to run as a background process.)\n"
00625 " In this case, the file named by -p is not used.\n\n"
00626
00627 " -n\n"
00628 " Do not attempt to restart the process under any circumstance.\n"
00629 " The program can still be used to execute a script on abnormal\n"
00630 " process termination.\n\n"
00631
00632 " -t\n"
00633 " Stop on terminate: don't restart if the child process exits\n"
00634 " normally or is killed with a SIGTERM. With this flag, the\n"
00635 " child process will be restarted only if it exits with a\n"
00636 " non-zero exit status, or if it is killed with a signal other\n"
00637 " than SIGTERM. Without this flag, the default behavior is to\n"
00638 " restart the child process if it exits for any reason.\n\n"
00639
00640 " -r count,secs,sleep\n"
00641 " Sleep 'sleep' seconds if the process respawns 'count' times\n"
00642 " within 'secs' seconds. This is designed to prevent respawning\n"
00643 " from using too many system resources if something is wrong with\n"
00644 " the child process. The default value is %d,%d,%d. Use -r 0,0,0\n"
00645 " to disable this feature.\n\n"
00646
00647 " -s \"command\"\n"
00648 " Run the indicated command or script each time the process is\n"
00649 " respawned, using the system() call. This may be useful, for\n"
00650 " instance, to notify an operator via email each time a respawn\n"
00651 " occurs. If -c is also specified, an additional parameter will\n"
00652 " be appended to the command, indicating the number of times the\n"
00653 " respawn has occurred in the given time interval.\n\n"
00654
00655 " -c secs\n"
00656 " Specifies the number of seconds over which to count respawn events\n"
00657 " for the purposes of passing an argument to the script named with\n"
00658 " -s.\n\n"
00659
00660 " -d secs\n"
00661 " Specifies the number of seconds to delay for between restarts.\n"
00662 " The default is %d.\n\n"
00663
00664 #ifdef HAVE_LIBCURL
00665 " -W watchdog_url,start,cycle,timeout\n"
00666 " Specifies an optional URL to watch while waiting for the process\n"
00667 " to terminate. If this is specified, autorestart will start the process,\n"
00668 " wait start seconds, and then repeatedly poll the indicated URL\n"
00669 " every cycle seconds. If a HTTP failure code is detected,\n"
00670 " or no response is received within timeout seconds, then the\n"
00671 " child is terminated and restarted. The start, cycle, and timeout\n"
00672 " parameters are all required.\n\n"
00673 #endif
00674
00675 " -U username\n"
00676 " Change to the indicated user upon startup. The logfile is still\n"
00677 " created as the initial user.\n\n"
00678
00679 " -G groupname\n"
00680 " Change to the indicated group upon startup.\n\n"
00681
00682 " -D dirname\n"
00683 " Change to the indicated working directory upon startup. The logfile\n"
00684 " is still created relative to the initial startup directory.\n\n"
00685
00686 " -h\n"
00687 " Output this help information.\n\n",
00688 spam_respawn_count, spam_respawn_time, spam_restart_delay_time, respawn_delay_time);
00689 }
00690
00691 void
00692 parse_int_triplet(char *param, int *a, int *b, int *c) {
00693 char *comma;
00694 char *comma2;
00695
00696 comma = strchr(param, ',');
00697 if (comma == NULL) {
00698 fprintf(stderr, "Comma required: %s\n", param);
00699 exit(1);
00700 }
00701
00702 comma2 = strchr(comma+1, ',');
00703 if (comma2 == NULL) {
00704 fprintf(stderr, "Second comma required: %s\n", param);
00705 exit(1);
00706 }
00707
00708 *comma = '\0';
00709 *comma2 = '\0';
00710
00711 *a = atoi(param);
00712 *b = atoi(comma + 1);
00713 *c = atoi(comma2 + 1);
00714 }
00715
00716 void
00717 parse_watchdog(char *param) {
00718 char *comma;
00719 char *comma2;
00720 char *comma3;
00721
00722 #ifndef HAVE_LIBCURL
00723 fprintf(stderr, "-W requires autorestart to have been compiled with libcurl support.\n");
00724 exit(1);
00725 #endif
00726
00727 comma = strrchr(param, ',');
00728 if (comma == NULL) {
00729 fprintf(stderr, "Comma required: %s\n", param);
00730 exit(1);
00731 }
00732 *comma = '\0';
00733
00734 comma2 = strrchr(param, ',');
00735 if (comma2 == NULL) {
00736 *comma = ',';
00737 fprintf(stderr, "Second comma required: %s\n", param);
00738 exit(1);
00739 }
00740 *comma2 = '\0';
00741
00742 comma3 = strrchr(param, ',');
00743 if (comma3 == NULL) {
00744 *comma = ',';
00745 *comma2 = ',';
00746 fprintf(stderr, "Third comma required: %s\n", param);
00747 exit(1);
00748 }
00749 *comma3 = '\0';
00750
00751 watchdog_url = param;
00752 watchdog_start_sec = atoi(comma3 + 1);
00753 watchdog_cycle_sec = atoi(comma2 + 1);
00754 watchdog_timeout_sec = atoi(comma + 1);
00755 }
00756
00757
00758 int
00759 main(int argc, char *argv[]) {
00760 extern char *optarg;
00761 extern int optind;
00762
00763 static const char *optflags = "+l:p:fntr:s:c:d:W:U:G:D:h";
00764 int flag;
00765
00766 flag = getopt(argc, argv, optflags);
00767 while (flag != EOF) {
00768 switch (flag) {
00769 case 'l':
00770 logfile_name = optarg;
00771 break;
00772
00773 case 'p':
00774 pidfile_name = optarg;
00775 break;
00776
00777 case 'f':
00778 dont_fork = 1;
00779 break;
00780
00781 case 'n':
00782 stop_always = 1;
00783 break;
00784
00785 case 't':
00786 stop_on_terminate = 1;
00787 break;
00788
00789 case 'r':
00790 parse_int_triplet(optarg, &spam_respawn_count, &spam_respawn_time, &spam_restart_delay_time);
00791 break;
00792
00793 case 's':
00794 respawn_script = optarg;
00795 break;
00796
00797 case 'c':
00798 respawn_count_time = atoi(optarg);
00799 break;
00800
00801 case 'd':
00802 respawn_delay_time = atoi(optarg);
00803 break;
00804
00805 case 'W':
00806 parse_watchdog(optarg);
00807 break;
00808
00809 case 'U':
00810 startup_username = optarg;
00811 break;
00812
00813 case 'G':
00814 startup_groupname = optarg;
00815 break;
00816
00817 case 'D':
00818 startup_chdir = optarg;
00819 break;
00820
00821 case 'h':
00822 help();
00823 return 1;
00824
00825 case '?':
00826 case '+':
00827 usage();
00828 return 1;
00829
00830 default:
00831 fprintf(stderr, "Unhandled switch: -%c\n", flag);
00832 return 1;
00833 }
00834 flag = getopt(argc, argv, optflags);
00835 }
00836
00837 argc -= (optind - 1);
00838 argv += (optind - 1);
00839
00840 if (argc < 2) {
00841 fprintf(stderr, "No program to execute given.\n");
00842 usage();
00843 return 1;
00844 }
00845
00846 params = &argv[1];
00847
00848 if (logfile_name != NULL) {
00849 logfile_fd = open(logfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
00850 if (logfile_fd < 0) {
00851 fprintf(stderr, "Cannot write to logfile %s: %s\n",
00852 logfile_name, strerror(errno));
00853 return 1;
00854 }
00855 fprintf(stderr, "Generating output to %s.\n", logfile_name);
00856 }
00857
00858 if (startup_chdir != NULL) {
00859 if (chdir(startup_chdir) != 0) {
00860 perror(startup_chdir);
00861 return 1;
00862 }
00863 }
00864
00865 if (startup_groupname != NULL) {
00866 struct group *grp;
00867 grp = getgrnam(startup_groupname);
00868 if (grp == NULL) {
00869 perror(startup_groupname);
00870 return 1;
00871 }
00872
00873 if (setgid(grp->gr_gid) != 0) {
00874 perror(startup_groupname);
00875 return 1;
00876 }
00877 }
00878
00879 if (startup_username != NULL) {
00880 struct passwd *pwd;
00881 pwd = getpwnam(startup_username);
00882 if (pwd == NULL) {
00883 perror(startup_username);
00884 return 1;
00885 }
00886
00887 if (setuid(pwd->pw_uid) != 0) {
00888 perror(startup_username);
00889 return 1;
00890 }
00891 }
00892
00893 if (dont_fork) {
00894 do_autorestart();
00895 } else {
00896 double_fork();
00897 }
00898
00899 return 0;
00900 }
00901