--- busybox-1.00/networking/udhcp/pidfile.h-dist 2004-04-15 03:51:26.000000000 +1000 +++ busybox-1.00/networking/udhcp/pidfile.h 2004-10-27 15:46:38.000000000 +1000 @@ -21,5 +21,5 @@ int pidfile_acquire(const char *pidfile); -void pidfile_write_release(int pid_fd); +int pidfile_reassign(const char *pidfile, int newpid); --- busybox-1.00/networking/udhcp/pidfile.c-dist 2004-04-15 03:51:25.000000000 +1000 +++ busybox-1.00/networking/udhcp/pidfile.c 2004-10-27 19:43:40.000000000 +1000 @@ -25,6 +25,7 @@ #include #include #include +#include #include "pidfile.h" #include "common.h" @@ -37,39 +38,146 @@ } -int pidfile_acquire(const char *pidfile) +static int pidfile_open(const char *pidfile) { - int pid_fd; - if (!pidfile) return -1; + int fd; - pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644); - if (pid_fd < 0) { - LOG(LOG_ERR, "Unable to open pidfile %s: %m\n", pidfile); - } else { - lockf(pid_fd, F_LOCK, 0); - if (!saved_pidfile) - atexit(pidfile_delete); - saved_pidfile = (char *) pidfile; + if ((fd = open(pidfile, O_CREAT | O_RDWR, 0644)) < 0) { + LOG(LOG_ERR, "pidfile_open: open %s failed: %m\n", pidfile); + return (-1); + } + + /* NOTE: lockf is not inherited by child after fork */ + if (lockf(fd, F_LOCK, 0) < 0) { + LOG(LOG_ERR, "pidfile_open: lock %s failed: %m\n", pidfile); + close(fd); + return (-1); + } + + return (fd); +} + + +static int pidfile_check(int fd, const char *pidfile) +{ + int len, pid; + char buf[20]; + + if (lseek(fd, 0L, SEEK_SET) < 0) { + LOG(LOG_ERR, "pidfile_check: lseek %s failed: %m\n", pidfile); + return (-1); + } + + if ((len = read(fd, buf, sizeof buf - 1)) < 0) { + LOG(LOG_ERR, "pidfile_check: read %s failed: %m\n", pidfile); + return (-1); + } + + if (len == 0) + return (0); + + buf[len] = '\0'; + + if ((pid = atoi(buf)) <= 1) { + LOG(LOG_WARNING, + "pidfile_check: ignoring bogus pid (%s) in %s\n", + buf, pidfile); + return (0); + } + + if (kill((pid_t)pid, 0) == 0) { + LOG(LOG_ERR, "pidfile_check: process %d exists (%s)\n", + pid, pidfile); + return (-1); + } + + if (errno != ESRCH) { + LOG(LOG_ERR, "pidfile_check: kill %d failed (%s): %m\n", + pid, pidfile); + return (-1); + } + + return (0); +} + + +static int pidfile_store(int fd, const char *pidfile, int pid) +{ + int len; + char buf[20]; + + if (lseek(fd, 0L, SEEK_SET) < 0) { + LOG(LOG_ERR, "pidfile_store: lseek %s failed: %m\n", pidfile); + return (-1); + } + + len = snprintf(buf, sizeof buf - 1, "%d\n", pid); + buf[len] = '\0'; + + if (write(fd, buf, len) < 0) { + LOG(LOG_ERR, "pidfile_store: write %s failed: %m\n", + pidfile); + return (-1); + } + + if (ftruncate(fd, len) < 0) { + LOG(LOG_ERR, "pidfile_store: ftruncate %d failed (%s): %m\n", + len, pidfile); + return (-1); } - return pid_fd; + return (0); } -void pidfile_write_release(int pid_fd) +static void pidfile_close(int fd) { - FILE *out; + (void)lseek(fd, 0L, SEEK_SET); + (void)lockf(fd, F_ULOCK, 0); + (void)close(fd); +} - if (pid_fd < 0) return; - if ((out = fdopen(pid_fd, "w")) != NULL) { - fprintf(out, "%d\n", getpid()); - fclose(out); +int pidfile_acquire(const char *pidfile) +{ + int fd, result; + if (!pidfile) return (-1); + + if ((fd = pidfile_open(pidfile)) < 0) + return (-1); + + if ((result = pidfile_check(fd, pidfile)) == 0) + result = pidfile_store(fd, pidfile, getpid()); + + pidfile_close(fd); + + if (result == 0) { + saved_pidfile = (char *) pidfile; + atexit(pidfile_delete); } - lockf(pid_fd, F_UNLCK, 0); - close(pid_fd); + + return (result); } +/* + * reassign the pid in a pidfile - used just after a fork so a parent + * can store the pid of its child into the file without any window + * where the pid in the file is a dead process (which might let another + * instance of the program start). Note the parent must use _exit() to + * avoid triggering the unlink scheduled above in pidfile_acquire() + */ +int pidfile_reassign(const char *pidfile, int pid) +{ + int fd, result; + if (!pidfile) return (-1); + + if ((fd = pidfile_open(pidfile)) < 0) + return (-1); + result = pidfile_store(fd, pidfile, pid); + pidfile_close(fd); + + return (result); +} --- busybox-1.00/networking/udhcp/common.c-dist 2004-05-19 19:18:04.000000000 +1000 +++ busybox-1.00/networking/udhcp/common.c 2004-10-27 19:58:10.000000000 +1000 @@ -64,16 +64,34 @@ #ifdef __uClinux__ LOG(LOG_ERR, "Cannot background in uclinux (yet)"); #else /* __uClinux__ */ - int pid_fd; + int pid, fd; - /* hold lock during fork. */ - pid_fd = pidfile_acquire(pidfile); - if (daemon(0, 0) == -1) { + /* NOTE: lockf is not inherited by the child after fork */ + if ((pid = fork()) < 0) { perror("fork"); exit(1); } + + if (pid > 0) { + /* parent */ + if (pidfile_reassign(pidfile, pid) < 0) { + (void)kill(pid, SIGKILL); + exit(1); + } else + _exit(0); + } + + /* child */ + (void)chdir("/"); + if ((fd = open("/dev/null", O_RDWR)) >= 0) { + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); + (void)close(fd); + } + (void)setsid(); + daemonized++; - pidfile_write_release(pid_fd); #endif /* __uClinux__ */ } @@ -97,14 +115,12 @@ void start_log_and_pid(const char *client_server, const char *pidfile) { - int pid_fd; - /* Make sure our syslog fd isn't overwritten */ sanitize_fds(); /* do some other misc startup stuff while we are here to save bytes */ - pid_fd = pidfile_acquire(pidfile); - pidfile_write_release(pid_fd); + if (pidfile_acquire(pidfile) < 0) + exit(1); /* equivelent of doing a fflush after every \n */ setlinebuf(stdout); @@ -150,8 +166,8 @@ sanitize_fds(); /* do some other misc startup stuff while we are here to save bytes */ - pid_fd = pidfile_acquire(pidfile); - pidfile_write_release(pid_fd); + if (pidfile_acquire(pidfile) < 0) + exit(1); /* equivelent of doing a fflush after every \n */ setlinebuf(stdout); --- busybox-1.00/networking/udhcp/common.h-dist 2004-05-19 18:29:05.000000000 +1000 +++ busybox-1.00/networking/udhcp/common.h 2004-10-27 15:10:16.000000000 +1000 @@ -42,7 +42,6 @@ long uptime(void); void background(const char *pidfile); void start_log_and_pid(const char *client_server, const char *pidfile); -void background(const char *pidfile); void udhcp_logging(int level, const char *fmt, ...); #define LOG(level, str, args...) udhcp_logging(level, str, ## args) --- busybox-1.00/networking/udhcp/script.c-dist 2004-05-19 17:45:47.000000000 +1000 +++ busybox-1.00/networking/udhcp/script.c 2004-10-27 15:54:04.000000000 +1000 @@ -228,6 +228,6 @@ execle(client_config.script, client_config.script, name, NULL, envp); LOG(LOG_ERR, "script %s failed: %m", client_config.script); - exit(1); + _exit(1); } }