static inline JaConfig *initialize_jacques(void) { JaConfig *cfg = read_config(); g_mkdir_with_parents(CONFIG_RUNTIME_LOCATION, 0755); g_mkdir_with_parents(CONFIG_LOG_LOCATION, 0755); g_mkdir_with_parents(CONFIG_LOG_LOCATION, 0755); gint running = already_running(); if (running > 0) { g_printf(_("jacqueas is already running!!!\n")); exit(EXIT_MASTER_ALREADY_RUNNING); } else if (running < 0) { g_printf(_("Unable to create pid file:%s\n"), strerror(errno)); exit(EXIT_MASTER_INITIALIZE); } else if (!daemonize() || !initialize_default_log() || !lock_pidfile()) { g_printf(_("Unable to initialize jacques:%s\n"), strerror(errno)); exit(EXIT_MASTER_INITIALIZE); } return cfg; }
static void run_service(void) { int fd; bool res; #ifndef _WIN32 // Before we redirect stdin/stdout to the log files, move any inetd-provided // socket to a different descriptor number. if (inetd_style) { if (!w_listener_prep_inetd()) { return; } } #endif // redirect std{in,out,err} fd = open("/dev/null", O_RDONLY); if (fd != -1) { ignore_result(dup2(fd, STDIN_FILENO)); close(fd); } fd = open(log_name, O_WRONLY|O_APPEND|O_CREAT, 0600); if (fd != -1) { ignore_result(dup2(fd, STDOUT_FILENO)); ignore_result(dup2(fd, STDERR_FILENO)); close(fd); } if (!lock_pidfile()) { return; } #ifndef _WIN32 /* we are the child, let's set things up */ ignore_result(chdir("/")); #endif w_set_thread_name("listener"); { char hostname[256]; gethostname(hostname, sizeof(hostname)); hostname[sizeof(hostname) - 1] = '\0'; w_log(W_LOG_ERR, "Watchman %s %s starting up on %s\n", PACKAGE_VERSION, #ifdef WATCHMAN_BUILD_INFO WATCHMAN_BUILD_INFO, #else "<no build info set>", #endif hostname); } #ifndef _WIN32 // Block SIGCHLD by default; we only want it to be delivered // to the reaper thread and only when it is ready to reap. // This MUST happen before we spawn any threads so that they // can pick up our default blocked signal mask. { sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGCHLD); sigprocmask(SIG_BLOCK, &sigset, NULL); } #endif watchman_watcher_init(); w_clockspec_init(); // Start the reaper before we load any state; the state may // have triggers associated with it which may spawn processes w_start_reaper(); w_state_load(); res = w_start_listener(sock_name); w_root_free_watched_roots(); if (res) { exit(0); } exit(1); }
static pid_t read_pidfile__(const char *pidfile, bool delete_if_stale) { struct stat s, s2; struct flock lck; char line[128]; FILE *file; int error; if ((pidfile_ino || pidfile_dev) && !stat(pidfile, &s) && s.st_ino == pidfile_ino && s.st_dev == pidfile_dev) { /* It's our own pidfile. We can't afford to open it, because closing * *any* fd for a file that a process has locked also releases all the * locks on that file. * * Fortunately, we know the associated pid anyhow: */ return getpid(); } file = fopen(pidfile, "r+"); if (!file) { if (errno == ENOENT && delete_if_stale) { return 0; } error = errno; VLOG_WARN("%s: open: %s", pidfile, ovs_strerror(error)); goto error; } error = lock_pidfile__(file, F_GETLK, &lck); if (error) { VLOG_WARN("%s: fcntl: %s", pidfile, ovs_strerror(error)); goto error; } if (lck.l_type == F_UNLCK) { /* pidfile exists but it isn't locked by anyone. We need to delete it * so that a new pidfile can go in its place. But just calling * unlink(pidfile) makes a nasty race: what if someone else unlinks it * before we do and then replaces it by a valid pidfile? We'd unlink * their valid pidfile. We do a little dance to avoid the race, by * locking the invalid pidfile. Only one process can have the invalid * pidfile locked, and only that process has the right to unlink it. */ if (!delete_if_stale) { error = ESRCH; VLOG_DBG("%s: pid file is stale", pidfile); goto error; } /* Get the lock. */ error = lock_pidfile(file, F_SETLK); if (error) { /* We lost a race with someone else doing the same thing. */ VLOG_WARN("%s: lost race to lock pidfile", pidfile); goto error; } /* Is the file we have locked still named 'pidfile'? */ if (stat(pidfile, &s) || fstat(fileno(file), &s2) || s.st_ino != s2.st_ino || s.st_dev != s2.st_dev) { /* No. We lost a race with someone else who got the lock before * us, deleted the pidfile, and closed it (releasing the lock). */ error = EALREADY; VLOG_WARN("%s: lost race to delete pidfile", pidfile); goto error; } /* We won the right to delete the stale pidfile. */ if (unlink(pidfile)) { error = errno; VLOG_WARN("%s: failed to delete stale pidfile (%s)", pidfile, ovs_strerror(error)); goto error; } VLOG_DBG("%s: deleted stale pidfile", pidfile); fclose(file); return 0; } if (!fgets(line, sizeof line, file)) { if (ferror(file)) { error = errno; VLOG_WARN("%s: read: %s", pidfile, ovs_strerror(error)); } else { error = ESRCH; VLOG_WARN("%s: read: unexpected end of file", pidfile); } goto error; } if (lck.l_pid != strtoul(line, NULL, 10)) { /* The process that has the pidfile locked is not the process that * created it. It must be stale, with the process that has it locked * preparing to delete it. */ error = ESRCH; VLOG_WARN("%s: stale pidfile for pid %s being deleted by pid %ld", pidfile, line, (long int) lck.l_pid); goto error; } fclose(file); return lck.l_pid; error: if (file) { fclose(file); } return -error; }
/* If a pidfile has been configured, creates it and stores the running * process's pid in it. Ensures that the pidfile will be deleted when the * process exits. */ static void make_pidfile(void) { long int pid = getpid(); struct stat s; char *tmpfile; FILE *file; int error; /* Create a temporary pidfile. */ if (overwrite_pidfile) { tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); fatal_signal_add_file_to_unlink(tmpfile); } else { /* Everyone shares the same file which will be treated as a lock. To * avoid some uncomfortable race conditions, we can't set up the fatal * signal unlink until we've acquired it. */ tmpfile = xasprintf("%s.tmp", pidfile); } file = fopen(tmpfile, "a+"); if (!file) { VLOG_FATAL("%s: create failed (%s)", tmpfile, ovs_strerror(errno)); } error = lock_pidfile(file, F_SETLK); if (error) { /* Looks like we failed to acquire the lock. Note that, if we failed * for some other reason (and '!overwrite_pidfile'), we will have * left 'tmpfile' as garbage in the file system. */ VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile, ovs_strerror(error)); } if (!overwrite_pidfile) { /* We acquired the lock. Make sure to clean up on exit, and verify * that we're allowed to create the actual pidfile. */ fatal_signal_add_file_to_unlink(tmpfile); check_already_running(); } if (fstat(fileno(file), &s) == -1) { VLOG_FATAL("%s: fstat failed (%s)", tmpfile, ovs_strerror(errno)); } if (ftruncate(fileno(file), 0) == -1) { VLOG_FATAL("%s: truncate failed (%s)", tmpfile, ovs_strerror(errno)); } fprintf(file, "%ld\n", pid); if (fflush(file) == EOF) { VLOG_FATAL("%s: write failed (%s)", tmpfile, ovs_strerror(errno)); } error = rename(tmpfile, pidfile); /* Due to a race, 'tmpfile' may be owned by a different process, so we * shouldn't delete it on exit. */ fatal_signal_remove_file_to_unlink(tmpfile); if (error < 0) { VLOG_FATAL("failed to rename \"%s\" to \"%s\" (%s)", tmpfile, pidfile, ovs_strerror(errno)); } /* Ensure that the pidfile will get deleted on exit. */ fatal_signal_add_file_to_unlink(pidfile); /* Clean up. * * We don't close 'file' because its file descriptor must remain open to * hold the lock. */ pidfile_dev = s.st_dev; pidfile_ino = s.st_ino; free(tmpfile); }
static void run_service(void) { int fd; bool res; #ifndef _WIN32 // Before we redirect stdin/stdout to the log files, move any inetd-provided // socket to a different descriptor number. if (inetd_style) { if (!w_listener_prep_inetd()) { return; } } #endif // redirect std{in,out,err} fd = open("/dev/null", O_RDONLY); if (fd != -1) { ignore_result(dup2(fd, STDIN_FILENO)); close(fd); } fd = open(log_name, O_WRONLY|O_APPEND|O_CREAT, 0600); if (fd != -1) { ignore_result(dup2(fd, STDOUT_FILENO)); ignore_result(dup2(fd, STDERR_FILENO)); close(fd); } if (!lock_pidfile()) { return; } #ifndef _WIN32 /* we are the child, let's set things up */ ignore_result(chdir("/")); #endif w_set_thread_name("listener"); { char hostname[256]; gethostname(hostname, sizeof(hostname)); hostname[sizeof(hostname) - 1] = '\0'; w_log(W_LOG_ERR, "Watchman %s %s starting up on %s\n", PACKAGE_VERSION, #ifdef WATCHMAN_BUILD_INFO WATCHMAN_BUILD_INFO, #else "<no build info set>", #endif hostname); } watchman_watcher_init(); w_clockspec_init(); w_state_load(); w_start_reaper(); res = w_start_listener(sock_name); w_root_free_watched_roots(); if (res) { exit(0); } exit(1); }
/* If a pidfile has been configured, creates it and stores the running * process's pid in it. Ensures that the pidfile will be deleted when the * process exits. */ static void make_pidfile(void) { long int pid = getpid(); struct stat s; char *tmpfile; FILE *file; int error; /* Create a temporary pidfile. */ tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); fatal_signal_add_file_to_unlink(tmpfile); file = fopen(tmpfile, "w+"); if (!file) { VLOG_FATAL("%s: create failed (%s)", tmpfile, strerror(errno)); } if (fstat(fileno(file), &s) == -1) { VLOG_FATAL("%s: fstat failed (%s)", tmpfile, strerror(errno)); } fprintf(file, "%ld\n", pid); if (fflush(file) == EOF) { VLOG_FATAL("%s: write failed (%s)", tmpfile, strerror(errno)); } error = lock_pidfile(file, F_SETLK); if (error) { VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile, strerror(error)); } /* Rename or link it to the correct name. */ if (overwrite_pidfile) { if (rename(tmpfile, pidfile) < 0) { VLOG_FATAL("failed to rename \"%s\" to \"%s\" (%s)", tmpfile, pidfile, strerror(errno)); } } else { do { error = link(tmpfile, pidfile) == -1 ? errno : 0; if (error == EEXIST) { check_already_running(); } } while (error == EINTR || error == EEXIST); if (error) { VLOG_FATAL("failed to link \"%s\" as \"%s\" (%s)", tmpfile, pidfile, strerror(error)); } } /* Ensure that the pidfile will get deleted on exit. */ fatal_signal_add_file_to_unlink(pidfile); /* Delete the temporary pidfile if it still exists. */ if (!overwrite_pidfile) { error = fatal_signal_unlink_file_now(tmpfile); if (error) { VLOG_FATAL("%s: unlink failed (%s)", tmpfile, strerror(error)); } } /* Clean up. * * We don't close 'file' because its file descriptor must remain open to * hold the lock. */ pidfile_dev = s.st_dev; pidfile_ino = s.st_ino; free(tmpfile); free(pidfile); pidfile = NULL; }