static void open_shell(void) { const char *shell; struct passwd *pw; #ifdef __linux__ const char *sys = rc_sys(); /* VSERVER and OPENVZ systems cannot really drop to shells */ if (sys && (strcmp(sys, "VSERVER") == 0 || strcmp(sys, "OPENVZ") == 0)) { execl("/sbin/halt", "/sbin/halt", "-f", (char *) NULL); eerrorx("%s: unable to exec `/sbin/halt': %s", applet, strerror(errno)); } #endif shell = rc_conf_value("rc_shell"); /* No shell set, so obey env, then passwd, then default to /bin/sh */ if (shell == NULL) { shell = getenv("SHELL"); if (shell == NULL) { pw = getpwuid(getuid()); if (pw) shell = pw->pw_shell; if (shell == NULL) shell = "/bin/sh"; } } run_program(shell); }
void env_filter(void) { RC_STRINGLIST *env_allow; RC_STRINGLIST *profile; RC_STRINGLIST *env_list; RC_STRING *env; char *e; size_t i = 0; profile = rc_config_load(RC_PROFILE_ENV); /* Copy the env and work from this so we can manipulate it safely */ env_list = rc_stringlist_new(); while (environ && environ[i]) { env = rc_stringlist_add(env_list, environ[i++]); e = strchr(env->value, '='); if (e) *e = '\0'; } if (rc_conf_value("rc_env_allow") != "*") { /* Add the user defined list of vars */ env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " "); TAILQ_FOREACH(env, env_list, entries) { /* Check the whitelist */ for (i = 0; env_whitelist[i]; i++) { if (strcmp(env_whitelist[i], env->value) == 0) break; } if (env_whitelist[i]) continue; /* Check our user defined list */ if (rc_stringlist_find(env_allow, env->value)) continue; /* OK, not allowed! */ unsetenv(env->value); } }
void env_filter(void) { RC_STRINGLIST *env_allow; RC_STRINGLIST *profile; RC_STRINGLIST *env_list; RC_STRING *env; char *e; size_t i = 0; /* Add the user defined list of vars */ env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " "); /* * If '*' is an entry in rc_env_allow, do nothing as we are to pass * through all environment variables. */ if (rc_stringlist_find(env_allow, "*")) return; profile = rc_config_load(RC_PROFILE_ENV); /* Copy the env and work from this so we can manipulate it safely */ env_list = rc_stringlist_new(); while (environ && environ[i]) { env = rc_stringlist_add(env_list, environ[i++]); e = strchr(env->value, '='); if (e) *e = '\0'; } TAILQ_FOREACH(env, env_list, entries) { /* Check the whitelist */ for (i = 0; env_whitelist[i]; i++) { if (strcmp(env_whitelist[i], env->value) == 0) break; } if (env_whitelist[i]) continue; /* Check our user defined list */ if (rc_stringlist_find(env_allow, env->value)) continue; /* OK, not allowed! */ unsetenv(env->value); } /* Now add anything missing from the profile */ TAILQ_FOREACH(env, profile, entries) { e = strchr(env->value, '='); *e = '\0'; if (!getenv(env->value)) setenv(env->value, e + 1, 1); }
static const char * get_systype(void) { char *systype = rc_conf_value("rc_sys"); if (systype) { char *s = systype; /* Convert to uppercase */ while (s && *s) { if (islower((unsigned char) *s)) *s = toupper((unsigned char) *s); s++; } } return systype; }
bool rc_conf_yesno(const char *setting) { return rc_yesno(rc_conf_value (setting)); }
void rc_logger_open(const char *level) { int slave_tty; struct termios tt; struct winsize ws; char buffer[BUFSIZ]; struct pollfd fd[2]; int s = 0; size_t bytes; int i; FILE *log = NULL; FILE *plog = NULL; const char *logfile; int log_error = 0; if (!rc_conf_yesno("rc_logger")) return; if (pipe(signal_pipe) == -1) eerrorx("pipe: %s", strerror(errno)); for (i = 0; i < 2; i++) if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 || fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1)) eerrorx("fcntl: %s", strerror (errno)); if (isatty(STDOUT_FILENO)) { tcgetattr(STDOUT_FILENO, &tt); ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); if (openpty(&rc_logger_tty, &slave_tty, NULL, &tt, &ws)) return; } else if (openpty(&rc_logger_tty, &slave_tty, NULL, NULL, NULL)) return; if ((s = fcntl(rc_logger_tty, F_GETFD, 0)) == 0) fcntl(rc_logger_tty, F_SETFD, s | FD_CLOEXEC); if ((s = fcntl(slave_tty, F_GETFD, 0)) == 0) fcntl(slave_tty, F_SETFD, s | FD_CLOEXEC); rc_logger_pid = fork(); switch (rc_logger_pid) { case -1: eerror("fork: %s", strerror(errno)); break; case 0: rc_in_logger = true; close(signal_pipe[1]); signal_pipe[1] = -1; runlevel = level; if ((log = fopen(TMPLOG, "ae"))) write_time(log, "started"); else { free(logbuf); logbuf_size = BUFSIZ * 10; logbuf = xmalloc(sizeof (char) * logbuf_size); logbuf_len = 0; } fd[0].fd = signal_pipe[0]; fd[0].events = fd[1].events = POLLIN; fd[0].revents = fd[1].revents = 0; if (rc_logger_tty >= 0) fd[1].fd = rc_logger_tty; for (;;) { if ((s = poll(fd, rc_logger_tty >= 0 ? 2 : 1, -1)) == -1) { eerror("poll: %s", strerror(errno)); break; } else if (s == 0) continue; if (fd[1].revents & (POLLIN | POLLHUP)) { memset(buffer, 0, BUFSIZ); bytes = read(rc_logger_tty, buffer, BUFSIZ); if (write(STDOUT_FILENO, buffer, bytes) == -1) eerror("write: %s", strerror(errno)); if (log) write_log(fileno (log), buffer, bytes); else { if (logbuf_size - logbuf_len < bytes) { logbuf_size += BUFSIZ * 10; logbuf = xrealloc(logbuf, sizeof(char ) * logbuf_size); } memcpy(logbuf + logbuf_len, buffer, bytes); logbuf_len += bytes; } } /* Only SIGTERMS signals come down this pipe */ if (fd[0].revents & (POLLIN | POLLHUP)) break; } if (logbuf) { if ((log = fopen(TMPLOG, "ae"))) { write_time(log, "started"); write_log(fileno(log), logbuf, logbuf_len); } free(logbuf); } if (log) { write_time(log, "stopped"); fclose(log); } /* Append the temporary log to the real log */ logfile = rc_conf_value("rc_log_path"); if (logfile == NULL) logfile = DEFAULTLOG; if (!strcmp(logfile, TMPLOG)) { eerror("Cowardly refusing to concatenate a logfile into itself."); eerrorx("Please change rc_log_path to something other than %s to get rid of this message", TMPLOG); } if ((plog = fopen(logfile, "ae"))) { if ((log = fopen(TMPLOG, "re"))) { while ((bytes = fread(buffer, sizeof(*buffer), BUFSIZ, log)) > 0) { if (fwrite(buffer, sizeof(*buffer), bytes, plog) < bytes) { log_error = 1; eerror("Error: write(%s) failed: %s", logfile, strerror(errno)); break; } } } else { log_error = 1; eerror("Error: fopen(%s) failed: %s", TMPLOG, strerror(errno)); } fclose(log); fclose(plog); } else { /* * logfile or its basedir may be read-only during sysinit and * shutdown so skip the error in this case */ if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0))) { log_error = 1; eerror("Error: fopen(%s) failed: %s", logfile, strerror(errno)); } } /* Try to keep the temporary log in case of errors */ if (!log_error) { if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0))) if (unlink(TMPLOG) == -1) eerror("Error: unlink(%s) failed: %s", TMPLOG, strerror(errno)); } else if (exists(TMPLOG)) eerrorx("Warning: temporary logfile left behind: %s", TMPLOG); exit(0); /* NOTREACHED */ default: setpgid(rc_logger_pid, 0); fd_stdout = dup(STDOUT_FILENO); fd_stderr = dup(STDERR_FILENO); if ((s = fcntl(fd_stdout, F_GETFD, 0)) == 0) fcntl(fd_stdout, F_SETFD, s | FD_CLOEXEC); if ((s = fcntl(fd_stderr, F_GETFD, 0)) == 0) fcntl(fd_stderr, F_SETFD, s | FD_CLOEXEC); dup2(slave_tty, STDOUT_FILENO); dup2(slave_tty, STDERR_FILENO); if (slave_tty != STDIN_FILENO && slave_tty != STDOUT_FILENO && slave_tty != STDERR_FILENO) close(slave_tty); close(signal_pipe[0]); signal_pipe[0] = -1; break; } }
static void do_stop_services(RC_STRINGLIST *types_n, RC_STRINGLIST *start_services, const RC_STRINGLIST *stop_services, const RC_DEPTREE *deptree, const char *newlevel, bool parallel, bool going_down) { pid_t pid; RC_STRING *service, *svc1, *svc2; RC_STRINGLIST *deporder, *tmplist, *kwords; RC_SERVICE state; RC_STRINGLIST *nostop; bool crashed, nstop; if (!types_n) { types_n = rc_stringlist_new(); rc_stringlist_add(types_n, "needsme"); } crashed = rc_conf_yesno("rc_crashed_stop"); nostop = rc_stringlist_split(rc_conf_value("rc_nostop"), " "); TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) { state = rc_service_state(service->value); if (state & RC_SERVICE_STOPPED || state & RC_SERVICE_FAILED) continue; /* Sometimes we don't ever want to stop a service. */ if (rc_stringlist_find(nostop, service->value)) { rc_service_mark(service->value, RC_SERVICE_FAILED); continue; } kwords = rc_deptree_depend(deptree, service->value, "keyword"); if (rc_stringlist_find(kwords, "-stop") || rc_stringlist_find(kwords, "nostop") || (going_down && (rc_stringlist_find(kwords, "-shutdown") || rc_stringlist_find(kwords, "noshutdown")))) nstop = true; else nstop = false; rc_stringlist_free(kwords); if (nstop) { rc_service_mark(service->value, RC_SERVICE_FAILED); continue; } /* If the service has crashed, skip futher checks and just stop it */ if (crashed && rc_service_daemons_crashed(service->value)) goto stop; /* If we're in the start list then don't bother stopping us */ svc1 = rc_stringlist_find(start_services, service->value); if (svc1) { if (newlevel && strcmp(runlevel, newlevel) != 0) { /* So we're in the start list. But we should * be stopped if we have a runlevel * configuration file for either the current * or next so we use the correct one. */ if (!runlevel_config(service->value,runlevel) && !runlevel_config(service->value,newlevel)) continue; } else continue; } /* We got this far. Last check is to see if any any service * that going to be started depends on us */ if (!svc1) { tmplist = rc_stringlist_new(); rc_stringlist_add(tmplist, service->value); deporder = rc_deptree_depends(deptree, types_n, tmplist, newlevel ? newlevel : runlevel, RC_DEP_STRICT | RC_DEP_TRACE); rc_stringlist_free(tmplist); svc2 = NULL; TAILQ_FOREACH(svc1, deporder, entries) { svc2 = rc_stringlist_find(start_services, svc1->value); if (svc2) break; }