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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 529 process_start_fakeroot(const char *const argv[], const char *pidfile) 530 { 531 return process_start_internal(argv, pidfile, true); 532 } 533