Ejemplo n.º 1
0
int
main(int argc, char *argv[])
{
	struct pidfh *pfh = NULL;
	sigset_t mask, oldmask;
	int ch, nochdir, noclose, restart;
	const char *pidfile, *user;
	pid_t otherpid, pid;

	nochdir = noclose = 1;
	restart = 0;
	pidfile = user = NULL;
	while ((ch = getopt(argc, argv, "-cfp:ru:")) != -1) {
		switch (ch) {
		case 'c':
			nochdir = 0;
			break;
		case 'f':
			noclose = 0;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'r':
			restart = 1;
			break;
		case 'u':
			user = optarg;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0)
		usage();

	pfh = NULL;
	/*
	 * Try to open the pidfile before calling daemon(3),
	 * to be able to report the error intelligently
	 */
	if (pidfile != NULL) {
		pfh = pidfile_open(pidfile, 0600, &otherpid);
		if (pfh == NULL) {
			if (errno == EEXIST) {
				errx(3, "process already running, pid: %d",
				    otherpid);
			}
			err(2, "pidfile ``%s''", pidfile);
		}
	}

	if (daemon(nochdir, noclose) == -1)
		err(1, NULL);

	/*
	 * If the pidfile or restart option is specified the daemon
	 * executes the command in a forked process and wait on child
	 * exit to remove the pidfile or restart the command. Normally
	 * we don't want the monitoring daemon to be terminated
	 * leaving the running process and the stale pidfile, so we
	 * catch SIGTERM and forward it to the children expecting to
	 * get SIGCHLD eventually.
	 */
	pid = -1;
	if (pidfile != NULL || restart) {
		/*
		 * Restore default action for SIGTERM in case the
		 * parent process decided to ignore it.
		 */
		if (signal(SIGTERM, SIG_DFL) == SIG_ERR)
			err(1, "signal");
		/*
		 * Because SIGCHLD is ignored by default, setup dummy handler
		 * for it, so we can mask it.
		 */
		if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR)
			err(1, "signal");
		/*
		 * Block interesting signals.
		 */
		sigemptyset(&mask);
		sigaddset(&mask, SIGTERM);
		sigaddset(&mask, SIGCHLD);
		if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1)
			err(1, "sigprocmask");
		/*
		 * Try to protect against pageout kill. Ignore the
		 * error, madvise(2) will fail only if a process does
		 * not have superuser privileges.
		 */
		(void)madvise(NULL, 0, MADV_PROTECT);
restart:
		/*
		 * Spawn a child to exec the command, so in the parent
		 * we could wait for it to exit and remove pidfile.
		 */
		pid = fork();
		if (pid == -1) {
			pidfile_remove(pfh);
			err(1, "fork");
		}
	}
	if (pid <= 0) {
		if (pid == 0) {
			/* Restore old sigmask in the child. */
			if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
				err(1, "sigprocmask");
		}
		/* Now that we are the child, write out the pid. */
		pidfile_write(pfh);

		if (user != NULL)
			restrict_process(user);

		execvp(argv[0], argv);

		/*
		 * execvp() failed -- report the error. The child is
		 * now running, so the exit status doesn't matter.
		 */
		err(1, "%s", argv[0]);
	}
	setproctitle("%s[%d]", argv[0], pid);
	if (wait_child(pid, &mask) == 0 && restart) {
		sleep(1);
		goto restart;
	}
	pidfile_remove(pfh);
	exit(0); /* Exit status does not matter. */
}
Ejemplo n.º 2
0
int
main(int argc, char *argv[])
{
	struct pidfh *pfh = NULL;
	int ch, nochdir, noclose, errcode;
	const char *pidfile, *user;
	pid_t otherpid;

	nochdir = noclose = 1;
	pidfile = user = NULL;
	while ((ch = getopt(argc, argv, "-cfp:u:")) != -1) {
		switch (ch) {
		case 'c':
			nochdir = 0;
			break;
		case 'f':
			noclose = 0;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'u':
			user = optarg;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0)
		usage();

	if (user != NULL)
		restrict_process(user);

	/*
	 * Try to open the pidfile before calling daemon(3),
	 * to be able to report the error intelligently
	 */
	if (pidfile) {
		pfh = pidfile_open(pidfile, 0600, &otherpid);
		if (pfh == NULL) {
			if (errno == EEXIST) {
				errx(3, "process already running, pid: %d",
				    otherpid);
			}
			err(2, "pidfile ``%s''", pidfile);
		}
	}

	if (daemon(nochdir, noclose) == -1)
		err(1, NULL);

	/* Now that we are the child, write out the pid */
	if (pidfile)
		pidfile_write(pfh);

	execvp(argv[0], argv);

	/*
	 * execvp() failed -- unlink pidfile if any, and
	 * report the error
	 */
	errcode = errno; /* Preserve errcode -- unlink may reset it */
	if (pidfile)
		pidfile_remove(pfh);

	/* The child is now running, so the exit status doesn't matter. */
	errc(1, errcode, "%s", argv[0]);
}
Ejemplo n.º 3
0
heartbeat_daemon_tool(int argc, char *argv[])
{
    struct pidfh *ppfh, *pfh;
    sigset_t mask, oldmask;
    int ch, nochdir, noclose, restart, serrno;
    const char *pidfile, *ppidfile, *user;
    pid_t otherpid, pid;

    nochdir = noclose = 1;
    restart = 0;
    ppidfile = pidfile = user = NULL;
    while ((ch = getopt(argc, argv, "cfp:P:ru:")) != -1) {
        switch (ch) {
            case 'c':
                nochdir = 0;
                break;
            case 'f':
                noclose = 0;
                break;
            case 'p':
                pidfile = optarg;
                break;
            case 'P':
                ppidfile = optarg;
                break;
            case 'r':
                restart = 1;
                break;
            case 'u':
                user = optarg;
                break;
            default:
                daemon_tool_usage();
        }
    }
    argc -= optind;
    argv += optind;

    if (argc == 0)
        daemon_tool_usage();

    if (pidfile != NULL) {
        pfh = pidfile_open(pidfile, 0600, &otherpid);
        if (pfh == NULL) {
            if (errno == EEXIST) {
                errx(3, "process already running, pid: %d", otherpid);
            }
            err(2, "pidfile ``%s''", pidfile);
        }
    }

    if (ppidfile != NULL) {
        ppfh = pidfile_open(ppidfile, 0600, &otherpid);
        if (ppfh == NULL) {
            serrno = errno;
            pidfile_remove(pfh);
            errno = serrno;
            if (errno = EEXIST) {
                errx(3, "process already running, pid: %d", otherpid);
            }
            err(2, "ppidfile ``%s''", ppidfile);
        }
    }

    if (daemon(nochdir, noclose) == -1) {
        warn("daemon");
        goto exit;
    }

    pidfile_write(ppfh);

    pid = -1;

    if (pidfile != NULL || ppidfile != NULL || restart) {
        if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
            warn("signal");
            goto exit;
        }
        if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) {
            warn("signal");
            goto exit;
        }

        sigemptyset(&mask);
        sigaddset(&mask, SIGTERM);
        sigaddset(&mask, SIGCHLD);
        if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) {
            warn("sigprocmask");
            goto exit;
        }
        (void)madvise(NULL, 0, MADV_PROTECT);

restart:
            pid = fork();
            if (pid == -1) {
                warn("fork");
                goto exit;
            }
    }
    if (pid <= 0) {
        if (pid == 0) {
            if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
                err(1, "sigprocmask");
        }

        pidfile_write(pfh);

        if (user != NULL)
            restrict_process(user);

        execvp(argv[0], argv);
        err(1, "%s", argv[0]);
    }
    setproctitle("%s[%d", argv[0], pid);
    if (wait_child(pid, &mask) == 0 && restart) {
        sleep(1);
        goto restart;
    }

exit:
        pidfile_remove(pfh);
        pidfile_remove(ppfh);
        exit(1);
}