head 1.5; access; symbols; locks; strict; comment @ * @; 1.5 date 2008.10.29.21.07.30; author wessels; state Exp; branches; next 1.4; 1.4 date 2008.07.11.06.06.47; author wessels; state Exp; branches; next 1.3; 1.3 date 2008.04.16.18.39.24; author wessels; state Exp; branches; next 1.2; 1.2 date 2007.05.21.16.41.07; author wessels; state Exp; branches; next 1.1; 1.1 date 2003.07.18.14.29.00; author wessels; state Exp; branches; next ; desc @@ 1.5 log @- make --pidfile refuse to start if pidfile exists and is killable - added --quit-signal option. respawn will quit if child exits due to that signal @ text @#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MAXPATHLEN #define MAXPATHLEN 512 #endif #define DEFAULT_PID_FMT "/var/run/%s.pid" int failcount = 5; int failtime = 10; char *pidfile = NULL; char *userid = NULL; char *ch_dir = NULL; char *output = NULL; int quit_signal = 0; void unlink_pid(void){ if (pidfile) unlink(pidfile); } void write_pid(const char *p) { FILE *pf; char tb[128]; pid_t pid; if (NULL == pidfile) { static char pid_path[MAXPATHLEN]; const char *t = strrchr(p, '/'); if (t) p = t; snprintf(pid_path, MAXPATHLEN, DEFAULT_PID_FMT, p); pidfile = pid_path; } pf = fopen(pidfile, "r"); if (NULL != pf) { fgets(tb, 128, pf); fclose(pf); strtok(tb, "\r\n"); pid = strtol(tb, NULL, 10); if (pid > 0 && 0 == kill(pid, 0)) { syslog(LOG_NOTICE, "Process %d already running\n", pid); exit(0); } } pf = fopen(pidfile, "w"); if (NULL != pf) { fprintf(pf, "%d\n", (int)getpid()); atexit(unlink_pid); fclose(pf); } } void usage(const char *me) { fprintf(stderr, "usage: %s\n\t--user=login\n\t--pidfile=path\n\t--fail-count=N\n\t--fail-time=N\n\t--stdouterr=file\n\t--chdir=dir\n\t--quit-signal=num\n", me); exit(1); } static struct option longopts[] = { {"user", required_argument, NULL, 'u'}, {"pidfile", required_argument, NULL, 'p'}, {"chdir", required_argument, NULL, 'c'}, {"stdouterr", required_argument, NULL, 's'}, {"quit-signal", required_argument, NULL, 'q'}, {"fail-count", required_argument, &failcount, 1001}, {"fail-time", required_argument, &failtime, 1002}, {NULL, 0, NULL, 0} }; int main(int argc, char *argv[]) { pid_t pid = -1; int fd = -1; time_t start = 0; time_t stop = 0; int fails = 0; int status; char *appname; char *t; uid_t uid = 0; int ch; if ((t = strrchr(argv[0], '/'))) appname = t + 1; else appname = argv[0]; openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_DAEMON); while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) { switch (ch) { case 'u': userid = strdup(optarg); break; case 'p': pidfile = strdup(optarg); break; case 'c': ch_dir = strdup(optarg); break; case 's': output = strdup(optarg); break; case 'q': quit_signal = atoi(optarg); break; default: usage(appname); break; } } argc -= optind; argv += optind; if (userid) { struct passwd *p = getpwnam(userid); if (NULL == p) errx(1, "Unknown user '%s'", userid); uid = p->pw_uid; setenv("HOME", p->pw_dir, 1); } if ((pid = fork()) < 0) syslog(LOG_ALERT, "fork failed: %s", strerror(errno)); else if (pid > 0) exit(0); if (setsid() < 0) syslog(LOG_ALERT, "setsid failed: %s", strerror(errno)); closelog(); #ifdef TIOCNOTTY if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, NULL); close(fd); } #endif fd = open("/dev/null", O_RDWR); if (fd < 0) syslog(LOG_ERR, "/dev/null: %s\n", strerror(errno)); else { dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } if (output) { fd = open(output, O_CREAT|O_WRONLY|O_APPEND); syslog(LOG_ERR, "output is %s\n", output); if (fd < 0) syslog(LOG_ERR, "output: %s\n", strerror(errno)); else { dup2(fd, 1); dup2(fd, 2); close(fd); } } openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_DAEMON); for (;;) { if ((pid = fork()) == 0) { /* child */ write_pid(argv[0]); if (uid > 0) { syslog(LOG_NOTICE, "changing to user %s/%d", userid, uid); setuid(uid); } if (ch_dir) chdir(ch_dir); syslog(LOG_NOTICE, "running '%s'", argv[0]); execvp(argv[0], &argv[0]); syslog(LOG_ALERT, "execvp '%s' failed: %s", argv[0], strerror(errno)); } /* parent */ openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_DAEMON); time(&start); pid = waitpid(-1, &status, 0); time(&stop); if (WIFEXITED(status)) { syslog(LOG_NOTICE, "child process %d exited with status %d", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { syslog(LOG_NOTICE, "child process %d exited due to signal %d", pid, WTERMSIG(status)); } else { syslog(LOG_NOTICE, "child process %d exited", pid); } if (stop - start < failtime) fails++; else fails = 0; if (fails == failcount) { syslog(LOG_ALERT, "Exiting due to repeated, frequent failures"); exit(1); } if (WIFEXITED(status)) if (WEXITSTATUS(status) == 0) exit(0); if (WIFSIGNALED(status)) { if (quit_signal == WTERMSIG(status)) exit(0); switch (WTERMSIG(status)) { case SIGKILL: exit(0); break; default: break; } } } } @ 1.4 log @*** empty log message *** @ text @d9 1 d27 1 d38 2 d48 11 d70 1 a70 1 fprintf(stderr, "usage: %s --user=login --pidfile=path --fail-count=N --fail-time=N\n", me); d79 1 d105 1 a105 1 while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) d119 3 d126 1 d161 2 a162 1 fd = open(output, O_WRONLY|O_APPEND); d215 2 @ 1.3 log @add new features @ text @d24 2 d27 4 a30 1 void unlink_pid(void) { if (pidfile) unlink(pidfile); } d37 3 a39 3 static char pid_path[MAXPATHLEN]; const char *t = strrchr(p, '/'); if (t) d41 1 a41 1 snprintf(pid_path, MAXPATHLEN, DEFAULT_PID_FMT, p); d47 1 a47 1 atexit(unlink_pid); d60 7 a66 5 { "user", required_argument, NULL, 'u' }, { "pidfile", required_argument, NULL, 'p' }, { "fail-count", required_argument, &failcount, 'c' }, { "fail-time", required_argument, &failtime, 't' }, { NULL, 0, NULL, 0 } d80 1 a80 1 uid_t uid = -1; d84 1 a84 1 appname = t+1; d89 20 a108 14 while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) switch (ch) { case 'u': userid = strdup(optarg); break; case 'p': pidfile = strdup(optarg); break; default: usage(appname); break; } argc -= optind; argv += optind; d115 1 a116 1 d132 1 a132 1 if (fd < 0) { d134 1 a134 1 } else { d140 10 d155 7 a161 5 write_pid(argv[0]); if (uid > 0) { syslog(LOG_NOTICE, "changing to user %s/%d", userid, uid); setuid(uid); } d191 2 a192 2 if (WEXITSTATUS(status) == 0) exit(0); @ 1.2 log @Now writes /var/run/%s.pid @ text @d12 3 d19 5 a23 2 #define PID_PATH "/var/run/%s.pid" char pid_path[MAXPATHLEN]; d25 1 a25 1 void unlink_pid(void) { unlink(pid_path); } a29 1 const char *t = strrchr(p, '/'); d31 9 a39 4 if (t) p = t; snprintf(pid_path, MAXPATHLEN, PID_PATH, p); pf = fopen(pid_path, "w"); d47 15 d69 1 a69 1 int failcount = 0; d73 2 a75 1 pid_path[0] = '\0'; d81 22 a128 1 write_pid(argv[1]); a129 1 d132 8 a139 3 syslog(LOG_NOTICE, "running '%s'", argv[1]); execvp(argv[1], &argv[1]); syslog(LOG_ALERT, "execvp '%s' failed: %s", argv[1], strerror(errno)); d157 2 a158 2 if (stop - start < 10) failcount++; d160 2 a161 2 failcount = 0; if (failcount == 5) { @ 1.1 log @Initial revision @ text @d3 1 d13 24 d49 1 d55 1 d81 1 @