コード例 #1
0
ファイル: daemon.c プロジェクト: dcbradley/parrot_cvmfs
void daemonize (int cdroot)
{
	/* Become seesion leader and lose controlling terminal */
	pid_t pid = fork();
	if (pid < 0) {
		debug(D_DEBUG, "could not fork: %s", strerror(errno));
		exit(EXIT_FAILURE);
	} else if (pid > 0) {
		exit(EXIT_SUCCESS); /* exit parent */
	}

	pid_t group = setsid();
	if (group == (pid_t) -1) {
		debug(D_DEBUG, "could not create session: %s", strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* Second fork ensures process cannot acquire controlling terminal */
	pid = fork();
	if (pid < 0) {
		debug(D_DEBUG, "could not fork: %s", strerror(errno));
		exit(EXIT_FAILURE);
	} else if (pid > 0) {
		exit(EXIT_SUCCESS); /* exit parent */
	}

	if (cdroot){
		int status = chdir("/");
		if (status == -1) {
			debug(D_DEBUG, "could not chdir to `/': %s", strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	umask(0);

	int fd, max = fd_max();
	for (fd = 0; fd < max; fd++) {
		if (close(fd) == -1 && errno != EBADF) {
			debug(D_DEBUG, "could not close open file descriptor: %s", strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	int fd0 = open("/dev/null", O_RDONLY);
	int fd1 = open("/dev/null", O_WRONLY);
	int fd2 = open("/dev/null", O_WRONLY);

	if (!(fd0 == STDIN_FILENO && fd1 == STDOUT_FILENO && fd2 == STDERR_FILENO)) {
		debug(D_DEBUG, "could not open `/dev/null': %d %d %d: %s", fd0, fd1, fd2, strerror(errno));
		exit(EXIT_FAILURE);
	}
}
コード例 #2
0
ファイル: impl.c プロジェクト: Hochikong/huptime
void
impl_init(void)
{
    const char* mode_env = getenv("HUPTIME_MODE");
    const char* multi_env = getenv("HUPTIME_MULTI");
    const char* revive_env = getenv("HUPTIME_REVIVE");
    const char* debug_env = getenv("HUPTIME_DEBUG");
    const char* pipe_env = getenv("HUPTIME_PIPE");
    const char* wait_env = getenv("HUPTIME_WAIT");

    if( debug_env != NULL && strlen(debug_env) > 0 )
    {
        debug_enabled = !strcasecmp(debug_env, "true") ? TRUE: FALSE;
    }

    DEBUG("Initializing...");

    /* Initialize our lock. */
    impl_init_lock();

    /* Save this pid as our master pid.
     * This is done to handle processes that use
     * process pools. We remember the master pid and
     * will do the full fork()/exec() only when we are
     * the master. Otherwise, we will simply shutdown
     * gracefully, and all the master to restart. */
    master_pid = getpid();

    /* Grab our exit strategy. */
    if( mode_env != NULL && strlen(mode_env) > 0 )
    {
        if( !strcasecmp(mode_env, "fork") )
        {
            exit_strategy = FORK;
            DEBUG("Exit strategy is fork.");
        }
        else if( !strcasecmp(mode_env, "exec") )
        {
            exit_strategy = EXEC;
            DEBUG("Exit strategy is exec.");
        }
        else
        {
            fprintf(stderr, "Unknown exit strategy.");
            libc.exit(1);
        }
    }

    /* Check if we have something to unlink. */
    to_unlink = getenv("HUPTIME_UNLINK");
    if( to_unlink != NULL && strlen(to_unlink) > 0 )
    {
        DEBUG("Unlink is '%s'.", to_unlink);
    }

    /* Clear up any outstanding child processes.
     * Because we may have exited before the process
     * could do appropriate waitpid()'s, we try to
     * clean up children here. Note that we may have
     * some zombies that hang around during the life
     * of the program, but at every restart they will
     * be cleaned up (so at least they won't grow
     * without bound). */
    int status = 0;
    while( waitpid((pid_t)-1, &status, WNOHANG) > 0 );

    /* Check if we're in multi mode. */
    if( multi_env != NULL && strlen(multi_env) > 0 )
    {
        multi_mode = !strcasecmp(multi_env, "true") ? TRUE: FALSE;
    }
#ifndef SO_REUSEPORT
    if( multi_mode == TRUE )
    {
        fprintf(stderr, "WARNING: Multi mode not supported.\n");
        fprintf(stderr, "(Requires at least Linux 3.9 and recent headers).\n");
    } 
#endif

    /* Check if we're in revive mode. */
    if( revive_env != NULL && strlen(revive_env) > 0 )
    {
        revive_mode = !strcasecmp(revive_env, "true") ? TRUE : FALSE;
    }

    /* Check if we are in wait mode. */
    if( wait_env != NULL && strlen(wait_env) > 0 )
    {
        wait_mode = !strcasecmp(wait_env, "true") ? TRUE : FALSE;
    }

    /* Check if we're a respawn. */
    if( pipe_env != NULL && strlen(pipe_env) > 0 )
    {
        int fd = -1;
        fdinfo_t *info = NULL;
        int pipefd = strtol(pipe_env, NULL, 10);

        DEBUG("Loading all file descriptors.");

        /* Decode all passed information. */
        while( !info_decode(pipefd, &fd, &info) )
        {
            fd_save(fd, info);
            DEBUG("Decoded fd %d (type %d).", fd, info->type);
            info = NULL;
        }
        if( info != NULL )
        {
            dec_ref(info);
        }

        /* Finished with the pipe. */
        libc.close(pipefd);
        unsetenv("HUPTIME_PIPE");
        DEBUG("Finished decoding.");

        /* Close all non-encoded descriptors. */
        for( fd = 0; fd < fd_max(); fd += 1 )
        {
            info = fd_lookup(fd);
            if( info == NULL )
            {
                DEBUG("Closing fd %d.", fd);
                libc.close(fd);
            }
        }

        /* Restore all given file descriptors. */
        for( fd = 0; fd < fd_limit(); fd += 1 )
        {
            info = fd_lookup(fd);
            if( info != NULL && info->type == SAVED )
            {
                fdinfo_t *orig_info = fd_lookup(info->saved.fd);
                if( orig_info != NULL )
                {
                    /* Uh-oh, conflict. Move the original (best effort). */
                    do_dup(info->saved.fd);
                    do_close(info->saved.fd);
                }

                /* Return the offset (ignore failure). */
                if( info->saved.offset != (off_t)-1 )
                {
                    lseek(fd, info->saved.offset, SEEK_SET);
                }

                /* Move the SAVED fd back. */
                libc.dup2(fd, info->saved.fd);
                DEBUG("Restored fd %d.", info->saved.fd);
            }
        }
    }
    else
    {
        DEBUG("Saving all initial file descriptors.");

        /* Save all of our initial files. These are used
         * for re-execing the process. These are persisted
         * effectively forever, and on restarts we close
         * everything that is not a BOUND socket or a SAVED
         * file descriptor. */
        for( int fd = 0; fd < fd_max(); fd += 1 )
        {
            fdinfo_t *info = fd_lookup(fd);
            if( info != NULL )
            {
                /* Encoded earlier. */
                continue;
            }

            /* Make a new SAVED FD. */
            int newfd = libc.dup(fd);
            if( newfd >= 0 )
            {
                fdinfo_t *saved_info = alloc_info(SAVED);

                if( saved_info != NULL )
                {
                    saved_info->saved.fd = fd;
                    saved_info->saved.offset = lseek(fd, 0, SEEK_CUR);
                    fd_save(newfd, saved_info);
                    DEBUG("Saved fd %d (offset %lld).",
                        fd, (long long int)saved_info->saved.offset);
                }
            }
        }
    }

    /* Save the environment.
     *
     * NOTE: We reserve extra space in the environment
     * for our special start-up parameters, which will be added
     * in impl_exec() below. (The encoded BOUND/SAVED sockets).
     *
     * We also filter out the special variables above that were
     * used to pass in information about sockets that were bound. */
    free(environ_copy);
    environ_copy = (char**)read_nul_sep("/proc/self/environ");
    DEBUG("Saved environment.");

    /* Save the arguments. */
    free(args_copy);
    args_copy = (char**)read_nul_sep("/proc/self/cmdline");
    DEBUG("Saved args.");
    for( int i = 0; args_copy[i] != NULL; i += 1 )
    {
        DEBUG(" arg%d=%s", i, args_copy[i]);
    }

    /* Save the cwd & exe. */
    free(cwd_copy);
    cwd_copy = (char*)read_link("/proc/self/cwd");
    DEBUG("Saved cwd.");
    free(exe_copy);
    exe_copy = (char*)read_link("/proc/self/exe");
    DEBUG("Saved exe.");

    /* Install our signal handlers. */
    impl_install_sighandlers();

    /* Initialize our thread. */
    impl_init_thread();

    /* Unblock our signals.
     * Note that we have specifically masked the
     * signals prior to the exec() below, to cover
     * the race between program start and having
     * installed the appropriate handlers. */
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGHUP);
    sigprocmask(SIG_UNBLOCK, &set, NULL);

    /* Done. */
    DEBUG("Initialization complete.");
}