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; }
/** * 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(); }
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; }
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); }