static SCHEDULEITEM * parse_schedule_item(const char *string) { const char *after_hyph; int sig; SCHEDULEITEM *item = xmalloc(sizeof(*item)); item->value = 0; item->gotoitem = NULL; if (strcmp(string,"forever") == 0) item->type = SC_FOREVER; else if (isdigit((unsigned char)string[0])) { item->type = SC_TIMEOUT; errno = 0; if (sscanf(string, "%d", &item->value) != 1) eerrorx("%s: invalid timeout value in schedule `%s'", applet, string); } else if ((after_hyph = string + (string[0] == '-')) && ((sig = parse_signal(after_hyph)) != -1)) { item->type = SC_SIGNAL; item->value = (int)sig; } else eerrorx("%s: invalid schedule item `%s'", applet, string); return item; }
int main(int argc, char **argv) { int skip_count = 0; long long last_fault_count = 0; int signal; const char *signame; char **suspects; /* Determine which signal to send. */ if (argc < 2) { signal = SIGSTOP; signame = "SIGSTOP"; } else { int error = parse_signal(argv[1], &signal, &signame); if (error) { usage(argc, argv); return 1; } } /* Determine the list of candidate processes. */ suspects = argc > 2 ? &argv[2] : NULL; /* Set our scheduling priority higher. */ (void)setpriority(PRIO_PROCESS, 0, SCHED_PRIO); while (1) { /* Collect data. */ struct test_data d = { .worst_pid = -1, .worst_oom_score = MIN_OOM_SCORE, .total_faults = 0, }; iterate_processes(suspects, test_process, &d); /* Determine if things are looking bad and we haven't recently stoped something. */ if (is_system_unstable(last_fault_count, d.total_faults)) { if (d.worst_pid != -1 && skip_count == 0) { #if DEBUG printf("Sending %s to pid %d.\n", signame, d.worst_pid); #endif int error = kill(d.worst_pid, signal); if (!error) { syslog(LOG_ALERT, "auto-stop: Sending %s to pid %d to prevent system melt-down.\n", signame, d.worst_pid); skip_count = SLEEP_AFTER_STOP_SECONDS / SLEEP_TIME; } } } if (skip_count > 0) skip_count--; last_fault_count = d.total_faults; sleep(SLEEP_TIME); } return 0; }
static status_check parse_status_check_arg(const std::string& arg) { const std::string::size_type delimiter = arg.find(':'); bool negated = (arg.compare(0, 4, "not-") == 0); const std::string action_str = arg.substr(0, delimiter); const std::string action = negated ? action_str.substr(4) : action_str; const std::string value_str = ( delimiter == std::string::npos ? "" : arg.substr(delimiter + 1)); int value; status_check_t type; if (action == "eq") { // Deprecated; use exit instead. TODO: Remove after 0.10. type = sc_exit; if (negated) throw atf::application::usage_error("Cannot negate eq checker"); negated = false; value = parse_exit_code(value_str); } else if (action == "exit") { type = sc_exit; if (value_str.empty()) value = INT_MIN; else value = parse_exit_code(value_str); } else if (action == "ignore") { if (negated) throw atf::application::usage_error("Cannot negate ignore checker"); type = sc_ignore; value = INT_MIN; } else if (action == "ne") { // Deprecated; use not-exit instead. TODO: Remove after 0.10. type = sc_exit; if (negated) throw atf::application::usage_error("Cannot negate ne checker"); negated = true; value = parse_exit_code(value_str); } else if (action == "signal") { type = sc_signal; if (value_str.empty()) value = INT_MIN; else value = parse_signal(value_str); } else throw atf::application::usage_error("Invalid output checker"); return status_check(type, negated, value); }
/** * Callback to parse scan results */ int wireless_network::scan_cb(struct nl_msg* msg, void* instance) { auto wn = static_cast<wireless_network*>(instance); auto gnlh = static_cast<genlmsghdr*>(nlmsg_data(nlmsg_hdr(msg))); struct nlattr* tb[NL80211_ATTR_MAX + 1]; struct nlattr* bss[NL80211_BSS_MAX + 1]; struct nla_policy bss_policy[NL80211_BSS_MAX + 1]{}; bss_policy[NL80211_BSS_TSF].type = NLA_U64; bss_policy[NL80211_BSS_FREQUENCY].type = NLA_U32; bss_policy[NL80211_BSS_BSSID].type = NLA_UNSPEC; bss_policy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16; bss_policy[NL80211_BSS_CAPABILITY].type = NLA_U16; bss_policy[NL80211_BSS_INFORMATION_ELEMENTS].type = NLA_UNSPEC; bss_policy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32; bss_policy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8; bss_policy[NL80211_BSS_STATUS].type = NLA_U32; if (nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), nullptr) < 0) { return NL_SKIP; } if (tb[NL80211_ATTR_BSS] == nullptr) { return NL_SKIP; } if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy) != 0) { return NL_SKIP; } if (!wn->associated_or_joined(bss)) { return NL_SKIP; } wn->parse_essid(bss); wn->parse_frequency(bss); wn->parse_signal(bss); wn->parse_quality(bss); return NL_SKIP; }
static void start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **names, const gchar **values, gpointer user_data, GError **error) { ParserData *data = (ParserData*)user_data; #ifdef G_ENABLE_DEBUG if (GTK_DEBUG_CHECK (BUILDER)) { GString *tags = g_string_new (""); int i; for (i = 0; names[i]; i++) g_string_append_printf (tags, "%s=\"%s\" ", names[i], values[i]); if (i) { g_string_insert_c (tags, 0, ' '); g_string_truncate (tags, tags->len - 1); } g_message ("<%s%s>", element_name, tags->str); g_string_free (tags, TRUE); } #endif if (!data->last_element && strcmp (element_name, "interface") != 0) { error_unhandled_tag (data, element_name, error); return; } data->last_element = element_name; if (data->subparser) { if (!subparser_start (context, element_name, names, values, data, error)) return; } if (strcmp (element_name, "requires") == 0) parse_requires (data, element_name, names, values, error); else if (strcmp (element_name, "object") == 0) parse_object (context, data, element_name, names, values, error); else if (strcmp (element_name, "template") == 0) parse_template (context, data, element_name, names, values, error); else if (data->requested_objects && !data->inside_requested_object) { /* If outside a requested object, simply ignore this tag */ } else if (strcmp (element_name, "child") == 0) parse_child (data, element_name, names, values, error); else if (strcmp (element_name, "property") == 0) parse_property (data, element_name, names, values, error); else if (strcmp (element_name, "signal") == 0) parse_signal (data, element_name, names, values, error); else if (strcmp (element_name, "interface") == 0) parse_interface (data, element_name, names, values, error); else if (strcmp (element_name, "menu") == 0) _gtk_builder_menu_start (data, element_name, names, values, error); else if (strcmp (element_name, "placeholder") == 0) { /* placeholder has no special treatmeant, but it needs an * if clause to avoid an error below. */ } else if (!parse_custom (context, element_name, names, values, data, error)) error_unhandled_tag (data, element_name, error); }
static void start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **names, const gchar **values, gpointer user_data, GError **error) { ParserData *data = (ParserData*)user_data; #ifdef GTK_ENABLE_DEBUG if (gtk_debug_flags & GTK_DEBUG_BUILDER) { GString *tags = g_string_new (""); int i; for (i = 0; names[i]; i++) g_string_append_printf (tags, "%s=\"%s\" ", names[i], values[i]); if (i) { g_string_insert_c (tags, 0, ' '); g_string_truncate (tags, tags->len - 1); } g_print ("<%s%s>\n", element_name, tags->str); g_string_free (tags, TRUE); } #endif if (!data->last_element && strcmp (element_name, "interface") != 0) { g_set_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_UNHANDLED_TAG, _("Invalid root element: '%s'"), element_name); return; } data->last_element = element_name; if (data->subparser) if (!subparser_start (context, element_name, names, values, data, error)) return; if (strcmp (element_name, "requires") == 0) parse_requires (data, element_name, names, values, error); else if (strcmp (element_name, "object") == 0) parse_object (context, data, element_name, names, values, error); else if (data->requested_objects && !data->inside_requested_object) { /* If outside a requested object, simply ignore this tag */ return; } else if (strcmp (element_name, "child") == 0) parse_child (data, element_name, names, values, error); else if (strcmp (element_name, "property") == 0) parse_property (data, element_name, names, values, error); else if (strcmp (element_name, "signal") == 0) parse_signal (data, element_name, names, values, error); else if (strcmp (element_name, "interface") == 0) parse_interface (data, element_name, names, values, error); else if (strcmp (element_name, "placeholder") == 0) { /* placeholder has no special treatmeant, but it needs an * if clause to avoid an error below. */ } else if (!parse_custom (context, element_name, names, values, data, error)) g_set_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_UNHANDLED_TAG, _("Unhandled tag: '%s'"), element_name); }
int main(int argc, char **argv) { int ch; unsigned long i; int foreground, preserve; int error, pstat, status; int killsig = SIGTERM; pid_t pid, cpid; double first_kill; double second_kill; bool timedout = false; bool do_second_kill = false; bool child_done = false; struct sigaction signals; struct procctl_reaper_status info; struct procctl_reaper_kill killemall; int signums[] = { -1, SIGTERM, SIGINT, SIGHUP, SIGCHLD, SIGALRM, SIGQUIT, }; foreground = preserve = 0; second_kill = 0; const struct option longopts[] = { { "preserve-status", no_argument, &preserve, 1 }, { "foreground", no_argument, &foreground, 1 }, { "kill-after", required_argument, NULL, 'k'}, { "signal", required_argument, NULL, 's'}, { "help", no_argument, NULL, 'h'}, { NULL, 0, NULL, 0 } }; while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) { switch (ch) { case 'k': do_second_kill = true; second_kill = parse_duration(optarg); break; case 's': killsig = parse_signal(optarg); break; case 0: break; case 'h': default: usage(); break; } } argc -= optind; argv += optind; if (argc < 2) usage(); first_kill = parse_duration(argv[0]); argc--; argv++; if (!foreground) { /* Aquire a reaper */ if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1) err(EX_OSERR, "Fail to acquire the reaper"); } memset(&signals, 0, sizeof(signals)); sigemptyset(&signals.sa_mask); if (killsig != SIGKILL && killsig != SIGSTOP) signums[0] = killsig; for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++) sigaddset(&signals.sa_mask, signums[i]); signals.sa_handler = sig_handler; signals.sa_flags = SA_RESTART; for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++) if (signums[i] != -1 && signums[i] != 0 && sigaction(signums[i], &signals, NULL) == -1) err(EX_OSERR, "sigaction()"); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); pid = fork(); if (pid == -1) err(EX_OSERR, "fork()"); else if (pid == 0) { /* child process */ signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); error = execvp(argv[0], argv); if (error == -1) { if (errno == ENOENT) err(127, "exec(%s)", argv[0]); else err(126, "exec(%s)", argv[0]); } } if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) err(EX_OSERR, "sigprocmask()"); /* parent continues here */ set_interval(first_kill); for (;;) { sigemptyset(&signals.sa_mask); sigsuspend(&signals.sa_mask); if (sig_chld) { sig_chld = 0; while ((cpid = waitpid(-1, &status, WNOHANG)) != 0) { if (cpid < 0) { if (errno == EINTR) continue; else break; } else if (cpid == pid) { pstat = status; child_done = true; } } if (child_done) { if (foreground) { break; } else { procctl(P_PID, getpid(), PROC_REAP_STATUS, &info); if (info.rs_children == 0) break; } } } else if (sig_alrm) { sig_alrm = 0; timedout = true; if (!foreground) { killemall.rk_sig = killsig; killemall.rk_flags = 0; procctl(P_PID, getpid(), PROC_REAP_KILL, &killemall); } else kill(pid, killsig); if (do_second_kill) { set_interval(second_kill); second_kill = 0; sig_ign = killsig; killsig = SIGKILL; } else break; } else if (sig_term) { if (!foreground) { killemall.rk_sig = sig_term; killemall.rk_flags = 0; procctl(P_PID, getpid(), PROC_REAP_KILL, &killemall); } else kill(pid, sig_term); if (do_second_kill) { set_interval(second_kill); second_kill = 0; sig_ign = killsig; killsig = SIGKILL; } else break; } } while (!child_done && wait(&pstat) == -1) { if (errno != EINTR) err(EX_OSERR, "waitpid()"); } if (!foreground) procctl(P_PID, getpid(), PROC_REAP_RELEASE, NULL); if (WEXITSTATUS(pstat)) pstat = WEXITSTATUS(pstat); else if(WIFSIGNALED(pstat)) pstat = 128 + WTERMSIG(pstat); if (timedout && !preserve) pstat = EXIT_TIMEOUT; return (pstat); }
int main(int argc, char **argv) { int ch; unsigned long i; int foreground, preserve; int error, pstat, status; int killsig = SIGTERM; pid_t pgid, pid, cpid; double first_kill; double second_kill; bool timedout = false; bool do_second_kill = false; struct sigaction signals; int signums[] = { -1, SIGTERM, SIGINT, SIGHUP, SIGCHLD, SIGALRM, SIGQUIT, }; foreground = preserve = 0; second_kill = 0; cpid = -1; pgid = -1; const struct option longopts[] = { { "preserve-status", no_argument, &preserve, 1 }, { "foreground", no_argument, &foreground, 1 }, { "kill-after", required_argument, NULL, 'k'}, { "signal", required_argument, NULL, 's'}, { "help", no_argument, NULL, 'h'}, { NULL, 0, NULL, 0 } }; while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) { switch (ch) { case 'k': do_second_kill = true; second_kill = parse_duration(optarg); break; case 's': killsig = parse_signal(optarg); break; case 0: break; case 'h': default: usage(); break; } } argc -= optind; argv += optind; if (argc < 2) usage(); first_kill = parse_duration(argv[0]); argc--; argv++; if (!foreground) { pgid = setpgid(0,0); if (pgid == -1) err(EX_OSERR, "setpgid()"); } memset(&signals, 0, sizeof(signals)); sigemptyset(&signals.sa_mask); if (killsig != SIGKILL && killsig != SIGSTOP) signums[0] = killsig; for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++) sigaddset(&signals.sa_mask, signums[i]); signals.sa_handler = sig_handler; signals.sa_flags = SA_RESTART; for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++) if (signums[i] != -1 && signums[i] != 0 && sigaction(signums[i], &signals, NULL) == -1) err(EX_OSERR, "sigaction()"); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); pid = fork(); if (pid == -1) err(EX_OSERR, "fork()"); else if (pid == 0) { /* child process */ signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); error = execvp(argv[0], argv); if (error == -1) err(EX_UNAVAILABLE, "exec()"); } if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) err(EX_OSERR, "sigprocmask()"); /* parent continues here */ set_interval(first_kill); for (;;) { sigemptyset(&signals.sa_mask); sigsuspend(&signals.sa_mask); if (sig_chld) { sig_chld = 0; while (((cpid = wait(&status)) < 0) && errno == EINTR) continue; if (cpid == pid) { pstat = status; break; } } else if (sig_alrm) { sig_alrm = 0; timedout = true; if (!foreground) killpg(pgid, killsig); else kill(pid, killsig); if (do_second_kill) { set_interval(second_kill); second_kill = 0; sig_ign = killsig; killsig = SIGKILL; } else break; } else if (sig_term) { if (!foreground) killpg(pgid, killsig); else kill(pid, sig_term); if (do_second_kill) { set_interval(second_kill); second_kill = 0; sig_ign = killsig; killsig = SIGKILL; } else break; } } while (cpid != pid && wait(&pstat) == -1) { if (errno != EINTR) err(EX_OSERR, "waitpid()"); } if (WEXITSTATUS(pstat)) pstat = WEXITSTATUS(pstat); else if(WIFSIGNALED(pstat)) pstat = 128 + WTERMSIG(pstat); if (timedout && !preserve) pstat = EXIT_TIMEOUT; return (pstat); }
int main(int argc, char **argv) { int devnull_fd = -1; #ifdef TIOCNOTTY int tty_fd = -1; #endif #ifdef HAVE_PAM pam_handle_t *pamh = NULL; int pamr; const char *const *pamenv = NULL; #endif int opt; bool start = false; bool stop = false; bool oknodo = false; bool test = false; char *exec = NULL; char *startas = NULL; char *name = NULL; char *pidfile = NULL; char *retry = NULL; int sig = -1; int nicelevel = 0, ionicec = -1, ioniced = 0; bool background = false; bool makepidfile = false; bool interpreted = false; bool progress = false; uid_t uid = 0; gid_t gid = 0; char *home = NULL; int tid = 0; char *redirect_stderr = NULL; char *redirect_stdout = NULL; int stdin_fd; int stdout_fd; int stderr_fd; pid_t pid, spid; int i; char *svcname = getenv("RC_SVCNAME"); RC_STRINGLIST *env_list; RC_STRING *env; char *tmp, *newpath, *np; char *p; char *token; char exec_file[PATH_MAX]; struct passwd *pw; struct group *gr; char line[130]; FILE *fp; size_t len; mode_t numask = 022; char **margv; unsigned int start_wait = 0; applet = basename_c(argv[0]); TAILQ_INIT(&schedule); #ifdef DEBUG_MEMORY atexit(cleanup); #endif signal_setup(SIGINT, handle_signal); signal_setup(SIGQUIT, handle_signal); signal_setup(SIGTERM, handle_signal); if ((tmp = getenv("SSD_NICELEVEL"))) if (sscanf(tmp, "%d", &nicelevel) != 1) eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, tmp); /* Get our user name and initial dir */ p = getenv("USER"); home = getenv("HOME"); if (home == NULL || p == NULL) { pw = getpwuid(getuid()); if (pw != NULL) { if (p == NULL) setenv("USER", pw->pw_name, 1); if (home == NULL) { setenv("HOME", pw->pw_dir, 1); home = pw->pw_dir; } } } while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) switch (opt) { case 'I': /* --ionice */ if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0) eerrorx("%s: invalid ionice `%s'", applet, optarg); if (ionicec == 0) ioniced = 0; else if (ionicec == 3) ioniced = 7; ionicec <<= 13; /* class shift */ break; case 'K': /* --stop */ stop = true; break; case 'N': /* --nice */ if (sscanf(optarg, "%d", &nicelevel) != 1) eerrorx("%s: invalid nice level `%s'", applet, optarg); break; case 'P': /* --progress */ progress = true; break; case 'R': /* --retry <schedule>|<timeout> */ retry = optarg; break; case 'S': /* --start */ start = true; break; case 'b': /* --background */ background = true; break; case 'c': /* --chuid <username>|<uid> */ /* DEPRECATED */ ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead"); case 'u': /* --user <username>|<uid> */ { p = optarg; tmp = strsep(&p, ":"); changeuser = xstrdup(tmp); if (sscanf(tmp, "%d", &tid) != 1) pw = getpwnam(tmp); else pw = getpwuid((uid_t)tid); if (pw == NULL) eerrorx("%s: user `%s' not found", applet, tmp); uid = pw->pw_uid; home = pw->pw_dir; unsetenv("HOME"); if (pw->pw_dir) setenv("HOME", pw->pw_dir, 1); unsetenv("USER"); if (pw->pw_name) setenv("USER", pw->pw_name, 1); if (gid == 0) gid = pw->pw_gid; if (p) { tmp = strsep (&p, ":"); if (sscanf(tmp, "%d", &tid) != 1) gr = getgrnam(tmp); else gr = getgrgid((gid_t) tid); if (gr == NULL) eerrorx("%s: group `%s'" " not found", applet, tmp); gid = gr->gr_gid; } } break; case 'd': /* --chdir /new/dir */ ch_dir = optarg; break; case 'e': /* --env */ putenv(optarg); break; case 'g': /* --group <group>|<gid> */ if (sscanf(optarg, "%d", &tid) != 1) gr = getgrnam(optarg); else gr = getgrgid((gid_t)tid); if (gr == NULL) eerrorx("%s: group `%s' not found", applet, optarg); gid = gr->gr_gid; break; case 'i': /* --interpreted */ interpreted = true; break; case 'k': if (parse_mode(&numask, optarg)) eerrorx("%s: invalid mode `%s'", applet, optarg); break; case 'm': /* --make-pidfile */ makepidfile = true; break; case 'n': /* --name <process-name> */ name = optarg; break; case 'o': /* --oknodo */ /* DEPRECATED */ ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future"); oknodo = true; break; case 'p': /* --pidfile <pid-file> */ pidfile = optarg; break; case 's': /* --signal <signal> */ sig = parse_signal(optarg); break; case 't': /* --test */ test = true; break; case 'r': /* --chroot /new/root */ ch_root = optarg; break; case 'a': /* --startas <name> */ /* DEPRECATED */ ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead"); startas = optarg; break; case 'w': if (sscanf(optarg, "%d", &start_wait) != 1) eerrorx("%s: `%s' not a number", applet, optarg); break; case 'x': /* --exec <executable> */ exec = optarg; break; case '1': /* --stdout /path/to/stdout.lgfile */ redirect_stdout = optarg; break; case '2': /* --stderr /path/to/stderr.logfile */ redirect_stderr = optarg; break; case_RC_COMMON_GETOPT } endpwent(); argc -= optind; argv += optind; /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq * instead of forcing --stop --oknodo as well */ if (!start && !stop && sig != SIGINT && sig != SIGTERM && sig != SIGQUIT && sig != SIGKILL) oknodo = true; if (!exec) exec = startas; else if (!name) name = startas; if (!exec) { exec = *argv; if (!exec) exec = name; if (name && start) *argv = name; } else if (name) { *--argv = name; ++argc; } else if (exec) { *--argv = exec; ++argc; }; if (stop || sig != -1) { if (sig == -1) sig = SIGTERM; if (!*argv && !pidfile && !name && !uid) eerrorx("%s: --stop needs --exec, --pidfile," " --name or --user", applet); if (background) eerrorx("%s: --background is only relevant with" " --start", applet); if (makepidfile) eerrorx("%s: --make-pidfile is only relevant with" " --start", applet); if (redirect_stdout || redirect_stderr) eerrorx("%s: --stdout and --stderr are only relevant" " with --start", applet); } else { if (!exec) eerrorx("%s: nothing to start", applet); if (makepidfile && !pidfile) eerrorx("%s: --make-pidfile is only relevant with" " --pidfile", applet); if ((redirect_stdout || redirect_stderr) && !background) eerrorx("%s: --stdout and --stderr are only relevant" " with --background", applet); } /* Expand ~ */ if (ch_dir && *ch_dir == '~') ch_dir = expand_home(home, ch_dir); if (ch_root && *ch_root == '~') ch_root = expand_home(home, ch_root); if (exec) { if (*exec == '~') exec = expand_home(home, exec); /* Validate that the binary exists if we are starting */ if (*exec == '/' || *exec == '.') { /* Full or relative path */ if (ch_root) snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec); else snprintf(exec_file, sizeof(exec_file), "%s", exec); } else { /* Something in $PATH */ p = tmp = xstrdup(getenv("PATH")); *exec_file = '\0'; while ((token = strsep(&p, ":"))) { if (ch_root) snprintf(exec_file, sizeof(exec_file), "%s/%s/%s", ch_root, token, exec); else snprintf(exec_file, sizeof(exec_file), "%s/%s", token, exec); if (exists(exec_file)) break; *exec_file = '\0'; } free(tmp); } } if (start && !exists(exec_file)) { eerror("%s: %s does not exist", applet, *exec_file ? exec_file : exec); exit(EXIT_FAILURE); } /* If we don't have a pidfile we should check if it's interpreted * or not. If it we, we need to pass the interpreter through * to our daemon calls to find it correctly. */ if (interpreted && !pidfile) { fp = fopen(exec_file, "r"); if (fp) { p = fgets(line, sizeof(line), fp); fclose(fp); if (p != NULL && line[0] == '#' && line[1] == '!') { p = line + 2; /* Strip leading spaces */ while (*p == ' ' || *p == '\t') p++; /* Remove the trailing newline */ len = strlen(p) - 1; if (p[len] == '\n') p[len] = '\0'; token = strsep(&p, " "); strncpy(exec_file, token, sizeof(exec_file)); opt = 0; for (nav = argv; *nav; nav++) opt++; nav = xmalloc(sizeof(char *) * (opt + 3)); nav[0] = exec_file; len = 1; if (p) nav[len++] = p; for (i = 0; i < opt; i++) nav[i + len] = argv[i]; nav[i + len] = '\0'; } } } margv = nav ? nav : argv; if (stop || sig != -1) { if (sig == -1) sig = SIGTERM; if (!stop) oknodo = true; if (retry) parse_schedule(retry, sig); else if (test || oknodo) parse_schedule("0", sig); else parse_schedule(NULL, sig); i = run_stop_schedule(exec, (const char *const *)margv, pidfile, uid, test, progress); if (i < 0) /* We failed to stop something */ exit(EXIT_FAILURE); if (test || oknodo) return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE; /* Even if we have not actually killed anything, we should * remove information about it as it may have unexpectedly * crashed out. We should also return success as the end * result would be the same. */ if (pidfile && exists(pidfile)) unlink(pidfile); if (svcname) rc_service_daemon_set(svcname, exec, (const char *const *)argv, pidfile, false); exit(EXIT_SUCCESS); } if (pidfile) pid = get_pid(pidfile); else pid = 0; if (do_stop(exec, (const char * const *)margv, pid, uid, 0, test) > 0) eerrorx("%s: %s is already running", applet, exec); if (test) { if (rc_yesno(getenv("EINFO_QUIET"))) exit (EXIT_SUCCESS); einfon("Would start"); while (argc-- > 0) printf(" %s", *argv++); printf("\n"); eindent(); if (uid != 0) einfo("as user id %d", uid); if (gid != 0) einfo("as group id %d", gid); if (ch_root) einfo("in root `%s'", ch_root); if (ch_dir) einfo("in dir `%s'", ch_dir); if (nicelevel != 0) einfo("with a priority of %d", nicelevel); if (name) einfo ("with a process name of %s", name); eoutdent(); exit(EXIT_SUCCESS); } ebeginv("Detaching to start `%s'", exec); eindentv(); /* Remove existing pidfile */ if (pidfile) unlink(pidfile); if (background) signal_setup(SIGCHLD, handle_signal); if ((pid = fork()) == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); /* Child process - lets go! */ if (pid == 0) { pid_t mypid = getpid(); umask(numask); #ifdef TIOCNOTTY tty_fd = open("/dev/tty", O_RDWR); #endif devnull_fd = open("/dev/null", O_RDWR); if (nicelevel) { if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1) eerrorx("%s: setpritory %d: %s", applet, nicelevel, strerror(errno)); } if (ionicec != -1 && ioprio_set(1, mypid, ionicec | ioniced) == -1) eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced, strerror(errno)); if (ch_root && chroot(ch_root) < 0) eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno)); if (ch_dir && chdir(ch_dir) < 0) eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno)); if (makepidfile && pidfile) { fp = fopen(pidfile, "w"); if (! fp) eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); fprintf(fp, "%d\n", mypid); fclose(fp); } #ifdef HAVE_PAM if (changeuser != NULL) { pamr = pam_start("start-stop-daemon", changeuser, &conv, &pamh); if (pamr == PAM_SUCCESS) pamr = pam_acct_mgmt(pamh, PAM_SILENT); if (pamr == PAM_SUCCESS) pamr = pam_open_session(pamh, PAM_SILENT); if (pamr != PAM_SUCCESS) eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr)); } #endif if (gid && setgid(gid)) eerrorx("%s: unable to set groupid to %d", applet, gid); if (changeuser && initgroups(changeuser, gid)) eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid); if (uid && setuid(uid)) eerrorx ("%s: unable to set userid to %d", applet, uid); /* Close any fd's to the passwd database */ endpwent(); #ifdef TIOCNOTTY ioctl(tty_fd, TIOCNOTTY, 0); close(tty_fd); #endif /* Clean the environment of any RC_ variables */ env_list = rc_stringlist_new(); i = 0; while (environ[i]) rc_stringlist_add(env_list, environ[i++]); #ifdef HAVE_PAM if (changeuser != NULL) { pamenv = (const char *const *)pam_getenvlist(pamh); if (pamenv) { while (*pamenv) { /* Don't add strings unless they set a var */ if (strchr(*pamenv, '=')) putenv(xstrdup(*pamenv)); else unsetenv(*pamenv); pamenv++; } } } #endif TAILQ_FOREACH(env, env_list, entries) { if ((strncmp(env->value, "RC_", 3) == 0 && strncmp(env->value, "RC_SERVICE=", 10) != 0 && strncmp(env->value, "RC_SVCNAME=", 10) != 0) || strncmp(env->value, "SSD_NICELEVEL=", 14) == 0) { p = strchr(env->value, '='); *p = '\0'; unsetenv(env->value); continue; } } rc_stringlist_free(env_list); /* For the path, remove the rcscript bin dir from it */ if ((token = getenv("PATH"))) { len = strlen(token); newpath = np = xmalloc(len + 1); while (token && *token) { p = strchr(token, ':'); if (p) { *p++ = '\0'; while (*p == ':') p++; } if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 && strcmp(token, RC_LIBEXECDIR "/sbin") != 0) { len = strlen(token); if (np != newpath) *np++ = ':'; memcpy(np, token, len); np += len; } token = p; } *np = '\0'; unsetenv("PATH"); setenv("PATH", newpath, 1); } stdin_fd = devnull_fd; stdout_fd = devnull_fd; stderr_fd = devnull_fd; if (redirect_stdout) { if ((stdout_fd = open(redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) == -1) eerrorx("%s: unable to open the logfile" " for stdout `%s': %s", applet, redirect_stdout, strerror(errno)); } if (redirect_stderr) { if ((stderr_fd = open(redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) == -1) eerrorx("%s: unable to open the logfile" " for stderr `%s': %s", applet, redirect_stderr, strerror(errno)); } if (background) dup2(stdin_fd, STDIN_FILENO); if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET"))) dup2(stdout_fd, STDOUT_FILENO); if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET"))) dup2(stderr_fd, STDERR_FILENO); for (i = getdtablesize() - 1; i >= 3; --i) close(i); setsid(); execvp(exec, argv); #ifdef HAVE_PAM if (changeuser != NULL && pamr == PAM_SUCCESS) pam_close_session(pamh, PAM_SILENT); #endif eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno)); }