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; }
static int parse_signal(const char *sig) { typedef struct signalpair { const char *name; int signal; } SIGNALPAIR; static const SIGNALPAIR signallist[] = { { "ABRT", SIGABRT }, { "ALRM", SIGALRM }, { "FPE", SIGFPE }, { "HUP", SIGHUP }, { "ILL", SIGILL }, { "INT", SIGINT }, { "KILL", SIGKILL }, { "PIPE", SIGPIPE }, { "QUIT", SIGQUIT }, { "SEGV", SIGSEGV }, { "TERM", SIGTERM }, { "USR1", SIGUSR1 }, { "USR2", SIGUSR2 }, { "CHLD", SIGCHLD }, { "CONT", SIGCONT }, { "STOP", SIGSTOP }, { "TSTP", SIGTSTP }, { "TTIN", SIGTTIN }, { "TTOU", SIGTTOU }, { "NULL", 0 }, }; unsigned int i = 0; const char *s; if (!sig || *sig == '\0') return -1; if (sscanf(sig, "%u", &i) == 1) { if (i < NSIG) return i; eerrorx("%s: `%s' is not a valid signal", applet, sig); } if (strncmp(sig, "SIG", 3) == 0) s = sig + 3; else s = NULL; for (i = 0; i < ARRAY_SIZE(signallist); ++i) if (strcmp(sig, signallist[i].name) == 0 || (s && strcmp(s, signallist[i].name) == 0)) return signallist[i].signal; eerrorx("%s: `%s' is not a valid signal", applet, sig); /* NOTREACHED */ }
int main(int argc, char **argv) { int opt, sflag = 0, wflag = 0; const char *file = RC_SHUTDOWNTIME; struct stat sb; struct timeval tv; applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 's': sflag = 1; break; case 'w': wflag = 1; break; case_RC_COMMON_GETOPT } } if (optind < argc) file = argv[optind++]; if (sflag) { if (stat(file, &sb) == -1) { opt = open(file, O_WRONLY | O_CREAT, 0644); if (opt == -1) eerrorx("swclock: open: %s", strerror(errno)); close(opt); } else if (utime(file, NULL) == -1) eerrorx("swclock: utime: %s", strerror(errno)); return 0; } if (stat(file, &sb) == -1) { if (wflag != 0 && errno == ENOENT) ewarn("swclock: `%s': %s", file, strerror(errno)); else eerrorx("swclock: `%s': %s", file, strerror(errno)); return 0; } tv.tv_sec = sb.st_mtime; tv.tv_usec = 0; if (settimeofday(&tv, NULL) == -1) eerrorx("swclock: settimeofday: %s", strerror(errno)); return 0; }
static void cancel_shutdown(void) { pid_t pid; pid = get_pid(applet, shutdown_pid); if (pid <= 0) eerrorx("%s: Unable to cancel shutdown", applet); if (kill(pid, SIGTERM) != -1) einfo("%s: shutdown canceled", applet); else eerrorx("%s: Unable to cancel shutdown", applet); }
static int do_mount(struct ENT *ent) { char *argv[8]; pid_t pid; int status; argv[0] = UNCONST("mount"); argv[1] = UNCONST("-o"); argv[2] = ENT_OPTS(*ent); argv[3] = UNCONST("-t"); argv[4] = ENT_TYPE(*ent); argv[5] = ENT_BLOCKDEVICE(*ent); argv[6] = ENT_FILE(*ent); argv[7] = NULL; switch (pid = vfork()) { case -1: eerrorx("%s: vfork: %s", applet, strerror(errno)); /* NOTREACHED */ case 0: execvp(argv[0], argv); eerror("%s: execv: %s", applet, strerror(errno)); _exit(EXIT_FAILURE); /* NOTREACHED */ default: waitpid(pid, &status, 0); if (WIFEXITED(status)) return WEXITSTATUS(status); else return -1; /* NOTREACHED */ } }
/* Authenticates the user, returns 0 on success, 1 on fail */ static int check_auth() { struct passwd *pw; uid_t uid; #ifdef HAVE_AUDIT uid = audit_getloginuid(); if (uid == (uid_t) -1) uid = getuid(); #else uid = getuid(); #endif pw = getpwuid(uid); if (!pw) { eerror("cannot find your entry in the passwd file."); return (-1); } printf("Authenticating %s.\n", pw->pw_name); /* do the actual check */ if (check_password(pw->pw_name) == 0) { return 0; } eerrorx("Authentication failed for %s", pw->pw_name); return 1; }
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); }
int main(int argc, char **argv) { bool ok = false; char *service; char *exec; int idx = 0; RC_SERVICE state, bit; applet = basename_c(argv[0]); if (argc > 1) service = argv[1]; else service = getenv("RC_SVCNAME"); if (service == NULL || *service == '\0') eerrorx("%s: no service specified", applet); state = rc_service_state(service); bit = lookup_service_state(applet); if (bit) { ok = (state & bit); } else if (strcmp(applet, "service_started_daemon") == 0) { service = getenv("RC_SVCNAME"); exec = argv[1]; if (argc > 3) { service = argv[1]; exec = argv[2]; sscanf(argv[3], "%d", &idx); } else if (argc == 3) { if (sscanf(argv[2], "%d", &idx) != 1) { service = argv[1]; exec = argv[2]; } } ok = rc_service_started_daemon(service, exec, NULL, idx); } else if (strcmp(applet, "service_crashed") == 0) { ok = (_rc_can_find_pids() && rc_service_daemons_crashed(service) && errno != EACCES); } else eerrorx("%s: unknown applet", applet); return ok ? EXIT_SUCCESS : EXIT_FAILURE; }
static void run_program(const char *prog) { struct sigaction sa; sigset_t full; sigset_t old; pid_t pid; /* We need to block signals until we have forked */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigfillset(&full); sigprocmask(SIG_SETMASK, &full, &old); pid = fork(); if (pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); if (pid == 0) { /* Restore default handlers */ sigaction(SIGCHLD, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGWINCH, &sa, NULL); /* Unmask signals */ sigprocmask(SIG_SETMASK, &old, NULL); if (termios_orig) tcsetattr(STDIN_FILENO, TCSANOW, termios_orig); execl(prog, prog, (char *)NULL); eerror("%s: unable to exec `%s': %s", applet, prog, strerror(errno)); _exit(EXIT_FAILURE); } /* Unmask signals and wait for child */ sigprocmask(SIG_SETMASK, &old, NULL); if (rc_waitpid(pid) == -1) eerrorx("%s: failed to exec `%s'", applet, prog); }
int main(int argc, char **argv) { char *arg = NULL; int opt; bool dryrun = false; RC_STRINGLIST *omits = rc_stringlist_new(); int sig = SIGKILL; char *here; char *token; /* Ensure that we are only quiet when explicitly told to be */ unsetenv("EINFO_QUIET"); applet = basename_c(argv[0]); rc_stringlist_addu(omits, "1"); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'd': dryrun = true; break; case 'o': here = optarg; while ((token = strsep(&here, ",;:"))) { if ((pid_t) atoi(token) > 0) rc_stringlist_addu(omits, token); else { eerror("Invalid omit pid value %s", token); usage(EXIT_FAILURE); } } break; case_RC_COMMON_GETOPT } } if (argc > optind) { arg = argv[optind]; sig = atoi(arg); if (sig <= 0 || sig > 31) { rc_stringlist_free(omits); eerror("Invalid signal %s", arg); usage(EXIT_FAILURE); } } openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON); if (mount_proc() != 0) { rc_stringlist_free(omits); eerrorx("Unable to mount /proc file system"); } signal_processes(sig, omits, dryrun); rc_stringlist_free(omits); return 0; }
static void handle_signal(int sig) { int status; int serrno = errno; char *signame = NULL; switch (sig) { case SIGINT: if (!signame) xasprintf(&signame, "SIGINT"); /* FALLTHROUGH */ case SIGTERM: if (!signame) xasprintf(&signame, "SIGTERM"); /* FALLTHROUGH */ case SIGQUIT: if (!signame) xasprintf(&signame, "SIGQUIT"); eerrorx("%s: caught %s, aborting", applet, signame); /* NOTREACHED */ case SIGCHLD: for (;;) { if (waitpid(-1, &status, WNOHANG) < 0) { if (errno != ECHILD) eerror("%s: waitpid: %s", applet, strerror(errno)); break; } } break; default: eerror("%s: caught unknown signal %d", applet, sig); } /* free signame */ free(signame); /* Restore errno */ errno = serrno; }
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)); }
static void parse_schedule(const char *string, int timeout) { char buffer[20]; const char *slash; int count = 0; SCHEDULEITEM *repeatat = NULL; size_t len; SCHEDULEITEM *item; if (string) for (slash = string; *slash; slash++) if (*slash == '/') count++; free_schedulelist(); if (count == 0) { item = xmalloc(sizeof(*item)); item->type = SC_SIGNAL; item->value = timeout; item->gotoitem = NULL; TAILQ_INSERT_TAIL(&schedule, item, entries); item = xmalloc(sizeof(*item)); item->type = SC_TIMEOUT; item->gotoitem = NULL; TAILQ_INSERT_TAIL(&schedule, item, entries); if (string) { if (sscanf(string, "%d", &item->value) != 1) eerrorx("%s: invalid timeout in schedule", applet); } else item->value = 5; return; } while (string != NULL) { if ((slash = strchr(string, '/'))) len = slash - string; else len = strlen(string); if (len >= (ptrdiff_t)sizeof(buffer)) eerrorx("%s: invalid schedule item, far too long", applet); memcpy(buffer, string, len); buffer[len] = 0; string = slash ? slash + 1 : NULL; item = parse_schedule_item(buffer); TAILQ_INSERT_TAIL(&schedule, item, entries); if (item->type == SC_FOREVER) { if (repeatat) eerrorx("%s: invalid schedule, `forever' " "appears more than once", applet); repeatat = item; continue; } } if (repeatat) { item = xmalloc(sizeof(*item)); item->type = SC_GOTO; item->value = 0; item->gotoitem = repeatat; TAILQ_INSERT_TAIL(&schedule, item, entries); } return; }
static void handle_signal(int sig) { int serrno = errno; char signame[10] = { '\0' }; pid_t pid; RC_PID *pi; int status = 0; struct winsize ws; sigset_t sset; switch (sig) { case SIGCHLD: do { pid = waitpid(-1, &status, WNOHANG); if (pid < 0) { if (errno != ECHILD) eerror("waitpid: %s", strerror(errno)); return; } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); /* Remove that pid from our list */ if (pid > 0) remove_pid(pid); break; case SIGWINCH: if (rc_logger_tty >= 0) { ioctl(STDIN_FILENO, TIOCGWINSZ, &ws); ioctl(rc_logger_tty, TIOCSWINSZ, &ws); } break; case SIGINT: if (!signame[0]) snprintf(signame, sizeof(signame), "SIGINT"); /* FALLTHROUGH */ case SIGTERM: if (!signame[0]) snprintf(signame, sizeof(signame), "SIGTERM"); /* FALLTHROUGH */ case SIGQUIT: if (!signame[0]) snprintf(signame, sizeof(signame), "SIGQUIT"); eerrorx("%s: caught %s, aborting", applet, signame); /* NOTREACHED */ case SIGUSR1: eerror("rc: Aborting!"); /* Block child signals */ sigemptyset(&sset); sigaddset(&sset, SIGCHLD); sigprocmask(SIG_BLOCK, &sset, NULL); /* Kill any running services we have started */ LIST_FOREACH(pi, &service_pids, entries) kill(pi->pid, SIGTERM); /* Notify plugins we are aborting */ rc_plugin_run(RC_HOOK_ABORT, NULL); exit(EXIT_FAILURE); /* NOTREACHED */ default: eerror("%s: caught unknown signal %d", applet, sig); } /* Restore errno */ errno = serrno; }
int main(int argc, char **argv) { int opt; char *service; RC_STRINGLIST *list; RC_STRING *s; RC_SERVICE state; bool if_crashed = false; bool if_exists = false; bool if_inactive = false; bool if_notstarted = false; bool if_started = false; bool if_stopped = false; applet = basename_c(argv[0]); /* Ensure that we are only quiet when explicitly told to be */ unsetenv("EINFO_QUIET"); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'd': setenv("RC_DEBUG", "yes", 1); break; case 'D': setenv("RC_NODEPS", "yes", 1); break; case 'e': service = rc_service_resolve(optarg); opt = service ? EXIT_SUCCESS : EXIT_FAILURE; free(service); return opt; /* NOTREACHED */ case 'c': if_crashed = true; break; case 'i': if_exists = true; break; case 'I': if_inactive = true; break; case 'N': if_notstarted = true; break; case 'l': list = rc_services_in_runlevel(NULL); if (TAILQ_FIRST(list) == NULL) return EXIT_FAILURE; rc_stringlist_sort(&list); TAILQ_FOREACH(s, list, entries) printf("%s\n", s->value); rc_stringlist_free(list); return EXIT_SUCCESS; /* NOTREACHED */ case 'r': service = rc_service_resolve(optarg); if (service == NULL) return EXIT_FAILURE; printf("%s\n", service); free(service); return EXIT_SUCCESS; /* NOTREACHED */ case 's': if_started = true; break; case 'S': if_stopped = true; break; case 'Z': setenv("IN_DRYRUN", "yes", 1); break; case_RC_COMMON_GETOPT } } argc -= optind; argv += optind; if (*argv == NULL) eerrorx("%s: you need to specify a service", applet); if ((service = rc_service_resolve(*argv)) == NULL) { if (if_exists) return 0; eerrorx("%s: service `%s' does not exist", applet, *argv); } state = rc_service_state(*argv); if (if_crashed && ! (rc_service_daemons_crashed(*argv) && errno != EACCES)) return 0; if (if_inactive && ! (state & RC_SERVICE_INACTIVE)) return 0; if (if_notstarted && (state & RC_SERVICE_STARTED)) return 0; if (if_started && ! (state & RC_SERVICE_STARTED)) return 0; if (if_stopped && ! (state & RC_SERVICE_STOPPED)) return 0; *argv = service; execv(*argv, argv); eerrorx("%s: %s", applet, strerror(errno)); /* NOTREACHED */ }
void selinux_setup(char **argv) { char *new_context = NULL; char *curr_context = NULL; context_t curr_con; char *curr_t = NULL; char *run_init_t = NULL; /* Return, if selinux is disabled. */ if (is_selinux_enabled() < 1) { return; } if (read_context_file(RUN_INIT_FILE, &run_init_t) != 0) { /* assume a reasonable default, rather than bailing out */ run_init_t = xstrdup("run_init_t"); ewarn("Assuming SELinux run_init type is %s", run_init_t); } /* Get our current context. */ if (getcon(&curr_context) < 0) { if (errno == ENOENT) { /* should only hit this if proc is not mounted. this * happens on Gentoo right after init starts, when * the init script processing starts. */ goto out; } else { perror("getcon"); exit(1); } } /* extract the type from the context */ curr_con = context_new(curr_context); if (!curr_con) { free(curr_context); goto out; } curr_t = context_type_get(curr_con); if (!curr_t) { context_free(curr_con); free(curr_context); goto out; } curr_t = xstrdup(curr_t); /* dont need them anymore so free() now */ context_free(curr_con); free(curr_context); /* if we are not in the run_init domain, we should not do anything */ if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) { goto out; } free(curr_t); free(run_init_t); if (check_auth() != 0) { eerrorx("Authentication failed."); } /* Get the context for the script to be run in. */ if (read_context_file(INITRC_FILE, &new_context) != 0) { /* assume a reasonable default, rather than bailing out */ new_context = xstrdup("system_u:system_r:initrc_t"); ewarn("Assuming SELinux initrc context is %s", new_context); } /* Set the new context */ if (setexeccon(new_context) < 0) { eerrorx("Could not set SELinux exec context to %s.", new_context); } free(new_context); /* * exec will recycle ptys so try and use open_init_pty if it exists * which will open the pty with initrc_devpts_t, if it doesnt exist, * fall back to plain exec */ if (!access("/usr/sbin/open_init_pty", X_OK)) { if (execvp("/usr/sbin/open_init_pty", argv)) { perror("execvp"); exit(-1); } } else if (execvp(argv[1], argv + 1)) { perror("execvp"); exit(-1); } out: free(run_init_t); free(curr_t); }
void rc_logger_open(const char *level) { int slave_tty; struct termios tt; struct winsize ws; char *buffer; struct pollfd fd[2]; int s = 0; size_t bytes; int i; FILE *log = NULL; 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(LOGFILE, "a"))) write_time(log, "started"); else { free(logbuf); logbuf_size = BUFSIZ * 10; logbuf = xmalloc(sizeof (char) * logbuf_size); logbuf_len = 0; } buffer = xmalloc(sizeof (char) * BUFSIZ); 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; } free(buffer); if (logbuf) { if ((log = fopen(LOGFILE, "a"))) { write_time(log, "started"); write_log(fileno(log), logbuf, logbuf_len); } free(logbuf); } if (log) { write_time(log, "stopped"); fclose(log); } /* Try and cat our new logfile to a more permament location and then punt it */ if (system(MOVELOG) == -1) eerror("system: %s: %s", MOVELOG, strerror(errno)); 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; } }
int main(int argc, char **argv) { int opt; bool start = false; bool stop = false; char *exec = NULL; char *pidfile = NULL; char *home = NULL; int tid = 0; pid_t child_pid, pid; char *svcname = getenv("RC_SVCNAME"); char *tmp; char *p; char *token; int i; char exec_file[PATH_MAX]; struct passwd *pw; struct group *gr; FILE *fp; mode_t numask = 022; applet = basename_c(argv[0]); atexit(cleanup); signal_setup(SIGINT, handle_signal); signal_setup(SIGQUIT, handle_signal); signal_setup(SIGTERM, handle_signal); openlog(applet, LOG_PID, LOG_DAEMON); 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 'S': /* --start */ start = true; 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 'k': if (parse_mode(&numask, optarg)) eerrorx("%s: invalid mode `%s'", applet, optarg); break; case 'p': /* --pidfile <pid-file> */ pidfile = optarg; break; case 'r': /* --chroot /new/root */ ch_root = optarg; break; 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 '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 } if (!pidfile) eerrorx("%s: --pidfile must be specified", applet); endpwent(); argc -= optind; argv += optind; exec = *argv; if (start) { if (!exec) eerrorx("%s: nothing to start", 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)) eerrorx("%s: %s does not exist", applet, *exec_file ? exec_file : exec); if (stop) { pid = get_pid(pidfile); if (pid == -1) i = pid; else i = kill(pid, SIGTERM); if (i != 0) /* We failed to stop something */ exit(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); } pid = get_pid(pidfile); if (pid != -1) if (kill(pid, 0) == 0) eerrorx("%s: %s is already running", applet, exec); einfov("Detaching to start `%s'", exec); eindentv(); /* Remove existing pidfile */ if (pidfile) unlink(pidfile); /* * Make sure we can write a pid file */ fp = fopen(pidfile, "w"); if (! fp) eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); fclose(fp); child_pid = fork(); if (child_pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); /* first parent process, do nothing. */ if (child_pid != 0) exit(EXIT_SUCCESS); child_pid = fork(); if (child_pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); if (child_pid != 0) { /* this is the supervisor */ umask(numask); #ifdef TIOCNOTTY tty_fd = open("/dev/tty", O_RDWR); #endif devnull_fd = open("/dev/null", O_RDWR); fp = fopen(pidfile, "w"); if (! fp) eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); fprintf(fp, "%d\n", getpid()); fclose(fp); /* * Supervisor main loop */ i = 0; while (!exiting) { wait(&i); if (exiting) { syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); kill(child_pid, SIGTERM); } else { if (WIFEXITED(i)) syslog(LOG_INFO, "%s, pid %d, exited with return code %d", exec, child_pid, WEXITSTATUS(i)); else if (WIFSIGNALED(i)) syslog(LOG_INFO, "%s, pid %d, terminated by signal %d", exec, child_pid, WTERMSIG(i)); child_pid = fork(); if (child_pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); if (child_pid == 0) child_process(exec, argv); } } if (svcname) rc_service_daemon_set(svcname, exec, (const char * const *) argv, pidfile, true); exit(EXIT_SUCCESS); } else if (child_pid == 0) child_process(exec, argv); }
int main(int argc, char **argv) { int opt; int cmd_count = 0; applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'd': do_wtmp = false; break; case 'D': do_dryrun = true; break; case 'H': do_halt = true; cmd_count++; break; case 'K': do_kexec = true; cmd_count++; break; case 'p': do_poweroff = true; cmd_count++; break; case 'R': do_reexec = true; cmd_count++; break; case 'r': do_reboot = true; cmd_count++; break; case 's': do_single = true; cmd_count++; break; case 'w': do_wtmp_only = true; cmd_count++; break; case_RC_COMMON_GETOPT } } if (geteuid() != 0 && ! do_dryrun) eerrorx("%s: you must be root\n", applet); if (cmd_count != 1) { eerror("%s: %s\n", applet, exclusive); usage(EXIT_FAILURE); } if (do_halt) send_cmd("halt"); else if (do_kexec) send_cmd("kexec"); else if (do_poweroff) send_cmd("poweroff"); else if (do_reboot) send_cmd("reboot"); else if (do_reexec) send_cmd("reexec"); else if (do_wtmp_only) log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); else if (do_single) send_cmd("single"); return 0; }
int rc_depend(int argc, char **argv) { RC_STRINGLIST *list; RC_STRINGLIST *types; RC_STRINGLIST *services; RC_STRINGLIST *depends; RC_STRING *s; RC_DEPTREE *deptree = NULL; int options = RC_DEP_TRACE, update = 0; bool first = true; char *runlevel = xstrdup(getenv("RC_RUNLEVEL")); int opt; char *token; types = rc_stringlist_new(); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'a': options |= RC_DEP_START; break; case 'o': options |= RC_DEP_STOP; break; case 's': options |= RC_DEP_STRICT; break; case 't': while ((token = strsep(&optarg, ","))) rc_stringlist_add(types, token); break; case 'u': update = 1; break; case 'T': options &= RC_DEP_TRACE; break; case_RC_COMMON_GETOPT } } if (!(deptree = _rc_deptree_load(update, NULL))) eerrorx("failed to load deptree"); if (!runlevel) runlevel = rc_runlevel_get(); services = rc_stringlist_new(); while (optind < argc) { list = rc_stringlist_new(); rc_stringlist_add(list, argv[optind]); errno = 0; depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0); if (!depends && errno == ENOENT) eerror("no dependency info for service `%s'", argv[optind]); else rc_stringlist_add(services, argv[optind]); rc_stringlist_free(depends); rc_stringlist_free(list); optind++; } if (!TAILQ_FIRST(services)) { rc_stringlist_free(services); rc_stringlist_free(types); rc_deptree_free(deptree); free(runlevel); if (update) return EXIT_SUCCESS; eerrorx("no services specified"); } /* If we don't have any types, then supply some defaults */ if (!TAILQ_FIRST(types)) { rc_stringlist_add(types, "ineed"); rc_stringlist_add(types, "iuse"); } depends = rc_deptree_depends(deptree, types, services, runlevel, options); if (TAILQ_FIRST(depends)) { TAILQ_FOREACH(s, depends, entries) { if (first) first = false; else printf (" "); printf ("%s", s->value); } printf ("\n"); } rc_stringlist_free(types); rc_stringlist_free(services); rc_stringlist_free(depends); rc_deptree_free(deptree); free(runlevel); return EXIT_SUCCESS; }
int main(int argc, char **argv) { char *ch = NULL; int opt; int cmd_count = 0; int hour = 0; int min = 0; int shutdown_delay = 0; struct sigaction sa; struct tm *lt; time_t tv; bool need_warning = false; char *msg = NULL; char *state = NULL; char *time_arg = NULL; FILE *fp; applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'c': do_cancel = true; cmd_count++; break; case 'd': do_wtmp = false; break; case 'D': do_dryrun = true; break; case 'H': do_halt = true; xasprintf(&state, "%s", "halt"); cmd_count++; break; case 'K': do_kexec = true; xasprintf(&state, "%s", "reboot"); cmd_count++; break; case 'p': do_poweroff = true; xasprintf(&state, "%s", "power off"); cmd_count++; break; case 'R': do_reexec = true; cmd_count++; break; case 'r': do_reboot = true; xasprintf(&state, "%s", "reboot"); cmd_count++; break; case 's': do_single = true; xasprintf(&state, "%s", "go down for maintenance"); cmd_count++; break; case 'w': do_wtmp_only = true; cmd_count++; break; case_RC_COMMON_GETOPT } } if (geteuid() != 0) eerrorx("%s: you must be root\n", applet); if (cmd_count != 1) { eerror("%s: %s\n", applet, exclusive); usage(EXIT_FAILURE); } if (do_cancel) { cancel_shutdown(); exit(EXIT_SUCCESS); } else if (do_reexec) { send_cmd("reexec"); exit(EXIT_SUCCESS); } else if (do_wtmp_only) { log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); exit(EXIT_SUCCESS); } if (optind >= argc) { eerror("%s: No shutdown time specified", applet); usage(EXIT_FAILURE); } time_arg = argv[optind]; if (*time_arg == '+') time_arg++; if (strcasecmp(time_arg, "now") == 0) strcpy(time_arg, "0"); for (ch=time_arg; *ch; ch++) if ((*ch < '0' || *ch > '9') && *ch != ':') { eerror("%s: invalid time %s", applet, time_arg); usage(EXIT_FAILURE); } if (strchr(time_arg, ':')) { if ((sscanf(time_arg, "%2d:%2d", &hour, &min) != 2) || (hour > 23) || (min > 59)) { eerror("%s: invalid time %s", applet, time_arg); usage(EXIT_FAILURE); } time(&tv); lt = localtime(&tv); shutdown_delay = (hour * 60 + min) - (lt->tm_hour * 60 + lt->tm_min); if (shutdown_delay < 0) shutdown_delay += 1440; } else { shutdown_delay = atoi(time_arg); } fp = fopen(shutdown_pid, "w"); if (!fp) eerrorx("%s: fopen `%s': %s", applet, shutdown_pid, strerror(errno)); fprintf(fp, "%d\n", getpid()); fclose(fp); openlog(applet, LOG_PID, LOG_DAEMON); memset(&sa, 0, sizeof(sa)); sa.sa_handler = stop_shutdown; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); while (shutdown_delay > 0) { need_warning = false; if (shutdown_delay > 180) need_warning = (shutdown_delay % 60 == 0); else if (shutdown_delay > 60) need_warning = (shutdown_delay % 30 == 0); else if (shutdown_delay > 10) need_warning = (shutdown_delay % 15 == 0); else need_warning = true; if (shutdown_delay <= 5) create_nologin(shutdown_delay); if (need_warning) { xasprintf(&msg, "\rThe system will %s in %d minutes\r\n", state, shutdown_delay); broadcast(msg); free(msg); } sleep_no_interrupt(60); shutdown_delay--; } xasprintf(&msg, "\rThe system will %s now\r\n", state); broadcast(msg); syslog(LOG_NOTICE, "The system will %s now", state); unlink(nologin_file); unlink(shutdown_pid); if (do_halt) send_cmd("halt"); else if (do_kexec) send_cmd("kexec"); else if (do_poweroff) send_cmd("poweroff"); else if (do_reboot) send_cmd("reboot"); else if (do_single) send_cmd("single"); return 0; }
int fstabinfo(int argc, char **argv) { struct ENT *ent; int result = EXIT_SUCCESS; char *token; int i, p; int opt; int output = OUTPUT_FILE; RC_STRINGLIST *files = rc_stringlist_new(); RC_STRING *file, *file_np; bool filtered = false; #ifdef HAVE_GETMNTENT FILE *fp; #endif /* Ensure that we are only quiet when explicitly told to be */ unsetenv("EINFO_QUIET"); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'M': output = OUTPUT_MOUNT; break; case 'R': output = OUTPUT_REMOUNT; break; case 'b': output = OUTPUT_BLOCKDEV; break; case 'o': output = OUTPUT_OPTIONS; break; case 'm': output = OUTPUT_MOUNTARGS; break; case 'p': switch (optarg[0]) { case '=': case '<': case '>': if (sscanf(optarg + 1, "%d", &i) != 1) eerrorx("%s: invalid passno %s", argv[0], optarg + 1); filtered = true; opt = optarg[0]; START_ENT; while ((ent = GET_ENT)) { if (strcmp(ENT_FILE(ent), "none") == 0) continue; p = ENT_PASS(ent); if ((opt == '=' && i == p) || (opt == '<' && i > p && p != 0) || (opt == '>' && i < p && p != 0)) rc_stringlist_add(files, ENT_FILE(ent)); } END_ENT; break; default: rc_stringlist_add(files, optarg); output = OUTPUT_PASSNO; break; } break; case 't': filtered = true; while ((token = strsep(&optarg, ","))) { START_ENT; while ((ent = GET_ENT)) if (strcmp(token, ENT_TYPE(ent)) == 0) rc_stringlist_add(files, ENT_FILE(ent)); END_ENT; } break; case_RC_COMMON_GETOPT } } if (optind < argc) { if (TAILQ_FIRST(files)) { TAILQ_FOREACH_SAFE(file, files, entries, file_np) { for (i = optind; i < argc; i++) if (strcmp(argv[i], file->value) == 0) break; if (i >= argc) rc_stringlist_delete(files, file->value); } } else { while (optind < argc) rc_stringlist_add(files, argv[optind++]); } } else if (!filtered) {
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; } }
int checkpath(int argc, char **argv) { int opt; uid_t uid = geteuid(); gid_t gid = getgid(); mode_t mode = 0; struct passwd *pw = NULL; struct group *gr = NULL; inode_t type = inode_unknown; int retval = EXIT_SUCCESS; bool trunc = false; bool chowner = false; bool writable = false; bool selinux_on = false; while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { case 'D': trunc = true; case 'd': type = inode_dir; break; case 'F': trunc = true; case 'f': type = inode_file; break; case 'p': type = inode_fifo; break; case 'm': if (parse_mode(&mode, optarg) != 0) eerrorx("%s: invalid mode `%s'", applet, optarg); break; case 'o': chowner = true; if (parse_owner(&pw, &gr, optarg) != 0) eerrorx("%s: owner `%s' not found", applet, optarg); break; case 'W': writable = true; break; case_RC_COMMON_GETOPT } } if (optind >= argc) usage(EXIT_FAILURE); if (writable && type != inode_unknown) eerrorx("%s: -W cannot be specified along with -d, -f or -p", applet); if (pw) { uid = pw->pw_uid; gid = pw->pw_gid; } if (gr) gid = gr->gr_gid; if (selinux_util_open() == 1) selinux_on = true; while (optind < argc) { if (writable) exit(!is_writable(argv[optind])); if (do_check(argv[optind], uid, gid, mode, type, trunc, chowner, selinux_on)) retval = EXIT_FAILURE; optind++; } if (selinux_on) selinux_util_close(); return retval; }
static void child_process(char *exec, char **argv) { RC_STRINGLIST *env_list; RC_STRING *env; int i; char *p; char *token; size_t len; char *newpath; char *np; char **c; char cmdline[PATH_MAX]; #ifdef HAVE_PAM pam_handle_t *pamh = NULL; int pamr; const char *const *pamenv = NULL; #endif setsid(); if (nicelevel) { if (setpriority(PRIO_PROCESS, getpid(), nicelevel) == -1) eerrorx("%s: setpriority %d: %s", applet, nicelevel, strerror(errno)); } if (ionicec != -1 && ioprio_set(1, getpid(), 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)); #ifdef HAVE_PAM if (changeuser != NULL) { pamr = pam_start("supervise-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)); } dup2(stdin_fd, STDIN_FILENO); if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET"))) dup2(stdout_fd, STDOUT_FILENO); if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET"))) dup2(stderr_fd, STDERR_FILENO); for (i = getdtablesize() - 1; i >= 3; --i) close(i); *cmdline = '\0'; c = argv; while (*c) { strcat(cmdline, *c); strcat(cmdline, " "); c++; } syslog(LOG_INFO, "Running command line: %s", cmdline); 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)); }