1 /*
2 * Utility functions for tests that use subprocesses.
3 *
4 * Provides utility functions for subprocess manipulation. Specifically,
5 * provides a function, run_setup, which runs a command and bails if it fails,
6 * using its error message as the bail output, and is_function_output, which
7 * runs a function in a subprocess and checks its output and exit status
8 * against expected values.
9 *
10 * Requires an Autoconf probe for sys/select.h and a replacement for a missing
11 * mkstemp.
12 *
13 * The canonical version of this file is maintained in the rra-c-util package,
14 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
15 *
16 * Written by Russ Allbery <eagle@eyrie.org>
17 * Copyright 2002, 2004-2005, 2013, 2016-2017 Russ Allbery <eagle@eyrie.org>
18 * Copyright 2009-2011, 2013-2014
19 * The Board of Trustees of the Leland Stanford Junior University
20 *
21 * Permission is hereby granted, free of charge, to any person obtaining a
22 * copy of this software and associated documentation files (the "Software"),
23 * to deal in the Software without restriction, including without limitation
24 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
25 * and/or sell copies of the Software, and to permit persons to whom the
26 * Software is furnished to do so, subject to the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be included in
29 * all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
34 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
36 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
37 * DEALINGS IN THE SOFTWARE.
38 *
39 * SPDX-License-Identifier: MIT
40 */
41
42 #include <config.h>
43 #include <portable/system.h>
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #ifdef HAVE_SYS_SELECT_H
49 # include <sys/select.h>
50 #endif
51 #include <sys/stat.h>
52 #ifdef HAVE_SYS_TIME_H
53 # include <sys/time.h>
54 #endif
55 #include <sys/wait.h>
56 #include <time.h>
57
58 #include <tests/tap/basic.h>
59 #include <tests/tap/process.h>
60 #include <tests/tap/string.h>
61
62 /* May be defined by the build system. */
63 #ifndef PATH_FAKEROOT
64 # define PATH_FAKEROOT ""
65 #endif
66
67 /* How long to wait for the process to start in seconds. */
68 #define PROCESS_WAIT 10
69
70 /*
71 * Used to store information about a background process. This contains
72 * everything required to stop the process and clean up after it.
73 */
74 struct process {
75 pid_t pid; /* PID of child process */
76 char *pidfile; /* PID file to delete on process stop */
77 char *tmpdir; /* Temporary directory for log file */
78 char *logfile; /* Log file of process output */
79 bool is_child; /* Whether we can waitpid for process */
80 struct process *next; /* Next process in global list */
81 };
82
83 /*
84 * Global list of started processes, which will be cleaned up automatically on
85 * program exit if they haven't been explicitly stopped with process_stop
86 * prior to that point.
87 */
88 static struct process *processes = NULL;
89
90
91 /*
92 * Given a function, an expected exit status, and expected output, runs that
93 * function in a subprocess, capturing stdout and stderr via a pipe, and
94 * returns the function output in newly allocated memory. Also captures the
95 * process exit status.
96 */
97 static void
run_child_function(test_function_type function,void * data,int * status,char ** output)98 run_child_function(test_function_type function, void *data, int *status,
99 char **output)
100 {
101 int fds[2];
102 pid_t child;
103 char *buf;
104 ssize_t count, ret, buflen;
105 int rval;
106
107 /* Flush stdout before we start to avoid odd forking issues. */
108 fflush(stdout);
109
110 /* Set up the pipe and call the function, collecting its output. */
111 if (pipe(fds) == -1)
112 sysbail("can't create pipe");
113 child = fork();
114 if (child == (pid_t) -1) {
115 sysbail("can't fork");
116 } else if (child == 0) {
117 /* In child. Set up our stdout and stderr. */
118 close(fds[0]);
119 if (dup2(fds[1], 1) == -1)
120 _exit(255);
121 if (dup2(fds[1], 2) == -1)
122 _exit(255);
123
124 /* Now, run the function and exit successfully if it returns. */
125 (*function)(data);
126 fflush(stdout);
127 _exit(0);
128 } else {
129 /*
130 * In the parent; close the extra file descriptor, read the output if
131 * any, and then collect the exit status.
132 */
133 close(fds[1]);
134 buflen = BUFSIZ;
135 buf = bmalloc(buflen);
136 count = 0;
137 do {
138 ret = read(fds[0], buf + count, buflen - count - 1);
139 if (SSIZE_MAX - count <= ret)
140 bail("maximum output size exceeded in run_child_function");
141 if (ret > 0)
142 count += ret;
143 if (count >= buflen - 1) {
144 buflen += BUFSIZ;
145 buf = brealloc(buf, buflen);
146 }
147 } while (ret > 0);
148 buf[count] = '\0';
149 if (waitpid(child, &rval, 0) == (pid_t) -1)
150 sysbail("waitpid failed");
151 close(fds[0]);
152 }
153
154 /* Store the output and return. */
155 *status = rval;
156 *output = buf;
157 }
158
159
160 /*
161 * Given a function, data to pass to that function, an expected exit status,
162 * and expected output, runs that function in a subprocess, capturing stdout
163 * and stderr via a pipe, and compare the combination of stdout and stderr
164 * with the expected output and the exit status with the expected status.
165 * Expects the function to always exit (not die from a signal).
166 */
167 void
is_function_output(test_function_type function,void * data,int status,const char * output,const char * format,...)168 is_function_output(test_function_type function, void *data, int status,
169 const char *output, const char *format, ...)
170 {
171 char *buf, *msg;
172 int rval;
173 va_list args;
174
175 run_child_function(function, data, &rval, &buf);
176
177 /* Now, check the results against what we expected. */
178 va_start(args, format);
179 bvasprintf(&msg, format, args);
180 va_end(args);
181 ok(WIFEXITED(rval), "%s (exited)", msg);
182 is_int(status, WEXITSTATUS(rval), "%s (status)", msg);
183 is_string(output, buf, "%s (output)", msg);
184 free(buf);
185 free(msg);
186 }
187
188
189 /*
190 * A helper function for run_setup. This is a function to run an external
191 * command, suitable for passing into run_child_function. The expected
192 * argument must be an argv array, with argv[0] being the command to run.
193 */
194 static void
exec_command(void * data)195 exec_command(void *data)
196 {
197 char *const *argv = data;
198
199 execvp(argv[0], argv);
200 }
201
202
203 /*
204 * Given a command expressed as an argv struct, with argv[0] the name or path
205 * to the command, run that command. If it exits with a non-zero status, use
206 * the part of its output up to the first newline as the error message when
207 * calling bail.
208 */
209 void
run_setup(const char * const argv[])210 run_setup(const char *const argv[])
211 {
212 char *output, *p;
213 int status;
214
215 run_child_function(exec_command, (void *) argv, &status, &output);
216 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
217 p = strchr(output, '\n');
218 if (p != NULL)
219 *p = '\0';
220 if (output[0] != '\0')
221 bail("%s", output);
222 else
223 bail("setup command failed with no output");
224 }
225 free(output);
226 }
227
228
229 /*
230 * Free the resources associated with tracking a process, without doing
231 * anything to the process. This is kept separate so that we can free
232 * resources during shutdown in a non-primary process.
233 */
234 static void
process_free(struct process * process)235 process_free(struct process *process)
236 {
237 struct process **prev;
238
239 /* Do nothing if called with a NULL argument. */
240 if (process == NULL)
241 return;
242
243 /* Remove the process from the global list. */
244 prev = &processes;
245 while (*prev != NULL && *prev != process)
246 prev = &(*prev)->next;
247 if (*prev == process)
248 *prev = process->next;
249
250 /* Free resources. */
251 free(process->pidfile);
252 free(process->logfile);
253 test_tmpdir_free(process->tmpdir);
254 free(process);
255 }
256
257
258 /*
259 * Kill a process and wait for it to exit. Returns the status of the process.
260 * Calls bail on a system failure or a failure of the process to exit.
261 *
262 * We are quite aggressive with error reporting here because child processes
263 * that don't exit or that don't exist often indicate some form of test
264 * failure.
265 */
266 static int
process_kill(struct process * process)267 process_kill(struct process *process)
268 {
269 int result, i;
270 int status = -1;
271 struct timeval tv;
272 unsigned long pid = process->pid;
273
274 /* If the process is not a child, just kill it and hope. */
275 if (!process->is_child) {
276 if (kill(process->pid, SIGTERM) < 0 && errno != ESRCH)
277 sysbail("cannot send SIGTERM to process %lu", pid);
278 return 0;
279 }
280
281 /* Check if the process has already exited. */
282 result = waitpid(process->pid, &status, WNOHANG);
283 if (result < 0)
284 sysbail("cannot wait for child process %lu", pid);
285 else if (result > 0)
286 return status;
287
288 /*
289 * Kill the process and wait for it to exit. I don't want to go to the
290 * work of setting up a SIGCHLD handler or a full event loop here, so we
291 * effectively poll every tenth of a second for process exit (and
292 * hopefully faster when it does since the SIGCHLD may interrupt our
293 * select, although we're racing with it.
294 */
295 if (kill(process->pid, SIGTERM) < 0 && errno != ESRCH)
296 sysbail("cannot send SIGTERM to child process %lu", pid);
297 for (i = 0; i < PROCESS_WAIT * 10; i++) {
298 tv.tv_sec = 0;
299 tv.tv_usec = 100000;
300 select(0, NULL, NULL, NULL, &tv);
301 result = waitpid(process->pid, &status, WNOHANG);
302 if (result < 0)
303 sysbail("cannot wait for child process %lu", pid);
304 else if (result > 0)
305 return status;
306 }
307
308 /* The process still hasn't exited. Bail. */
309 bail("child process %lu did not exit on SIGTERM", pid);
310
311 /* Not reached, but some compilers may get confused. */
312 return status;
313 }
314
315
316 /*
317 * Stop a particular process given its process struct. This kills the
318 * process, waits for it to exit if possible (giving it at most five seconds),
319 * and then removes it from the global processes struct so that it isn't
320 * stopped again during global shutdown.
321 */
322 void
process_stop(struct process * process)323 process_stop(struct process *process)
324 {
325 int status;
326 unsigned long pid = process->pid;
327
328 /* Stop the process. */
329 status = process_kill(process);
330
331 /* Call diag to flush logs as well as provide exit status. */
332 if (process->is_child)
333 diag("stopped process %lu (exit status %d)", pid, status);
334 else
335 diag("stopped process %lu", pid);
336
337 /* Remove the log and PID file. */
338 diag_file_remove(process->logfile);
339 unlink(process->pidfile);
340 unlink(process->logfile);
341
342 /* Free resources. */
343 process_free(process);
344 }
345
346
347 /*
348 * Stop all running processes. This is called as a cleanup handler during
349 * process shutdown. The first argument, which says whether the test was
350 * successful, is ignored, since the same actions should be performed
351 * regardless. The second argument says whether this is the primary process,
352 * in which case we do the full shutdown. Otherwise, we only free resources
353 * but don't stop the process.
354 */
355 static void
process_stop_all(int success UNUSED,int primary)356 process_stop_all(int success UNUSED, int primary)
357 {
358 while (processes != NULL) {
359 if (primary)
360 process_stop(processes);
361 else
362 process_free(processes);
363 }
364 }
365
366
367 /*
368 * Read the PID of a process from a file. This is necessary when running
369 * under fakeroot to get the actual PID of the remctld process.
370 */
371 static pid_t
read_pidfile(const char * path)372 read_pidfile(const char *path)
373 {
374 FILE *file;
375 char buffer[BUFSIZ];
376 long pid;
377
378 file = fopen(path, "r");
379 if (file == NULL)
380 sysbail("cannot open %s", path);
381 if (fgets(buffer, sizeof(buffer), file) == NULL)
382 sysbail("cannot read from %s", path);
383 fclose(file);
384 pid = strtol(buffer, NULL, 10);
385 if (pid <= 0)
386 bail("cannot read PID from %s", path);
387 return (pid_t) pid;
388 }
389
390
391 /*
392 * Start a process and return its status information. The status information
393 * is also stored in the global processes linked list so that it can be
394 * stopped automatically on program exit.
395 *
396 * The boolean argument says whether to start the process under fakeroot. If
397 * true, PATH_FAKEROOT must be defined, generally by Autoconf. If it's not
398 * found, call skip_all.
399 *
400 * This is a helper function for process_start and process_start_fakeroot.
401 */
402 static struct process *
process_start_internal(const char * const argv[],const char * pidfile,bool fakeroot)403 process_start_internal(const char *const argv[], const char *pidfile,
404 bool fakeroot)
405 {
406 size_t i;
407 int log_fd;
408 const char *name;
409 struct timeval tv;
410 struct process *process;
411 const char **fakeroot_argv = NULL;
412 const char *path_fakeroot = PATH_FAKEROOT;
413
414 /* Check prerequisites. */
415 if (fakeroot && path_fakeroot[0] == '\0')
416 skip_all("fakeroot not found");
417
418 /* Create the process struct and log file. */
419 process = bcalloc(1, sizeof(struct process));
420 process->pidfile = bstrdup(pidfile);
421 process->tmpdir = test_tmpdir();
422 name = strrchr(argv[0], '/');
423 if (name != NULL)
424 name++;
425 else
426 name = argv[0];
427 basprintf(&process->logfile, "%s/%s.log.XXXXXX", process->tmpdir, name);
428 log_fd = mkstemp(process->logfile);
429 if (log_fd < 0)
430 sysbail("cannot create log file for %s", argv[0]);
431
432 /* If using fakeroot, rewrite argv accordingly. */
433 if (fakeroot) {
434 for (i = 0; argv[i] != NULL; i++)
435 ;
436 fakeroot_argv = bcalloc(2 + i + 1, sizeof(const char *));
437 fakeroot_argv[0] = path_fakeroot;
438 fakeroot_argv[1] = "--";
439 for (i = 0; argv[i] != NULL; i++)
440 fakeroot_argv[i + 2] = argv[i];
441 fakeroot_argv[i + 2] = NULL;
442 argv = fakeroot_argv;
443 }
444
445 /*
446 * Fork off the child process, redirect its standard output and standard
447 * error to the log file, and then exec the program.
448 */
449 process->pid = fork();
450 if (process->pid < 0)
451 sysbail("fork failed");
452 else if (process->pid == 0) {
453 if (dup2(log_fd, STDOUT_FILENO) < 0)
454 sysbail("cannot redirect standard output");
455 if (dup2(log_fd, STDERR_FILENO) < 0)
456 sysbail("cannot redirect standard error");
457 close(log_fd);
458 if (execv(argv[0], (char *const *) argv) < 0)
459 sysbail("exec of %s failed", argv[0]);
460 }
461 close(log_fd);
462 free(fakeroot_argv);
463
464 /*
465 * In the parent. Wait for the child to start by watching for the PID
466 * file to appear in 100ms intervals.
467 */
468 for (i = 0; i < PROCESS_WAIT * 10 && access(pidfile, F_OK) != 0; i++) {
469 tv.tv_sec = 0;
470 tv.tv_usec = 100000;
471 select(0, NULL, NULL, NULL, &tv);
472 }
473
474 /*
475 * If the PID file still hasn't appeared after ten seconds, attempt to
476 * kill the process and then bail.
477 */
478 if (access(pidfile, F_OK) != 0) {
479 kill(process->pid, SIGTERM);
480 alarm(5);
481 waitpid(process->pid, NULL, 0);
482 alarm(0);
483 bail("cannot start %s", argv[0]);
484 }
485
486 /*
487 * Read the PID back from the PID file. This usually isn't necessary for
488 * non-forking daemons, but always doing this makes this function general,
489 * and it's required when running under fakeroot.
490 */
491 if (fakeroot)
492 process->pid = read_pidfile(pidfile);
493 process->is_child = !fakeroot;
494
495 /* Register the log file as a source of diag messages. */
496 diag_file_add(process->logfile);
497
498 /*
499 * Add the process to our global list and set our cleanup handler if this
500 * is the first process we started.
501 */
502 if (processes == NULL)
503 test_cleanup_register(process_stop_all);
504 process->next = processes;
505 processes = process;
506
507 /* All done. */
508 return process;
509 }
510
511
512 /*
513 * Start a process and return the opaque process struct. The process must
514 * create pidfile with its PID when startup is complete.
515 */
516 struct process *
process_start(const char * const argv[],const char * pidfile)517 process_start(const char *const argv[], const char *pidfile)
518 {
519 return process_start_internal(argv, pidfile, false);
520 }
521
522
523 /*
524 * Start a process under fakeroot and return the opaque process struct. If
525 * fakeroot is not available, calls skip_all. The process must create pidfile
526 * with its PID when startup is complete.
527 */
528 struct process *
process_start_fakeroot(const char * const argv[],const char * pidfile)529 process_start_fakeroot(const char *const argv[], const char *pidfile)
530 {
531 return process_start_internal(argv, pidfile, true);
532 }
533