void conf_parse_cond(svc_t *svc, char *cond) { size_t i = 0; char *ptr; if (!svc) { _e("Invalid service pointer"); return; } /* By default we assume UNIX daemons support SIGHUP */ if (svc_is_daemon(svc)) svc->sighup = 1; if (!cond) return; /* First character must be '!' if SIGHUP is not supported. */ ptr = cond; if (ptr[i] == '!') { svc->sighup = 0; ptr++; } while (ptr[i] != '>' && ptr[i] != 0) i++; ptr[i] = 0; if (i >= sizeof(svc->cond)) { logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr); return; } strlcpy(svc->cond, ptr, sizeof(svc->cond)); }
/* Remember: service_enabled() must be called before calling service_start() */ int service_start(svc_t *svc) { int respawn, sd = 0; pid_t pid; sigset_t nmask, omask; if (!svc) return 1; respawn = svc->pid != 0; /* Don't try and start service if it doesn't exist. */ if (!fexist(svc->cmd) && !svc->inetd.cmd) { if (verbose) { char msg[80]; snprintf(msg, sizeof(msg), "Service %s does not exist!", svc->cmd); print_desc("", msg); print_result(1); } return 1; } /* Ignore if finit is SIGSTOP'ed */ if (is_norespawn()) return 0; #ifndef INETD_DISABLED if (svc_is_inetd(svc)) { char ifname[IF_NAMESIZE] = "UNKNOWN"; sd = svc->inetd.watcher.fd; if (svc->inetd.type == SOCK_STREAM) { /* Open new client socket from server socket */ sd = accept(sd, NULL, NULL); if (sd < 0) { FLOG_PERROR("Failed accepting inetd service %d/tcp", svc->inetd.port); return 1; } _d("New client socket %d accepted for inetd service %d/tcp", sd, svc->inetd.port); /* Find ifname by means of getsockname() and getifaddrs() */ inetd_stream_peek(sd, ifname); } else { /* SOCK_DGRAM */ /* Find ifname by means of IP_PKTINFO sockopt --> ifindex + if_indextoname() */ inetd_dgram_peek(sd, ifname); } if (!inetd_is_allowed(&svc->inetd, ifname)) { FLOG_INFO("Service %s on port %d not allowed from interface %s.", svc->inetd.name, svc->inetd.port, ifname); if (svc->inetd.type == SOCK_STREAM) close(sd); return 1; } FLOG_INFO("Starting inetd service %s for requst from iface %s ...", svc->inetd.name, ifname); } else #endif if (verbose) { if (svc_is_daemon(svc)) print_desc("", svc->desc); else if (!respawn) print_desc("Starting ", svc->desc); } /* Block sigchild while forking. */ sigemptyset(&nmask); sigaddset(&nmask, SIGCHLD); sigprocmask(SIG_BLOCK, &nmask, &omask); pid = fork(); sigprocmask(SIG_SETMASK, &omask, NULL); if (pid == 0) { int i = 0; int status; #ifdef ENABLE_STATIC int uid = 0; /* XXX: Fix better warning that dropprivs is disabled. */ #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); /* Set default path for regular users */ if (uid > 0) setenv("PATH", _PATH_DEFPATH, 1); } /* Serve copy of args to process in case it modifies them. */ for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++) args[i] = svc->args[i]; args[i] = NULL; /* Redirect inetd socket to stdin for service */ if (svc_is_inetd(svc)) { /* sd set previously */ dup2(sd, STDIN_FILENO); close(sd); dup2(STDIN_FILENO, STDOUT_FILENO); dup2(STDIN_FILENO, STDERR_FILENO); } else if (debug) { int fd; char buf[CMD_SIZE] = ""; fd = open(CONSOLE, O_WRONLY | O_APPEND); if (-1 != fd) { dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } for (i = 0; i < MAX_NUM_SVC_ARGS && args[i]; i++) { char arg[MAX_ARG_LEN]; snprintf(arg, sizeof(arg), "%s ", args[i]); if (strlen(arg) < (sizeof(buf) - strlen(buf))) strcat(buf, arg); } _e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf); } if (svc->inetd.cmd) status = svc->inetd.cmd(svc->inetd.type); else status = execv(svc->cmd, args); /* XXX: Maybe use execve() to be able to launch scripts? */ if (svc_is_inetd(svc)) { if (svc->inetd.type == SOCK_STREAM) { close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } } exit(status); } svc->pid = pid; if (svc_is_inetd(svc)) { if (svc->inetd.type == SOCK_STREAM) close(sd); } else { int result; if (SVC_TYPE_RUN == svc->type) result = WEXITSTATUS(complete(svc->cmd, pid)); else if (!respawn) result = svc->pid > 1 ? 0 : 1; else result = 0; if (verbose) print_result(result); } return 0; }