int main(int argc, char **argv) { int errflag = 0; int sts; int c; __pmSetProgname(argv[0]); indomp = (__pmInDom_int *)&indom; while ((c = getopt(argc, argv, "D:")) != EOF) { switch (c) { #ifdef PCP_DEBUG case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; #endif case '?': default: errflag++; break; } } if (errflag) { fprintf(stderr, "Usage: %s [-D...] [a|b|c|d|...|i 1|2|3}\n", pmProgname); exit(1); } while (optind < argc) { if (strcmp(argv[optind], "a") == 0) _a(0, 1, 1); else if (strcmp(argv[optind], "b") == 0) _b(); else if (strcmp(argv[optind], "c") == 0) _c(); else if (strcmp(argv[optind], "d") == 0) _a(1, 0, 1); else if (strcmp(argv[optind], "e") == 0) _e(0); else if (strcmp(argv[optind], "f") == 0) _e(3600); else if (strcmp(argv[optind], "g") == 0) _g(); else if (strcmp(argv[optind], "h") == 0) _h(); else if (strcmp(argv[optind], "i") == 0) { optind++; _i(atoi(argv[optind])); } else if (strcmp(argv[optind], "j") == 0) _j(); else fprintf(stderr, "torture_cache: no idea what to do with option \"%s\"\n", argv[optind]); optind++; } exit(0); }
/** * load_one - Load one plugin * @path: Path to finit plugins, usually %PLUGIN_PATH * @name: Name of plugin, optionally ending in ".so" * * Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from * the plugin @name it is added before attempting to load. * * It is up to the plugin itself ot register itself as a "ctor" with the * %PLUGIN_INIT macro so that plugin_register() is called automatically. * * Returns: * POSIX OK(0) on success, non-zero otherwise. */ static int load_one(char *path, char *name) { int noext; char sofile[CMD_SIZE]; void *handle; plugin_t *plugin; if (!path || !fisdir(path) || !name) { errno = EINVAL; return 1; } /* Compose full path, with optional .so extension, to plugin */ noext = strcmp(name + strlen(name) - 3, ".so"); snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : ""); _d("Loading plugin %s ...", basename(sofile)); handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL); if (!handle) { _e("Failed loading plugin %s: %s", sofile, dlerror()); return 1; } plugin = TAILQ_LAST(&plugins, plugin_head); if (!plugin) { _e("Plugin %s failed to register, unloading from memory", sofile); dlclose(handle); return 1; } /* Remember handle from dlopen() for plugin_unregister() */ plugin->handle = handle; return 0; }
/* Standard reboot/shutdown utilities talk to init using /dev/initctl. * We should check if the fifo was recreated and reopen it. */ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) { struct init_request rq; _d("Receiving request on %s...", FINIT_FIFO); while (1) { ssize_t len = read(fd, &rq, sizeof(rq)); if (len <= 0) { if (-1 == len) { if (EINTR == errno) continue; if (EAGAIN == errno) break; _e("Failed reading initctl request, error %d: %s", errno, strerror(errno)); } break; } if (rq.magic != INIT_MAGIC || len != sizeof(rq)) { _e("Invalid initctl request."); break; } _d("Magic OK..."); if (rq.cmd == INIT_CMD_RUNLVL) { switch (rq.runlevel) { case '0': _d("Halting system (SIGUSR2)"); do_shutdown(SIGUSR2); break; case 's': case 'S': rq.runlevel = '1'; /* Fall through to regular processing */ case '1'...'5': _d("Setting new runlevel %c ...", rq.runlevel); svc_runlevel(rq.runlevel - '0'); break; case '6': _d("Rebooting system (SIGUSR1)"); do_shutdown(SIGUSR1); break; default: _d("Unsupported runlevel: %d", rq.runlevel); break; } } else if (rq.cmd == INIT_CMD_DEBUG) { debug = !debug; } else { _d("Unsupported cmd: %d", rq.cmd); } }
char* XMLDecode(const char* src) { typedef const struct XMLEntity { const char* name; size_t nameLen; char value; } XMLEntity; /* This is ugly, but better than specifying the lengths by hand */ #define _e(str,c) {str,sizeof(str)-1,c} const XMLEntity ents[] = { _e("quot;",'"'), _e("apos;",'\''), _e("lt;", '<'), _e("gt;", '>'), _e("amp;", '&') }; size_t len; const char *s; char *out, *o; if ( !src || !(len = strlen(src)) || !(out = malloc(len+1)) ) return 0; o = out; s = src; while (s <= src+len) /* Make sure the terminator is also copied */ { if ( *s == '&' ) { bool entFound = false; int i; s++; for ( i = 0; i < sizeof(ents)/sizeof(ents[0]); i++) { if ( strncmp(s, ents[i].name, ents[i].nameLen) == 0 ) { entFound = true; break; } } if ( entFound ) { *o++ = ents[i].value; s += ents[i].nameLen; continue; } } *o++ = *s++; } return out; }
CHAR8* XMLDecode(const CHAR8* src) { typedef const struct XMLEntity { const CHAR8* name; UINTN nameLen; CHAR8 value; } XMLEntity; /* This is ugly, but better than specifying the lengths by hand */ #define _e(str,c) {str,sizeof(str)-1,c} const XMLEntity ents[] = { _e("quot;",'"'), _e("apos;",'\''), _e("lt;", '<'), _e("gt;", '>'), _e("amp;", '&') }; UINTN len; const CHAR8 *s; CHAR8 *out, *o; if ( !src || !(len = AsciiStrLen(src)) || !(out = AllocateZeroPool(len+1)) ) return 0; o = out; s = src; while (s <= src+len) /* Make sure the terminator is also copied */ { if ( *s == '&' ) { BOOLEAN entFound = FALSE; UINTN i; s++; for ( i = 0; i < sizeof(ents); i++) { if ( AsciiStrnCmp(s, ents[i].name, ents[i].nameLen) == 0 ) { entFound = TRUE; break; } } if ( entFound ) { *o++ = ents[i].value; s += ents[i].nameLen; continue; } } *o++ = *s++; } return out; }
/** * service_enabled - Should the service run? * @svc: Pointer to &svc_t object * @event: Dynamic event, opaque flag passed to callback * @arg: Event argument, used only by external service plugins. * * This method calls an associated service callback, if registered by a * plugin, and returns the &svc_cmd_t status. If no plugin is registered * the service is statically enabled in /etc/finit.conf and the result * will always be %SVC_START. * * Returns: * Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD. */ svc_cmd_t service_enabled(svc_t *svc, int event, void *arg) { if (!svc) { errno = EINVAL; return SVC_STOP; } if (!svc_in_runlevel(svc, runlevel)) return SVC_STOP; /* * Event conditions for services are ignored during bootstrap. */ if (runlevel && !event_service_cond(svc->events)) return SVC_STOP; /* Is there a service plugin registered? */ if (svc->cb) { int status; pid_t pid; /* Let callback run in separate process so it doesn't crash PID 1 */ pid = fork(); if (-1 == pid) { _pe("Failed in %s callback", svc->cmd); return SVC_STOP; } if (!pid) { status = svc->cb(svc, event, arg); exit(status); } if (waitpid(pid, &status, 0) == -1) { _pe("Failed reading status from %s callback", svc->cmd); return SVC_STOP; } /* Callback normally exits here. */ if (WIFEXITED(status)) return WEXITSTATUS(status); /* Check for SEGFAULT or other error ... */ if (WIFSIGNALED(status) && WCOREDUMP(status)) _e("Callback to %s crashed!\n", svc->cmd); else _e("Callback to %s did not exit normally!\n", svc->cmd); return SVC_STOP; } /* No service plugin, default to start, since listed in finit.conf */ return SVC_START; }
int svc_stop(svc_t *svc) { int res = 1; if (!svc) { _e("Failed, no svc pointer."); return 1; } if (svc->pid <= 1) { _d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc); svc->pid = 0; svc->stat_restart_counter = 0; return 1; } if (runlevel != 1) print_desc("Stopping ", svc->desc); _d("Sending SIGTERM to pid:%d name:'%s'", svc->pid, pid_get_name(svc->pid, NULL, 0)); res = kill(svc->pid, SIGTERM); if (runlevel != 1) print_result(res); svc->pid = 0; svc->stat_restart_counter = 0; return res; }
int plugin_load_all(char *path) { int fail = 0; DIR *dp = opendir(path); struct dirent *entry; if (!dp) { _e("Failed, cannot open plugin directory %s: %s", path, strerror(errno)); return 1; } plugpath = path; while ((entry = readdir(dp))) { if (entry->d_name[0] == '.') continue; /* Skip . and .. directories */ // print_desc(" Loading plugin ", basename(plugin)); if (load_one(path, entry->d_name)) fail++; // print_result(result); } closedir(dp); init_plugins(); return fail; }
void conf_parse_cond(svc_t *svc, char *cond) { size_t i = 0; char *ptr; if (!svc) { _e("Invalid service pointer"); return; } /* By default we assume UNIX daemons support SIGHUP */ if (svc_is_daemon(svc)) svc->sighup = 1; if (!cond) return; /* First character must be '!' if SIGHUP is not supported. */ ptr = cond; if (ptr[i] == '!') { svc->sighup = 0; ptr++; } while (ptr[i] != '>' && ptr[i] != 0) i++; ptr[i] = 0; if (i >= sizeof(svc->cond)) { logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr); return; } strlcpy(svc->cond, ptr, sizeof(svc->cond)); }
static int load_plugins(char *path) { int fail = 0; DIR *dp; struct dirent *entry; if (!silent) print_desc("Loading plugins", NULL); dp = opendir(path); if (!dp) { _e("Failed, cannot open plugin directory %s: %s", path, strerror(errno)); return 1; } plugpath = path; while ((entry = readdir(dp))) { if (entry->d_name[0] == '.') continue; /* Skip . and .. directories */ if (load_one(path, entry->d_name)) fail++; } closedir(dp); return fail; }
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; } }
static void fifo_open(void) { plugin.io.fd = open(FINIT_FIFO, O_RDWR | O_NONBLOCK | O_CLOEXEC); if (-1 == plugin.io.fd) { _e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno)); return; } }
/* Wait for process completion, returns status of waitpid(2) syscall */ int complete(char *cmd, int pid) { int status = 0; if (waitpid(pid, &status, 0) == -1) { if (errno == EINTR) _e("Caught unblocked signal waiting for %s, aborting.", cmd); else if (errno == ECHILD) _e("Caught SIGCHLD waiting for %s, aborting.", cmd); else _e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno)); return -1; } return status; }
static void setup(void) { if (plugin.io.fd) close(plugin.io.fd); plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0) _e("Failed starting TTY watcher: %s", strerror(errno)); }
bool exist(vector<vector<char> > &board, string word) { int m = (int)board.size(), n = (int)board.front().size(), len = (int)word.length(); for (int i=0; i<m; ++i) for (int j=0; j<n; ++j) if (board[i][j] == word[0]) { memset(v, false, sizeof(v)); v[i][j] = true; if (_e(i, j, 0, m, n, len, board, word)) return true; } return false; }
static void nl_link(struct nlmsghdr *nlmsg) { int la; char ifname[IFNAMSIZ + 1]; struct rtattr *a; struct ifinfomsg *i; if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { _e("Packet too small or truncated!"); return; } i = NLMSG_DATA(nlmsg); a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg))); la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg)); while (RTA_OK(a, la)) { if (a->rta_type == IFLA_IFNAME) { strlcpy(ifname, RTA_DATA(a), sizeof(ifname)); switch (nlmsg->nlmsg_type) { case RTM_NEWLINK: /* * New interface has appeared, or interface flags has changed. * Check ifi_flags here to see if the interface is UP/DOWN */ _d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change); net_cond_set(ifname, "exist", 1); net_cond_set(ifname, "up", i->ifi_flags & IFF_UP); net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING); break; case RTM_DELLINK: /* NOTE: Interface has disappeared, not link down ... */ _d("%s: Delete link", ifname); net_cond_set(ifname, "exist", 0); net_cond_set(ifname, "up", 0); net_cond_set(ifname, "running", 0); break; case RTM_NEWADDR: _d("%s: New Address", ifname); break; case RTM_DELADDR: _d("%s: Deconfig Address", ifname); break; default: _d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type); break; } } a = RTA_NEXT(a, la); } }
bool _e(int x, int y, int d, const int m, const int n, const int len, vector<vector<char> > &board, string &word) { if (d == len - 1) return true; for (int k=0; k<4; ++k) { int tx = x + dx[k], ty = y + dy[k]; if (tx < 0 || tx >= m || ty < 0 || ty >= n || board[tx][ty] != word[d+1] || v[tx][ty]) continue; v[tx][ty] = true; if (_e(tx, ty, d+1, m, n, len, board, word)) return true; v[tx][ty] = false; } return false; }
void plugin_exit(void) { #ifndef ENABLE_STATIC plugin_t *p, *tmp; PLUGIN_ITERATOR(p, tmp) { if (dlclose(p->handle)) _e("Failed: unloading plugin %s: %s", p->name, dlerror()); } #endif }
/* Connect to/create shared memory area of registered servies */ static void __connect_shm(void) { if (!services) { services = finit_svc_connect(); if (!services) { /* This should never happen, but if it does we're probably * knee-deep in more serious problems already... */ _e("Failed allocating shared memory, error %d: %s", errno, strerror (errno)); abort(); } } }
int plugin_io_init(plugin_t *p) { if (!is_io_plugin(p)) return 0; _d("Initializing plugin %s for I/O", basename(p->name)); if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) { _e("Failed setting up I/O plugin %s", basename(p->name)); return 1; } return 0; }
static void nl_route(struct nlmsghdr *nlmsg) { struct rtmsg *r; struct rtattr *a; int la; int gw = 0, dst = 0, mask = 0, idx = 0; if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) { _e("Packet too small or truncated!"); return; } r = NLMSG_DATA(nlmsg); a = RTM_RTA(r); la = RTM_PAYLOAD(nlmsg); while (RTA_OK(a, la)) { void *data = RTA_DATA(a); switch (a->rta_type) { case RTA_GATEWAY: gw = *((int *)data); //_d("GW: 0x%04x", gw); break; case RTA_DST: dst = *((int *)data); mask = r->rtm_dst_len; //_d("MASK: 0x%04x", mask); break; case RTA_OIF: idx = *((int *)data); //_d("IDX: 0x%04x", idx); break; } a = RTA_NEXT(a, la); } if ((!dst && !mask) && (gw || idx)) { if (nlmsg->nlmsg_type == RTM_DELROUTE) cond_clear("net/route/default"); else cond_set("net/route/default"); } }
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; } }
/** * service_reload - Send SIGHUP to a service * @svc: Service to reload * * This function does some basic checks of the runtime state of Finit * and a sanity check of the @svc before sending %SIGHUP. * * Returns: * POSIX OK(0) or non-zero on error. */ int service_reload(svc_t *svc) { /* Ignore if finit is SIGSTOP'ed */ if (is_norespawn()) return 0; if (!svc) { _e("Failed, no svc pointer."); return 1; } if (svc->pid <= 1) { _d("Bad PID %d for %s, SIGHUP", svc->pid, svc->cmd); svc->pid = 0; return 1; } _d("Sending SIGHUP to PID %d", svc->pid); return kill(svc->pid, SIGHUP); }
static void parse_dynamic(char *line, time_t mtime) { char *x; /* Skip comments, i.e. lines beginning with # */ if (MATCH_CMD(line, "#", x)) return; /* Monitored daemon, will be respawned on exit, as * long as the (optional) service callback returns * non-zero */ if (MATCH_CMD(line, "service ", x)) { service_register(SVC_TYPE_SERVICE, x, mtime, NULL); return; } /* One-shot task, will not be respawned. Only runs if * the (optional) service callback returns true */ if (MATCH_CMD(line, "task ", x)) { service_register(SVC_TYPE_TASK, x, mtime, NULL); return; } /* Like task but waits for completion, useful w/ [S] */ if (MATCH_CMD(line, "run ", x)) { service_register(SVC_TYPE_RUN, x, mtime, NULL); return; } /* Classic inetd service */ if (MATCH_CMD(line, "inetd ", x)) { #ifndef INETD_DISABLED service_register(SVC_TYPE_INETD, x, mtime, NULL); #else _e("Finit built with inetd support disabled, cannot register service inetd %s!", x); #endif return; } }
static int do_query_inetd(char *buf, size_t len) { int id = 1; char *ptr, *input = sanitize(buf, len); svc_t *svc; if (!input) return -1; ptr = strchr(input, ':'); if (ptr) { *ptr++ = 0; id = atonum(ptr); } svc = svc_find_by_jobid(atonum(input), id); if (!svc || !svc_is_inetd(svc)) { _e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", input); return 1; } return inetd_filter_str(&svc->inetd, buf, len); }
/** * load_one - Load one plugin * @path: Path to finit plugins, usually %PLUGIN_PATH * @name: Name of plugin, optionally ending in ".so" * * Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from * the plugin @name it is added before attempting to load. * * It is up to the plugin itself ot register itself as a "ctor" with the * %PLUGIN_INIT macro so that plugin_register() is called automatically. * * Returns: * POSIX OK(0) on success, non-zero otherwise. */ static int load_one(char *path, char *name) { int noext; char plugin[CMD_SIZE]; void *handle; if (!path || !fisdir(path) || !name) { errno = EINVAL; return 1; } /* Compose full path, with optional .so extension, to plugin */ noext = strcmp(name + strlen(name) - 3, ".so"); snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : ""); _d("Loading plugin %s ...", basename(plugin)); handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL); if (!handle) { _e("Failed loading plugin %s: %s", plugin, dlerror()); return 1; } return 0; }
void plugin_monitor(void) { int ret; size_t i; while ((ret = poll(fds, num_fds, 500))) { if (-1 == ret) { if (EINTR == errno) continue; _e("Failed polling I/O plugin descriptors, error %d: %s", errno, strerror(errno)); break; } /* Traverse all I/O fds and run callbacks */ for (i = 0; i < num_fds; i++) { if (fds[i].revents) generic_io_cb(&fds[i]); } break; } }
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) { int sd; struct init_request rq; sd = accept(w->fd, NULL, NULL); if (sd < 0) { _pe("Failed serving API request"); return; } while (1) { int result = 0; ssize_t len; len = read(sd, &rq, sizeof(rq)); if (len <= 0) { if (-1 == len) { if (EINTR == errno) continue; if (EAGAIN == errno) break; _e("Failed reading initctl request, error %d: %s", errno, strerror(errno)); } break; } if (rq.magic != INIT_MAGIC || len != sizeof(rq)) { _e("Invalid initctl request."); break; } switch (rq.cmd) { case INIT_CMD_RUNLVL: switch (rq.runlevel) { case '0': _d("Halting system (SIGUSR2)"); do_shutdown(SIGUSR2); break; case 's': case 'S': _d("Cannot enter bootstrap after boot ..."); rq.runlevel = '1'; /* Fall through to regular processing */ case '1'...'5': case '7'...'9': _d("Setting new runlevel %c", rq.runlevel); service_runlevel(rq.runlevel - '0'); break; case '6': _d("Rebooting system (SIGUSR1)"); do_shutdown(SIGUSR1); break; default: _d("Unsupported runlevel: %d", rq.runlevel); break; } break; case INIT_CMD_DEBUG: debug = !debug; if (debug) silent = 0; else silent = quiet ? 1 : SILENT_MODE; break; case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */ service_reload_dynamic(); break; case INIT_CMD_START_SVC: result = do_start(rq.data, sizeof(rq.data)); break; case INIT_CMD_STOP_SVC: result = do_pause(rq.data, sizeof(rq.data)); break; case INIT_CMD_RESTART_SVC: result = do_restart(rq.data, sizeof(rq.data)); break; #ifndef INETD_DISABLED case INIT_CMD_QUERY_INETD: result = do_query_inetd(rq.data, sizeof(rq.data)); break; #endif case INIT_CMD_EMIT: result = do_handle_emit(rq.data, sizeof(rq.data)); break; case INIT_CMD_GET_RUNLEVEL: rq.runlevel = runlevel; result = 0; break; case INIT_CMD_ACK: _d("Client failed reading ACK."); goto leave; default: _d("Unsupported cmd: %d", rq.cmd); break; } if (result) rq.cmd = INIT_CMD_NACK; else rq.cmd = INIT_CMD_ACK; len = write(sd, &rq, sizeof(rq)); if (len != sizeof(rq)) _d("Failed sending ACK/NACK back to client."); } leave: close(sd); }
/* Standard reboot/shutdown utilities talk to init using /dev/initctl. * We should check if the fifo was recreated and reopen it. */ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) { struct init_request rq; while (1) { ssize_t len = read(fd, &rq, sizeof(rq)); if (len <= 0) { if (-1 == len) { if (EINTR == errno) continue; if (EAGAIN == errno) break; _e("Failed reading initctl request, error %d: %s", errno, strerror(errno)); } _d("Nothing to do, bailing out."); break; } if (rq.magic != INIT_MAGIC || len != sizeof(rq)) { _e("Invalid initctl request."); break; } switch (rq.cmd) { case INIT_CMD_RUNLVL: switch (rq.runlevel) { case '0': _d("Halting system (SIGUSR2)"); do_shutdown(SIGUSR2); break; case 's': case 'S': _d("Cannot enter bootstrap after boot ..."); rq.runlevel = '1'; /* Fall through to regular processing */ case '1'...'5': case '7'...'9': _d("Setting new runlevel %c", rq.runlevel); service_runlevel(rq.runlevel - '0'); break; case '6': _d("Rebooting system (SIGUSR1)"); do_shutdown(SIGUSR1); break; default: _d("Unsupported runlevel: %d", rq.runlevel); break; } break; case INIT_CMD_RELOAD: service_reload_dynamic(); break; default: _d("Unsupported cmd: %d", rq.cmd); break; } } close(fd); fifo_open(); }
/* * SIGSEGV: mostly if service callbacks segfault */ static void sigsegv_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { _e("PID %d caused a segfault!\n", getpid()); exit(-1); }