Skip to content

Commit 4194148

Browse files
committed
misc, *-daemon: Implement s6-style readiness notification.
Adds two helper functions, and allows scripts to wait until services are ready before proceeding with it's dependees by setting `ready=fd:<num>`, where <num> is the file descriptor the daemon should write a new line to.
1 parent da04d1c commit 4194148

File tree

4 files changed

+90
-4
lines changed

4 files changed

+90
-4
lines changed

src/shared/misc.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,46 @@ pid_t get_pid(const char *applet,const char *pidfile)
521521
return pid;
522522
}
523523

524+
struct ready ready_parse(const char *applet, const char *ready_string)
525+
{
526+
struct ready ready = {0};
527+
if (sscanf(ready_string, "fd:%d", &ready.fd) != 1)
528+
eerrorx("%s: invalid ready '%s'.", applet, optarg);
529+
530+
ready.type = READY_FD;
531+
532+
if (pipe(ready.pipe) == -1)
533+
eerrorx("%s: pipe failed: %s", applet, strerror(errno));
534+
535+
return ready;
536+
}
537+
538+
bool ready_wait(const char *applet, struct ready ready)
539+
{
540+
if (ready.type == READY_NONE)
541+
return true;
542+
543+
close(ready.pipe[1]);
544+
ready.fd = ready.pipe[0];
545+
546+
for (;;) {
547+
char buf[BUFSIZ];
548+
ssize_t bytes = read(ready.fd, buf, BUFSIZ);
549+
if (bytes == -1) {
550+
if (errno != EINTR) {
551+
eerror("%s: read failed '%s'\n", applet, strerror(errno));
552+
return false;
553+
}
554+
continue;
555+
}
556+
557+
if (memchr(buf, '\n', bytes))
558+
break;
559+
}
560+
561+
return true;
562+
}
563+
524564
#ifndef HAVE_CLOSE_RANGE
525565
static inline int close_range(int first RC_UNUSED,
526566
int last RC_UNUSED,

src/shared/misc.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,17 @@ pid_t get_pid(const char *applet, const char *pidfile);
6666

6767
void cloexec_fds_from(int);
6868

69+
struct ready {
70+
enum {
71+
READY_NONE = 0,
72+
READY_FD,
73+
} type;
74+
75+
int pipe[2];
76+
int fd;
77+
};
78+
79+
struct ready ready_parse(const char *applet, const char *ready_string);
80+
bool ready_wait(const char *applet, struct ready ready);
81+
6982
#endif

src/start-stop-daemon/start-stop-daemon.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum {
8989
LONGOPT_SCHEDULER,
9090
LONGOPT_SCHEDULER_PRIO,
9191
LONGOPT_SECBITS,
92+
LONGOPT_READY,
9293
};
9394

9495
const char *applet = NULL;
@@ -130,6 +131,7 @@ const struct option longopts[] = {
130131
{ "progress", 0, NULL, 'P'},
131132
{ "scheduler", 1, NULL, LONGOPT_SCHEDULER},
132133
{ "scheduler-priority", 1, NULL, LONGOPT_SCHEDULER_PRIO},
134+
{ "ready", 1, NULL, LONGOPT_READY},
133135
longopts_COMMON
134136
};
135137
const char * const longopts_help[] = {
@@ -353,6 +355,8 @@ int main(int argc, char **argv)
353355
int pipefd[2];
354356
char readbuf[1];
355357
ssize_t ss;
358+
struct ready ready;
359+
int ret = EXIT_SUCCESS;
356360

357361
applet = basename_c(argv[0]);
358362
atexit(cleanup);
@@ -618,6 +622,10 @@ int main(int argc, char **argv)
618622
sscanf(optarg, "%d", &sched_prio);
619623
break;
620624

625+
case LONGOPT_READY:
626+
ready = ready_parse(applet, optarg);
627+
break;
628+
621629
case_RC_COMMON_GETOPT
622630
}
623631

@@ -1100,6 +1108,11 @@ int main(int argc, char **argv)
11001108

11011109
cloexec_fds_from(3);
11021110

1111+
if (ready.type == READY_FD) {
1112+
close(ready.pipe[0]);
1113+
dup2(ready.pipe[1], ready.fd);
1114+
}
1115+
11031116
if (scheduler != NULL) {
11041117
int scheduler_index;
11051118
struct sched_param sched = {.sched_priority = sched_prio};
@@ -1184,7 +1197,11 @@ int main(int argc, char **argv)
11841197
start_wait = 0;
11851198
}
11861199

1187-
if (start_wait > 0) {
1200+
/* TODO: timeout on waiting readiness. */
1201+
if (ready.type != READY_NONE) {
1202+
if (!ready_wait(applet, ready))
1203+
ret = EXIT_FAILURE;
1204+
} else if (start_wait > 0) {
11881205
struct timespec ts;
11891206
bool alive = false;
11901207

@@ -1224,6 +1241,6 @@ int main(int argc, char **argv)
12241241
rc_service_daemon_set(svcname, exec,
12251242
(const char *const *)margv, pidfile, true);
12261243

1227-
exit(EXIT_SUCCESS);
1244+
exit(ret);
12281245
/* NOTREACHED */
12291246
}

src/supervise-daemon/supervise-daemon.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ enum {
8282
LONGOPT_SECBITS,
8383
LONGOPT_STDERR_LOGGER,
8484
LONGOPT_STDOUT_LOGGER,
85+
LONGOPT_READY,
8586
};
8687

8788
const char *applet = NULL;
@@ -116,6 +117,7 @@ const struct option longopts[] = {
116117
{ "stdout-logger",1, NULL, LONGOPT_STDOUT_LOGGER},
117118
{ "stderr-logger",1, NULL, LONGOPT_STDERR_LOGGER},
118119
{ "reexec", 0, NULL, '3'},
120+
{ "ready", 1, NULL, LONGOPT_READY},
119121
longopts_COMMON
120122
};
121123
const char * const longopts_help[] = {
@@ -165,6 +167,7 @@ static int devnull_fd = -1;
165167
static int stdin_fd;
166168
static int stdout_fd;
167169
static int stderr_fd;
170+
static struct ready ready;
168171
static char *redirect_stderr = NULL;
169172
static char *redirect_stdout = NULL;
170173
static char *stderr_process = NULL;
@@ -588,6 +591,9 @@ RC_NORETURN static void child_process(char *exec, char **argv)
588591

589592
cloexec_fds_from(3);
590593

594+
if (ready.type == READY_FD)
595+
dup2(ready.pipe[1], ready.fd);
596+
591597
cmdline = make_cmdline(argv);
592598
syslog(LOG_INFO, "Child command line: %s", cmdline);
593599
free(cmdline);
@@ -1068,6 +1074,10 @@ int main(int argc, char **argv)
10681074
stderr_process = optarg;
10691075
break;
10701076

1077+
case LONGOPT_READY:
1078+
ready = ready_parse(applet, optarg);
1079+
break;
1080+
10711081
case_RC_COMMON_GETOPT
10721082
}
10731083

@@ -1205,19 +1215,25 @@ int main(int argc, char **argv)
12051215
if (child_pid == -1)
12061216
eerrorx("%s: fork: %s", applet, strerror(errno));
12071217
if (child_pid != 0)
1208-
/* first parent process, do nothing. */
1209-
exit(EXIT_SUCCESS);
1218+
exit(ready_wait(applet, ready) ? EXIT_SUCCESS : EXIT_FAILURE);
1219+
12101220
#ifdef TIOCNOTTY
12111221
tty_fd = open("/dev/tty", O_RDWR);
12121222
#endif
12131223
devnull_fd = open("/dev/null", O_RDWR);
12141224
dup2(devnull_fd, STDIN_FILENO);
12151225
dup2(devnull_fd, STDOUT_FILENO);
12161226
dup2(devnull_fd, STDERR_FILENO);
1227+
1228+
if (ready.type == READY_FD)
1229+
close(ready.pipe[0]);
1230+
12171231
child_pid = fork();
12181232
if (child_pid == -1)
12191233
eerrorx("%s: fork: %s", applet, strerror(errno));
12201234
else if (child_pid != 0) {
1235+
if (ready.type == READY_FD)
1236+
close(ready.pipe[1]);
12211237
c = argv;
12221238
x = 0;
12231239
while (c && *c) {

0 commit comments

Comments
 (0)