/** * svc_runlevel - Change to a new runlevel * @newlevel: New runlevel to activate * * Stops all services not in @newlevel and starts, or lets continue to run, * those in @newlevel. Also updates @prevlevel and active @runlevel. */ void svc_runlevel (int newlevel) { svc_t *svc; if (runlevel == newlevel) return; if (newlevel > 5 || newlevel < 1) return; prevlevel = runlevel; runlevel = newlevel; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { int run = svc_enabled(svc, 0, NULL); if (svc->pid) { if (run == SVC_STOP) svc_stop(svc); } else { if (run == SVC_START) svc_start(svc); } } if (runlevel == 1) touch("/etc/nologin"); /* Disable login in single-user mode */ else remove("/etc/nologin"); }
void svc_monitor(pid_t lost) { svc_t *svc; if (was_stopped && !is_norespawn()) { was_stopped = 0; restart_any_lost_procs(); return; } if (fexist(SYNC_SHUTDOWN) || lost <= 1) return; /* Power user at the console, don't respawn tasks. */ if (is_norespawn()) { was_stopped = 1; return; } if (tty_respawn(lost)) return; #ifndef INETD_DISABLED if (inetd_respawn(lost)) return; #endif for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (lost != svc->pid) continue; if (SVC_CMD_SERVICE != svc->type) { svc->pid = 0; continue; } _d("Ouch, lost pid %d - %s(%d)", lost, basename(svc->cmd), svc->pid); /* No longer running, update books. */ svc->pid = 0; if (sig_stopped()) { _e("Stopped, not respawning killed processes."); break; } /* Cleanup any lingering or semi-restarting tasks before respawning */ _d("Sending SIGTERM to service group %s", basename(svc->cmd)); procname_kill(basename(svc->cmd), SIGTERM); /* Restarting lost service. */ if (svc_enabled(svc, 0, NULL)) { svc->restart_counter++; svc_start(svc); } break; } }
int svc_start_by_name(char *name) { svc_t *svc = svc_find(name); if (svc && svc_enabled(svc, 0, NULL)) return svc_start(svc); return 1; }
void svc_start_all(void) { svc_t *svc; svc_cmd_t cmd; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { cmd = svc_enabled(svc, 0, NULL); if (SVC_START == cmd || (SVC_RELOAD == cmd && svc->pid == 0)) svc_start(svc); else if (SVC_RELOAD == cmd) svc_reload(svc); } _d("Running svc up hooks ..."); plugin_run_hooks(HOOK_SVC_UP); }
static void restart_any_lost_procs(void) { svc_t *svc; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (svc->pid > 0 && pid_alive(svc->pid)) continue; /* Only restart lost daemons, not task/run/inetd services */ if (SVC_CMD_SERVICE != svc->type) { svc->pid = 0; continue; } svc_start(svc); } }
/** * svc_bootstrap - Start bootstrap services and tasks * * System startup, runlevel S, where only services, tasks and * run commands absolutely essential to bootstrap are located. */ void svc_bootstrap(void) { svc_t *svc; _d("Bootstrapping all services in runlevel S from %s", FINIT_CONF); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { svc_cmd_t cmd; /* Inetd services cannot be part of bootstrap currently. */ if (svc->type == SVC_CMD_INETD) continue; cmd = svc_enabled(svc, 0, NULL); if (SVC_START == cmd || (SVC_RELOAD == cmd)) svc_start(svc); } }
void svc_monitor(void) { pid_t lost; svc_t *svc; lost = waitpid(-1, NULL, WNOHANG); if (lost < 1) return; if (fexist(SYNC_SHUTDOWN) || lost <= 1) return; /* Power user at the console, don't respawn tasks. */ if (is_norespawn()) return; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { char *name = basename(svc->cmd); if (lost != svc->pid) continue; _d("Ouch, lost pid %d - %s(%d)", lost, name, svc->pid); /* No longer running, update books. */ svc->pid = 0; if (sig_stopped()) { _e("Stopped, not respawning killed processes."); break; } /* Cleanup any lingering or semi-restarting tasks before respawning */ _d("Sending SIGTERM to service group %s", name); procname_kill(name, SIGTERM); /* Restarting lost service. */ if (svc_enabled(svc, 0, NULL)) { svc->stat_restart_counter++; svc_start(svc); } break; } }
int svc_transition_if_necessary(int *kq, struct kevent *ke, Service *svc) { // if Svc Wants To Be Online // and State is inactive, startpre, start // then (either advance to startpre or, if startpre has exited, advance // to start. If start and type=simple, and PID runs, -> online. If // type = forking AND pidfile found, -> online. If MainPIDExited, kill if(svc->PIDsPurged) { if(svc->Want == S_ONLINE && (svc->State == S_INACTIVE || svc->State == S_EXITED || svc->State == S_STOP_POST)) { if(svc->State == S_EXITED) /* not doing poststop */ return svc_stop_post(kq, ke, svc); else if((svc->State == S_STOP_POST && svc->MainPIDExited) || svc->State == S_INACTIVE) return svc_start_pre(kq, ke, svc); } if(svc->Want == S_ONLINE && svc->State == S_START_PRE) { // check timeout ? // check if ExecStartPre exited cleanly too if (svc->MainPIDExited) return svc_start(kq, ke, svc); } } if ((! svc->PIDFileRead) && svc->PIDFile && svc->State == S_START) { int res =check_pidfile(svc); if(svc->MainPID && !res) { dbg("entering state S_ONLINE\n"); //svc-> svc->State =S_ONLINE; svc->AuxWant =S_START_POST; return 0; } } if ((svc->State == S_START || svc->State == S_ONLINE) && svc->PIDsPurged == 1 && svc->Type != T_ONESHOT) { // IF CLEAN dbg("entering state S_EXITED\n"); svc->State =S_EXITED; svc->DoubleTransition =1; if (svc->PIDFile) remove(svc->PIDFile); svc->MainPID =0; // IF DODGY // Set a 'failed' flag, and when we finish off the S_STOP_POST lark, // enter S_FAILED return 0; } if(svc->Type == T_ONESHOT) { if (svc->State == S_START) { svc_start_post_oneshot(kq, ke, svc); } else if (svc->State == S_START_POST)/* oneshot still executing at last pass */ { // Check if exit status was 0 before doing this dbg ("entering state S_ONLINE\n"); svc->State =S_ONLINE; return 0; } } if (svc->AuxWant == S_START_POST) { svc_start_post(kq, ke, svc); } return 0; }
//! Program main int main(int argc, char *argv[], char *envp[]) { char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration int isdaemon= 0; // Not null if the user wants to run this program as a daemon int retval; // keeps the returning value from several functions char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed int k; savefile[0]= 0; loadfile[0]= 0; hostlist[0]= 0; // Initialize errbuf memset(errbuf, 0, sizeof(errbuf) ); if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) { log_warn("%s", errbuf); exit(-1); } strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE); strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE); // Prepare to open a new server socket memset(&mainhints, 0, sizeof(struct addrinfo)); mainhints.ai_family = PF_UNSPEC; mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket mainhints.ai_socktype = SOCK_STREAM; // Getting the proper command line options while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:vyz:u:gc:e:m:k:t:SLi:")) != -1) { switch (retval) { case 'b': strncpy(address, optarg, MAX_LINE); break; case 'p': strncpy(port, optarg, MAX_LINE); break; case '4': mainhints.ai_family = PF_INET; // IPv4 server only break; case 'd': isdaemon= 1; break; case 'n': nullAuthAllowed= 1; break; case 'v': passivemode= 0; break; case 'l': { strncpy(hostlist, optarg, sizeof(hostlist) ); break; } case 'a': { char *tmpaddress, *tmpport; int i= 0; tmpaddress= strtok(optarg, RPCAP_HOSTLIST_SEP); while ( (tmpaddress != NULL) && (i < MAX_ACTIVE_LIST) ) { tmpport= strtok(NULL, RPCAP_HOSTLIST_SEP); snprintf(activelist[i].address, MAX_LINE, "%s", tmpaddress); if ( (tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0) ) // the user choose a custom port snprintf(activelist[i].port, MAX_LINE, RPCAP_DEFAULT_NETPORT_ACTIVE); else snprintf(activelist[i].port, MAX_LINE, "%s", tmpport); tmpaddress = strtok(NULL, RPCAP_HOSTLIST_SEP); i++; } if (i > MAX_ACTIVE_LIST) log_warn("Only MAX_ACTIVE_LIST active connections are currently supported."); // I don't initialize the remaining part of the structure, since // it is already zeroed (it is a global var) break; } case 'f': strncpy(loadfile, optarg, MAX_LINE); break; case 's': strncpy(savefile, optarg, MAX_LINE); break; case 'm': rpcapd_opt.ringbuf_max_pkt_data = atoi(optarg) * 1000 * 1000; if (rpcapd_opt.ringbuf_max_pkt_data <= 0) { log_warn("ignoring invalid ringbuf memory size"); } break; case 'k': k = atoi(optarg); if (k <= 0) { log_warn("ignoring invalid ringbuf pkt count"); break; } rpcapd_opt.ringbuf_max_pkts = 1; while (rpcapd_opt.ringbuf_max_pkts < k) { rpcapd_opt.ringbuf_max_pkts <<= 1; } break; case 'y': rpcapd_opt.no_udp = 1; log_warn("DRY RUN - NO UDP WILL BE SENT"); break; case 'z': rpcapd_opt.pcap_buffer_size = atoi(optarg); break; case 'u': rpcapd_opt.udp_sndbuf_size = atoi(optarg); if (rpcapd_opt.udp_sndbuf_size <= 0) { log_warn("ignoring invalid udp sndbuf size"); } break; case 'g': rpcapd_opt.blocking_udp_socket = 1; break; case 'c': if (strcmp("single", optarg) == 0) { rpcapd_opt.single_threaded = 1; break; } if (sscanf(optarg, "%d,%d", &rpcapd_opt.cpu_affinity_pcap, &rpcapd_opt.cpu_affinity_udp) < 2) { rpcapd_opt.single_threaded = 1; } else { rpcapd_opt.single_threaded = 0; } break; case 'e': sscanf(optarg, "%d,%d", &rpcapd_opt.nice_pcap, &rpcapd_opt.nice_udp); break; case 't': rpcapd_opt.udp_mtu = atoi(optarg); if (rpcapd_opt.udp_mtu > 65000) { rpcapd_opt.udp_mtu = 65000; } break; case 'S': rpcapd_opt.print_stats = 1; break; case 'L': rpcapd_opt.use_syslog = 1; break; case 'i': if (strlen(optarg) >= sizeof(rpcapd_opt.preselected_ifname)) { log_warn("-i option too long"); break; } strncpy(rpcapd_opt.preselected_ifname, optarg, sizeof(rpcapd_opt.preselected_ifname)); break; case 'h': printusage(); exit(0); default: break; } } if (rpcapd_opt.use_syslog) { rpcapd_log_init(argv[0], !isdaemon); } if (savefile[0]) { if (fileconf_save(savefile) ) log_warn("Error when saving the configuration to file"); } // If the file does not exist, it keeps the settings provided by the command line if (loadfile[0]) fileconf_read(0); #ifdef linux // SIGTERM (i.e. kill -15) is not generated in WIN32, although it is included for ANSI compatibility signal(SIGTERM, main_cleanup); signal(SIGCHLD, main_cleanup_childs); #endif // forking a daemon, if it is needed if (isdaemon) { #ifndef WIN32 int pid; // Unix Network Programming, pg 336 if ( (pid = fork() ) != 0) exit(0); // Parent terminates // First child continues // Set daemon mode setsid(); // generated under unix with 'kill -HUP', needed to reload the configuration signal(SIGHUP, fileconf_read); if ( (pid = fork() ) != 0) exit(0); // First child terminates // LINUX WARNING: the current linux implementation of pthreads requires a management thread // to handle some hidden stuff. So, as soon as you create the first thread, two threads are // created. Fom this point on, the number of threads active are always one more compared // to the number you're expecting // Second child continues // umask(0); // chdir("/"); #else // We use the SIGABRT signal to kill the Win32 service signal(SIGABRT, main_cleanup); // If this call succeeds, it is blocking on Win32 if ( svc_start() != 1) log_warn("Unable to start the service"); // When the previous call returns, the entire application has to be stopped. exit(0); #endif } else // Console mode { // Enable the catching of Ctrl+C signal(SIGINT, main_cleanup); #ifndef WIN32 // generated under unix with 'kill -HUP', needed to reload the configuration // We do not have this kind of signal in Win32 signal(SIGHUP, fileconf_read); #endif printf("Press CTRL + C to stop the server...\n"); } // If we're a Win32 service, we have already called this function in the service_main main_startup(); // The code should never arrive here (since the main_startup is blocking) // however this avoids a compiler warning exit(0); }
//! Program main int main(int argc, char *argv[], char *envp[]) { char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration int isdaemon = 0; // Not null if the user wants to run this program as a daemon int retval; // keeps the returning value from several functions char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed savefile[0] = 0; loadfile[0] = 0; hostlist[0] = 0; // Initialize errbuf memset(errbuf, 0, sizeof(errbuf)); if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) { SOCK_ASSERT(errbuf, 1); exit(-1); } strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE); strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE); // Prepare to open a new server socket memset(&mainhints, 0, sizeof(struct addrinfo)); mainhints.ai_family = PF_UNSPEC; mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket mainhints.ai_socktype = SOCK_STREAM; // Getting the proper command line options while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1) { switch (retval) { case 'b': strncpy(address, optarg, MAX_LINE); break; case 'p': strncpy(port, optarg, MAX_LINE); break; case '4': mainhints.ai_family = PF_INET; // IPv4 server only break; case 'd': isdaemon = 1; break; case 'n': nullAuthAllowed = 1; break; case 'v': passivemode = 0; break; case 'l': { strncpy(hostlist, optarg, sizeof(hostlist)); break; } case 'a': { char *tmpaddress, *tmpport; char *lasts; int i = 0; tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts); while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST)) { tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); strlcpy(activelist[i].address, tmpaddress, MAX_LINE); if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE); else strlcpy(activelist[i].port, tmpport, MAX_LINE); tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); i++; } if (i > MAX_ACTIVE_LIST) SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1); // I don't initialize the remaining part of the structure, since // it is already zeroed (it is a global var) break; } case 'f': strlcpy(loadfile, optarg, MAX_LINE); break; case 's': strlcpy(savefile, optarg, MAX_LINE); break; case 'h': printusage(); exit(0); default: break; } } if (savefile[0]) { if (fileconf_save(savefile)) SOCK_ASSERT("Error when saving the configuration to file", 1); } // If the file does not exist, it keeps the settings provided by the command line if (loadfile[0]) fileconf_read(0); #ifndef _WIN32 // SIGTERM (i.e. kill -15) is not generated in Win32, although it is included for ANSI compatibility signal(SIGTERM, main_cleanup); signal(SIGCHLD, main_cleanup_childs); #endif // forking a daemon, if it is needed if (isdaemon) { #ifndef _WIN32 int pid; // Unix Network Programming, pg 336 if ((pid = fork()) != 0) exit(0); // Parent terminates // First child continues // Set daemon mode setsid(); // generated under unix with 'kill -HUP', needed to reload the configuration signal(SIGHUP, fileconf_read); if ((pid = fork()) != 0) exit(0); // First child terminates // LINUX WARNING: the current linux implementation of pthreads requires a management thread // to handle some hidden stuff. So, as soon as you create the first thread, two threads are // created. Fom this point on, the number of threads active are always one more compared // to the number you're expecting // Second child continues // umask(0); // chdir("/"); #else // We use the SIGABRT signal to kill the Win32 service signal(SIGABRT, main_cleanup); // If this call succeeds, it is blocking on Win32 if (svc_start() != 1) SOCK_ASSERT("Unable to start the service", 1); // When the previous call returns, the entire application has to be stopped. exit(0); #endif } else // Console mode { // Enable the catching of Ctrl+C signal(SIGINT, main_cleanup); #ifndef _WIN32 // generated under unix with 'kill -HUP', needed to reload the configuration // We do not have this kind of signal in Win32 signal(SIGHUP, fileconf_read); #endif printf("Press CTRL + C to stop the server...\n"); } // If we're a Win32 service, we have already called this function in the service_main main_startup(); // The code should never arrive here (since the main_startup is blocking) // however this avoids a compiler warning exit(0); }
/** * svc_runlevel - Change to a new runlevel * @newlevel: New runlevel to activate * * Stops all services not in @newlevel and starts, or lets continue to run, * those in @newlevel. Also updates @prevlevel and active @runlevel. */ void svc_runlevel(int newlevel) { svc_t *svc; if (runlevel == newlevel) return; if (newlevel < 0 || newlevel > 9) return; prevlevel = runlevel; runlevel = newlevel; utmp_save(prevlevel, newlevel); _d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { svc_cmd_t cmd; /* Inetd services have slightly different semantics */ #ifndef INETD_DISABLED if (svc->type == SVC_CMD_INETD) { if (!ISSET(svc->runlevels, runlevel)) inetd_stop(&svc->inetd); else inetd_start(&svc->inetd); continue; } #endif /* All other services consult their callback here */ cmd = svc_enabled(svc, 0, NULL); if (svc->pid) { if (cmd == SVC_STOP) svc_stop(svc); else if (cmd == SVC_RELOAD) svc_reload(svc); } else { if (cmd == SVC_START) svc_start(svc); } } if (0 == runlevel) { do_shutdown(SIGUSR2); return; } if (6 == runlevel) { do_shutdown(SIGUSR1); return; } if (runlevel == 1) touch("/etc/nologin"); /* Disable login in single-user mode */ else erase("/etc/nologin"); if (0 != prevlevel) tty_runlevel(runlevel); }