static bool want_interactive(void) { char c; static bool gotinteractive; static bool interactive; if (rc_yesno(getenv("EINFO_QUIET"))) return false; if (!gotinteractive) { gotinteractive = true; interactive = rc_conf_yesno("rc_interactive"); } if (!interactive) return false; c = read_key(false); return (c == 'I' || c == 'i') ? true : false; }
static void do_sysinit() { struct utsname uts; const char *sys; /* exec init-early.sh if it exists * This should just setup the console to use the correct * font. Maybe it should setup the keyboard too? */ if (exists(INITEARLYSH)) run_program(INITEARLYSH); uname(&uts); printf("\n %sOpenRC %s" VERSION "%s is starting up %s", ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE), ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET)); #ifdef BRANDING printf(BRANDING " (%s)", uts.machine); #else printf("%s %s (%s)", uts.sysname, uts.release, uts.machine); #endif if ((sys = rc_sys())) printf(" [%s]", sys); printf("%s\n\n", ecolor(ECOLOR_NORMAL)); if (!rc_yesno(getenv ("EINFO_QUIET")) && rc_conf_yesno("rc_interactive")) printf("Press %sI%s to enter interactive boot mode\n\n", ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL)); setenv("RC_RUNLEVEL", RC_LEVEL_SYSINIT, 1); run_program(INITSH); /* init may have mounted /proc so we can now detect or real * sys */ if ((sys = rc_sys())) setenv("RC_SYS", sys, 1); }
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; } }
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; }