/* the echo service. stupid, but useful for testing */ static int qh_echo(int sd, char *buf, unsigned int len) { if (!strcmp(buf, "help")) { nsock_printf_nul(sd, "Query handler that simply echoes back what you send it."); return 0; } return nsock_write_all(sd, buf, len); }
int daemon_init(void) { int pid = 0; int lockfile = 0; int val = 0; char buf[256]; struct flock lock; if (set_working_directory() == (ERROR)) { return (ERROR); } umask(S_IWGRP | S_IWOTH); lockfile = open(lock_file, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (lockfile < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Failed to obtain lock on file %s: %s\n", lock_file, strerror(errno)); nm_log(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, "Bailing out due to errors encountered while attempting to daemonize... (PID=%d)", (int)getpid()); return (ERROR); } /* see if we can read the contents of the lockfile */ if ((val = read(lockfile, buf, (size_t)10)) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Lockfile exists but cannot be read"); return (ERROR); } /* we read something - check the PID */ if (val > 0) { if ((val = sscanf(buf, "%d", &pid)) < 1) { nm_log(NSLOG_RUNTIME_ERROR, "Lockfile '%s' does not contain a valid PID (%s)", lock_file, buf); return (ERROR); } } /* check for SIGHUP */ if (val == 1 && pid == (int)getpid()) { return OK; } else { lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(lockfile, F_GETLK, &lock) == -1) { nm_log(NSLOG_RUNTIME_ERROR, "Failed to access lockfile '%s'. %s. Bailing out...", lock_file, strerror(errno)); return (ERROR); } if (lock.l_type != F_UNLCK) { nm_log(NSLOG_RUNTIME_ERROR, "Lockfile '%s' looks like its already held by another instance of Naemon (PID %d). Bailing out, pre-fork...", lock_file, (int)lock.l_pid); return (ERROR); } } /* * set up a pipe used for sending a message from the child to the parent * when initialization is complete. */ if (pipe(upipe_fd) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Failed to set up unnamned pipe: %s", strerror(errno)); return (ERROR); } if ((pid = (int)fork()) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Unable to fork out the daemon process: %s", strerror(errno)); return (ERROR); } else if (pid != 0) { /* parent stops - when child is done, we exit here */ int return_code = EXIT_FAILURE; if (close(upipe_fd[PIPE_WRITE]) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Unable to close parent write end: %s", strerror(errno)); return_code = EXIT_FAILURE; } /* * wait for child to send the OK return code, if the child dies * we stop blocking and the return code remains EXIT_FAILURE. */ if (read(upipe_fd[PIPE_READ], &return_code, sizeof(int)) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Unable to read from pipe: %s", strerror(errno)); return_code = EXIT_FAILURE; } if (close(upipe_fd[PIPE_READ]) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Unable to close parent read end: %s", strerror(errno)); return_code = EXIT_FAILURE; } if (return_code != OK) { /* signal the child to die in case an error occurs in parent */ kill(pid, SIGTERM); } exit(return_code); } else { /* close read end of the pipe in the child */ if (close(upipe_fd[PIPE_READ]) < 0) { nm_log(NSLOG_RUNTIME_ERROR, "Unable to close child read end: %s", strerror(errno)); return ERROR; } } /* child becomes session leader... */ setsid(); /* place a file lock on the lock file */ lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; lock.l_pid = getpid(); if (fcntl(lockfile, F_SETLK, &lock) == -1) { if (errno == EACCES || errno == EAGAIN) { fcntl(lockfile, F_GETLK, &lock); nm_log(NSLOG_RUNTIME_ERROR, "Lockfile '%s' looks like its already held by another instance of Naemon (PID %d). Bailing out, post-fork...", lock_file, (int)lock.l_pid); } else nm_log(NSLOG_RUNTIME_ERROR, "Cannot lock lockfile '%s': %s. Bailing out...", lock_file, strerror(errno)); return (ERROR); } /* write PID to lockfile... */ lseek(lockfile, 0, SEEK_SET); if (ftruncate(lockfile, 0) != 0) { nm_log(NSLOG_RUNTIME_ERROR, "Cannot truncate lockfile '%s': %s. Bailing out...", lock_file, strerror(errno)); return (ERROR); } sprintf(buf, "%d\n", (int)getpid()); if (nsock_write_all(lockfile, buf, strlen(buf)) != 0) { nm_log(NSLOG_RUNTIME_ERROR, "Cannot write PID to lockfile '%s': %s. Bailing out...", lock_file, strerror(errno)); return (ERROR); } /* make sure lock file stays open while program is executing... */ val = fcntl(lockfile, F_GETFD, 0); val |= FD_CLOEXEC; fcntl(lockfile, F_SETFD, val); /* close existing stdin, stdout, stderr */ close(0); close(1); close(2); /* THIS HAS TO BE DONE TO AVOID PROBLEMS WITH STDERR BEING REDIRECTED TO SERVICE MESSAGE PIPE! */ /* re-open stdin, stdout, stderr with known values */ open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); broker_program_state(NEBTYPE_PROCESS_DAEMONIZE, NEBFLAG_NONE, NEBATTR_NONE); return OK; }