Example #1
0
/* Entry point */
int
main(int argc, char **argv)
{
	/* Init debugging level */
	mem_allocated = 0;
	debug = 0;

	/*
	 * Parse command line and set debug level.
	 * bits 0..7 reserved by main.c
	 */
	parse_cmdline(argc, argv);

	openlog(PROG, LOG_PID | ((debug & 1) ? LOG_CONS : 0), log_facility);
	log_message(LOG_INFO, "Starting " VERSION_STRING);

	/* Check if keepalived is already running */
	if (keepalived_running(daemon_mode)) {
		log_message(LOG_INFO, "daemon is already running");
		goto end;
	}

	if (debug & 1)
		enable_console_log();

	/* daemonize process */
	if (!(debug & 2))
		xdaemon(0, 0, 0);

	/* write the father's pidfile */
	if (!pidfile_write(main_pidfile, getpid()))
		goto end;

#ifndef _DEBUG_
	/* Signal handling initialization  */
	signal_init();
#endif

	/* Create the master thread */
	master = thread_make_master();

	/* Init daemon */
	start_keepalived();

#ifndef _DEBUG_
	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish daemon process */
	stop_keepalived();
#endif

	/*
	 * Reached when terminate signal catched.
	 * finally return from system
	 */
end:
	closelog();
	exit(0);
}
Example #2
0
void daemon_init(void)
{
    /* Our process ID and Session ID */
    pid_t pid, sid;
    
    struct pidfh *pfh;
    pid_t otherpid;

    pfh = pidfile_open("/var/run/ubd.pid", 0600, &otherpid);
    if( pfh == NULL ){
        if( errno == EEXIST ){
            syslog(LOG_ERR,"Other deamon allready running.");
            exit(EXIT_FAILURE);
        }
        syslog(LOG_ERR,"Cannot open or create  pidfile.");
    }

    /* Fork off the parent process */
    pid = fork();
    if (pid < 0) {
            exit(EXIT_FAILURE);
    }
    /* If we got a good PID, then
        we can exit the parent process. */
    if (pid > 0) {
            exit(EXIT_SUCCESS);
    }

    /* Change the file mode mask */
    umask(0);
    
    pidfile_write(pfh);

    /* Open any logs here */        
            
    /* Create a new SID for the child process */
    sid = setsid();
    if (sid < 0) {
            /* Log the failure */
            exit(EXIT_FAILURE);
    }
    
    /* Change the current working directory */
    if ((chdir("/")) < 0) {
            /* Log the failure */
            exit(EXIT_FAILURE);
    }
    
    /* Close out the standard file descriptors */
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
 }
Example #3
0
File: util.c Project: vstakhov/mpd
int
PIDCheck(const char *filename, int killem)
{
	int n_tries;
	struct pidfh *pfh = NULL;

/* Sanity */

	assert(!lockFp);

/* Atomically open and lock file */

	for (n_tries = 0; n_tries < MAX_LOCK_ATTEMPTS; n_tries++) {
		pid_t old_pid;

		pfh = pidfile_open(filename, 0644, &old_pid);
		if (pfh == NULL) {
			if (errno == EEXIST) {
				if (!killem) {
					Log(LG_ERR, ("already running as process %d", old_pid));
					return (-1);
				}
				if (kill(old_pid, SIGTERM) < 0)
					switch (errno) {
					case ESRCH:
						Log(LG_ERR, ("process %d no longer exists", old_pid));
						break;
					default:
						Perror("%s: kill(%d)", __FUNCTION__, old_pid);
						return (-1);
					}
				/* Wait and try again */
				Log(LG_ERR, ("waiting for process %d to die...", old_pid));
				sleep(1);
			} else {
				Perror("cannot open pid file");
				return (-1);
			}
		} else {
			pidfile_write(pfh);
			break;
		}
	}
	if (n_tries == MAX_LOCK_ATTEMPTS) {
		Log(LG_ERR, ("can't lock %s after %d attempts", filename, n_tries));
		return (-1);
	}
	return (0);
}
Example #4
0
int main(int argc, char **argv)
{
	int pid_fd = -1, r = 0;
	pid_t old_pid;
	struct pfiled pfiled;

	init_perr("pfiled");
	parse_cmdline(argc, argv);

	perr(PI, 0, "p = %ld, nr_ops = %lu\n", cmdline_portno, cmdline_nr_ops);
	
	if (cmdline_pidfile){
		pid_fd = pidfile_open(cmdline_pidfile, &old_pid);
		if (pid_fd < 0) {
			if (old_pid) {
				perr(PFE, 0, "Daemon already running, pid: %d.", old_pid);
			} else {
				perr(PFE, 0, "Cannot open or create pidfile");
			}
			return -1;
		}
	}

	if (cmdline_daemon){
		if (daemon(0, 1) < 0){
			perr(PFE, 0, "Cannot daemonize");
			r = -1;
			goto out;
		}
	}
	setup_signals();
	if (pid_fd > 0)
		pidfile_write(pid_fd);


	if (pfiled_init(&pfiled) < 0){
		r = -1;
		goto out;
	}

	r = pfiled_loop(&pfiled);
out:
	if (pid_fd > 0)
		pidfile_remove(cmdline_pidfile, pid_fd);
	return r;

}
Example #5
0
int
main(int argc, char **argv)
{
	struct agent_core_t core;
	struct agent_plugin_t *plug;
	struct pidfh *pfh = NULL;

	core.config = calloc(1,sizeof(struct agent_config_t));
	assert(core.config);
	core.plugins = NULL;
	core_alloc_plugins(&core);
	core_opt(&core, argc, argv);
	base64_init();
	core_plugins(&core);
	
	if (core.config->P_arg)
		p_open(&pfh, core.config->P_arg);

	sandbox(&core);
	if (core.config->d_arg)
		logger(-1, "Plugins initialized. -d argument given, so not forking.");
	else
		v_daemon(&pfh);
		
	if (pfh)
		pidfile_write(pfh);
	ipc_sanity(&core);
	threads_started = 1;
	for (plug = core.plugins; plug != NULL; plug = plug->next) {
		if (plug->start != NULL)
			plug->thread = plug->start(&core, plug->name);
	}
	threads_started = 2;
	for (plug = core.plugins; plug; plug = plug->next) {
		if (plug->thread) {
			pthread_join(*(pthread_t *)plug->thread, NULL);
			free(plug->thread);
		}
	}
	/*
	 * XXX: Might want to do this on SIGTERM too I suppose.
	 */
	if (pfh)
		pidfile_remove(pfh);
	return 0;
}
Example #6
0
/*
 * Test that pidfile_open() can create a pidfile and that pidfile_write()
 * can write to it.
 */
static const char *
test_pidfile_uncontested(void)
{
	const char *fn = "test_pidfile_uncontested";
	struct pidfh *pf;
	pid_t other = 0;

	unlink(fn);
	pf = pidfile_open(fn, 0600, &other);
	if (pf == NULL && other != 0)
		return ("pidfile exists and is locked");
	if (pf == NULL)
		return (strerror(errno));
	if (pidfile_write(pf) != 0) {
		pidfile_close(pf);
		unlink(fn);
		return ("failed to write PID");
	}
	pidfile_close(pf);
	unlink(fn);
	return (NULL);
}
Example #7
0
/*
 * Test that pidfile_open() locks against self.
 */
static const char *
test_pidfile_self(void)
{
	const char *fn = "test_pidfile_self";
	struct pidfh *pf1, *pf2;
	pid_t other = 0;
	int serrno;

	unlink(fn);
	pf1 = pidfile_open(fn, 0600, &other);
	if (pf1 == NULL && other != 0)
		return ("pidfile exists and is locked");
	if (pf1 == NULL)
		return (strerror(errno));
	if (pidfile_write(pf1) != 0) {
		serrno = errno;
		pidfile_close(pf1);
		unlink(fn);
		return (strerror(serrno));
	}
	// second open should fail
	pf2 = pidfile_open(fn, 0600, &other);
	if (pf2 != NULL) {
		pidfile_close(pf1);
		pidfile_close(pf2);
		unlink(fn);
		return ("managed to opened pidfile twice");
	}
	if (other != getpid()) {
		pidfile_close(pf1);
		unlink(fn);
		return ("pidfile contained wrong PID");
	}
	pidfile_close(pf1);
	unlink(fn);
	return (NULL);
}
int
main(
    int argc,
    char *argv[])
{
    const char *program = basename(argv[0]);

    int fps = DEFAULT_FPS;
    suseconds_t frameDuration =  1000000 / fps;
    bool isDaemon =  false;
    uint32_t sourceDisplayNumber = DEFAULT_SOURCE_DISPLAY_NUMBER;
    uint32_t destDisplayNumber = DEFAULT_DESTINATION_DISPLAY_NUMBER;
	int32_t layerNumber = DEFAULT_LAYER_NUMBER;
    const char *pidfile = NULL;

    //---------------------------------------------------------------------

    static const char *sopts = "d:f:hl:p:s:D";
    static struct option lopts[] = 
    {
        { "destination", required_argument, NULL, 'd' },
        { "fps", required_argument, NULL, 'f' },
        { "help", no_argument, NULL, 'h' },
        { "layer", required_argument, NULL, 'l' },
        { "pidfile", required_argument, NULL, 'p' },
        { "source", required_argument, NULL, 's' },
        { "daemon", no_argument, NULL, 'D' },
        { NULL, no_argument, NULL, 0 }
    };

    int opt = 0;

    while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1)
    {
        switch (opt)
        {
        case 'd':

            destDisplayNumber = atoi(optarg);
            break;

        case 'f':

            fps = atoi(optarg);

            if (fps > 0)
            {
                frameDuration = 1000000 / fps;
            }
            else
            {
                fps = 1000000 / frameDuration;
            }

            break;

        case 'h':

            printUsage(stdout, program);
            exit(EXIT_SUCCESS);

            break;

        case 'l':

            layerNumber = atoi(optarg);
            break;

        case 'p':

            pidfile = optarg;

            break;

        case 's':

            sourceDisplayNumber = atoi(optarg);
            break;

        case 'D':

            isDaemon = true;
            break;

        default:

            printUsage(stderr, program);
            exit(EXIT_FAILURE);

            break;
        }
    }

    //---------------------------------------------------------------------

    struct pidfh *pfh = NULL;

    if (isDaemon)
    {
        if (pidfile != NULL)
        {
            pid_t otherpid;
            pfh = pidfile_open(pidfile, 0600, &otherpid);

            if (pfh == NULL)
            {
                fprintf(stderr,
                        "%s is already running %jd\n",
                        program,
                        (intmax_t)otherpid);
                exit(EXIT_FAILURE);
            }
        }
        
        if (daemon(0, 0) == -1)
        {
            fprintf(stderr, "daemonize failed\n");

            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        if (pfh)
        {
            pidfile_write(pfh);
        }

        openlog(program, LOG_PID, LOG_USER);
    }

    //---------------------------------------------------------------------

    if (signal(SIGINT, signalHandler) == SIG_ERR)
    {
        perrorLog(isDaemon, program, "installing SIGINT signal handler");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    if (signal(SIGTERM, signalHandler) == SIG_ERR)
    {
        perrorLog(isDaemon, program, "installing SIGTERM signal handler");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    bcm_host_init();

    //---------------------------------------------------------------------

    int result = 0;

    //---------------------------------------------------------------------
    // Make sure the VC_DISPLAY variable isn't set. 

    unsetenv("VC_DISPLAY");

    //---------------------------------------------------------------------

    DISPMANX_DISPLAY_HANDLE_T sourceDisplay
        = vc_dispmanx_display_open(sourceDisplayNumber);

    if (sourceDisplay == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "open source display failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_MODEINFO_T sourceInfo;

    result = vc_dispmanx_display_get_info(sourceDisplay, &sourceInfo);

    if (result != 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "getting source display dimensions failed");

        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    DISPMANX_DISPLAY_HANDLE_T destDisplay
        = vc_dispmanx_display_open(destDisplayNumber);

    if (destDisplay == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "open destination display failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_MODEINFO_T destInfo;

    result = vc_dispmanx_display_get_info(destDisplay, &destInfo);

    if (result != 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "getting destination display dimensions failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    //---------------------------------------------------------------------

    messageLog(isDaemon,
               program,
               LOG_INFO,
               "copying from [%d] %dx%d to [%d] %dx%d",
               sourceDisplayNumber,
               sourceInfo.width,
               sourceInfo.height,
               destDisplayNumber,
               destInfo.width,
               destInfo.height);

    //---------------------------------------------------------------------

    uint32_t image_ptr;

    DISPMANX_RESOURCE_HANDLE_T resource = 
        vc_dispmanx_resource_create(VC_IMAGE_RGBA32,
                                    destInfo.width,
                                    destInfo.height,
                                    &image_ptr);

    //---------------------------------------------------------------------

    VC_RECT_T sourceRect;
    vc_dispmanx_rect_set(&sourceRect,
                         0,
                         0,
                         destInfo.width << 16,
                         destInfo.height << 16);
    
    VC_RECT_T destRect;
    vc_dispmanx_rect_set(&destRect, 0, 0, 0, 0);

    //---------------------------------------------------------------------

    VC_DISPMANX_ALPHA_T alpha =
    {
        DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
        255,
        0
    };

    DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);

    if (update == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "display update failed");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    DISPMANX_ELEMENT_HANDLE_T element;
    element = vc_dispmanx_element_add(update,
                                      destDisplay,
                                      layerNumber,
                                      &destRect,
                                      resource,
                                      &sourceRect,
                                      DISPMANX_PROTECTION_NONE,
                                      &alpha,
                                      NULL,
                                      DISPMANX_NO_ROTATE);
    if (element == 0)
    {
        messageLog(isDaemon,
                   program,
                   LOG_ERR,
                   "failed to create DispmanX element");
        exitAndRemovePidFile(EXIT_FAILURE, pfh);
    }

    vc_dispmanx_update_submit_sync(update);

    //---------------------------------------------------------------------

    struct timeval start_time;
    struct timeval end_time;
    struct timeval elapsed_time;

    //---------------------------------------------------------------------

    while (run)
    {
        gettimeofday(&start_time, NULL);

        //-----------------------------------------------------------------

        result = vc_dispmanx_snapshot(sourceDisplay,
                                      resource,
                                      DISPMANX_NO_ROTATE);

        if (result != 0)
        {
            messageLog(isDaemon,
                       program,
                       LOG_ERR,
                       "DispmanX snapshot failed");
            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        //-----------------------------------------------------------------

        update = vc_dispmanx_update_start(0);

        if (update == 0)
        {
            messageLog(isDaemon,
                       program,
                       LOG_ERR,
                       "display update failed");
            exitAndRemovePidFile(EXIT_FAILURE, pfh);
        }

        vc_dispmanx_element_change_source(update, element, resource);
        vc_dispmanx_update_submit_sync(update);

        //-----------------------------------------------------------------

        gettimeofday(&end_time, NULL);
        timersub(&end_time, &start_time, &elapsed_time);

        if (elapsed_time.tv_sec == 0)
        {
            if (elapsed_time.tv_usec < frameDuration)
            {
                usleep(frameDuration -  elapsed_time.tv_usec);
            }
        }
    }

    //---------------------------------------------------------------------

    update = vc_dispmanx_update_start(0);
    vc_dispmanx_element_remove(update, element);
    vc_dispmanx_update_submit_sync(update);

    vc_dispmanx_resource_delete(resource);

    vc_dispmanx_display_close(sourceDisplay);
    vc_dispmanx_display_close(destDisplay);

    //---------------------------------------------------------------------

    messageLog(isDaemon, program, LOG_INFO, "exiting");

    if (isDaemon)
    {
        closelog();
    }

    if (pfh)
    {
        pidfile_remove(pfh);
    }

    //---------------------------------------------------------------------

    return 0 ;
}
Example #9
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);
}
Example #10
0
int main(int argc, char **argv) {
  char *options, *path;
  int fd, inotify, option, pwd, waitargs;
  pid_t pid;
  time_t started;
  struct sigaction action;

  progname = argv[0];

  /* Redirect stdin from /dev/null. */
  if ((fd = open("/dev/null", O_RDWR)) < 0)
    error(EXIT_FAILURE, errno, "open /dev/null");
  if (fd != STDIN_FILENO)
    if ((dup2(fd, STDIN_FILENO)) < 0)
      error(EXIT_FAILURE, errno, "dup2");

  /* Redirect stdout and/or stderr to /dev/null if closed. */
  while (fd <= STDERR_FILENO)
    if ((fd = dup(fd)) < 0)
      error(EXIT_FAILURE, errno, "dup");
  close(fd);

  /* Close all file descriptors apart from stdin, stdout and stderr. */
  fd = getdtablesize() - 1;
  while (fd > STDERR_FILENO)
    close(fd--);

  options = "+:cfl:p:ru:w:", waitargs = 0;
  while ((option = getopt(argc, argv, options)) > 0)
    switch (option) {
      case 'c':
        command.chdir = 1;
        break;
      case 'f':
        /* On by default; ignored for compatibility with BSD daemon(1). */
        break;
      case 'l':
        logger_setup(optarg);
        break;
      case 'p':
        pidfile_open(optarg);
        break;
      case 'r':
        command.restart = 1;
        break;
      case 'u':
        user_setup(optarg);
        break;
      case 'w':
        waitargs++;
        break;
      default:
        usage(argv[0]);
    }

  if (argc <= optind)
    usage(argv[0]);

  switch (fork()) {
    case -1:
      error(EXIT_FAILURE, errno, "fork");
    case 0:
      setsid(); /* This should work after forking; ignore errors anyway. */
      break;
    default:
      _exit(EXIT_SUCCESS); /* Don't delete pidfile in atexit() handler. */
  }

  logger_start();
  pidfile_write();

  /* We can handle all -w command line arguments now we're daemonized. */
  if (waitargs > 0) {
    if ((inotify = inotify_init1(IN_CLOEXEC)) < 0)
      error(EXIT_FAILURE, errno, "inotify_init1");

    /* Open the working directory so we can restore it after each await(). */
    if ((pwd = open(".", O_RDONLY | O_DIRECTORY)) < 0)
      error(EXIT_FAILURE, errno, "open pwd");

    optind = 0; /* Need to reset optind to reprocess arguments. */
    while ((option = getopt(argc, argv, options)) > 0)
      if (option == 'w') {
        if (!(path = strdup(optarg)))
          error(EXIT_FAILURE, errno, "strdup");
        await(path, inotify, 0);
        free(path);
        fchdir(pwd);
      }

    close(inotify);
    close(pwd);
  }

  if (command.chdir && chdir("/") < 0)
    error(EXIT_FAILURE, errno, "chdir");

  command.argv = argv + optind;
  if (!command.restart && !pidfile.path) {
    /* We don't need to supervise in this case, so just exec. */
    if (command.gid > 0 && setgid(command.gid) < 0)
      error(EXIT_FAILURE, errno, "setgid");
    if (command.uid > 0 && setuid(command.uid) < 0)
      error(EXIT_FAILURE, errno, "setuid");
    execvp(command.argv[0], command.argv);
    error(EXIT_FAILURE, errno, "exec");
  }

  /* Handle and pass on HUP, INT, TERM, USR1, USR2 signals. */
  sigfillset(&action.sa_mask);
  action.sa_flags = SA_RESTART;
  action.sa_handler = handler;
  sigaction(SIGHUP, &action, NULL);
  sigaction(SIGINT, &action, NULL);
  sigaction(SIGTERM, &action, NULL);
  sigaction(SIGUSR1, &action, NULL);
  sigaction(SIGUSR2, &action, NULL);

  do {
    command.killed = 0; /* Have we signalled the child? */
    switch (command.pid = fork()) {
      case -1:
        error(EXIT_FAILURE, errno, "fork");
      case 0:
        if (command.gid > 0 && setgid(command.gid) < 0)
          error(EXIT_FAILURE, errno, "setgid");
        if (command.uid > 0 && setuid(command.uid) < 0)
          error(EXIT_FAILURE, errno, "setuid");
        setsid(); /* This should work after forking; ignore errors anyway. */
        execvp(command.argv[0], command.argv);
        error(EXIT_FAILURE, errno, "exec");
    }

    started = time(NULL);
    while (pid = wait(NULL), pid != (pid_t) command.pid)
      if (pid < 0 && errno != EINTR)
        error(EXIT_FAILURE, errno, "wait");

    /* Try to avoid restarting a crashing command in a tight loop. */
    if (command.restart && !command.killed && time(NULL) < started + 5)
      error(EXIT_FAILURE, 0, "Child died within 5 seconds: not restarting");
  } while (command.restart);

  return EXIT_SUCCESS;
}
Example #11
0
/*
 * Daemonize and persist pid
 */
int
daemon_start()
{
	struct iftot ift, *tot;
	time_t epoch;
	struct sigaction sig_action;
	sigset_t sig_set;
	pid_t otherpid;
	int curPID;

	tot = &ift;

	char *no_fork = getenv("no_fork");

	if (!no_fork || strcmp("1", no_fork)) {

		/* Check if parent process id is set */
		if (getppid() == 1) {
			/* PPID exists, therefore we are already a daemon */
			return (EXIT_FAILURE);
		}
		/* Check if we can acquire the pid file */
		pfh = pidfile_open(pid_filename, 0600, &otherpid);

		if (pfh == NULL) {
			if (errno == EEXIST) {
				errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", (intmax_t)otherpid);
			}
			warn("Cannot open or create pidfile: %s", pid_filename);
		}
		/* start daemonizing */
		curPID = fork();

		switch (curPID) {
		case 0:		/* This process is the child */
			break;
		case -1:		/* fork() failed, should exit */
			return (EXIT_FAILURE);
		default:		/* fork() successful, should exit */
			return (EXIT_SUCCESS);
		}

		/* we are the child, complete the daemonization */

		/* Close standard IO */
		fclose(stdin);
		fclose(stdout);
		fclose(stderr);

		/* Block unnecessary signals */
		sigemptyset(&sig_set);
		sigaddset(&sig_set, SIGCHLD);	/* ignore child - i.e. we
						 * don't need to wait for it */
		sigaddset(&sig_set, SIGTSTP);	/* ignore Tty stop signals */
		sigaddset(&sig_set, SIGTTOU);	/* ignore Tty background
						 * writes */
		sigaddset(&sig_set, SIGTTIN);	/* ignore Tty background reads */
		sigprocmask(SIG_BLOCK, &sig_set, NULL);	/* Block the above
							 * specified signals */

		/* Catch necessary signals */
		sig_action.sa_handler = signal_handler;
		sigemptyset(&sig_action.sa_mask);
		sig_action.sa_flags = 0;

		sigaction(SIGTERM, &sig_action, NULL);
		sigaction(SIGHUP, &sig_action, NULL);
		sigaction(SIGINT, &sig_action, NULL);

		/* create new session and process group */
		if (setsid() < 0)
			return (EXIT_FAILURE);

		/* persist pid */
		pidfile_write(pfh);

	}
	FILE *cache_file = fopen(cache_filename, "a");

	/* looping to collect traffic stat every RESOLUTION seconds */
	while (1) {

		epoch = wait_for(RESOLUTION);

		flockfile(cache_file);

		fill_iftot(tot);
		fprintf(cache_file, "obytes.value %ld:%lu\nrbytes.value %ld:%lu\n", epoch, tot->ift_ob, epoch, tot->ift_ib);
		fflush(cache_file);

		funlockfile(cache_file);
	}

	fclose(cache_file);
	return (0);
}
Example #12
0
/* Register VRRP thread */
int
start_vrrp_child(void)
{
#ifndef _DEBUG_
	pid_t pid;
	int ret;

	/* Initialize child process */
	pid = fork();

	if (pid < 0) {
		log_message(LOG_INFO, "VRRP child process: fork error(%s)"
			       , strerror(errno));
		return -1;
	} else if (pid) {
		vrrp_child = pid;
		log_message(LOG_INFO, "Starting VRRP child process, pid=%d"
			       , pid);

		/* Start respawning thread */
		thread_add_child(master, vrrp_respawn_thread, NULL,
				 pid, RESPAWN_TIMER);
		return 0;
	}

	signal_handler_destroy();

	/* Opening local VRRP syslog channel */
	openlog(PROG_VRRP, LOG_PID | ((__test_bit(LOG_CONSOLE_BIT, &debug)) ? LOG_CONS : 0)
			 , (log_facility==LOG_DAEMON) ? LOG_LOCAL1 : log_facility);

	/* Child process part, write pidfile */
	if (!pidfile_write(vrrp_pidfile, getpid())) {
		/* Fatal error */
		log_message(LOG_INFO, "VRRP child process: cannot write pidfile");
		exit(0);
	}

	/* Create the new master thread */
	thread_destroy_master(master);
	master = thread_make_master();

	/* change to / dir */
	ret = chdir("/");
	if (ret < 0) {
		log_message(LOG_INFO, "VRRP child process: error chdir");
	}

	/* Set mask */
	umask(0);
#endif

	/* If last process died during a reload, we can get there and we
	 * don't want to loop again, because we're not reloading anymore.
	 */
	UNSET_RELOAD;

	/* Signal handling initialization */
	vrrp_signal_init();

	/* Start VRRP daemon */
	start_vrrp();

	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish VRRP daemon process */
	stop_vrrp();
	exit(0);
}
Example #13
0
int main(int argc, char *argv[], char *envp[]) {
    log_open(LOG_FILE);
    FM_LOG_TRACE("---");
    check_pid();

    int sockfd;
    socklen_t clilen;
    struct sockaddr_in serv_addr{};
    struct sockaddr_in cli_addr{};
    const char *cfg_file;

    if (argc > 1) {
        cfg_file = argv[1];
    } else {
        cfg_file = DEFAULT_CFG_FILE;
    }
    read_config(cfg_file);
    FM_LOG_TRACE("read_config");

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        fatal_error("ERROR opening socket");
    }
    FM_LOG_TRACE("socket");

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    if (inet_aton(oj_config.ip, &serv_addr.sin_addr) == 0) {
        serv_addr.sin_addr.s_addr = INADDR_ANY;
    }
    serv_addr.sin_port = htons(oj_config.port);
    FM_LOG_NOTICE("IP address: %s %s", oj_config.ip, inet_ntoa(serv_addr.sin_addr));
    FM_LOG_NOTICE("port: %d %d", oj_config.port, ntohs(serv_addr.sin_port));

    int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        fatal_error("setsockopt SO_REUSEADDR failed");
    }

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        fatal_error("ERROR on binding");
    }
    FM_LOG_TRACE("bind");

    clilen = sizeof(cli_addr);

    if (listen(sockfd, oj_config.backlog) < 0) {
        fatal_error("ERROR on listening");
    }
    FM_LOG_NOTICE("listen  backlog: %d", oj_config.backlog);

    if (daemon(0, 0) == -1) {
        FM_LOG_FATAL("Cannot daemonize");
        pidfile_remove(pfh);

        exit(EXIT_FAILURE);
    }

    print_word_dir();
    print_user_group();

    pidfile_write(pfh);

    struct sigaction sa{};
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == -1) {   // install signal hander for timeout
        FM_LOG_FATAL("cannot handle SIGTERM");
        exit(EXIT_FAILURE);
    } else {
        FM_LOG_DEBUG("set signal_handler");
    }
    for (int i = 0; i < oj_config.thread_num; i++) {
        std::thread t(ThreadWork);
        t.detach();
    }
    FM_LOG_NOTICE("thread count: %d", oj_config.thread_num);

    std::thread(SendWork).detach();

    while (isRunning) {
        int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd != -1) {
            work(newsockfd, cli_addr);
        }
    }

    pidfile_remove(pfh);
    close(sockfd);
    return 0;
}
Example #14
0
/* Register CHECK thread */
int
start_check_child(void)
{
#ifndef _DEBUG_
	pid_t pid;
	int ret;
	char *syslog_ident;

	/* Initialize child process */
	pid = fork();

	if (pid < 0) {
		log_message(LOG_INFO, "Healthcheck child process: fork error(%s)"
			       , strerror(errno));
		return -1;
	} else if (pid) {
		checkers_child = pid;
		log_message(LOG_INFO, "Starting Healthcheck child process, pid=%d"
			       , pid);

		/* Start respawning thread */
		thread_add_child(master, check_respawn_thread, NULL,
				 pid, RESPAWN_TIMER);
		return 0;
	}

	if ((instance_name
#if HAVE_DECL_CLONE_NEWNET
			   || network_namespace
#endif
					       ) &&
	     (check_syslog_ident = make_syslog_ident(PROG_CHECK)))
		syslog_ident = check_syslog_ident;
	else
		syslog_ident = PROG_CHECK;

	/* Opening local CHECK syslog channel */
	openlog(syslog_ident, LOG_PID | ((__test_bit(LOG_CONSOLE_BIT, &debug)) ? LOG_CONS : 0)
			    , (log_facility==LOG_DAEMON) ? LOG_LOCAL2 : log_facility);

#ifdef _MEM_CHECK_
	mem_log_init(PROG_CHECK, "Healthcheck child process");
#endif

	free_parent_mallocs_startup(true);

	/* Child process part, write pidfile */
	if (!pidfile_write(checkers_pidfile, getpid())) {
		log_message(LOG_INFO, "Healthcheck child process: cannot write pidfile");
		exit(KEEPALIVED_EXIT_FATAL);
	}

	/* Create the new master thread */
	signal_handler_destroy();
	thread_destroy_master(master);	/* This destroys any residual settings from the parent */
	master = thread_make_master();

	/* change to / dir */
	ret = chdir("/");
	if (ret < 0) {
		log_message(LOG_INFO, "Healthcheck child process: error chdir");
	}

	/* Set mask */
	umask(0);
#endif

	/* If last process died during a reload, we can get there and we
	 * don't want to loop again, because we're not reloading anymore.
	 */
	UNSET_RELOAD;

	/* Signal handling initialization */
	check_signal_init();

	/* Start Healthcheck daemon */
	start_check();

	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish healthchecker daemon process */
	stop_check(EXIT_SUCCESS);

	/* unreachable */
	exit(EXIT_SUCCESS);
}
Example #15
0
int
main(int argc, char *argv[])
{
	int c, i, j, configured = 0;
	pid_t opid;
	char prgname[80], filename[256], *p;
	struct servent *servent;
	pthread_t tid;

	/* Default plugin_base */
	strlcpy(plugin_base, PLUGIN_PATH, sizeof(plugin_base));

	if ((servent = getservbyname("bootps", 0)) == NULL)
		errx(EX_UNAVAILABLE, "getservbyname(bootps)");
	bootps_port = servent->s_port;
	if ((servent = getservbyname("bootpc", 0)) == NULL)
		errx(EX_UNAVAILABLE, "getservbyname(bootpc)");
	bootpc_port = servent->s_port;

	openlog("dhcprelya", LOG_NDELAY | LOG_PID, LOG_DAEMON);

	strlcpy(prgname, argv[0], sizeof(prgname));
	filename[0] = '\0';
	while ((c = getopt(argc, argv, "A:c:df:hi:p:")) != -1) {
		switch (c) {
		case 'A':
			if (configured == 2)
				errx(1, "Either config file or command line options allowed. Not both.");
			max_packet_size = strtol(optarg, NULL, 10);
			if (max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX)
				errx(1, "Wrong packet size");
			break;
		case 'c':
			if (configured == 2)
				errx(1, "Either config file or command line options allowed. Not both.");
			max_hops = strtol(optarg, NULL, 10);
			if (max_hops < 1 || max_hops > 16)
				errx(1, "Wrong hops number");
			break;
		case 'd':
			debug++;
			break;
		case 'f':
			if (configured == 1)
				errx(1, "Either config file or command line options allowed. Not both.");
			if (configured == 2)
				errx(1, "only one config file allowed");
			configured = 2;
			read_config(optarg);
			break;
		case 'i':
			if (configured == 2)
				errx(1, "Either config file or command line options allowed. Not both.");
			configured = 1;
			if (!open_interface(optarg))
				logd(LOG_DEBUG, "Interface %s does not exist. Ignored.", optarg);
			break;
		case 'p':
			strlcpy(filename, optarg, sizeof(filename));
			break;
		case 'h':
		default:
			usage(prgname);
		}
	}

	argc -= optind;
	argv += optind;

	if (optind == 0)
		argc--;

	if ((configured == 1 && argc < 1) || (configured == 2 && argc >= 1))
		usage(prgname);

	/* Initialize polugins */
	for (i = 0; i < plugins_number; i++) {
		if (plugins[i]->init)
			if ((plugins[i]->init) (options_heads[i]) == 0)
				errx(1, "Can't initialize a plugin %s\n", plugins[i]->name);
	}

	for (i = 0; i < argc; i++) {
		open_server(argv[i]);
		for (j = 0; j < if_num; j++) {
			if (i > ifs[j]->srv_num - 1) {
				ifs[j]->srv_num++;
				ifs[j]->srvrs = realloc(ifs[j]->srvrs, ifs[j]->srv_num * sizeof(int));
			}
			ifs[j]->srvrs[ifs[j]->srv_num - 1] = i;
		}
	}

	if (if_num == 0)
		errx(1, "No interfaces found to listen. Exiting.");

	logd(LOG_WARNING, "Total interfaces: %d", if_num);

	/* Make a PID filename */
	if (filename[0] == '\0') {
		strlcpy(filename, "/var/run/", sizeof(filename));
		p = strrchr(prgname, '/');
		if (p == NULL)
			p = prgname;
		else
			p++;
		strlcat(filename, p, sizeof(filename));
		strlcat(filename, ".pid", sizeof(filename));
	}
	/* Create a PID file and daemonize if no debug flag */
	if (!debug && (pfh = pidfile_open(filename, 0644, &opid)) == NULL) {
		if (errno == EEXIST)
			errx(1, "Already run with PID %lu. Exiting.", (unsigned long)opid);
		errx(1, "Can't create PID file");
	}
	signal(SIGHUP, SIG_IGN);

	if (!debug) {
		if (daemon(0, 0) == -1)
			process_error(1, "Can't daemonize. Exiting.");
		else
			logd(LOG_DEBUG, "Runned as %d", getpid());
	}
	if (pfh)
		pidfile_write(pfh);

	STAILQ_INIT(&q_head);

	pthread_mutex_init(&queue_lock, NULL);

	/* Create listeners for every interface */
	for (i = 0; i < if_num; i++) {
		pthread_create(&tid, NULL, listener, ifs[i]);
		pthread_detach(tid);
	}

	/* Main loop */
	while (1) {
		if (queue_size > 0)
			process_queue();

		/* Process one packet from server(s) */
		process_server_answer();
	}

	/* Destroy polugins */
	for (i = 0; i < plugins_number; i++) {
		if (plugins[i]->destroy)
			(plugins[i]->destroy) ();
	}
	pthread_mutex_destroy(&queue_lock);
}
Example #16
0
/* Entry point */
int
main(int argc, char **argv)
{
	int report_stopped = true;

	/* Init debugging level */
	debug = 0;

	/* Initialise daemon_mode */
	__set_bit(DAEMON_VRRP, &daemon_mode);
	__set_bit(DAEMON_CHECKERS, &daemon_mode);

	/*
	 * Parse command line and set debug level.
	 * bits 0..7 reserved by main.c
	 */
	parse_cmdline(argc, argv);

	openlog(PROG, LOG_PID | ((__test_bit(LOG_CONSOLE_BIT, &debug)) ? LOG_CONS : 0)
		    , log_facility);
#ifdef GIT_COMMIT
	log_message(LOG_INFO, "Starting %s, git commit %s", VERSION_STRING, GIT_COMMIT);
#else
	log_message(LOG_INFO, "Starting %s", VERSION_STRING);
#endif

	/* Check if keepalived is already running */
	if (keepalived_running(daemon_mode)) {
		log_message(LOG_INFO, "daemon is already running");
		report_stopped = false;
		goto end;
	}

	if (__test_bit(LOG_CONSOLE_BIT, &debug))
		enable_console_log();

	/* daemonize process */
	if (!__test_bit(DONT_FORK_BIT, &debug))
		xdaemon(0, 0, 0);

	/* write the father's pidfile */
	if (!pidfile_write(main_pidfile, getpid()))
		goto end;

#ifndef _DEBUG_
	/* Signal handling initialization  */
	signal_init();
#endif

	/* Create the master thread */
	master = thread_make_master();

	/* Init daemon */
	start_keepalived();

#ifndef _DEBUG_
	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish daemon process */
	stop_keepalived();
#endif

	/*
	 * Reached when terminate signal catched.
	 * finally return from system
	 */
end:
	if (report_stopped) {
#ifdef GIT_COMMIT
		log_message(LOG_INFO, "Stopped %s, git commit %s", VERSION_STRING, GIT_COMMIT);
#else
		log_message(LOG_INFO, "Stopped %s", VERSION_STRING);
#endif
	}

	closelog();
	exit(0);
}
Example #17
0
/*
 * Common code for test_pidfile_{contested,inherited}.
 */
static const char *
common_test_pidfile_child(const char *fn, int parent_open)
{
	struct pidfh *pf = NULL;
	pid_t other = 0, pid = 0;
	int fd[2], serrno, status;
	char ch;

	unlink(fn);
	if (pipe(fd) != 0)
		return (strerror(errno));

	if (parent_open) {
		pf = pidfile_open(fn, 0600, &other);
		if (pf == NULL && other != 0)
			return ("pidfile exists and is locked");
		if (pf == NULL)
			return (strerror(errno));
	}

	pid = fork();
	if (pid == -1)
		return (strerror(errno));
	if (pid == 0) {
		// child
		close(fd[0]);
		signal(SIGINT, signal_handler);
		if (!parent_open) {
			pf = pidfile_open(fn, 0600, &other);
			if (pf == NULL && other != 0)
				return ("pidfile exists and is locked");
			if (pf == NULL)
				return (strerror(errno));
		}
		if (pidfile_write(pf) != 0) {
			serrno = errno;
			pidfile_close(pf);
			unlink(fn);
			return (strerror(serrno));
		}
		if (pf == NULL)
			_exit(1);
		if (pidfile_write(pf) != 0)
			_exit(1);
		if (write(fd[1], "*", 1) != 1)
			_exit(1);
		select(0, 0, 0, 0, 0);
		_exit(0);
	}
	// parent
	close(fd[1]);
	if (pf)
		pidfile_close(pf);

	// wait for the child to signal us
	if (read(fd[0], &ch, 1) != 1) {
		serrno = errno;
		unlink(fn);
		kill(pid, SIGTERM);
		errno = serrno;
		return (strerror(errno));
	}

	// We shouldn't be able to lock the same pidfile as our child
	pf = pidfile_open(fn, 0600, &other);
	if (pf != NULL) {
		pidfile_close(pf);
		unlink(fn);
		return ("managed to lock contested pidfile");
	}

	// Failed to lock, but not because it was contested
	if (other == 0) {
		unlink(fn);
		return (strerror(errno));
	}

	// Locked by the wrong process
	if (other != pid) {
		unlink(fn);
		return ("pidfile contained wrong PID");
	}

	// check our child's fate
	if (pf)
		pidfile_close(pf);
	unlink(fn);
	if (kill(pid, SIGINT) != 0)
		return (strerror(errno));
	if (waitpid(pid, &status, 0) == -1)
		return (strerror(errno));
	if (WIFSIGNALED(status))
		return ("child caught signal");
	if (WEXITSTATUS(status) != 0) 
		return ("child returned non-zero status");

	// success
	return (NULL);
}
Example #18
0
/*
 * Daemonize and persist pid
 */
int
daemon_start()
{
    struct sigaction sig_action;
    sigset_t sig_set;
    pid_t otherpid;
    int curPID;
    pthread_t tcp4_thread, udp4_thread;
    pthread_t tcp6_thread, udp6_thread;

    /* Check if we can acquire the pid file */
    pfh = pidfile_open(NULL, 0600, &otherpid);

    if (pfh == NULL) {
        if (errno == EEXIST) {
            errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", (intmax_t)otherpid);
        }
        err(EXIT_FAILURE, "Cannot open or create pidfile");
    }
    init_logger();

    /* Initialize TCP46 and UDP46 sockets */
    if (init_tcp() == EXIT_FAILURE)
        return (EXIT_FAILURE);
    if (init_udp() == EXIT_FAILURE)
        return (EXIT_FAILURE);

    /* start daemonizing */
    curPID = fork();

    switch (curPID) {
    case 0:			/* This process is the child */
        break;
    case -1:			/* fork() failed, should exit */
        perror("fork");
        return (EXIT_FAILURE);
    default:			/* fork() successful, should exit
					 * (parent) */
        return (EXIT_SUCCESS);
    }

    /* we are the child, complete the daemonization */

    /* Close standard IO */
    fclose(stdin);
    fclose(stdout);
    fclose(stderr);

    /* Block unnecessary signals */
    sigemptyset(&sig_set);
    sigaddset(&sig_set, SIGCHLD);	/* ignore child - i.e. we don't need
					 * to wait for it */
    sigaddset(&sig_set, SIGTSTP);	/* ignore tty stop signals */
    sigaddset(&sig_set, SIGTTOU);	/* ignore tty background writes */
    sigaddset(&sig_set, SIGTTIN);	/* ignore tty background reads */
    sigprocmask(SIG_BLOCK, &sig_set, NULL);	/* Block the above specified
						 * signals */

    /* Catch necessary signals */
    sig_action.sa_handler = signal_handler;
    sigemptyset(&sig_action.sa_mask);
    sig_action.sa_flags = 0;

    sigaction(SIGTERM, &sig_action, NULL);
    sigaction(SIGHUP, &sig_action, NULL);
    sigaction(SIGINT, &sig_action, NULL);

    /* create new session and process group */
    setsid();

    /* persist pid */
    pidfile_write(pfh);

    /* Create TCP and UDP listener threads */
    pthread_create(&tcp4_thread, NULL, tcp4_handler, NULL);
    pthread_create(&udp4_thread, NULL, udp4_handler, NULL);
#ifdef PF_INET6
    pthread_create(&tcp6_thread, NULL, tcp6_handler, NULL);
    pthread_create(&udp6_thread, NULL, udp6_handler, NULL);
#endif

    /*
     * Wait for threads to terminate, which normally shouldn't ever
     * happen
     */
    pthread_join(tcp4_thread, NULL);
    pthread_join(udp4_thread, NULL);
#ifdef PF_INET6
    pthread_join(tcp6_thread, NULL);
    pthread_join(udp6_thread, NULL);
#endif

    return (EXIT_SUCCESS);
}
Example #19
0
void
process_args(nmsgtool_ctx *c) {
	char *t;
	FILE *fp_pidfile = NULL;
	nmsg_msgmod_t mod = NULL;

	if (c->help)
		usage(NULL);

	if (c->version) {
#ifdef HAVE_LIBXS
		fprintf(stderr, "%s: version %s\n", argv_program, PACKAGE_VERSION);
#else /* HAVE_LIBXS */
		fprintf(stderr, "%s: version %s (without libxs support)\n",
			argv_program, PACKAGE_VERSION);
#endif /* HAVE_LIBXS */
		exit(EXIT_SUCCESS);
	}

	if (c->endline == NULL)
		c->endline_str = strdup("\n");
	else
		c->endline_str = unescape(c->endline);

	if (c->mtu == 0)
		c->mtu = NMSG_WBUFSZ_JUMBO;

	if (c->vname == NULL && c->mname != NULL)
		c->vname = "base";

	if (c->vname != NULL) {
		if (c->mname == NULL)
			usage("-V requires -T");
		c->vid = nmsg_msgmod_vname_to_vid(c->vname);
		if (c->vid == 0)
			usage("invalid vendor ID");
		if (c->debug >= 2)
			fprintf(stderr, "%s: input vendor = %s\n",
				argv_program, c->vname);
	}
	if (c->mname != NULL) {
		if (c->vname == NULL)
			usage("-T requires -V");
		c->msgtype = nmsg_msgmod_mname_to_msgtype(c->vid, c->mname);
		if (c->msgtype == 0)
			usage("invalid message type");
		if (c->debug >= 2)
			fprintf(stderr, "%s: input msgtype = %s\n",
				argv_program, c->mname);
	}
	if (c->debug < 1)
		c->debug = 1;
	if (c->debug > 0)
		nmsg_io_set_debug(c->io, c->debug);
	if (c->count > 0)
		nmsg_io_set_count(c->io, c->count);
	if (c->interval > 0)
		nmsg_io_set_interval(c->io, c->interval);
	if (c->mirror == true)
		nmsg_io_set_output_mode(c->io, nmsg_io_output_mode_mirror);

	/* bpf string */
	if (c->bpfstr == NULL) {
		t = getenv("NMSG_BPF");
		if (t != NULL)
			c->bpfstr = strdup(t);
	}

	/* kicker command */
	if (c->kicker == NULL) {
		t = getenv("NMSG_KICKER");
		if (t != NULL)
			c->kicker = strdup(t);
	}

	/* set source, operator, group */
	if (c->set_source_str != NULL) {
		c->set_source = (unsigned) strtoul(c->set_source_str, &t, 0);
		if (*t != '\0')
			usage("invalid source ID");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg source set to %#.08x\n",
				argv_program, c->set_source);
	}

	if (c->set_operator_str != NULL) {
		c->set_operator = nmsg_alias_by_value(nmsg_alias_operator,
						      c->set_operator_str);
		if (c->set_operator == 0)
			usage("unknown operator name");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg operator set to '%s' (%u)\n",
				argv_program,
				c->set_operator_str,
				c->set_operator);
	}

	if (c->set_group_str != NULL) {
		c->set_group = nmsg_alias_by_value(nmsg_alias_group,
						   c->set_group_str);
		if (c->set_group == 0)
			usage("unknown group name");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg group set to '%s' (%u)\n",
				argv_program,
				c->set_group_str,
				c->set_group);
	}

	/* get source, operator, group */
	if (c->get_source_str != NULL) {
		c->get_source = (unsigned) strtoul(c->get_source_str, &t, 0);
		if (*t != '\0')
			usage("invalid filter source ID");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg source filter set to "
					"%#.08x\n",
				argv_program, c->get_source);
	}

	if (c->get_operator_str != NULL) {
		c->get_operator = nmsg_alias_by_value(nmsg_alias_operator,
						      c->get_operator_str);
		if (c->get_operator == 0)
			usage("unknown filter operator name");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg filter operator set to "
					"'%s' (%u)\n",
				argv_program,
				c->get_operator_str,
				c->get_operator);
	}

	if (c->get_group_str != NULL) {
		c->get_group = nmsg_alias_by_value(nmsg_alias_group,
						   c->get_group_str);
		if (c->get_group == 0)
			usage("unknown filter group name");
		if (c->debug >= 2)
			fprintf(stderr, "%s: nmsg filter group set to "
					"'%s' (%u)\n",
				argv_program,
				c->get_group_str,
				c->get_group);
	}

	/* -V, -T sanity check */
	if (ARGV_ARRAY_COUNT(c->r_pres) > 0 ||
	    ARGV_ARRAY_COUNT(c->r_pcapfile) > 0 ||
	    ARGV_ARRAY_COUNT(c->r_pcapif) > 0)
	{
		if (c->vname == NULL || c->mname == NULL)
			usage("reading presentation or pcap data requires "
			      "-V, -T");
		mod = nmsg_msgmod_lookup(c->vid, c->msgtype);
		if (mod == NULL)
			usage("unknown msgmod");
	}

#define process_args_loop(arry, func) do { \
	for (int i = 0; i < ARGV_ARRAY_COUNT(arry); i++) \
		func(c, *ARGV_ARRAY_ENTRY_P(arry, char *, i)); \
} while(0)

#define process_args_loop_mod(arry, func, mod) do { \
	for (int i = 0; i < ARGV_ARRAY_COUNT(arry); i++) \
		func(c, mod, *ARGV_ARRAY_ENTRY_P(arry, char *, i)); \
} while(0)

	/* pcap interface inputs */
	process_args_loop_mod(c->r_pcapif, add_pcapif_input, mod);

	/* open pidfile if necessary */
	if (c->pidfile != NULL)
		fp_pidfile = pidfile_open(c->pidfile);
	else
		fp_pidfile = NULL;

	/* drop privileges */
	if (c->username != NULL)
		droproot(c, fp_pidfile);

	/* pcap file inputs */
	process_args_loop_mod(c->r_pcapfile, add_pcapfile_input, mod);

	/* XS context */
	if (ARGV_ARRAY_COUNT(c->r_xsock) > 0 ||
	    ARGV_ARRAY_COUNT(c->w_xsock) > 0 ||
	    ARGV_ARRAY_COUNT(c->r_xchannel) > 0)
	{
#ifdef HAVE_LIBXS
		c->xs_ctx = xs_init();
		if (c->xs_ctx == NULL) {
			fprintf(stderr, "%s: xs_init() failed: %s\n",
				argv_program, strerror(errno));
			exit(EXIT_FAILURE);
		}
#else /* HAVE_LIBXS */
		fprintf(stderr, "%s: Error: compiled without libxs support\n",
			argv_program);
		exit(EXIT_FAILURE);
#endif /* HAVE_LIBXS */
	}

	/* nmsg inputs and outputs */
	process_args_loop(c->r_sock, add_sock_input);
	process_args_loop(c->w_sock, add_sock_output);
	process_args_loop(c->r_xsock, add_xsock_input);
	process_args_loop(c->w_xsock, add_xsock_output);
	process_args_loop(c->r_nmsg, add_file_input);
	process_args_loop(c->w_nmsg, add_file_output);

	for (int i = 0; i < ARGV_ARRAY_COUNT(c->r_channel); i++) {
		char *ch;
		char **alias = NULL;
		int num_aliases;

		ch = *ARGV_ARRAY_ENTRY_P(c->r_channel, char *, i);
		if (c->debug >= 2)
			fprintf(stderr, "%s: looking up channel '%s'\n", argv_program, ch);
		num_aliases = nmsg_chalias_lookup(ch, &alias);
		if (num_aliases <= 0)
			usage("channel alias lookup failed");
		for (int j = 0; j < num_aliases; j++) {
			if (strstr(alias[j], "://"))
				usage("channel alias appears to be an xchannel");
			add_sock_input(c, alias[j]);
		}
		nmsg_chalias_free(&alias);
	}

	for (int i = 0; i < ARGV_ARRAY_COUNT(c->r_xchannel); i++) {
		char *ch;
		char **alias = NULL;
		int num_aliases;

		ch = *ARGV_ARRAY_ENTRY_P(c->r_xchannel, char *, i);
		if (c->debug >= 2)
			fprintf(stderr, "%s: looking up xchannel '%s'\n", argv_program, ch);
		num_aliases = nmsg_chalias_lookup(ch, &alias);
		if (num_aliases <= 0)
			usage("xchannel alias lookup failed");
		for (int j = 0; j < num_aliases; j++)
			add_xsock_input(c, alias[j]);
		nmsg_chalias_free(&alias);
	}

	/* pres inputs and outputs */
	process_args_loop_mod(c->r_pres, add_pres_input, mod);
	process_args_loop(c->w_pres, add_pres_output);

#undef process_args_loop
#undef process_args_loop_mod

	/* validation */
	if (c->n_inputs == 0)
		usage("no data sources specified");
	if (c->n_outputs == 0) {
		/* implicit "-o -" */
		add_pres_output(c, "-");
	}

	/* daemonize if necessary */
	if (c->daemon) {
		if (!daemonize()) {
			fprintf(stderr, "nmsgtool: unable to daemonize: %s\n",
				strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	/* write pidfile if necessary */
	if (c->pidfile != NULL && fp_pidfile != NULL)
		pidfile_write(fp_pidfile);
}
Example #20
0
/* Command line parser */
static void
parse_cmdline(int argc, char **argv)
{
	int c;

	struct option long_options[] = {
		{"use-file",          required_argument, 0, 'f'},
		{"vrrp",              no_argument,       0, 'P'},
		{"check",             no_argument,       0, 'C'},
		{"log-console",       no_argument,       0, 'l'},
		{"log-detail",        no_argument,       0, 'D'},
		{"log-facility",      required_argument, 0, 'S'},
		{"release-vips",      no_argument,       0, 'X'},
		{"dont-release-vrrp", no_argument,       0, 'V'},
		{"dont-release-ipvs", no_argument,       0, 'I'},
		{"dont-respawn",      no_argument,       0, 'R'},
		{"dont-fork",         no_argument,       0, 'n'},
		{"dump-conf",         no_argument,       0, 'd'},
		{"pid",               required_argument, 0, 'p'},
		{"vrrp_pid",          required_argument, 0, 'r'},
		{"checkers_pid",      required_argument, 0, 'c'},
 #ifdef _WITH_SNMP_
		{"snmp",              no_argument,       0, 'x'},
 #endif
		{"version",           no_argument,       0, 'v'},
		{"help",              no_argument,       0, 'h'},
		{0, 0, 0, 0}
	};

#ifdef _WITH_SNMP_
	while ((c = getopt_long(argc, argv, "vhlndVIDRS:f:PCp:c:r:x", long_options, NULL)) != EOF) {
#else
	while ((c = getopt_long(argc, argv, "vhlndVIDRS:f:PCp:c:r:", long_options, NULL)) != EOF) {
#endif
		switch (c) {
		case 'v':
			fprintf(stderr, VERSION_STRING);
			exit(0);
			break;
		case 'h':
			usage(argv[0]);
			exit(0);
			break;
		case 'l':
			debug |= DBG_OPT_LOG_CONSOLE;
			break;
		case 'n':
			debug |= DBG_OPT_DONT_FORK;
			break;
		case 'd':
			debug |= DBG_OPT_DUMP_CONF;
			break;
		case 'V':
		 	debug |= DBG_OPT_DONT_RELEASE_VRRP;
			break;
		case 'I':
			debug |= DBG_OPT_DONT_RELEASE_IPVS;
			break;
		case 'D':
			debug |= DBG_OPT_LOG_DETAIL;
			break;
		case 'R':
			debug |= DBG_OPT_DONT_RESPAWN;
			break;
		case 'X':
		        debug |= DBG_OPT_RELEASE_VIPS;
			break;
		case 'S':
			log_facility = LOG_FACILITY[atoi(optarg)].facility;
			break;
		case 'f':
			conf_file = optarg;
			break;
		case 'P':
			daemon_mode |= 1;
			break;
		case 'C':
			daemon_mode |= 2;
			break;
		case 'p':
			main_pidfile = optarg;
			break;
		case 'c':
			checkers_pidfile = optarg;
			break;
		case 'r':
			vrrp_pidfile = optarg;
			break;
#ifdef _WITH_SNMP_
		case 'x':
			snmp = 1;
			break;
#endif
		default:
			exit(0);
			break;
		}
	}

	if (optind < argc) {
		printf("Unexpected argument(s): ");
		while (optind < argc)
			printf("%s ", argv[optind++]);
		printf("\n");
	}
}

/* Entry point */
int
main(int argc, char **argv)
{
	/* Init debugging level */
	mem_allocated = 0;
	debug = 0;

	/*
	 * Parse command line and set debug level.
	 * bits 0..7 reserved by main.c
	 */
	parse_cmdline(argc, argv);

	openlog(PROG, LOG_PID | ((debug & DBG_OPT_LOG_CONSOLE) ? LOG_CONS : 0),
		log_facility);
	log_message(LOG_INFO, "Starting " VERSION_STRING);

	/* Check if keepalived is already running */
	if (keepalived_running(daemon_mode)) {
		log_message(LOG_INFO, "daemon is already running");
		goto end;
	}

	if (debug & DBG_OPT_LOG_CONSOLE)
		enable_console_log();

	/* daemonize process */
	if (!(debug & DBG_OPT_DONT_FORK))
		xdaemon(0, 0, 0);

	/* write the father's pidfile */
	if (!pidfile_write(main_pidfile, getpid()))
		goto end;

#ifndef _DEBUG_
	/* Signal handling initialization  */
	signal_init();
#endif

	/* Create the master thread */
	master = thread_make_master();

	/* Init daemon */
	start_keepalived();

#ifndef _DEBUG_
	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish daemon process */
	stop_keepalived();
#endif

	/*
	 * Reached when terminate signal catched.
	 * finally return from system
	 */
end:
	closelog();
	exit(0);
}
Example #21
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. */
}
Example #22
0
int main(int argc, char const* argv[])
{
    ir::IRXDaemon* instance;
    OperationEnum operation;
    ModeEnum mode;
    struct pidfh* pfh;
    pid_t pid;
    bool daemonize;
    int i;
    int result(EXIT_SUCCESS);
    
    if ((instance = ir::IRXDaemon::_new()) != NULL) {
        operation = OPERATION_UNKNOWN;
        mode = MODE_UNKNOWN;
        if (argc > 1) {
            if ((result = instance->usage(argc, argv)) == EXIT_SUCCESS) {
                for (i = 1; i < argc; ++i) {
                    if (strcmp(argv[i], "start") == 0) {
                        operation = OPERATION_START;
                    }
                    else if (strcmp(argv[i], "restart") == 0) {
                        operation = OPERATION_RESTART;
                    }
                    else if (strcmp(argv[i], "stop") == 0) {
                        operation = OPERATION_STOP;
                    }
                    else if (strcmp(argv[i], "--daemon") == 0) {
                        mode = MODE_DAEMON;
                    }
                    else if (strcmp(argv[i], "--application") == 0) {
                        mode = MODE_APPLICATION;
                    }
                }
            }
        }
        if (result == EXIT_SUCCESS) {
            if (operation == OPERATION_UNKNOWN) {
                operation = OPERATION_START;
            }
            if (mode == MODE_UNKNOWN) {
                mode = MODE_DAEMON;
            }
            g_quit = false;
            signal(SIGHUP, onSigHUP);
            signal(SIGINT, onSigINT);
            signal(SIGTERM, onSigTERM);
            signal(SIGCHLD, SIG_IGN);
            switch (operation) {
                case OPERATION_RESTART:
                case OPERATION_STOP:
                    if ((pfh = pidfile_open(NULL, 0600, &pid)) != NULL) {
                        instance->log(LOG_NOTICE, "already stopped");
                        pidfile_remove(pfh);
                    }
                    else {
                        switch (errno) {
                            case EEXIST:
                                if (kill(pid, SIGTERM) == 0) {
                                    instance->log(LOG_NOTICE, "stopping pid = %d...", pid);
                                    while (true) {
                                        if (g_quit) {
                                            result = EXIT_FAILURE;
                                            break;
                                        }
                                        if (kill(pid, 0) != 0) {
                                            instance->log(LOG_NOTICE, "stopping done");
                                            break;
                                        }
                                        sleep(1);
                                    }
                                }
                                else {
                                    instance->log(LOG_ERR, "can't stop pid = %d [%m]", pid);
                                    result = EX_OSERR;
                                }
                                break;
                            case EACCES:
                                instance->log(LOG_ERR, "run as super user");
                                result = EX_OSERR;
                                break;
                            default:
                                instance->log(LOG_ERR, "can't stop [%m]");
                                result = EX_OSERR;
                                break;
                        }
                    }
                    break;
                default:
                    // nop
                    break;
            }
            if (result == EXIT_SUCCESS) {
                switch (operation) {
                    case OPERATION_START:
                    case OPERATION_RESTART:
                        if ((pfh = pidfile_open(NULL, 0600, &pid)) != NULL) {
                            instance->log(LOG_NOTICE, "starting pid = %d...", getpid());
                            daemonize = true;
                            if (mode == MODE_APPLICATION) {
                                daemonize = false;
                            }
                            #ifdef __APPLE__
                            if (getppid() == 1) {
                                daemonize = false;
                            }
                            #endif
                            if (daemonize) {
                                if (daemon(0, 0) != 0) {
                                    instance->log(LOG_ERR, "can't daemonize pid = %d [%m]", getpid());
                                    result = EX_OSERR;
                                }
                            }
                            if (result == EXIT_SUCCESS) {
                                instance->log(LOG_NOTICE, "changing pid = %d...", getpid());
                                pidfile_write(pfh);
                                if ((result = instance->initialize()) == EXIT_SUCCESS) {
                                    instance->log(LOG_NOTICE, "starting done");
                                    while (true) {
                                        if (g_quit) {
                                            result = EXIT_FAILURE;
                                            break;
                                        }
                                        instance->loop();
                                    }
                                }
                                else {
                                    instance->log(LOG_ERR, "can't start pid = %d [%d]", getpid(), result);
                                }
                                instance->terminate();
                            }
                            pidfile_remove(pfh);
                        }
                        else {
                            switch (errno) {
                                case EEXIST:
                                    instance->log(LOG_ERR, "already started pid = %d", pid);
                                    result = EX_OSERR;
                                    break;
                                case EACCES:
                                    instance->log(LOG_ERR, "run as super user");
                                    result = EX_OSERR;
                                    break;
                                default:
                                    instance->log(LOG_ERR, "can't start [%m]");
                                    result = EX_OSERR;
                                    break;
                            }
                        }
                        break;
                    default:
                        // nop
                        break;
                }
            }
        }
        ir::IRXDaemon::_delete(instance);
    }
    else {
        result = EXIT_FAILURE;
    }
    return result;
}
Example #23
0
/*
 * Periodically pat the watchdog, preventing it from firing.
 */
int
main(int argc, char *argv[])
{
	struct rtprio rtp;
	struct pidfh *pfh;
	pid_t otherpid;

	if (getuid() != 0)
		errx(EX_SOFTWARE, "not super user");
		
	parseargs(argc, argv);

	if (do_syslog)
		openlog("watchdogd", LOG_CONS|LOG_NDELAY|LOG_PERROR,
		    LOG_DAEMON);

	rtp.type = RTP_PRIO_REALTIME;
	rtp.prio = 0;
	if (rtprio(RTP_SET, 0, &rtp) == -1)
		err(EX_OSERR, "rtprio");

	if (!is_dry_run && watchdog_init() == -1)
		errx(EX_SOFTWARE, "unable to initialize watchdog");

	if (is_daemon) {
		if (watchdog_onoff(1) == -1)
			err(EX_OSERR, "patting the dog");

		pfh = pidfile_open(pidfile, 0600, &otherpid);
		if (pfh == NULL) {
			if (errno == EEXIST) {
				watchdog_onoff(0);
				errx(EX_SOFTWARE, "%s already running, pid: %d",
				    getprogname(), otherpid);
			}
			warn("Cannot open or create pidfile");
		}

		if (debugging == 0 && daemon(0, 0) == -1) {
			watchdog_onoff(0);
			pidfile_remove(pfh);
			err(EX_OSERR, "daemon");
		}

		signal(SIGHUP, SIG_IGN);
		signal(SIGINT, sighandler);
		signal(SIGTERM, sighandler);

		pidfile_write(pfh);
		if (madvise(0, 0, MADV_PROTECT) != 0)
			warn("madvise failed");
		if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0)
			warn("mlockall failed");

		watchdog_loop();

		/* exiting */
		pidfile_remove(pfh);
		return (EX_OK);
	} else {
		if (passive)
			timeout |= WD_PASSIVE;
		else
			timeout |= WD_ACTIVE;
		if (watchdog_patpat(timeout) < 0)
			err(EX_OSERR, "patting the dog");
		return (EX_OK);
	}
}
int
main(int argc, char *argv[])
{
	struct pollfd pfd[1];
	char *ep, *cp;
	int on = 1;
	int send_time = 180;	/* Default time, 180 seconds (3 minutes) */
	struct sockaddr_in m_sin;
	uid_t unpriv_uid;
	gid_t unpriv_gid;
	long tmp;
	time_t delta = 0;
	struct timeval next, now;

	if (getuid())
		errx(1, "not super user");

	run_as(&unpriv_uid, &unpriv_gid);

	argv++; argc--;
	while (argc > 0 && *argv[0] == '-') {
		if (strcmp(*argv, "-m") == 0) {
			if (argc > 1 && *(argv + 1)[0] != '-') {
				/* Argument has been given */
				argv++, argc--;
				multicast_mode = SCOPED_MULTICAST;
				tmp = strtol(*argv, &ep, 10);
				if (*ep != '\0' || tmp < INT_MIN || tmp > INT_MAX)
					errx(1, "invalid ttl: %s", *argv);
				multicast_scope = (int)tmp;
				if (multicast_scope > MAX_MULTICAST_SCOPE)
					errx(1, "ttl must not exceed %u",
					MAX_MULTICAST_SCOPE);
			}
			else multicast_mode = PER_INTERFACE_MULTICAST;
		} else if (strcmp(*argv, "-g") == 0) {
			if (argc > 1 && *(argv + 1)[0] != '-') {
				argv++, argc--;
				send_time = (int)strtol(*argv, &ep, 10);
				if (send_time <= 0)
					errx(1, "time must be greater than 0");

				if (ep[0] != '\0') {
					if (ep[1] != '\0')
						errx(1, "invalid argument: %s", *argv);
					if (*ep == 'M' || *ep == 'm') {
						/* Time in minutes. */
						send_time *= 60;
					} else
						errx(1, "invalid argument: %s", *argv);
				}

				if (send_time > 180)
					errx(1, "cannot be greater than 180 seconds (3 minutes)");
			} else
				errx(1, "missing argument");
		} else if (strcmp(*argv, "-i") == 0)
			insecure_mode = 1;
		else if (strcmp(*argv, "-l") == 0)
			quiet_mode = 1;
		else if (strcmp(*argv, "-p") == 0)
			iff_flag = 0;
		else
			usage();
		argv++, argc--;
	}
	if (argc > 0)
		usage();
#ifndef DEBUG
        struct pidfh *pfh = NULL;
        pfh = pidfile_open(NULL, 600, NULL);
	daemon(1, 0);
        pidfile_write(pfh);
#endif
	signal(SIGHUP, hup);
	openlog("rwhod", LOG_PID, LOG_DAEMON);
	sp = getservbyname("who", "udp");
	if (sp == NULL)
		quit("udp/who: unknown service", WITHOUT_ERRNO);

	if (chdir(_PATH_RWHODIR) < 0)
		quit(_PATH_RWHODIR, WITH_ERRNO);

	/*
	 * Establish host name as returned by system.
	 */
	if (gethostname(myname, sizeof(myname)) < 0)
		quit("gethostname", WITH_ERRNO);

	if ((cp = strchr(myname, '.')) != NULL)
		*cp = '\0';
	strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname));
	utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
	if (utmpf < 0)
		quit(_PATH_UTMP, WITH_ERRNO);

	getboottime();
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		quit("socket", WITH_ERRNO);

	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
		quit("setsockopt SO_BROADCAST", WITH_ERRNO);

	memset(&m_sin, 0, sizeof(m_sin));
	m_sin.sin_len = sizeof(m_sin);
	m_sin.sin_family = AF_INET;
	m_sin.sin_port = sp->s_port;
	if (bind(s, (struct sockaddr *)&m_sin, sizeof(m_sin)) < 0)
		quit("bind", WITH_ERRNO);

	setgid(unpriv_gid);
	setgroups(1, &unpriv_gid);	/* XXX BOGUS groups[0] = egid */
	setuid(unpriv_uid);
	if (!configure(s))
		exit(1);

	if (!quiet_mode) {
		send_host_information();
		delta = send_time;
		gettimeofday(&now, NULL);
		timeadd(&now, delta, &next);
	}

	pfd[0].fd = s;
	pfd[0].events = POLLIN;
 
	for (;;) {
		int n;

		n = poll(pfd, 1, 1000);

		if (onsighup) {
			onsighup = 0;
			getboottime();
		}

		if (n == 1)
			handleread(s);
		if (!quiet_mode) {
			gettimeofday(&now, NULL);
			if (now.tv_sec > next.tv_sec) {
				send_host_information();
				timeadd(&now, delta, &next);
			}
		}
	}
}
Example #25
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]);
}
Example #26
0
int
main(int argc, char * argv[])
{
	struct timeval timeout;
	fd_set fdset;
	int nfds;
	struct pidfh *pfh = NULL;
	const char *pidfile = NULL;
	int freq, curfreq, initfreq, *freqs, i, j, *mwatts, numfreqs, load;
	int minfreq = -1, maxfreq = -1;
	int ch, mode, mode_ac, mode_battery, mode_none, idle, to;
	uint64_t mjoules_used;
	size_t len;

	/* Default mode for all AC states is adaptive. */
	mode_ac = mode_none = MODE_HIADAPTIVE;
	mode_battery = MODE_ADAPTIVE;
	cpu_running_mark = DEFAULT_ACTIVE_PERCENT;
	cpu_idle_mark = DEFAULT_IDLE_PERCENT;
	poll_ival = DEFAULT_POLL_INTERVAL;
	mjoules_used = 0;
	vflag = 0;

	/* User must be root to control frequencies. */
	if (geteuid() != 0)
		errx(1, "must be root to run");

	while ((ch = getopt(argc, argv, "a:b:i:m:M:n:p:P:r:v")) != -1)
		switch (ch) {
		case 'a':
			parse_mode(optarg, &mode_ac, ch);
			break;
		case 'b':
			parse_mode(optarg, &mode_battery, ch);
			break;
		case 'i':
			cpu_idle_mark = atoi(optarg);
			if (cpu_idle_mark < 0 || cpu_idle_mark > 100) {
				warnx("%d is not a valid percent",
				    cpu_idle_mark);
				usage();
			}
			break;
		case 'm':
			minfreq = atoi(optarg);
			if (minfreq < 0) {
				warnx("%d is not a valid CPU frequency",
				    minfreq);
				usage();
			}
			break;
		case 'M':
			maxfreq = atoi(optarg);
			if (maxfreq < 0) {
				warnx("%d is not a valid CPU frequency",
				    maxfreq);
				usage();
			}
			break;
		case 'n':
			parse_mode(optarg, &mode_none, ch);
			break;
		case 'p':
			poll_ival = atoi(optarg);
			if (poll_ival < 5) {
				warnx("poll interval is in units of ms");
				usage();
			}
			break;
		case 'P':
			pidfile = optarg;
			break;
		case 'r':
			cpu_running_mark = atoi(optarg);
			if (cpu_running_mark <= 0 || cpu_running_mark > 100) {
				warnx("%d is not a valid percent",
				    cpu_running_mark);
				usage();
			}
			break;
		case 'v':
			vflag = 1;
			break;
		default:
			usage();
		}

	mode = mode_none;

	/* Poll interval is in units of ms. */
	poll_ival *= 1000;

	/* Look up various sysctl MIBs. */
	len = 2;
	if (sysctlnametomib("kern.cp_times", cp_times_mib, &len))
		err(1, "lookup kern.cp_times");
	len = 4;
	if (sysctlnametomib("dev.cpu.0.freq", freq_mib, &len))
		err(EX_UNAVAILABLE, "no cpufreq(4) support -- aborting");
	len = 4;
	if (sysctlnametomib("dev.cpu.0.freq_levels", levels_mib, &len))
		err(1, "lookup freq_levels");

	/* Check if we can read the load and supported freqs. */
	if (read_usage_times(NULL))
		err(1, "read_usage_times");
	if (read_freqs(&numfreqs, &freqs, &mwatts, minfreq, maxfreq))
		err(1, "error reading supported CPU frequencies");
	if (numfreqs == 0)
		errx(1, "no CPU frequencies in user-specified range");

	/* Run in the background unless in verbose mode. */
	if (!vflag) {
		pid_t otherpid;

		pfh = pidfile_open(pidfile, 0600, &otherpid);
		if (pfh == NULL) {
			if (errno == EEXIST) {
				errx(1, "powerd already running, pid: %d",
				    otherpid);
			}
			warn("cannot open pid file");
		}
		if (daemon(0, 0) != 0) {
			warn("cannot enter daemon mode, exiting");
			pidfile_remove(pfh);
			exit(EXIT_FAILURE);

		}
		pidfile_write(pfh);
	}

	/* Decide whether to use ACPI or APM to read the AC line status. */
	acline_init();

	/*
	 * Exit cleanly on signals.
	 */
	signal(SIGINT, handle_sigs);
	signal(SIGTERM, handle_sigs);

	freq = initfreq = curfreq = get_freq();
	i = get_freq_id(curfreq, freqs, numfreqs);
	if (freq < 1)
		freq = 1;

	/*
	 * If we are in adaptive mode and the current frequency is outside the
	 * user-defined range, adjust it to be within the user-defined range.
	 */
	acline_read();
	if (acline_status > SRC_UNKNOWN)
		errx(1, "invalid AC line status %d", acline_status);
	if ((acline_status == SRC_AC &&
	    (mode_ac == MODE_ADAPTIVE || mode_ac == MODE_HIADAPTIVE)) ||
	    (acline_status == SRC_BATTERY &&
	    (mode_battery == MODE_ADAPTIVE || mode_battery == MODE_HIADAPTIVE)) ||
	    (acline_status == SRC_UNKNOWN &&
	    (mode_none == MODE_ADAPTIVE || mode_none == MODE_HIADAPTIVE))) {
		/* Read the current frequency. */
		len = sizeof(curfreq);
		if (sysctl(freq_mib, 4, &curfreq, &len, NULL, 0) != 0) {
			if (vflag)
				warn("error reading current CPU frequency");
		}
		if (curfreq < freqs[numfreqs - 1]) {
			if (vflag) {
				printf("CPU frequency is below user-defined "
				    "minimum; changing frequency to %d "
				    "MHz\n", freqs[numfreqs - 1]);
			}
			if (set_freq(freqs[numfreqs - 1]) != 0) {
				warn("error setting CPU freq %d",
				    freqs[numfreqs - 1]);
			}
		} else if (curfreq > freqs[0]) {
			if (vflag) {
				printf("CPU frequency is above user-defined "
				    "maximum; changing frequency to %d "
				    "MHz\n", freqs[0]);
			}
			if (set_freq(freqs[0]) != 0) {
				warn("error setting CPU freq %d",
				    freqs[0]);
			}
		}
	}

	idle = 0;
	/* Main loop. */
	for (;;) {
		FD_ZERO(&fdset);
		if (devd_pipe >= 0) {
			FD_SET(devd_pipe, &fdset);
			nfds = devd_pipe + 1;
		} else {
			nfds = 0;
		}
		if (mode == MODE_HIADAPTIVE || idle < 120)
			to = poll_ival;
		else if (idle < 360)
			to = poll_ival * 2;
		else
			to = poll_ival * 4;
		timeout.tv_sec = to / 1000000;
		timeout.tv_usec = to % 1000000;
		select(nfds, &fdset, NULL, &fdset, &timeout);

		/* If the user requested we quit, print some statistics. */
		if (exit_requested) {
			if (vflag && mjoules_used != 0)
				printf("total joules used: %u.%03u\n",
				    (u_int)(mjoules_used / 1000),
				    (int)mjoules_used % 1000);
			break;
		}

		/* Read the current AC status and record the mode. */
		acline_read();
		switch (acline_status) {
		case SRC_AC:
			mode = mode_ac;
			break;
		case SRC_BATTERY:
			mode = mode_battery;
			break;
		case SRC_UNKNOWN:
			mode = mode_none;
			break;
		default:
			errx(1, "invalid AC line status %d", acline_status);
		}

		/* Read the current frequency. */
		if (idle % 32 == 0) {
			if ((curfreq = get_freq()) == 0)
				continue;
			i = get_freq_id(curfreq, freqs, numfreqs);
		}
		idle++;
		if (vflag) {
			/* Keep a sum of all power actually used. */
			if (mwatts[i] != -1)
				mjoules_used +=
				    (mwatts[i] * (poll_ival / 1000)) / 1000;
		}

		/* Always switch to the lowest frequency in min mode. */
		if (mode == MODE_MIN) {
			freq = freqs[numfreqs - 1];
			if (curfreq != freq) {
				if (vflag) {
					printf("now operating on %s power; "
					    "changing frequency to %d MHz\n",
					    modes[acline_status], freq);
				}
				idle = 0;
				if (set_freq(freq) != 0) {
					warn("error setting CPU freq %d",
					    freq);
					continue;
				}
			}
			continue;
		}

		/* Always switch to the highest frequency in max mode. */
		if (mode == MODE_MAX) {
			freq = freqs[0];
			if (curfreq != freq) {
				if (vflag) {
					printf("now operating on %s power; "
					    "changing frequency to %d MHz\n",
					    modes[acline_status], freq);
				}
				idle = 0;
				if (set_freq(freq) != 0) {
					warn("error setting CPU freq %d",
					    freq);
					continue;
				}
			}
			continue;
		}

		/* Adaptive mode; get the current CPU usage times. */
		if (read_usage_times(&load)) {
			if (vflag)
				warn("read_usage_times() failed");
			continue;
		}

		if (mode == MODE_ADAPTIVE) {
			if (load > cpu_running_mark) {
				if (load > 95 || load > cpu_running_mark * 2)
					freq *= 2;
				else
					freq = freq * load / cpu_running_mark;
				if (freq > freqs[0])
					freq = freqs[0];
			} else if (load < cpu_idle_mark &&
			    curfreq * load < freqs[get_freq_id(
			    freq * 7 / 8, freqs, numfreqs)] *
			    cpu_running_mark) {
				freq = freq * 7 / 8;
				if (freq < freqs[numfreqs - 1])
					freq = freqs[numfreqs - 1];
			}
		} else { /* MODE_HIADAPTIVE */
			if (load > cpu_running_mark / 2) {
				if (load > 95 || load > cpu_running_mark)
					freq *= 4;
				else
					freq = freq * load * 2 / cpu_running_mark;
				if (freq > freqs[0] * 2)
					freq = freqs[0] * 2;
			} else if (load < cpu_idle_mark / 2 &&
			    curfreq * load < freqs[get_freq_id(
			    freq * 31 / 32, freqs, numfreqs)] *
			    cpu_running_mark / 2) {
				freq = freq * 31 / 32;
				if (freq < freqs[numfreqs - 1])
					freq = freqs[numfreqs - 1];
			}
		}
		if (vflag) {
		    printf("load %3d%%, current freq %4d MHz (%2d), wanted freq %4d MHz\n",
			load, curfreq, i, freq);
		}
		j = get_freq_id(freq, freqs, numfreqs);
		if (i != j) {
			if (vflag) {
				printf("changing clock"
				    " speed from %d MHz to %d MHz\n",
				    freqs[i], freqs[j]);
			}
			idle = 0;
			if (set_freq(freqs[j]))
				warn("error setting CPU frequency %d",
				    freqs[j]);
		}
	}
	if (set_freq(initfreq))
		warn("error setting CPU frequency %d", initfreq);
	free(freqs);
	free(mwatts);
	devd_close();
	if (!vflag)
		pidfile_remove(pfh);

	exit(0);
}
Example #27
0
int
main(int argc, char **argv)
{
    int ch, debug = 0, error, iscsi_fd, maxproc = 30, retval, saved_errno,
            timeout = 60;
    bool dont_daemonize = false;
    struct pidfh *pidfh;
    pid_t pid, otherpid;
    const char *pidfile_path = DEFAULT_PIDFILE;
    struct iscsi_daemon_request request;

    while ((ch = getopt(argc, argv, "P:dl:m:t:")) != -1) {
        switch (ch) {
        case 'P':
            pidfile_path = optarg;
            break;
        case 'd':
            dont_daemonize = true;
            debug++;
            break;
        case 'l':
            debug = atoi(optarg);
            break;
        case 'm':
            maxproc = atoi(optarg);
            break;
        case 't':
            timeout = atoi(optarg);
            break;
        case '?':
        default:
            usage();
        }
    }
    argc -= optind;
    if (argc != 0)
        usage();

    log_init(debug);

    pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
    if (pidfh == NULL) {
        if (errno == EEXIST)
            log_errx(1, "daemon already running, pid: %jd.",
                     (intmax_t)otherpid);
        log_err(1, "cannot open or create pidfile \"%s\"",
                pidfile_path);
    }

    iscsi_fd = open(ISCSI_PATH, O_RDWR);
    if (iscsi_fd < 0 && errno == ENOENT) {
        saved_errno = errno;
        retval = kldload("iscsi");
        if (retval != -1)
            iscsi_fd = open(ISCSI_PATH, O_RDWR);
        else
            errno = saved_errno;
    }
    if (iscsi_fd < 0)
        log_err(1, "failed to open %s", ISCSI_PATH);

    if (dont_daemonize == false) {
        if (daemon(0, 0) == -1) {
            log_warn("cannot daemonize");
            pidfile_remove(pidfh);
            exit(1);
        }
    }

    pidfile_write(pidfh);

    register_sigchld();

    for (;;) {
        log_debugx("waiting for request from the kernel");

        memset(&request, 0, sizeof(request));
        error = ioctl(iscsi_fd, ISCSIDWAIT, &request);
        if (error != 0) {
            if (errno == EINTR) {
                nchildren -= wait_for_children(false);
                assert(nchildren >= 0);
                continue;
            }

            log_err(1, "ISCSIDWAIT");
        }

        if (dont_daemonize) {
            log_debugx("not forking due to -d flag; "
                       "will exit after servicing a single request");
        } else {
            nchildren -= wait_for_children(false);
            assert(nchildren >= 0);

            while (maxproc > 0 && nchildren >= maxproc) {
                log_debugx("maxproc limit of %d child processes hit; "
                           "waiting for child process to exit", maxproc);
                nchildren -= wait_for_children(true);
                assert(nchildren >= 0);
            }
            log_debugx("incoming connection; forking child process #%d",
                       nchildren);
            nchildren++;

            pid = fork();
            if (pid < 0)
                log_err(1, "fork");
            if (pid > 0)
                continue;
        }

        pidfile_close(pidfh);
        handle_request(iscsi_fd, &request, timeout);
    }

    return (0);
}
Example #28
0
/* Entry point */
int
main(int argc, char **argv)
{
	int report_stopped = true;

	/* Init debugging level */
	debug = 0;

	/* Initialise daemon_mode */
	__set_bit(DAEMON_VRRP, &daemon_mode);
	__set_bit(DAEMON_CHECKERS, &daemon_mode);

	/*
	 * Parse command line and set debug level.
	 * bits 0..7 reserved by main.c
	 */
	parse_cmdline(argc, argv);

	openlog(PROG, LOG_PID | ((__test_bit(LOG_CONSOLE_BIT, &debug)) ? LOG_CONS : 0)
		    , log_facility);
#ifdef GIT_COMMIT
	log_message(LOG_INFO, "Starting %s, git commit %s", VERSION_STRING, GIT_COMMIT);
#else
	log_message(LOG_INFO, "Starting %s", VERSION_STRING);
#endif

#ifdef _MEM_CHECK_
	mem_log_init(PROG);
#endif

	/* Handle any core file requirements */
	core_dump_init();

	/* Check if keepalived is already running */
	if (keepalived_running(daemon_mode)) {
		log_message(LOG_INFO, "daemon is already running");
		report_stopped = false;
		goto end;
	}

	if (__test_bit(LOG_CONSOLE_BIT, &debug))
		enable_console_log();

	/* daemonize process */
	if (!__test_bit(DONT_FORK_BIT, &debug))
		xdaemon(0, 0, 0);

	/* Check we can read the configuration file(s).
 	   NOTE: the working directory will be / if we
 	   forked, but will be the current working directory
 	   when keepalived was run if we haven't forked.
 	   This means that if any config file names are not
 	   absolute file names, the behaviour will be different
 	   depending on whether we forked or not. */
	if (!check_conf_file(conf_file))
		goto end;

	/* write the father's pidfile */
	if (!pidfile_write(main_pidfile, getpid()))
		goto end;

#ifndef _DEBUG_
	/* Signal handling initialization  */
	signal_init();
#endif

	/* Create the master thread */
	master = thread_make_master();

	/* Init daemon */
	start_keepalived();

#ifndef _DEBUG_
	/* Launch the scheduling I/O multiplexer */
	launch_scheduler();

	/* Finish daemon process */
	stop_keepalived();
#endif

	/*
	 * Reached when terminate signal catched.
	 * finally return from system
	 */
end:
	if (report_stopped) {
#ifdef GIT_COMMIT
		log_message(LOG_INFO, "Stopped %s, git commit %s", VERSION_STRING, GIT_COMMIT);
#else
		log_message(LOG_INFO, "Stopped %s", VERSION_STRING);
#endif
	}

	/* Restore original core_pattern if necessary */
	if (orig_core_dump_pattern)
		update_core_dump_pattern(orig_core_dump_pattern);

	closelog();
	exit(0);
}
Example #29
0
void
tap_init(void)
{
	channel_t *chan;
	struct ifreq ifr;
	int fd, s;
	char pidfile[PATH_MAX];

	fd = open(interface_name, O_RDWR);
	if (fd == -1) {
		log_err("Could not open \"%s\": %m", interface_name);
		exit(EXIT_FAILURE);
	}

	memset(&ifr, 0, sizeof(ifr));
	if (ioctl(fd, TAPGIFNAME, &ifr) == -1) {
		log_err("Could not get interface name: %m");
		exit(EXIT_FAILURE);
	}

	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s == -1) {
		log_err("Could not open PF_LINK socket: %m");
		exit(EXIT_FAILURE);
	}

	ifr.ifr_addr.sa_family = AF_LINK;
	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
	b2eaddr(ifr.ifr_addr.sa_data, &local_bdaddr);

	if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) {
		log_err("Could not set %s physical address: %m", ifr.ifr_name);
		exit(EXIT_FAILURE);
	}

	if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
		log_err("Could not get interface flags: %m");
		exit(EXIT_FAILURE);
	}

	if ((ifr.ifr_flags & IFF_UP) == 0) {
		ifr.ifr_flags |= IFF_UP;

		if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) {
			log_err("Could not set IFF_UP: %m");
			exit(EXIT_FAILURE);
		}
	}

	close(s);

	log_info("Using interface %s with addr %s", ifr.ifr_name,
		ether_ntoa((struct ether_addr *)&ifr.ifr_addr.sa_data));

	chan = channel_alloc();
	if (chan == NULL)
		exit(EXIT_FAILURE);

	chan->send = tap_send;
	chan->recv = tap_recv;
	chan->mru = ETHER_HDR_LEN + ETHER_MAX_LEN;
	memcpy(chan->raddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
	memcpy(chan->laddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
	chan->state = CHANNEL_OPEN;
	if (!channel_open(chan, fd))
		exit(EXIT_FAILURE);

	snprintf(pidfile, sizeof(pidfile), "%s/%s.pid",
		_PATH_VARRUN, ifr.ifr_name);
	chan->pfh = pidfile_open(pidfile, 0600, NULL);
	if (chan->pfh == NULL)
		log_err("can't create pidfile");
	else if (pidfile_write(chan->pfh) < 0) {
		log_err("can't write pidfile");
		pidfile_remove(chan->pfh);
		chan->pfh = NULL;
	}
}
int main(int argc, char **argv)
{
    if (1 == argc) {
        utlog(LOG_ERR, "No configuration file was specified\n\n");
        print_help(EXIT_FAILURE);
    }

    int c;
    int foreground = 0;
    char *config_file = "";

    while (1) {

        static struct option long_options[] = {
            {"help",       no_argument,       0, 'h'},
            {"version",    no_argument,       0, 'v'},
            {"config",     required_argument, 0, 'c'},
            {"foreground", no_argument,       0, 'f'},
            {0, 0, 0, 0}
        };

        // getopt_long stores the option index here.
        int option_index = 0;

        c = getopt_long(argc, argv, "hvfc:",
                long_options, &option_index);

        // Detect the end of the options.
        if (c == -1) {
            break;
        }

        switch (c) {
            case 'h':
                print_help(EXIT_SUCCESS);
                break;

            case 'v':
                print_version(EXIT_SUCCESS);
                break;

            case 'c':
                config_file = optarg;
                break;

            case 'f':
                foreground = 1;
                break;

            case '?':
                // getopt_long already printed an error message.
                utlog(LOG_INFO, "\n");
                print_help(EXIT_FAILURE);
                break;

            default:
                break;
        }
    }

    pid_t pid;

    if (0 != (pid = pidfile_check(pidfile))) {
        utlog(LOG_ERR, "A instance of avm-motion-triggerd (%d) is already running\n",
                pid);
        exit(EXIT_FAILURE);
    }

    conf = get_config(config_file);
    validate_config(&conf);

    // Run as daemon if we should
    if (0 == foreground) {
        daemonize();
        utlog_mode(LOG_BACKGROUND);
        utlog_pri_mode(LOG_PRI_DISABLE);
    } else {
        utlog_mode(LOG_FOREGROUND);
        utlog_pri_mode(LOG_PRI_ENABLE);
    }

    // Write a pidfile for the current daemon process
    if (0 == pidfile_write(pidfile)) {
        exit(EXIT_FAILURE);
    }

    // Bind the signal handler
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);

    // Initialize the sensors
    init_sensors(&conf);

    // Call the business logic loop
    detect_motions(&conf);

    return EXIT_SUCCESS;
}