|
82 | 82 | LONGOPT_SECBITS, |
83 | 83 | LONGOPT_STDERR_LOGGER, |
84 | 84 | LONGOPT_STDOUT_LOGGER, |
| 85 | + LONGOPT_READY, |
85 | 86 | }; |
86 | 87 |
|
87 | 88 | const char *applet = NULL; |
@@ -115,6 +116,7 @@ const struct option longopts[] = { |
115 | 116 | { "stderr", 1, NULL, '2'}, |
116 | 117 | { "stdout-logger",1, NULL, LONGOPT_STDOUT_LOGGER}, |
117 | 118 | { "stderr-logger",1, NULL, LONGOPT_STDERR_LOGGER}, |
| 119 | + { "ready", 1, NULL, LONGOPT_READY}, |
118 | 120 | { "reexec", 0, NULL, '3'}, |
119 | 121 | longopts_COMMON |
120 | 122 | }; |
@@ -165,6 +167,8 @@ static int devnull_fd = -1; |
165 | 167 | static int stdin_fd; |
166 | 168 | static int stdout_fd; |
167 | 169 | static int stderr_fd; |
| 170 | +static int ready_fd = -1; |
| 171 | +static int ready_pipe[2]; |
168 | 172 | static char *redirect_stderr = NULL; |
169 | 173 | static char *redirect_stdout = NULL; |
170 | 174 | static char *stderr_process = NULL; |
@@ -588,6 +592,9 @@ RC_NORETURN static void child_process(char *exec, char **argv) |
588 | 592 |
|
589 | 593 | cloexec_fds_from(3); |
590 | 594 |
|
| 595 | + if (ready_fd != -1) |
| 596 | + dup2(ready_pipe[1], ready_fd); |
| 597 | + |
591 | 598 | cmdline = make_cmdline(argv); |
592 | 599 | syslog(LOG_INFO, "Child command line: %s", cmdline); |
593 | 600 | free(cmdline); |
@@ -786,6 +793,28 @@ RC_NORETURN static void supervisor(char *exec, char **argv) |
786 | 793 | exit(EXIT_SUCCESS); |
787 | 794 | } |
788 | 795 |
|
| 796 | +static void wait_ready(void) |
| 797 | +{ |
| 798 | + if (ready_fd == -1) |
| 799 | + exit(EXIT_SUCCESS); |
| 800 | + |
| 801 | + close(ready_pipe[1]); |
| 802 | + /* TODO: add timeout failure and stop child supervisor */ |
| 803 | + for (;;) { |
| 804 | + char buf[BUFSIZ]; |
| 805 | + int bytes = read(ready_pipe[0], buf, BUFSIZ); |
| 806 | + if (bytes == -1 && errno != EINTR) { |
| 807 | + eerror("%s: read failed '%s'\n", applet, strerror(errno)); |
| 808 | + exit(EXIT_FAILURE); |
| 809 | + } |
| 810 | + |
| 811 | + if (memchr(buf, '\n', bytes)) |
| 812 | + break; |
| 813 | + } |
| 814 | + |
| 815 | + exit(EXIT_SUCCESS); |
| 816 | +} |
| 817 | + |
789 | 818 | int main(int argc, char **argv) |
790 | 819 | { |
791 | 820 | int opt; |
@@ -1068,6 +1097,12 @@ int main(int argc, char **argv) |
1068 | 1097 | stderr_process = optarg; |
1069 | 1098 | break; |
1070 | 1099 |
|
| 1100 | + case LONGOPT_READY: |
| 1101 | + if (sscanf(optarg, "fd:%d", &ready_fd) != 1) |
| 1102 | + eerrorx("%s: invalid ready '%s'.", applet, optarg); |
| 1103 | + pipe(ready_pipe); |
| 1104 | + break; |
| 1105 | + |
1071 | 1106 | case_RC_COMMON_GETOPT |
1072 | 1107 | } |
1073 | 1108 |
|
@@ -1205,19 +1240,25 @@ int main(int argc, char **argv) |
1205 | 1240 | if (child_pid == -1) |
1206 | 1241 | eerrorx("%s: fork: %s", applet, strerror(errno)); |
1207 | 1242 | if (child_pid != 0) |
1208 | | - /* first parent process, do nothing. */ |
1209 | | - exit(EXIT_SUCCESS); |
| 1243 | + wait_ready(); |
| 1244 | + |
1210 | 1245 | #ifdef TIOCNOTTY |
1211 | 1246 | tty_fd = open("/dev/tty", O_RDWR); |
1212 | 1247 | #endif |
1213 | 1248 | devnull_fd = open("/dev/null", O_RDWR); |
1214 | 1249 | dup2(devnull_fd, STDIN_FILENO); |
1215 | 1250 | dup2(devnull_fd, STDOUT_FILENO); |
1216 | 1251 | dup2(devnull_fd, STDERR_FILENO); |
| 1252 | + |
| 1253 | + if (ready_fd != -1) |
| 1254 | + close(ready_pipe[0]); |
| 1255 | + |
1217 | 1256 | child_pid = fork(); |
1218 | 1257 | if (child_pid == -1) |
1219 | 1258 | eerrorx("%s: fork: %s", applet, strerror(errno)); |
1220 | 1259 | else if (child_pid != 0) { |
| 1260 | + if (ready_fd != -1) |
| 1261 | + close(ready_pipe[1]); |
1221 | 1262 | c = argv; |
1222 | 1263 | x = 0; |
1223 | 1264 | while (c && *c) { |
|
0 commit comments