/* * Converts the internet address plus port string in 'St' * into their network byte order representations. * * returns: - 0 -> conversion failed * - 1 -> only address part returned (inaddrPt) * - 2 -> address and port returned * */ static void getSockAdr(struct sockaddr *SaPt, socklen_t * SaLenPt, char *AddrSt, char *PortSt) { struct sockaddr_in *Sin4; struct sockaddr_in6 *Sin6; if (strchr(AddrSt, ':') == NULL) { Sin4 = SIN4(SaPt); memset(Sin4, 0, sizeof(*Sin4)); Sin4->sin_family = AF_INET; Sin4->sin_port = htons(atoi(PortSt)); if (inet_pton(AF_INET, AddrSt, &Sin4->sin_addr) <= 0) { smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt); exit(255); } *SaLenPt = sizeof(struct sockaddr_in); } else { Sin6 = SIN6(SaPt); memset(Sin6, 0, sizeof(*Sin6)); Sin6->sin6_family = AF_INET6; Sin6->sin6_port = htons(atoi(PortSt)); if (inet_pton(AF_INET6, AddrSt, &Sin6->sin6_addr) <= 0) { smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt); exit(255); } *SaLenPt = sizeof(struct sockaddr_in6); } }
static void SetOif4(int Sock, char *ifname) { struct ifreq IfReq; struct sockaddr_in *Sin4 = NULL; memset(&IfReq, 0, sizeof(IfReq)); strncpy(IfReq.ifr_name, ifname, sizeof(IfReq.ifr_name)); if (ioctl(Sock, SIOCGIFADDR, &IfReq) < 0) { smclog(LOG_ERR, "ioctl SIOCGIFADDR: %m"); exit(255); } switch (IfReq.ifr_addr.sa_family) { case AF_INET: Sin4 = SIN4(&IfReq.ifr_addr); break; default: fprintf(stderr, "SetOif4 - invalid address family: %d\n", IfReq.ifr_addr.sa_family); exit(1); } if (setsockopt(Sock, IPPROTO_IP, IP_MULTICAST_IF, &Sin4->sin_addr, sizeof(struct in_addr))) { smclog(LOG_ERR, "set IP_MULTICAST_IF: %m"); exit(255); } }
/* Parse .conf file and setup routes */ static void read_conf_file(const char *conf_file) { if (access(conf_file, R_OK)) { smclog(LOG_WARNING, errno, "Failed loading %s", conf_file); return; } if (parse_conf_file(conf_file)) smclog(LOG_WARNING, errno, "Failed reading %s", conf_file); }
/** * iface_init - Setup vector of active interfaces * * Builds up a vector with active system interfaces. Must be called * before any other interface functions in this module! */ void iface_init(void) { int family; struct iface *iface; struct ifaddrs *ifaddr, *ifa; num_ifaces = 0; if (iface_list) free(iface_list); iface_list = calloc(MAX_IF, sizeof(struct iface)); if (!iface_list) { smclog(LOG_ERR, "Failed allocating space for interfaces: %m"); exit(255); } if (getifaddrs(&ifaddr) == -1) { smclog(LOG_ERR, "Failed retrieving interface addresses: %m"); exit(255); } for (ifa = ifaddr; ifa && num_ifaces < MAX_IF; ifa = ifa->ifa_next) { /* Check if already added? */ if (iface_find_by_name(ifa->ifa_name)) continue; /* Copy data from interface iterator 'ifa' */ iface = &iface_list[num_ifaces++]; strncpy(iface->name, ifa->ifa_name, IFNAMSIZ); iface->name[IFNAMSIZ] = 0; /* * Only copy interface address if inteface has one. On * Linux we can enumerate VIFs using ifindex, useful for * DHCP interfaces w/o any address yet. Other UNIX * systems will fail on the MRT_ADD_VIF ioctl. if the * kernel cannot find a matching interface. */ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) iface->inaddr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; iface->flags = ifa->ifa_flags; iface->ifindex = if_nametoindex(iface->name); iface->vif = -1; iface->mif = -1; iface->threshold = DEFAULT_THRESHOLD; } freeifaddrs(ifaddr); }
static void SetTtl4(int Sock, unsigned Ttl) { if (setsockopt(Sock, IPPROTO_IP, IP_MULTICAST_TTL, &Ttl, sizeof(Ttl))) { smclog(LOG_ERR, "set IP_MULTICAST_TTL: %m"); exit(255); } }
static void SetTtl6(int Sock, unsigned Ttl) { if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &Ttl, sizeof(Ttl))) { smclog(LOG_ERR, "set IPV6_MULTICAST_HOPS: %m"); exit(255); } }
/* Cleans up, i.e. releases allocated resources. Called via atexit() */ static void clean(void) { mroute4_disable(); mroute6_disable(); ipc_exit(); smclog(LOG_NOTICE, 0, "Exiting."); }
static int daemonize(void) { int pid; pid = fork(); if (pid < 0) smclog(LOG_ERR, errno, "Cannot start in background"); if (!pid) { /* Detach deamon from terminal */ if (close(0) < 0 || close(1) < 0 || close(2) < 0 || open("/dev/null", 0) != 0 || dup2(0, 1) < 0 || dup2(0, 2) < 0 || setpgrp() < 0) smclog(LOG_ERR, errno, "Failed detaching deamon"); } return pid; }
/* Cleans up, i.e. releases allocated resources. Called via atexit() */ static void clean(void) { mroute4_disable(1); mroute6_disable(1); mcgroup4_disable(); mcgroup6_disable(); ipc_exit(); iface_exit(); smclog(LOG_NOTICE, "Exiting."); }
/* * Creates and connects a simple UDP socket to the target * 'inaddr':'Port' * * returns: - the opened socket */ int udp_socket_open(uint32 inaddr, uint16 port) { int sd; struct sockaddr_in sa; sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0) smclog(LOG_ERR, errno, "UDP socket open"); sa.sin_family = AF_INET; sa.sin_port = port; sa.sin_addr.s_addr = inaddr; memset(&sa.sin_zero, 0, sizeof(sa.sin_zero)); if (connect(sd, (struct sockaddr *)&sa, sizeof(sa))) smclog(LOG_ERR, errno, "UDP socket connect"); return sd; }
static void SetOif6(int Sock, char *ifname) { unsigned ifindex; ifindex = if_nametoindex(ifname); if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex))) { smclog(LOG_ERR, "set IPV6_MULTICAST_IF: %m"); exit(255); } }
static void signal_init(void) { struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); if (sigaction(SIGHUP, &sa, NULL) || sigaction(SIGTERM, &sa, NULL) || sigaction(SIGINT, &sa, NULL)) smclog(LOG_WARNING, "Failed setting up signal handlers: %s", strerror(errno)); }
/* Init everything before forking, so we can fail and return an * error code in the parent and the initscript will fail */ static void start_server(int background) { int sd, api = 0; if (background && daemonize()) return; smclog(LOG_NOTICE, 0, "%s", version_info); /* Build list of multicast-capable physical interfaces that * are currently assigned an IP address. */ iface_init(); if (!mroute4_enable()) api++; if (!mroute6_enable()) api++; /* At least one API (IPv4 or IPv6) must have initialized successfully * otherwise we abort the server initialization. */ if (!api) { smclog(LOG_INIT, ENOPROTOOPT, "Kernel does not support multicast routing"); exit(1); } sd = ipc_server_init(); if (sd < 0) smclog(LOG_WARNING, errno, "Failed setting up IPC socket, client communication disabled"); atexit(clean); signal_init(); read_conf_file(conf_file); /* Everything setup, notify any clients by creating the pidfile */ if (pidfile(NULL)) smclog(LOG_WARNING, errno, "Failed creating pidfile"); server_loop(sd); }
const char *cmd_convert_to_mroute4(struct mroute4 *mroute, const struct cmd *packet) { char *arg = (char *)packet->argv; memset(mroute, 0, sizeof(*mroute)); /* -a eth0 1.1.1.1 239.1.1.1 eth1 eth2 * * +----+-----+---+--------------------------------------------+ * | 42 | 'a' | 5 | "eth0\01.1.1.1\0239.1.1.1\0eth1\0eth2\0\0" | * +----+-----+---+--------------------------------------------+ * ^ ^ * | | * | | * +-----cmd------+ */ /* get input interface index */ if (!*arg || (mroute->inbound = iface_get_vif_by_name(arg)) < 0) return "Invalid input interface"; /* get origin */ arg += strlen(arg) + 1; if (!*arg || (inet_pton(AF_INET, arg, &mroute->sender) <= 0)) return "Invalid origin IPv4 address"; /* get multicast group */ arg += strlen(arg) + 1; if (!*arg || (inet_pton(AF_INET, arg, &mroute->group) <= 0) || !IN_MULTICAST(ntohl(mroute->group.s_addr))) return "Invalid multicast group"; /* * Scan output interfaces for the 'add' command only, just ignore it * for the 'remove' command to be compatible to the first release. */ if (packet->cmd == 'a') { for (arg += strlen(arg) + 1; *arg; arg += strlen(arg) + 1) { int vif; if ((vif = iface_get_vif_by_name(arg)) < 0) return "Invalid output interface"; if (vif == mroute->inbound) smclog(LOG_WARNING, 0, "Same outbound interface as inbound %s?", arg); mroute->ttl[vif] = 1; /* Use a TTL threashold */ } } return NULL; }
/* * Signal handler. Take note of the fact that the signal arrived * so that the main loop can take care of it. */ static void handler(int sig) { switch (sig) { case SIGINT: case SIGTERM: running = 0; break; case SIGHUP: smclog(LOG_NOTICE, 0, "Got SIGHUP, reloading %s ...", conf_file); restart(); read_conf_file(conf_file); break; } }
static void server_loop(int sd) { int result; fd_set fds; #ifdef HAVE_IPV6_MULTICAST_ROUTING int max_fd_num = MAX(sd, MAX(mroute4_socket, mroute6_socket)); #else int max_fd_num = MAX(sd, mroute4_socket); #endif /* Watch the MRouter and the IPC socket to the smcroute client */ while (running) { FD_ZERO(&fds); FD_SET(sd, &fds); FD_SET(mroute4_socket, &fds); #ifdef HAVE_IPV6_MULTICAST_ROUTING if (-1 != mroute6_socket) FD_SET(mroute6_socket, &fds); #endif /* wait for input */ result = select(max_fd_num + 1, &fds, NULL, NULL, NULL); if (result <= 0) { /* Log all errors, except when signalled, ignore failures. */ if (EINTR != errno) smclog(LOG_WARNING, errno, "select() failure"); continue; } if (FD_ISSET(mroute4_socket, &fds)) read_mroute4_socket(); #ifdef HAVE_IPV6_MULTICAST_ROUTING if (-1 != mroute6_socket && FD_ISSET(mroute6_socket, &fds)) read_mroute6_socket(); #endif /* loop back to select if there is no smcroute command */ if (FD_ISSET(sd, &fds)) read_ipc_command(); } }
const char *cmd_convert_to_mroute6(struct mroute6 *mroute, const struct cmd *packet) { const char *arg = (const char *)(packet + 1); memset(mroute, 0, sizeof(*mroute)); /* get input interface index */ if (!*arg || (mroute->inbound = iface_get_mif_by_name(arg)) < 0) return "Invalid input interface"; /* get origin */ arg += strlen(arg) + 1; if (!*arg || (inet_pton(AF_INET6, arg, &mroute->sender.sin6_addr) <= 0)) return "Invalid origin IPv6 address"; /* get multicast group */ arg += strlen(arg) + 1; if (!*arg || (inet_pton(AF_INET6, arg, &mroute->group.sin6_addr) <= 0) || !IN6_IS_ADDR_MULTICAST(&mroute->group.sin6_addr)) return "Invalid multicast group"; /* * Scan output interfaces for the 'add' command only, just ignore it * for the 'remove' command to be compatible to the first release. */ if (packet->cmd == 'a') { for (arg += strlen(arg) + 1; *arg; arg += strlen(arg) + 1) { int mif; if ((mif = iface_get_mif_by_name(arg)) < 0) return "Invalid output interface"; if (mif == mroute->inbound) smclog(LOG_WARNING, 0, "Same outbound interface as inbound %s?", arg); mroute->ttl[mif] = 1; /* Use a TTL threashold */ } } return NULL; }
static int compose_paths(void) { /* Default .conf file path: "/etc" + '/' + "smcroute" + ".conf" */ if (!conf_file) { size_t len = strlen(SYSCONFDIR) + strlen(ident) + 7; conf_file = malloc(len); if (!conf_file) { smclog(LOG_ERR, "Failed allocating memory, exiting: %s", strerror(errno)); exit(1); } snprintf(conf_file, len, "%s/%s.conf", SYSCONFDIR, ident); } /* Default is to let pidfile() API construct PID file from ident */ if (!pid_file) pid_file = ident; return 0; }
int main(int ArgCn, char *ArgVc[]) { unsigned TtlVal = 0; char *OifVal = NULL; char *AddrSt = NULL; char *PortSt = NULL; char *Pt; void (*SetTtl) (int, unsigned) = NULL; void (*SetOif) (int, char *) = NULL; struct sockaddr_storage TarAdr; socklen_t TarAdrLen = 0; if (ArgCn < 2) { usage(); exit(1); } while (*++ArgVc) { Pt = *ArgVc; /* option */ if (*Pt == '-') { switch (*++Pt) { case 'D': log_level = LOG_DEBUG; break; case 't': if (sscanf(Pt + 1, " %3u", &TtlVal) != 1 || TtlVal < 1) { usage(); exit(1); } break; case 'i': OifVal = Pt + 1; break; default: usage(); exit(1); } } else { /* argument */ memset(&TarAdr, 0, sizeof(TarAdr)); AddrSt = Pt; Pt = strrchr(AddrSt, ':'); if (Pt == NULL) { usage(); exit(1); } *Pt++ = '\0'; PortSt = Pt; getSockAdr(SA(&TarAdr), &TarAdrLen, AddrSt, PortSt); SetTtl = (TarAdr.ss_family == AF_INET) ? SetTtl4 : SetTtl6; SetOif = (TarAdr.ss_family == AF_INET) ? SetOif4 : SetOif6; } } if (TarAdrLen) { int UdpSock; UdpSock = socket(TarAdr.ss_family, SOCK_DGRAM, IPPROTO_UDP); if (UdpSock < 0) { smclog(LOG_ERR, "UDP socket open: %m"); exit(255); } if (TtlVal) (*SetTtl) (UdpSock, TtlVal); if (OifVal) (*SetOif) (UdpSock, OifVal); while (1) { if (sendto(UdpSock, McMsg, sizeof(McMsg), 0, SA(&TarAdr), TarAdrLen) != sizeof(McMsg)) smclog(LOG_WARNING, "send to UDP socket: %m"); sleep(1); } } return 0; }
/* Receive command from the smcroute client */ static int read_ipc_command(void) { const char *str; struct cmd *packet; struct mroute mroute; uint8 buf[MX_CMDPKT_SZ]; memset(buf, 0, sizeof(buf)); packet = ipc_server_read(buf, sizeof(buf)); if (!packet) { /* Skip logging client disconnects */ if (errno != ECONNRESET) smclog(LOG_WARNING, errno, "Failed receving IPC message from client"); return 1; } switch (packet->cmd) { case 'a': case 'r': if ((str = cmd_convert_to_mroute(&mroute, packet))) { smclog(LOG_WARNING, 0, str); ipc_send(log_last_message, strlen(log_last_message) + 1); break; } if (mroute.version == 4) { if ((packet->cmd == 'a' && mroute4_add(&mroute.u.mroute4)) || (packet->cmd == 'r' && mroute4_del(&mroute.u.mroute4))) { ipc_send(log_last_message, strlen(log_last_message) + 1); break; } } else { #ifndef HAVE_IPV6_MULTICAST_ROUTING smclog(LOG_WARNING, 0, "IPv6 multicast routing support disabled."); #else if ((packet->cmd == 'a' && mroute6_add(&mroute.u.mroute6)) || (packet->cmd == 'r' && mroute6_del(&mroute.u.mroute6))) { ipc_send(log_last_message, strlen(log_last_message) + 1); break; } #endif /* HAVE_IPV6_MULTICAST_ROUTING */ } ipc_send("", 1); break; case 'j': /* j <InputIntf> <McGroupAdr> */ case 'l': /* l <InputIntf> <McGroupAdr> */ { int result = -1; const char *ifname = (const char *)(packet + 1); const char *groupstr = ifname + strlen(ifname) + 1; if (strchr(groupstr, ':') == NULL) { struct in_addr group; /* check multicast address */ if (!*groupstr || !inet_aton(groupstr, &group) || !IN_MULTICAST(ntohl(group.s_addr))) { smclog(LOG_WARNING, 0, "Invalid multicast group: %s", groupstr); ipc_send(log_last_message, strlen(log_last_message) + 1); break; } /* join or leave */ if (packet->cmd == 'j') result = mcgroup4_join(ifname, group); else result = mcgroup4_leave(ifname, group); } else { /* IPv6 */ #ifndef HAVE_IPV6_MULTICAST_HOST smclog(LOG_WARNING, 0, "IPv6 multicast support disabled."); #else struct in6_addr group; /* check multicast address */ if (!*groupstr || (inet_pton(AF_INET6, groupstr, &group) <= 0) || !IN6_IS_ADDR_MULTICAST(&group)) { smclog(LOG_WARNING, 0, "Invalid multicast group: %s", groupstr); ipc_send(log_last_message, strlen(log_last_message) + 1); break; } /* join or leave */ if (packet->cmd == 'j') result = mcgroup6_join(ifname, group); else result = mcgroup6_leave(ifname, group); #endif /* HAVE_IPV6_MULTICAST_HOST */ } /* failed */ if (result) { ipc_send(log_last_message, strlen(log_last_message) + 1); break; } ipc_send("", 1); break; } case 'k': ipc_send("", 1); exit(0); } return 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, const char *argv[]) { int i, num_opts, result = 0; int start_daemon = 0; int background = 1; uint8 buf[MX_CMDPKT_SZ]; const char *arg; unsigned int cmdnum = 0; struct cmd *cmdv[16]; /* init syslog */ openlog(__progname, LOG_PID, LOG_DAEMON); if (argc <= 1) return usage(); /* Parse command line options */ for (num_opts = 1; (num_opts = num_option_arguments(argv += num_opts));) { if (num_opts < 0) /* error */ return usage(); /* handle option */ arg = argv[0]; switch (arg[1]) { case 'a': /* add route */ if (num_opts < 5) return usage(); break; case 'r': /* remove route */ if (num_opts < 4) return usage(); break; case 'j': /* join */ case 'l': /* leave */ if (num_opts != 3) return usage(); break; case 'k': /* kill daemon */ if (num_opts != 1) return usage(); break; case 'h': /* help */ return usage(); case 'v': /* verbose */ fputs(version_info, stderr); log_stderr = LOG_DEBUG; continue; case 'd': /* daemon */ start_daemon = 1; continue; case 'n': /* run daemon in foreground, i.e., do not fork */ background = 0; continue; case 'f': if (num_opts != 2) return usage(); conf_file = argv[1]; continue; case 'D': do_debug_logging = 1; continue; default: /* unknown option */ return usage(); } /* Check and build command argument list. */ if (cmdnum >= ARRAY_ELEMENTS(cmdv)) { fprintf(stderr, "Too many command options\n"); return usage(); } cmdv[cmdnum] = cmd_build(arg[1], argv + 1, num_opts - 1); if (!cmdv[cmdnum]) { perror("Failed parsing command"); for (i = 0; i < cmdnum; i++) free(cmdv[i]); return 1; } cmdnum++; } if (start_daemon) { /* only daemon parent enters */ if (geteuid() != 0) { smclog(LOG_ERR, 0, "Need root privileges to start %s", __progname); return 1; } start_server(background); if (!background) return 0; } /* Client or daemon parent only, the daemon never reaches this point */ /* send commands */ if (cmdnum) { int retry_count = 30; openlog(argv[0], LOG_PID, LOG_USER); /* connect to daemon */ while (ipc_client_init()) { switch (errno) { case EACCES: smclog(LOG_ERR, EACCES, "Need root privileges to connect to daemon"); break; case ENOENT: case ECONNREFUSED: /* When starting daemon, give it 30 times a 1/10 second to get ready */ if (start_daemon && --retry_count) { usleep(100000); continue; } smclog(LOG_WARNING, errno, "Daemon not running"); result = 1; break; default: smclog(LOG_WARNING, errno, "Failed connecting to daemon"); result = 1; break; } } for (i = 0; !result && i < cmdnum; i++) { int slen, rlen; struct cmd *command = cmdv[i]; /* Send command */ slen = ipc_send(command, command->len); /* Wait here for reply */ rlen = ipc_receive(buf, sizeof(buf)); if (slen < 0 || rlen < 0) { smclog(LOG_WARNING, errno, "Communication with daemon failed"); result = 1; } if (rlen != 1 || *buf != '\0') { fprintf(stderr, "Daemon error: %s\n", buf); result = 1; } } for (i = 0; i < cmdnum; i++) free(cmdv[i]); } return result; }
/* Init everything before forking, so we can fail and return an * error code in the parent and the initscript will fail */ static int start_server(void) { int api = 2, busy = 0; if (geteuid() != 0) { smclog(LOG_ERR, "Need root privileges to start %s", prognm); return 1; } if (background) { if (daemon(0, 0) < 0) { smclog(LOG_ERR, "Failed daemonizing: %s", strerror(errno)); return 1; } } /* Hello world! */ smclog(LOG_NOTICE, "%s", version_info); if (startup_delay > 0) { smclog(LOG_INFO, "Startup delay requested, waiting %d sec before continuing.", startup_delay); sleep(startup_delay); } /* * Timer API needs to be initilized before mroute4_enable() */ timer_init(); /* * Build list of multicast-capable physical interfaces */ iface_init(); if (mroute4_enable(do_vifs, table_id, cache_tmo)) { if (errno == EADDRINUSE) busy++; api--; } if (mroute6_enable(do_vifs, table_id)) { if (errno == EADDRINUSE) busy++; api--; } /* At least one API (IPv4 or IPv6) must have initialized successfully * otherwise we abort the server initialization. */ if (!api) { if (busy) smclog(LOG_ERR, "Another multicast routing application is already running."); else smclog(LOG_ERR, "Kernel does not support multicast routing."); exit(1); } atexit(clean); signal_init(); ipc_init(); conf_read(conf_file, do_vifs); /* Everything setup, notify any clients waiting for us */ notify_ready(pid_file, uid, gid); /* Drop root privileges before entering the server loop */ cap_drop_root(uid, gid); return server_loop(); }
/** * 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(); }