diff --git a/api.c b/api.c index 042ea422..55b6138a 100644 --- a/api.c +++ b/api.c @@ -316,6 +316,11 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) result = do_handle_emit(rq.data, sizeof(rq.data)); break; + case INIT_CMD_GET_RUNLEVEL: + rq.runlevel = runlevel; + result = 0; + break; + case INIT_CMD_ACK: _d("Client failed reading ACK."); goto leave; diff --git a/finit.h b/finit.h index 512b8b11..21df1b65 100644 --- a/finit.h +++ b/finit.h @@ -53,6 +53,7 @@ #define INIT_CMD_RESTART_SVC 7 /* STOP + START service */ #define INIT_CMD_QUERY_INETD 8 #define INIT_CMD_EMIT 9 +#define INIT_CMD_GET_RUNLEVEL 10 #define INIT_CMD_NACK 254 #define INIT_CMD_ACK 255 diff --git a/helpers.c b/helpers.c index 6bae592f..4eeeed50 100644 --- a/helpers.c +++ b/helpers.c @@ -58,23 +58,6 @@ void runlevel_set(int pre, int now) endutent(); } -int runlevel_get(void) -{ - int lvl = '?'; /* Non-existing runlevel */ - struct utmp *utent; - - setutent(); - while ((utent = getutent())) { - if (utent->ut_type == RUN_LVL) { - lvl = utent->ut_pid & 0xFF; - break; - } - } - endutent(); - - return lvl - '0'; -} - /** * runlevel_string - Convert a bit encoded runlevel to .conf syntax * @levels: Bit encoded runlevels diff --git a/helpers.h b/helpers.h index 616ad77e..82cac7d5 100644 --- a/helpers.h +++ b/helpers.h @@ -62,7 +62,6 @@ do { \ #define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0) void runlevel_set (int pre, int now); -int runlevel_get (void); char *runlevel_string (int levels); int pid_alive (pid_t pid); diff --git a/inetd.c b/inetd.c old mode 100644 new mode 100755 index 5fc37e3c..59720cbe --- a/inetd.c +++ b/inetd.c @@ -167,7 +167,7 @@ static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events)) memcpy(task->args, svc->args, sizeof(task->args)); snprintf(task->desc, sizeof(task->desc), "%s Connection", svc->desc); - task->stdin = stdin; + task->stdin_fd = stdin; service_step(task); if (!svc->inetd.forking) { diff --git a/initctl.c b/initctl.c index 160fe7f2..c45343a8 100644 --- a/initctl.c +++ b/initctl.c @@ -75,6 +75,42 @@ exit: return result; } +static int runlevel_get(void) +{ + struct init_request rq; + int sd, result = 255; + + rq.cmd = INIT_CMD_GET_RUNLEVEL; + rq.magic = INIT_MAGIC; + + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = INIT_SOCKET, + }; + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + if (-1 == sd) + return -1; + + if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) + goto error; + + if (write(sd, &rq, sizeof(rq)) != sizeof(rq)) + goto error; + + if (read(sd, &rq, sizeof(rq)) != sizeof(rq)) + goto error; + + result = rq.runlevel; + goto exit; +error: + perror("Failed communicating with finit"); + result = -1; +exit: + close(sd); + return result; +} + static int toggle_debug(char *UNUSED(arg)) { struct init_request rq = { diff --git a/service.c b/service.c old mode 100644 new mode 100755 index a04b568d..e3076b8e --- a/service.c +++ b/service.c @@ -162,7 +162,6 @@ static int service_start(svc_t *svc) sigprocmask(SIG_BLOCK, &nmask, &omask); pid = fork(); - sigprocmask(SIG_SETMASK, &omask, NULL); if (pid == 0) { int i = 0; int status; @@ -171,17 +170,8 @@ static int service_start(svc_t *svc) #else int uid = getuser(svc->username); #endif - struct sigaction sa; char *args[MAX_NUM_SVC_ARGS]; - sigemptyset(&nmask); - sigaddset(&nmask, SIGCHLD); - sigprocmask(SIG_UNBLOCK, &nmask, NULL); - - /* Reset signal handlers that were set by the parent process */ - for (i = 1; i < NSIG; i++) - DFLSIG(sa, i, 0); - /* Set desired user */ if (uid >= 0) { setuid(uid); @@ -199,13 +189,34 @@ static int service_start(svc_t *svc) /* Redirect inetd socket to stdin for connection */ #ifndef INETD_DISABLED if (svc_is_inetd_conn(svc)) { - dup2(svc->stdin, STDIN_FILENO); - close(svc->stdin); + dup2(svc->stdin_fd, STDIN_FILENO); + close(svc->stdin_fd); dup2(STDIN_FILENO, STDOUT_FILENO); dup2(STDIN_FILENO, STDERR_FILENO); } else #endif - if (debug) { + if (svc->log) { + /* Open PTY to connect to logger (A pty isn't buffered like a pipe, and it eats newlines so they aren't logged) */ + int fd = posix_openpt(O_RDWR); + /* SIGCHLD is still blocked for grantpt() and fork() */ + sigprocmask(SIG_BLOCK, &nmask, NULL); + if (fd >= 0 && grantpt(fd) == 0 && unlockpt(fd) == 0) { + pid = fork(); + if (pid == 0) { + int fds = open(ptsname(fd), O_RDONLY); + close(fd); + dup2(fds, STDIN_FILENO); + + /* Reset signals */ + sig_unblock(); + + exit(execlp("logger", "logger", "-t", strlen(svc->desc) > 0 ? svc->desc : svc->cmd, (char*)NULL)); + } + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + } else if (debug) { int fd; char buf[CMD_SIZE] = ""; @@ -240,15 +251,19 @@ static int service_start(svc_t *svc) close(STDOUT_FILENO); close(STDERR_FILENO); } - } + } else #endif + if (svc->log) { + waitpid(pid, NULL, 0); + } exit(status); } + svc->pid = pid; #ifndef INETD_DISABLED if (svc_is_inetd_conn(svc) && svc->inetd.type == SOCK_STREAM) - close(svc->stdin); + close(svc->stdin_fd); #endif plugin_run_hook(HOOK_SVC_START, (void *)(uintptr_t)pid); @@ -257,6 +272,8 @@ static int service_start(svc_t *svc) result = WEXITSTATUS(complete(svc->cmd, pid)); svc->pid = 0; } + + sigprocmask(SIG_SETMASK, &omask, NULL); if (!silent) print_result(result); @@ -542,6 +559,7 @@ int service_register(int type, char *line, time_t mtime, char *username) #ifndef INETD_DISABLED int forking = 0; #endif + int log = 0; char *service = NULL, *proto = NULL, *ifaces = NULL; char *cmd, *desc, *runlevels = NULL, *cond = NULL; svc_t *svc; @@ -580,6 +598,8 @@ int service_register(int type, char *line, time_t mtime, char *username) #endif else if (cmd[0] != '/' && strchr(cmd, '/')) service = cmd; /* inetd service/proto */ + else if (!strncasecmp(cmd, "log", 3)) + log = 1; else break; @@ -640,6 +660,7 @@ int service_register(int type, char *line, time_t mtime, char *username) } } + svc->log = log; if (desc) strlcpy(svc->desc, desc + 3, sizeof(svc->desc)); diff --git a/svc.h b/svc.h old mode 100644 new mode 100755 index ed0fa9a1..dc14404a --- a/svc.h +++ b/svc.h @@ -99,7 +99,9 @@ typedef struct svc { /* For inetd services */ inetd_t inetd; - int stdin; + int stdin_fd; + + int log; /* Identity */ char username[MAX_USER_LEN];