Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
/* 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);
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
/* 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;
}