Exemple #1
0
/**
 * Run @p argv in a child asynchronously.
 *
 * stdin, stdout and stderr are redirected as shown, unless those
 * filenames are NULL.  In that case they are left alone.
 *
 * @warning When called on the daemon, where stdin/stdout may refer to random
 * network sockets, all of the standard file descriptors must be redirected!
 **/
int dcc_spawn_child(char **argv, pid_t *pidptr,
                    const char *stdin_file,
                    const char *stdout_file,
                    const char *stderr_file)
{
    pid_t pid;

    dcc_trace_argv("forking to execute", argv);

    pid = fork();
    if (pid == -1) {
        rs_log_error("failed to fork: %s", strerror(errno));
        return EXIT_OUT_OF_MEMORY; /* probably */
    } else if (pid == 0) {
        /* If this is a remote compile,
         * put the child in a new group, so we can
         * kill it and all its descendents without killing distccd
         * FIXME: if you kill distccd while it's compiling, and
         * the compiler has an infinite loop bug, the new group
         * will run forever until you kill it.
         */
        if (stdout_file != NULL) {
            if (dcc_new_pgrp() != 0)
                rs_trace("Unable to start a new group\n");
        }
        dcc_inside_child(argv, stdin_file, stdout_file, stderr_file);
        /* !! NEVER RETURN FROM HERE !! */
    } else {
        *pidptr = pid;
        rs_trace("child started as pid%d", (int) pid);
        return 0;
    }
}
Exemple #2
0
/**
 * Be a standalone server, with responsibility for sockets and forking
 * children.  Puts the daemon in the background and detaches from the
 * controlling tty.
 **/
int dcc_standalone_server(void)
{
    int listen_fd;
    int n_cpus;
    int ret;
#ifdef HAVE_AVAHI
    void *avahi = NULL;
#endif

    if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
        return ret;

    dcc_defer_accept(listen_fd);

    set_cloexec_flag(listen_fd, 1);

    if (dcc_ncpus(&n_cpus) == 0)
        rs_log_info("%d CPU%s online on this server", n_cpus, n_cpus == 1 ? "" : "s");

    /* By default, allow one job per CPU, plus two for the pot.  The extra
     * ones are started to allow for a bit of extra concurrency so that the
     * machine is not idle waiting for disk or network IO. */
    if (arg_max_jobs)
        dcc_max_kids = arg_max_jobs;
    else
        dcc_max_kids = 2 + n_cpus;

    rs_log_info("allowing up to %d active jobs", dcc_max_kids);

    if (!opt_no_detach) {
        /* Don't go into the background until we're listening and
         * ready.  This is useful for testing -- when the daemon
         * detaches, we know we can go ahead and try to connect.  */
        dcc_detach();
    } else {
        /* Still create a new process group, even if not detached */
        rs_trace("not detaching");
        if ((ret = dcc_new_pgrp()) != 0)
            return ret;
        dcc_save_pid(getpid());
    }

    /* Don't catch signals until we've detached or created a process group. */
    dcc_daemon_catch_signals();

#ifdef HAVE_AVAHI
    /* Zeroconf registration */
    if (opt_zeroconf) {
        if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus, dcc_max_kids)))
            return EXIT_CONNECT_FAILED;
    }
#endif

    /* This is called in the master daemon, whether that is detached or
     * not.  */
    dcc_master_pid = getpid();

    if (opt_no_fork) {
        dcc_log_daemon_started("non-forking daemon");
        dcc_nofork_parent(listen_fd);
        ret = 0;
    } else {
        dcc_log_daemon_started("preforking daemon");
        ret = dcc_preforking_parent(listen_fd);
    }

#ifdef HAVE_AVAHI
    /* Remove zeroconf registration */
    if (opt_zeroconf) {
        if (dcc_zeroconf_unregister(avahi) != 0)
            return EXIT_CONNECT_FAILED;
    }
#endif

    return ret;
}