/** * 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; } }
/** * svc_find_by_pid - Find an service object by its PID * @pid: Process ID to match * * Returns: * A pointer to an &svc_t object, or %NULL if not found. */ svc_t *svc_find_by_pid(pid_t pid) { svc_t *svc; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (svc->pid == pid) return svc; } return NULL; }
/** * svc_find - Find a service object by its full path name * @path: Full path name, e.g., /sbin/syslogd * * Returns: * A pointer to an &svc_t object, or %NULL if not found. */ svc_t *svc_find(char *path) { svc_t *svc; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (!strncmp(path, svc->cmd, strlen(svc->cmd))) { _d("Found a matching svc for %s", path); return svc; } } return NULL; }
/* * Assert condition only if the service is running, but not if it's * recently been changed or while it's starting up. * * We must wait for the service to create/touch its pidfile. */ static void pidfile_reconf(void *_null) { static char name[MAX_ARG_LEN]; svc_t *svc; (void)(_null); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (svc->state == SVC_RUNNING_STATE && !svc_is_changed(svc) && !svc_is_starting(svc)) { snprintf(name, MAX_ARG_LEN, "svc%s", svc->cmd); cond_set_path(cond_path(name), COND_ON); } } }
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_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_TYPE_SERVICE != svc->type) { svc->pid = 0; continue; } service_start(svc); } }
/** * service_bootstrap - Start bootstrap services and tasks * * System startup, runlevel S, where only services, tasks and * run commands absolutely essential to bootstrap are located. */ void service_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_is_inetd(svc)) continue; cmd = service_enabled(svc, 0, NULL); if (SVC_START == cmd || (SVC_RELOAD == cmd)) service_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; } }
svc_t *svc_find_inetd(char *path, char *service, char *proto, char *port) { svc_t *svc; for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (svc->type != SVC_CMD_INETD) continue; if (strncmp(path, svc->cmd, strlen(svc->cmd))) continue; if (inetd_match(&svc->inetd, service, proto, port)) { _d("Found a matching svc for %s", path); return svc; } } return NULL; }
/* In verbose mode we skip the header and each service description. * This in favor of having all info on one line so a machine can more * easily parse it. */ static int show_status(char *UNUSED(arg)) { svc_t *svc; /* Fetch UTMP runlevel, needed for svc_status() call below */ runlevel = runlevel_get(); if (!verbose) { printf("# Status PID Runlevels Service Description\n"); printf("====================================================================================\n"); } for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { int inetd = svc_is_inetd(svc); char jobid[10], args[512] = ""; struct init_request rq = { .magic = INIT_MAGIC, .cmd = INIT_CMD_QUERY_INETD, }; if (svc_is_unique(svc)) snprintf(jobid, sizeof(jobid), "%d", svc->job); else snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); printf("%-5s %7s %-6d %-9s ", jobid, svc_status(svc), svc->pid, runlevel_string(svc->runlevels)); if (!verbose) { printf("%-20s %s\n", svc->cmd, svc->desc); continue; } if (inetd) { char *info; snprintf(rq.data, sizeof(rq.data), "%s", jobid); if (do_send(&rq, sizeof(rq))) { snprintf(args, sizeof(args), "Unknown inetd"); info = args; } else { info = rq.data; if (strcmp("internal", svc->cmd)) { char *ptr = strchr(info, ' '); if (ptr) info = ptr + 1; } } printf("%s %s\n", svc->cmd, info); } else { int i; for (i = 1; i < MAX_NUM_SVC_ARGS; i++) { strlcat(args, svc->args[i], sizeof(args)); strlcat(args, " ", sizeof(args)); } printf("%s %s\n", svc->cmd, args); } } return 0; }
void service_monitor(pid_t lost) { svc_t *svc; static int was_stopped = 0; if (was_stopped && !is_norespawn()) { was_stopped = 0; restart_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_TYPE_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; } /* Restarting lost service. */ if (service_enabled(svc, 0, NULL)) { if (svc->restart_counter > RESPAWN_MAX) { _e("Not restarting %s id %d, respawn MAX (%d) reached!", svc->cmd, svc->id, RESPAWN_MAX); break; } svc->restart_counter++; service_start(svc); } break; } }
/** * service_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 service_runlevel(int newlevel) { svc_t *svc; if (runlevel == newlevel) return; if (newlevel < 0 || newlevel > 9) return; prevlevel = runlevel; runlevel = newlevel; _d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel); runlevel_set(prevlevel, newlevel); /* Make sure to (re)load all *.conf in /etc/finit.d/ */ conf_reload_dynamic(); _d("Stopping services services not allowed in new runlevel ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (!svc_in_runlevel(svc, runlevel)) { #ifndef INETD_DISABLED if (svc_is_inetd(svc)) inetd_stop(&svc->inetd); else #endif service_stop(svc); } /* ... or disabled/removed services from /etc/finit.d/ */ if (svc_is_dynamic(svc) && svc_is_changed(svc)) service_stop(svc); } /* Prev runlevel services stopped, call hooks before starting new runlevel ... */ _d("All services have been stoppped, calling runlevel change hooks ..."); plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */ _d("Starting services services new to this runlevel ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { #ifndef INETD_DISABLED /* Inetd services have slightly different semantics */ if (svc_is_inetd(svc)) { if (svc_in_runlevel(svc, runlevel)) inetd_start(&svc->inetd); continue; } #endif /* All other services consult their callback here */ svc_dance(svc); } /* Cleanup stale services */ svc_clean_dynamic(service_unregister); 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); }
/** * 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); }