Пример #1
0
static int usage(int code)
{
    size_t i;
    char line[76] = "  ";
    char pidfn[80];
    struct debugname *d;

    compose_paths();
    if (pid_file && pid_file[0] != '/')
	snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", _PATH_PIMD_RUNDIR, pid_file);
    else
	snprintf(pidfn, sizeof(pidfn), "%s", pid_file);

    printf("Usage: %s [-DhlNnv] [-f FILE] [-d [SYS][,SYS...]] [-s LEVEL]\n\n", prognm);
    printf(" -f, --config=FILE   Configuration file, default uses ident NAME: %s\n", config_file);
    printf("     --no-fallback   When started without a config file, skip RP/BSR fallbacks\n");
    printf(" -n, --foreground    Run in foreground, do not detach from calling terminal\n");
    printf(" -d SYS[,SYS,SYS..]  Enable debug for SYS, see below for valid systems\n");
    printf(" -l, --loglevel=LVL  Set log level: none, err, info, notice (default), debug\n");
    printf(" -I, --ident=NAME    Identity for config + PID file, and syslog, default: %s\n", ident);
    printf(" -N, --disable-vifs  Disable all virtual interfaces (phyint) by default\n");
    printf(" -P, --pidfile=FILE  File to store process ID for signaling %s\n"
	   "                     Default uses ident NAME: %s\n", prognm, pidfn);
    printf(" -r                  Retry (forever) if not all phyint interfaces are available\n"
	   "                     yet when starting up, e.g. wait for DHCP lease\n");
    printf(" -s, --syslog        Use syslog, default unless running in foreground, -n\n");
    printf(" -t, --table-id=ID   Set multicast routing table ID.  Allowed table ID#:\n"
	   "                      0 .. 999999999.  Default: 0 (use default table)\n");
    printf(" -h, --help          Show this help text\n");
    printf(" -v, --version       Show %s version\n", prognm);
    printf("\n");

    /* From pimd v2.3.0 we show *all* the debug levels again */
    printf("Available subsystems for debug:\n");
    for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) {
	if (strlen(line) + strlen(d->name) + 3 >= sizeof(line)) {
	    /* Finish this line and send to console */
	    strlcat(line, "\n", sizeof(line));
	    printf("%s", line);

	    /* Prepare for next line */
	    strlcpy(line, "  ", sizeof(line));
	}

	strlcat(line, d->name, sizeof(line));

	if (i + 1 < ARRAY_LEN(debugnames))
	    strlcat(line, ", ", sizeof(line));
    }
    /* Flush remaining line. */
    strlcat(line, "\n", sizeof(line));
    printf("%s", line);

    printf("\nBug report address: %-40s\n", PACKAGE_BUGREPORT);
#ifdef PACKAGE_URL
    printf("Project homepage: %s\n", PACKAGE_URL);
#endif

    return code;
}
Пример #2
0
/**
 * main - Main program
 *
 * Parses command line options and enters either daemon or client mode.
 *
 * In daemon mode, acquires multicast routing sockets, opens IPC socket
 * and goes in receive-execute command loop.
 *
 * In client mode, creates commands from command line and sends them to
 * the daemon.
 */
int main(int argc, char *argv[])
{
	int log_opts = LOG_NDELAY | LOG_PID;
	int c, new_log_level = -1;

	prognm = progname(argv[0]);
	while ((c = getopt(argc, argv, "c:d:e:f:F:hI:l:m:nNp:P:st:v")) != EOF) {
		switch (c) {
		case 'c':	/* cache timeout */
			cache_tmo = atoi(optarg);
			break;

		case 'd':
			startup_delay = atoi(optarg);
			break;

		case 'e':
			script = optarg;
			break;

#ifndef ENABLE_DOTCONF
		case 'F':
		case 'f':
			warnx("Built without .conf file support.");
			break;
#else
		case 'F':
			log_level = LOG_INFO; /* Raise log level for verify */
			conf_vrfy = 1;
			/* fallthrough */
		case 'f':
			conf_file = optarg;
			break;
#endif

		case 'h':	/* help */
			return usage(0);

		case 'I':
			ident = optarg;
			break;

		case 'l':
			new_log_level = loglvl(optarg);
			break;

		case 'm':
#ifndef ENABLE_MRDISC
			warnx("Built without mrdisc support.");
#else
			interval = atoi(optarg);
			if (interval < 4 || interval > 180)
				errx(1, "Invalid mrdisc announcement interval, 4-180.");
#endif
			break;

		case 'n':	/* run daemon in foreground, i.e., do not fork */
			background = 0;
			do_syslog--;
			break;

		case 'N':
#ifndef ENABLE_DOTCONF
			errx(1, "Built without .conf file, no way to enable individual interfaces.");
#else
			do_vifs = 0;
#endif
			break;

		case 'p':
			cap_set_user(optarg, &uid, &gid);
			break;

		case 'P':
			pid_file = optarg;
			break;

		case 's':	/* Force syslog even though in foreground */
			do_syslog++;
			break;

		case 't':
#ifndef __linux__
			errx(1, "Different multicast routing tables only available on Linux.");
#else
			table_id = atoi(optarg);
			if (table_id < 0)
				return usage(1);
#endif
			break;

		case 'v':	/* version */
			fprintf(stderr, "%s\n", version_info);
			return 0;

		default:	/* unknown option */
			return usage(1);
		}
	}

	if (new_log_level != -1)
		log_level = new_log_level;

	compose_paths();

	if (conf_vrfy) {
		smclog(LOG_INFO, "Verifying configuration file %s ...", conf_file);
		c = conf_read(conf_file, do_vifs);
		smclog(LOG_INFO, "Configuration file %s.", c ? "has unrecoverable errors" : "is OK");

		return c;
	}

	if (!background && do_syslog < 1)
		log_opts |= LOG_PERROR;

	openlog(ident, log_opts, LOG_DAEMON);
	setlogmask(LOG_UPTO(log_level));

	return start_server();
}
Пример #3
0
static int usage(int code)
{
        char pidfn[80];

	compose_paths();
	if (pid_file[0] != '/')
		snprintf(pidfn, sizeof(pidfn), "%s/run/%s.pid", LOCALSTATEDIR, pid_file);
	else
		snprintf(pidfn, sizeof(pidfn), "%s", pid_file);

	printf("Usage: %s [hnNsv] [-c SEC] [-d SEC] [-e CMD] "
#ifdef ENABLE_DOTCONF
	       "[-f FILE] "
#endif
	       "[-l LVL] "
#ifdef ENABLE_MRDISC
	       "[-m SEC] "
#endif
	       "[-P FILE] "
	       "[-t ID] "
	       "\n\n"
	       "  -c SEC          Flush dynamic (*,G) multicast routes every SEC seconds,\n"
	       "                  default 60 sec.  Useful when source/interface changes\n"
	       "  -d SEC          Startup delay, useful for delaying interface probe at boot\n"
	       "  -e CMD          Script or command to call on startup/reload when all routes\n"
	       "                  have been installed, or when a (*,G) is installed\n"
#ifdef ENABLE_DOTCONF
	       "  -f FILE         Set configuration file, default uses ident NAME: %s\n"
	       "  -F FILE         Check configuration file syntax, use -l to increase verbosity\n"
#endif
	       "  -h              This help text\n"
	       "  -I NAME         Identity for config, PID file, and syslog, default: %s\n"
	       "  -l LVL          Set log level: none, err, notice*, info, debug\n"
#ifdef ENABLE_MRDISC
	       "  -m SEC          Multicast router discovery, 4-180, default: 20 sec\n"
#endif
	       "  -n              Run daemon in foreground, when started by systemd or finit\n"
#ifdef ENABLE_DOTCONF
	       "  -N              No multicast VIFs/MIFs created by default.  Use with\n"
	       "                  smcroute.conf `phyint enable` directive\n"
#endif
#ifdef ENABLE_LIBCAP
	       "  -p USER[:GROUP] After initialization set UID and GID to USER and GROUP\n"
#endif
	       "  -P FILE         Set daemon PID file name, with optional path.\n"
	       "                  Default uses ident NAME: %s\n"
	       "  -s              Use syslog, default unless running in foreground, -n\n"
	       "  -t ID           Set multicast routing table ID, default: 0\n"
	       "  -v              Show program version\n"
	       "\n"
	       "Bug report address: %s\n", prognm, conf_file,
#ifdef ENABLE_DOTCONF
	       ident,
#endif
	       pidfn, PACKAGE_BUGREPORT);
#ifdef PACKAGE_URL
	printf("Project homepage:   %s\n", PACKAGE_URL);
#endif

	return code;
}
Пример #4
0
int main(int argc, char *argv[])
{
    int foreground = 0, do_syslog = 1;
    fd_set fds;
    int nfds, fd, n = -1, i, ch;
    struct sigaction sa;
    struct option long_options[] = {
	{ "config",        1, 0, 'f' },
	{ "no-fallback",   0, 0, 500 },
	{ "disable-vifs",  0, 0, 'N' },
	{ "foreground",    0, 0, 'n' },
	{ "help",          0, 0, 'h' },
	{ "ident",         1, 0, 'I' },
	{ "loglevel",      1, 0, 'l' },
	{ "pidfile",       1, 0, 'P' },
	{ "syslog",        0, 0, 's' },
	{ "table-id",      1, 0, 't' },
	{ "version",       0, 0, 'v' },
	{ NULL, 0, 0, 0 }
    };

    snprintf(versionstring, sizeof (versionstring), "pimd version %s", PACKAGE_VERSION);

    prognm = ident = progname(argv[0]);
    while ((ch = getopt_long(argc, argv, "d:f:hI:l:nNP:rst:v", long_options, NULL)) != EOF) {
	const char *errstr;

	switch (ch) {
	    case 'd':
		{
		    char *p,*q;
		    size_t i, len;
		    struct debugname *d;

		    debug = 0;
		    p = optarg;
		    q = NULL;
		    while (p) {
			q = strchr(p, ',');
			if (q)
			    *q++ = '\0';
			len = strlen(p);
			for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) {
			    if (len >= d->nchars && strncmp(d->name, p, len) == 0)
				break;
			}

			if (i == ARRAY_LEN(debugnames))
			    return usage(1);

			debug |= d->level;
			p = q;
		    }
		}
		break;

	    case 'f':
		config_file = optarg;
		break;

	    case 500:
		no_fallback = 1;
		break;

	    case 'h':
		return usage(0);

	    case 'I':	/* --ident=NAME */
		ident = optarg;
		break;

	    case 'l':
		loglevel = loglvl(optarg);
		if (-1 == loglevel)
		    return usage(1);
		break;

	    case 'n':
		do_syslog--;
		foreground = 1;
		break;

	    case 'N':
		do_vifs = 0;
		break;

	    case 'P':	/* --pidfile=NAME */
		pid_file = strdup(optarg);
		break;

	    case 'r':
		retry_forever++;
		break;

	    case 's':
		do_syslog++;
		break;

	    case 't':
		mrt_table_id = strtonum(optarg, 0, 999999999, &errstr);
		if (errstr) {
		    fprintf(stderr, "Table ID %s!\n", errstr);
		    return usage(1);
		}
		break;

	    case 'v':
		printf("%s\n", versionstring);
		return 0;

	    default:
		return usage(1);
	}
    }

    argc -= optind;
    if (argc > 0)
	return usage(1);

    if (geteuid() != 0)
	errx(1, "Need root privileges to start.");

    compose_paths();
    setlinebuf(stderr);

    if (debug != 0) {
	struct debugname *d;
	char c;
	int tmpd = debug;

	fprintf(stderr, "debug level 0x%lx ", debug);
	c = '(';
	for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) {
	    if ((tmpd & d->level) == d->level) {
		tmpd &= ~d->level;
		fprintf(stderr, "%c%s", c, d->name);
		c = ',';
	    }
	}
	fprintf(stderr, ")\n");
    }

    if (!debug && !foreground) {
	/* Detach from the terminal */
	haveterminal = 0;
	if (fork())
	    exit(0);

	close(STDIN_FILENO);
	close(STDOUT_FILENO);
	close(STDERR_FILENO);

	fd = open("/dev/null", O_RDWR, 0);
	if (fd >= 0) {
	    dup2(fd, STDIN_FILENO);
	    dup2(fd, STDOUT_FILENO);
	    dup2(fd, STDERR_FILENO);
	    close(fd);
	}
#ifdef SYSV
	setpgrp();
#else
#ifdef TIOCNOTTY
	fd = open("/dev/tty", 2);
	if (fd >= 0) {
	    (void)ioctl(fd, TIOCNOTTY, (char *)0);
	    close(fd);
	}
#else
	if (setsid() < 0)
	    perror("setsid");
#endif /* TIOCNOTTY */
#endif /* SYSV */
    } /* End of child process code */

    /*
     * Create directory for runtime files
     */
    if (-1 == mkdir(_PATH_PIMD_RUNDIR, 0755) && errno != EEXIST)
	err(1, "Failed creating %s directory for runtime files", _PATH_PIMD_RUNDIR);

    /*
     * Setup logging
     */
    log_init(haveterminal && do_syslog > 0);
    logit(LOG_NOTICE, 0, "%s starting ...", versionstring);

    do_randomize();

    callout_init();
    init_igmp();
    init_pim();
    init_routesock(); /* Both for Linux netlink and BSD routing socket */
    init_pim_mrt();
    init_timers();
    ipc_init();

    /* Start up the log rate-limiter */
    resetlogging(NULL);

    /* TODO: check the kernel DVMRP/MROUTED/PIM support version */

    init_vifs();
    init_rp_and_bsr();   /* Must be after init_vifs() */
    add_static_rp();	 /* Must be after init_vifs() */
#ifdef RSRR
    rsrr_init();
#endif /* RSRR */

    sa.sa_handler = handle_signals;
    sa.sa_flags = 0;	/* Interrupt system calls */
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGUSR1, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);

    IF_DEBUG(DEBUG_IF)
	dump_vifs(stderr);
    IF_DEBUG(DEBUG_PIM_MRT)
	dump_pim_mrt(stderr);

    /* schedule first timer interrupt */
    timer_setTimer(TIMER_INTERVAL, timer, NULL);

    if (pidfile(pid_file))
	warn("Cannot create pidfile");

    /*
     * Main receive loop.
     */
    while (1) {
	if (check_signals())
	    break;

	FD_ZERO(&fds);
	for (i = 0, nfds = 0; i < nhandlers; i++) {
	    FD_SET(ihandlers[i].fd, &fds);
	    if (ihandlers[i].fd >= nfds)
		nfds = ihandlers[i].fd + 1;
	}

	n = select(nfds, &fds, NULL, NULL, timeout(n));
	if (n < 0) {
	    if (errno != EINTR) /* SIGALRM is expected */
		logit(LOG_WARNING, errno, "select failed");
	    continue;
	}

	for (i = 0; n > 0 && i < nhandlers; i++) {
	    if (FD_ISSET(ihandlers[i].fd, &fds))
		ihandlers[i].func(ihandlers[i].fd);
	}
    }

    logit(LOG_NOTICE, 0, "%s exiting.", versionstring);
    cleanup();
    exit(0);
}