1
0
Fork 0
mirror of https://github.com/pygos/init.git synced 2024-11-14 15:57:10 +01:00

Compare commits

..

No commits in common. "master" and "v0.10" have entirely different histories.

28 changed files with 460 additions and 233 deletions

View file

@ -3,6 +3,12 @@ shutdown_CPPFLAGS = $(AM_CPPFLAGS)
shutdown_CFLAGS = $(AM_CFLAGS) shutdown_CFLAGS = $(AM_CFLAGS)
shutdown_LDFLAGS = $(AM_LDFLAGS) shutdown_LDFLAGS = $(AM_LDFLAGS)
runsvc_SOURCES = cmd/runsvc/runsvc.c cmd/runsvc/env.c cmd/runsvc/runsvc.h
runsvc_CPPFLAGS = $(AM_CPPFLAGS)
runsvc_CFLAGS = $(AM_CFLAGS)
runsvc_LDFLAGS = $(AM_LDFLAGS)
runsvc_LDADD = libinit.a libcfg.a libutil.a
killall5_SOURCES = cmd/killall5.c killall5_SOURCES = cmd/killall5.c
killall5_CPPFLAGS = $(AM_CPPFLAGS) killall5_CPPFLAGS = $(AM_CPPFLAGS)
killall5_CFLAGS = $(AM_CFLAGS) killall5_CFLAGS = $(AM_CFLAGS)
@ -24,11 +30,11 @@ service_SOURCES += $(SRVHEADERS)
service_CPPFLAGS = $(AM_CPPFLAGS) service_CPPFLAGS = $(AM_CPPFLAGS)
service_CFLAGS = $(AM_CFLAGS) service_CFLAGS = $(AM_CFLAGS)
service_LDFLAGS = $(AM_LDFLAGS) service_LDFLAGS = $(AM_LDFLAGS)
service_LDADD = libinit.a libcfg.a service_LDADD = libinit.a libcfg.a libutil.a
dist_man8_MANS += cmd/shutdown.8 cmd/service/service.8 dist_man8_MANS += cmd/shutdown.8 cmd/service/service.8
EXTRA_DIST += $(SRVHEADERS) EXTRA_DIST += $(SRVHEADERS)
sbin_PROGRAMS += service shutdown sbin_PROGRAMS += service shutdown
helper_PROGRAMS += killall5 waitfile helper_PROGRAMS += killall5 runsvc waitfile

View file

@ -9,7 +9,9 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
static __attribute__((noreturn)) void usage_and_exit(void) #include "util.h"
static NORETURN void usage_and_exit(void)
{ {
fputs("Usage: killall5 SIGNAL\n", stderr); fputs("Usage: killall5 SIGNAL\n", stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

109
cmd/runsvc/env.c Normal file
View file

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: ISC */
#include "runsvc.h"
struct entry {
struct entry *next;
char data[];
};
extern char **environ;
static void free_list(struct entry *list)
{
struct entry *e;
while (list != NULL) {
e = list;
list = list->next;
free(e);
}
}
static struct entry *parse_list(rdline_t *rd)
{
struct entry *e, *list = NULL;
char *ptr;
while (rdline(rd) == 0) {
ptr = rd->line;
while (*ptr != '\0' && *ptr != ' ' && *ptr != '=')
++ptr;
if (*ptr == ' ')
memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
if (*(ptr++) != '=') {
fprintf(stderr, "%s: %zu: line is not of the shape "
"'key = value', skipping\n",
rd->filename, rd->lineno);
continue;
}
if (*ptr == ' ')
memmove(ptr, ptr + 1, strlen(ptr + 1) + 1);
if (unescape(ptr)) {
fprintf(stderr, "%s: %zu: malformed string constant, "
"skipping\n",
rd->filename, rd->lineno);
continue;
}
e = calloc(1, sizeof(*e) + strlen(rd->line) + 1);
if (e == NULL)
goto fail_oom;
strcpy(e->data, rd->line);
e->next = list;
list = e;
}
return list;
fail_oom:
fputs("out of memory\n", stderr);
free_list(list);
return NULL;
}
static struct entry *list_from_file(void)
{
struct entry *list;
rdline_t rd;
if (rdline_init(&rd, AT_FDCWD, ENVFILE, 0, NULL))
return NULL;
list = parse_list(&rd);
rdline_cleanup(&rd);
return list;
}
int initenv(void)
{
struct entry *list, *e;
int i, count;
char **envp;
list = list_from_file();
if (list == NULL)
return -1;
for (count = 0, e = list; e != NULL; e = e->next)
++count;
envp = malloc((count + 1) * sizeof(char *));
if (envp == NULL) {
fputs("out of memory\n", stderr);
free_list(list);
return -1;
}
for (i = 0, e = list; e != NULL; e = e->next)
envp[i] = e->data;
envp[i] = NULL;
environ = envp;
return 0;
}

72
cmd/runsvc/runsvc.c Normal file
View file

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: ISC */
#include "runsvc.h"
static int run_sequentially(exec_t *list)
{
pid_t ret, pid;
int status;
for (; list != NULL; list = list->next) {
if (list->next == NULL)
argv_exec(list);
pid = fork();
if (pid == 0)
argv_exec(list);
if (pid == -1) {
perror("fork");
return EXIT_FAILURE;
}
do {
ret = waitpid(pid, &status, 0);
} while (ret != pid);
if (!WIFEXITED(status))
return EXIT_FAILURE;
if (WEXITSTATUS(status) != EXIT_SUCCESS)
return WEXITSTATUS(status);
}
return EXIT_SUCCESS;
}
/*****************************************************************************/
int main(int argc, char **argv)
{
service_t *svc = NULL;
int dirfd;
if (argc != 3) {
fputs("usage: runsvc <directory> <filename>\n", stderr);
return EXIT_FAILURE;
}
if (getppid() != 1) {
fputs("must be run by init!\n", stderr);
return EXIT_FAILURE;
}
dirfd = open(argv[1], O_RDONLY | O_DIRECTORY);
if (dirfd < 0) {
perror(argv[1]);
return EXIT_FAILURE;
}
svc = rdsvc(dirfd, argv[2], RDSVC_NO_FNAME | RDSVC_NO_DEPS);
close(dirfd);
if (svc == NULL)
return EXIT_FAILURE;
if (initenv())
return EXIT_FAILURE;
if (setup_tty(svc->ctty, (svc->flags & SVC_FLAG_TRUNCATE_OUT) != 0))
return EXIT_FAILURE;
return run_sequentially(svc->exec);
}

21
cmd/runsvc/runsvc.h Normal file
View file

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: ISC */
#ifndef RUNSVC_H
#define RUNSVC_H
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "service.h"
#include "libcfg.h"
#include "util.h"
#define ENVFILE ETCPATH "/initd.env"
int initenv(void);
#endif /* RUNSVC_H */

View file

@ -93,7 +93,7 @@ static int cmd_dumpscript(int argc, char **argv)
strcat(filename, argv[i]); strcat(filename, argv[i]);
} }
svc = loadsvc(SVCDIR, filename); svc = loadsvc(SVCDIR, filename, 0);
if (svc == NULL) { if (svc == NULL) {
fprintf(stderr, "Could not load service '%s'\n", filename); fprintf(stderr, "Could not load service '%s'\n", filename);

View file

@ -24,7 +24,7 @@ static int cmd_list(int argc, char **argv)
if (check_arguments(argv[0], argc, 1, 2)) if (check_arguments(argv[0], argc, 1, 2))
return EXIT_FAILURE; return EXIT_FAILURE;
if (svcscan(SVCDIR, &list)) { if (svcscan(SVCDIR, &list, 0)) {
fprintf(stderr, "Error while reading services from %s\n", fprintf(stderr, "Error while reading services from %s\n",
SVCDIR); SVCDIR);
ret = EXIT_FAILURE; ret = EXIT_FAILURE;

View file

@ -5,7 +5,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
service_t *loadsvc(const char *directory, const char *filename) service_t *loadsvc(const char *directory, const char *filename, int flags)
{ {
service_t *svc; service_t *svc;
int dirfd; int dirfd;
@ -17,7 +17,7 @@ service_t *loadsvc(const char *directory, const char *filename)
return NULL; return NULL;
} }
svc = rdsvc(dirfd, filename); svc = rdsvc(dirfd, filename, flags);
close(dirfd); close(dirfd);
return svc; return svc;
} }

View file

@ -5,6 +5,7 @@
#include "servicecmd.h" #include "servicecmd.h"
#include "service.h" #include "service.h"
#include "config.h" #include "config.h"
#include "util.h"
command_t *commands; command_t *commands;

View file

@ -2,14 +2,13 @@
#ifndef SERVICECMD_H #ifndef SERVICECMD_H
#define SERVICECMD_H #define SERVICECMD_H
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include "service.h" #include "service.h"
#include "config.h" #include "util.h"
/* /*
Describes a command that can be launched by passing its name as Describes a command that can be launched by passing its name as
@ -40,13 +39,13 @@ typedef struct command_t {
/* Global list of available commands */ /* Global list of available commands */
extern command_t *commands; extern command_t *commands;
service_t *loadsvc(const char *directory, const char *filename); service_t *loadsvc(const char *directory, const char *filename, int flags);
/* /*
Implemented in servicecmd.c. Prints program usage message and Implemented in servicecmd.c. Prints program usage message and
terminates with the given exit status. terminates with the given exit status.
*/ */
void usage(int status) __attribute__((noreturn)); void usage(int status) NORETURN;
/* /*
Write a message to stderr that advises the user how to consult the Write a message to stderr that advises the user how to consult the

View file

@ -128,7 +128,9 @@ static int cmd_status(int argc, char **argv)
printf("\tTemplate name: %s\n", resp.service_name); printf("\tTemplate name: %s\n", resp.service_name);
printf("\tExit status: %d\n", resp.exit_status); printf("\tExit status: %d\n", resp.exit_status);
svc = loadsvc(SVCDIR, resp.filename); svc = loadsvc(SVCDIR, resp.filename,
RDSVC_NO_EXEC | RDSVC_NO_DEPS |
RDSVC_NO_CTTY | RDSVC_NO_FNAME);
if (svc == NULL) { if (svc == NULL) {
fputs("\tError loading service file\n", stdout); fputs("\tError loading service file\n", stdout);

View file

@ -10,6 +10,8 @@
#include <sys/reboot.h> #include <sys/reboot.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include "util.h"
#define FL_FORCE 0x01 #define FL_FORCE 0x01
#define FL_NOSYNC 0x02 #define FL_NOSYNC 0x02
@ -27,7 +29,7 @@ static const char *shortopt = "hprfn";
static const char *defact_str = "power-off"; static const char *defact_str = "power-off";
static int defact = RB_POWER_OFF; static int defact = RB_POWER_OFF;
static __attribute__((noreturn)) void usage(const char *progname, int status) static NORETURN void usage(const char *progname, int status)
{ {
fprintf(status == EXIT_SUCCESS ? stdout : stderr, fprintf(status == EXIT_SUCCESS ? stdout : stderr,
"%s [OPTIONS...]\n\n" "%s [OPTIONS...]\n\n"

View file

@ -1,8 +1,8 @@
init_SOURCES = initd/main.c initd/init.h initd/runsvc.c init_SOURCES = initd/main.c initd/init.h initd/signal_linux.c initd/runsvc.c
init_SOURCES += initd/status.c initd/supervisor.c initd/initsock.c init_SOURCES += initd/status.c initd/supervisor.c initd/initsock.c
init_CPPFLAGS = $(AM_CPPFLAGS) init_CPPFLAGS = $(AM_CPPFLAGS)
init_CFLAGS = $(AM_CFLAGS) init_CFLAGS = $(AM_CFLAGS)
init_LDFLAGS = $(AM_LDFLAGS) init_LDFLAGS = $(AM_LDFLAGS)
init_LDADD = libinit.a libcfg.a init_LDADD = libinit.a libcfg.a libutil.a
sbin_PROGRAMS += init sbin_PROGRAMS += init

View file

@ -17,15 +17,13 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <stdbool.h>
#include <signal.h> #include <signal.h>
#include "initsock.h" #include "initsock.h"
#include "service.h" #include "service.h"
#include "config.h" #include "util.h"
#define ENVFILE ETCPATH "/initd.env" #define RUNSVCBIN SCRIPTDIR "/runsvc"
#define PROCFDDIR "/proc/self/fd"
enum { enum {
STATUS_OK = 0, STATUS_OK = 0,
@ -79,6 +77,29 @@ void supervisor_start(int id);
void supervisor_stop(int id); void supervisor_stop(int id);
/********** signal_<platform>.c **********/
/*
Setup signal handling. Returns -1 on error, a file descriptor on
success.
The returned file descriptor can be polled and becomes readable
when a signal arrives. Reading from it returns a signalfd_siginfo
structure.
The returned file descriptor has the close on exec flag set.
The kernel is also told to send us SIGINT signals if a user presses
the local equivalent of CTRL+ALT+DEL.
*/
int sigsetup(void);
/*
Undo everything that sigsetup() changed about signal handling and
restore the default.
*/
void sigreset(void);
/********** initsock.c **********/ /********** initsock.c **********/
int init_socket_create(void); int init_socket_create(void);

View file

@ -96,29 +96,6 @@ void target_completed(int target)
} }
} }
static int sigsetup(void)
{
sigset_t mask;
int sfd;
sigfillset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
perror("sigprocmask");
return -1;
}
sfd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sfd == -1) {
perror("signalfd");
return -1;
}
if (reboot(LINUX_REBOOT_CMD_CAD_OFF))
perror("cannot disable CTRL+ALT+DEL");
return sfd;
}
int main(void) int main(void)
{ {
int i, ret, count; int i, ret, count;

View file

@ -3,175 +3,32 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <dirent.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include "init.h" #include "init.h"
static int setup_env(void)
{
int status = -1;
ssize_t ret;
FILE *fp;
clearenv();
fp = fopen(ENVFILE, "r");
if (fp == NULL) {
perror(ENVFILE);
return -1;
}
do {
char *line = NULL;
size_t n = 0;
errno = 0;
ret = getline(&line, &n, fp);
if (ret < 0) {
if (errno == 0) {
status = 0;
} else {
perror(ENVFILE);
}
} else if (ret > 0 && putenv(line) != 0) {
perror("putenv");
ret = -1;
}
free(line);
} while (ret >= 0);
fclose(fp);
return status;
}
static int close_all_files(void)
{
struct dirent *ent;
DIR *dir;
int fd;
dir = opendir(PROCFDDIR);
if (dir == NULL) {
perror(PROCFDDIR);
return -1;
}
while ((ent = readdir(dir)) != NULL) {
if (!isdigit(ent->d_name[0]))
continue;
fd = atoi(ent->d_name);
close(fd);
}
closedir(dir);
return 0;
}
static int setup_tty(const char *tty, bool truncate)
{
int fd;
if (tty == NULL)
return 0;
fd = open(tty, O_RDWR);
if (fd < 0) {
perror(tty);
return -1;
}
if (truncate)
ftruncate(fd, 0);
setsid();
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
return 0;
}
static __attribute__((noreturn)) void argv_exec(exec_t *e)
{
char **argv = alloca(sizeof(char *) * (e->argc + 1)), *ptr;
int i;
for (ptr = e->args, i = 0; i < e->argc; ++i, ptr += strlen(ptr) + 1)
argv[i] = ptr;
argv[i] = NULL;
execvp(argv[0], argv);
perror(argv[0]);
exit(EXIT_FAILURE);
}
static int run_sequentially(exec_t *list)
{
pid_t ret, pid;
int status;
for (; list != NULL; list = list->next) {
if (list->next == NULL)
argv_exec(list);
pid = fork();
if (pid == 0)
argv_exec(list);
if (pid == -1) {
perror("fork");
return EXIT_FAILURE;
}
do {
ret = waitpid(pid, &status, 0);
} while (ret != pid);
if (!WIFEXITED(status))
return EXIT_FAILURE;
if (WEXITSTATUS(status) != EXIT_SUCCESS)
return WEXITSTATUS(status);
}
return EXIT_SUCCESS;
}
pid_t runsvc(service_t *svc) pid_t runsvc(service_t *svc)
{ {
sigset_t mask; char *argv[4], *envp[1];
pid_t pid; pid_t pid;
argv[0] = (char *)RUNSVCBIN;
argv[1] = (char *)SVCDIR;
argv[2] = svc->fname;
argv[3] = NULL;
envp[0] = NULL;
pid = fork(); pid = fork();
if (pid == -1) if (pid == -1)
perror("fork"); perror("fork");
if (pid == 0) { if (pid == 0) {
sigemptyset(&mask); sigreset();
sigprocmask(SIG_SETMASK, &mask, NULL); execve(argv[0], argv, envp);
perror(argv[0]);
if (setup_env())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (close_all_files())
exit(EXIT_FAILURE);
if (setup_tty(svc->ctty,
(svc->flags & SVC_FLAG_TRUNCATE_OUT) != 0)) {
exit(EXIT_FAILURE);
}
exit(run_sequentially(svc->exec));
} }
return pid; return pid;

42
initd/signal_linux.c Normal file
View file

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: ISC */
#include <stdio.h>
#include "init.h"
int sigsetup(void)
{
sigset_t mask;
int sfd;
sigfillset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
perror("sigprocmask");
return -1;
}
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGHUP);
sfd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sfd == -1) {
perror("signalfd");
return -1;
}
if (reboot(LINUX_REBOOT_CMD_CAD_OFF))
perror("cannot disable CTRL+ALT+DEL");
return sfd;
}
void sigreset(void)
{
sigset_t mask;
sigemptyset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
}

View file

@ -175,7 +175,7 @@ void supervisor_init(void)
{ {
int status = STATUS_OK; int status = STATUS_OK;
if (svcscan(SVCDIR, &cfg)) if (svcscan(SVCDIR, &cfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY))
status = STATUS_FAIL; status = STATUS_FAIL;
target = TGT_BOOT; target = TGT_BOOT;
@ -191,7 +191,7 @@ void supervisor_reload_config(void)
service_t *svc; service_t *svc;
int i; int i;
if (svcscan(SVCDIR, &newcfg)) if (svcscan(SVCDIR, &newcfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY))
return; return;
for (i = 0; i < TGT_MAX; ++i) { for (i = 0; i < TGT_MAX; ++i) {
@ -317,7 +317,7 @@ static service_t *remove_by_id(service_t **list, int id)
if (prev == NULL) { if (prev == NULL) {
*list = svc->next; *list = svc->next;
} else { } else {
prev->next = svc->next; prev = svc->next;
} }
} }

View file

@ -7,9 +7,13 @@ libinit_a_SOURCES += lib/init/init_socket_recv_status.c
libinit_a_CPPFLAGS = $(AM_CPPFLAGS) libinit_a_CPPFLAGS = $(AM_CPPFLAGS)
libinit_a_CFLAGS = $(AM_CFLAGS) libinit_a_CFLAGS = $(AM_CFLAGS)
libutil_a_SOURCES = lib/util/argv_exec.c lib/include/util.h
libutil_a_CPPFLAGS = $(AM_CPPFLAGS)
libutil_a_CFLAGS = $(AM_CFLAGS)
libcfg_a_SOURCES = lib/libcfg/rdline.c lib/libcfg/unescape.c lib/libcfg/rdcfg.c libcfg_a_SOURCES = lib/libcfg/rdline.c lib/libcfg/unescape.c lib/libcfg/rdcfg.c
libcfg_a_SOURCES += lib/libcfg/pack_argv.c lib/include/libcfg.h libcfg_a_SOURCES += lib/libcfg/pack_argv.c lib/include/libcfg.h
libcfg_a_CPPFLAGS = $(AM_CPPFLAGS) libcfg_a_CPPFLAGS = $(AM_CPPFLAGS)
libcfg_a_CFLAGS = $(AM_CFLAGS) libcfg_a_CFLAGS = $(AM_CFLAGS)
noinst_LIBRARIES += libinit.a libcfg.a noinst_LIBRARIES += libinit.a libcfg.a libutil.a

View file

@ -27,7 +27,7 @@ typedef struct {
*/ */
unsigned int allow_block : 1; unsigned int allow_block : 1;
int (*handle)(void *obj, char *arg, rdline_t *rd); int (*handle)(void *obj, char *arg, rdline_t *rd, int flags);
} cfg_param_t; } cfg_param_t;
/* /*
@ -92,10 +92,11 @@ int pack_argv(char *str);
/* /*
Parse a configuration file containing '<keyword> [arguments...]' lines. Parse a configuration file containing '<keyword> [arguments...]' lines.
The cfgobj is passed to the callback in the params array. The cfgobj and flags are passed to the callback in the params array.
Returns zero on success. Returns zero on success.
*/ */
int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count); int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count,
int flags);
#endif /* LIBCONFIG_H */ #endif /* LIBCONFIG_H */

View file

@ -4,11 +4,7 @@
#include <sys/types.h> #include <sys/types.h>
typedef struct exec_t { #include "util.h"
struct exec_t *next;
int argc; /* number of elements in argument vector */
char args[]; /* argument vectot string blob */
} exec_t;
enum { enum {
/* /*
@ -35,6 +31,13 @@ enum {
TGT_MAX TGT_MAX
}; };
enum {
RDSVC_NO_FNAME = 0x01, /* do not store a copy of the filename */
RDSVC_NO_EXEC = 0x02, /* do not store executable script */
RDSVC_NO_CTTY = 0x04, /* do not store the controlling tty */
RDSVC_NO_DEPS = 0x08, /* do not store dependencies */
};
enum { enum {
/* truncate stdout */ /* truncate stdout */
SVC_FLAG_TRUNCATE_OUT = 0x01, SVC_FLAG_TRUNCATE_OUT = 0x01,
@ -79,7 +82,7 @@ typedef struct {
/* /*
Read a service from a file. Read a service from a file.
*/ */
service_t *rdsvc(int dirfd, const char *filename); service_t *rdsvc(int dirfd, const char *filename, int flags);
void delsvc(service_t *svc); void delsvc(service_t *svc);
@ -90,7 +93,7 @@ void delsvc(service_t *svc);
Returns 0 on success, -1 on failure. The function takes care of Returns 0 on success, -1 on failure. The function takes care of
printing error messages on failure. printing error messages on failure.
*/ */
int svcscan(const char *directory, service_list_t *list); int svcscan(const char *directory, service_list_t *list, int flags);
void del_svc_list(service_list_t *list); void del_svc_list(service_list_t *list);

39
lib/include/util.h Normal file
View file

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: ISC */
#ifndef UTIL_H
#define UTIL_H
#include <sys/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include "config.h"
#ifdef __GNUC__
#define NORETURN __attribute__((noreturn))
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
typedef struct exec_t {
struct exec_t *next;
int argc; /* number of elements in argument vector */
char args[]; /* argument vectot string blob */
} exec_t;
enum {
/* only allow root to connect */
SOCK_FLAG_ROOT_ONLY = 0x01,
/* allow everyone to connect */
SOCK_FLAG_EVERYONE = 0x02,
/* create a datagram socket, otherwise use a stream socket */
SOCK_FLAG_DGRAM = 0x04,
};
int setup_tty(const char *tty, bool truncate);
NORETURN void argv_exec(exec_t *e);
#endif /* UTIL_H */

View file

@ -11,6 +11,7 @@
#include "service.h" #include "service.h"
#include "libcfg.h" #include "libcfg.h"
#include "util.h"
static int try_unescape(char *arg, rdline_t *rd) static int try_unescape(char *arg, rdline_t *rd)
{ {
@ -43,9 +44,10 @@ static int try_pack_argv(char *str, rdline_t *rd)
return count; return count;
} }
static int svc_desc(void *user, char *arg, rdline_t *rd) static int svc_desc(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
(void)flags;
if (try_unescape(arg, rd)) if (try_unescape(arg, rd))
return -1; return -1;
@ -53,10 +55,13 @@ static int svc_desc(void *user, char *arg, rdline_t *rd)
return svc->desc == NULL ? -1 : 0; return svc->desc == NULL ? -1 : 0;
} }
static int svc_tty(void *user, char *arg, rdline_t *rd) static int svc_tty(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
if (flags & RDSVC_NO_CTTY)
return 0;
if (strncmp(arg, "truncate", 8) == 0 && isspace(arg[8])) { if (strncmp(arg, "truncate", 8) == 0 && isspace(arg[8])) {
svc->flags |= SVC_FLAG_TRUNCATE_OUT; svc->flags |= SVC_FLAG_TRUNCATE_OUT;
arg += 8; arg += 8;
@ -71,13 +76,16 @@ static int svc_tty(void *user, char *arg, rdline_t *rd)
return svc->ctty == NULL ? -1 : 0; return svc->ctty == NULL ? -1 : 0;
} }
static int svc_exec(void *user, char *arg, rdline_t *rd) static int svc_exec(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
exec_t *e, *end; exec_t *e, *end;
svc->flags |= SVC_FLAG_HAS_EXEC; svc->flags |= SVC_FLAG_HAS_EXEC;
if (flags & RDSVC_NO_EXEC)
return 0;
e = calloc(1, sizeof(*e) + strlen(arg) + 1); e = calloc(1, sizeof(*e) + strlen(arg) + 1);
if (e == NULL) { if (e == NULL) {
fprintf(stderr, "%s: %zu: out of memory\n", fprintf(stderr, "%s: %zu: out of memory\n",
@ -101,10 +109,13 @@ static int svc_exec(void *user, char *arg, rdline_t *rd)
return 0; return 0;
} }
static int svc_before(void *user, char *arg, rdline_t *rd) static int svc_before(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
if (flags & RDSVC_NO_DEPS)
return 0;
if (svc->before != NULL) { if (svc->before != NULL) {
fprintf(stderr, "%s: %zu: 'before' dependencies respecified\n", fprintf(stderr, "%s: %zu: 'before' dependencies respecified\n",
rd->filename, rd->lineno); rd->filename, rd->lineno);
@ -119,10 +130,13 @@ static int svc_before(void *user, char *arg, rdline_t *rd)
return (svc->num_before < 0) ? -1 : 0; return (svc->num_before < 0) ? -1 : 0;
} }
static int svc_after(void *user, char *arg, rdline_t *rd) static int svc_after(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
if (flags & RDSVC_NO_DEPS)
return 0;
if (svc->after != NULL) { if (svc->after != NULL) {
fprintf(stderr, "%s: %zu: 'after' dependencies respecified\n", fprintf(stderr, "%s: %zu: 'after' dependencies respecified\n",
rd->filename, rd->lineno); rd->filename, rd->lineno);
@ -137,10 +151,11 @@ static int svc_after(void *user, char *arg, rdline_t *rd)
return (svc->num_after < 0) ? -1 : 0; return (svc->num_after < 0) ? -1 : 0;
} }
static int svc_type(void *user, char *arg, rdline_t *rd) static int svc_type(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
int count = try_pack_argv(arg, rd); int count = try_pack_argv(arg, rd);
(void)flags;
if (count < 1) if (count < 1)
return -1; return -1;
@ -184,10 +199,11 @@ fail_limit:
return -1; return -1;
} }
static int svc_target(void *user, char *arg, rdline_t *rd) static int svc_target(void *user, char *arg, rdline_t *rd, int flags)
{ {
service_t *svc = user; service_t *svc = user;
int target; int target;
(void)flags;
if (try_unescape(arg, rd)) if (try_unescape(arg, rd))
return -1; return -1;
@ -214,7 +230,7 @@ static const cfg_param_t svc_params[] = {
{ "after", 0, svc_after }, { "after", 0, svc_after },
}; };
service_t *rdsvc(int dirfd, const char *filename) service_t *rdsvc(int dirfd, const char *filename, int flags)
{ {
const char *arg, *args[1]; const char *arg, *args[1];
service_t *svc = NULL; service_t *svc = NULL;
@ -238,17 +254,17 @@ service_t *rdsvc(int dirfd, const char *filename)
if (svc == NULL) if (svc == NULL)
goto fail_oom; goto fail_oom;
if (!(flags & RDSVC_NO_FNAME)) {
svc->fname = strdup(filename); svc->fname = strdup(filename);
if (svc->fname == NULL) if (svc->fname == NULL)
goto fail_oom; goto fail_oom;
}
memcpy(svc->name, filename, nlen); memcpy(svc->name, filename, nlen);
svc->id = -1; svc->id = -1;
if (rdcfg(svc, &rd, svc_params, if (rdcfg(svc, &rd, svc_params, ARRAY_SIZE(svc_params), flags))
sizeof(svc_params) / sizeof(svc_params[0]))) {
goto fail; goto fail;
}
out: out:
rdline_cleanup(&rd); rdline_cleanup(&rd);

View file

@ -23,7 +23,7 @@ int svc_type_from_string(const char *type)
{ {
size_t i; size_t i;
for (i = 0; i < sizeof(type_map) / sizeof(type_map[0]); ++i) { for (i = 0; i < ARRAY_SIZE(type_map); ++i) {
if (strcmp(type_map[i], type) == 0) if (strcmp(type_map[i], type) == 0)
return i; return i;
} }
@ -40,7 +40,7 @@ int svc_target_from_string(const char *target)
{ {
size_t i; size_t i;
for (i = 0; i < sizeof(target_map) / sizeof(target_map[0]); ++i) { for (i = 0; i < ARRAY_SIZE(target_map); ++i) {
if (strcmp(target_map[i], target) == 0) if (strcmp(target_map[i], target) == 0)
return i; return i;
} }

View file

@ -11,7 +11,7 @@
#include "service.h" #include "service.h"
int svcscan(const char *directory, service_list_t *list) int svcscan(const char *directory, service_list_t *list, int flags)
{ {
int i, dfd, type, ret = 0; int i, dfd, type, ret = 0;
struct dirent *ent; struct dirent *ent;
@ -66,7 +66,7 @@ int svcscan(const char *directory, service_list_t *list)
if (type != S_IFREG && type != S_IFLNK) if (type != S_IFREG && type != S_IFLNK)
continue; continue;
svc = rdsvc(dfd, ent->d_name); svc = rdsvc(dfd, ent->d_name, flags);
if (svc == NULL) { if (svc == NULL) {
ret = -1; ret = -1;
continue; continue;

View file

@ -47,7 +47,8 @@ static int splitkv(rdline_t *rd, char **k, char **v)
return 0; return 0;
} }
int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count) int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count,
int flags)
{ {
const cfg_param_t *p; const cfg_param_t *p;
char *key, *value; char *key, *value;
@ -66,7 +67,7 @@ int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count)
; ;
if (*value != '\0') { if (*value != '\0') {
ret = p->handle(cfgobj, value, rd); ret = p->handle(cfgobj, value, rd, flags);
if (ret) if (ret)
return -1; return -1;
} }
@ -74,7 +75,7 @@ int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count)
while ((ret = rdline(rd)) == 0) { while ((ret = rdline(rd)) == 0) {
if (strcmp(rd->line, "}") == 0) if (strcmp(rd->line, "}") == 0)
break; break;
if (p->handle(cfgobj, rd->line, rd)) if (p->handle(cfgobj, rd->line, rd, flags))
return -1; return -1;
} }
@ -82,7 +83,7 @@ int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count)
return -1; return -1;
if (ret > 0) if (ret > 0)
goto fail_bra; goto fail_bra;
} else if (p->handle(cfgobj, value, rd)) { } else if (p->handle(cfgobj, value, rd, flags)) {
return -1; return -1;
} }
} }

View file

@ -8,6 +8,7 @@
#include <fcntl.h> #include <fcntl.h>
#include "libcfg.h" #include "libcfg.h"
#include "util.h"
int rdline_init(rdline_t *t, int dirfd, const char *filename, int rdline_init(rdline_t *t, int dirfd, const char *filename,
int argc, const char *const *argv) int argc, const char *const *argv)

51
lib/util/argv_exec.c Normal file
View file

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: ISC */
#include "service.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
int setup_tty(const char *tty, bool truncate)
{
int fd;
if (tty == NULL)
return 0;
fd = open(tty, O_RDWR);
if (fd < 0) {
perror(tty);
return -1;
}
if (truncate)
ftruncate(fd, 0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
setsid();
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
return 0;
}
void argv_exec(exec_t *e)
{
char **argv = alloca(sizeof(char *) * (e->argc + 1)), *ptr;
int i;
for (ptr = e->args, i = 0; i < e->argc; ++i, ptr += strlen(ptr) + 1)
argv[i] = ptr;
argv[i] = NULL;
execvp(argv[0], argv);
perror(argv[0]);
exit(EXIT_FAILURE);
}