int main(int argc, char *argv[]) { int c, rc = 0, restart; struct option opt[] = { { "once", 0, 0, '1' }, { "continue-on-error", 0, 0, 'c' }, { "exec", 1, 0, 'e' }, { "config", 1, 0, 'f' }, { "iface", 1, 0, 'i' }, { "loglevel", 1, 0, 'l' }, { "help", 0, 0, 'h' }, { "foreground", 0, 0, 'n' }, { "pidfile", 1, 0, 100 }, { "drop-privs", 1, 0, 'p' }, { "syslog", 0, 0, 's' }, { "startup-delay", 1, 0, 't' }, { "version", 0, 0, 'v' }, { NULL, 0, 0, 0 } }; ddns_t *ctx = NULL; while ((c = getopt_long(argc, argv, "1ce:f:h?i:l:np:st:v", opt, NULL)) != EOF) { switch (c) { case '1': /* --once */ once = 1; break; case 'c': /* --continue-on-error */ ignore_errors = 1; break; case 'e': /* --exec=CMD */ script_exec = strdup(optarg); break; case 'f': /* --config=FILE */ config = strdup(optarg); break; case 'i': /* --iface=IFNAME */ iface = strdup(optarg); break; case 'l': /* --loglevel=LEVEL */ loglevel = loglvl(optarg); if (-1 == loglevel) return usage(1); break; case 'n': /* --foreground */ background = 0; break; case 100: /* --pidfile=BASENAME */ pidfile_name = strdup(optarg); break; case 'p': /* --drop-privs=USER[:GROUP] */ parse_privs(optarg); break; case 's': /* --syslog */ use_syslog = 1; break; case 't': /* --startup-delay=SEC */ startup_delay = atoi(optarg); break; case 'v': puts(VERSION); return 0; case 'h': /* --help */ case ':': /* Missing parameter for option. */ case '?': /* Unknown option. */ default: return usage(0); } } if (background) { if (daemon(0, 0) < 0) { fprintf(stderr, "Failed daemonizing %s: %m\n", __progname); return RC_OS_FORK_FAILURE; } use_syslog = 1; } if (use_syslog) { openlog(NULL, LOG_PID, LOG_USER); setlogmask(LOG_UPTO(loglevel)); } if (drop_privs()) { logit(LOG_WARNING, "Failed dropping privileges: %s", strerror(errno)); return RC_OS_CHANGE_PERSONA_FAILURE; } /* "Hello!" Let user know we've started up OK */ logit(LOG_NOTICE, "%s", VERSION_STRING); if (!config) config = strdup(DEFAULT_CONFIG_FILE); /* Prepare SSL library, if enabled */ ssl_init(); do { restart = 0; rc = alloc_context(&ctx); if (rc != RC_OK) break; if (os_install_signal_handler(ctx)) return RC_OS_INSTALL_SIGHANDLER_FAILED; cfg = conf_parse_file(config, ctx); if (!cfg) { free_context(ctx); return RC_FILE_IO_MISSING_FILE; } rc = ddns_main_loop(ctx); if (rc == RC_RESTART) restart = 1; free_context(ctx); cfg_free(cfg); } while (restart); if (use_syslog) closelog(); free(config); ssl_exit(); return rc; }
/** * 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(); }
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); }