1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2008 3f08c3bdfSopenharmony_ci * Author: Matt Helsley <matthltc@us.ibm.com> 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * This library is free software; you can redistribute it and/or 6f08c3bdfSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 7f08c3bdfSopenharmony_ci * License as published by the Free Software Foundation; either 8f08c3bdfSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This library is distributed in the hope that it will be useful, 11f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13f08c3bdfSopenharmony_ci * Lesser General Public License for more details. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 16f08c3bdfSopenharmony_ci * License along with this library; if not, write to the Free Software 17f08c3bdfSopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * Usage: $0 <num> 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * vfork <num> times, stopping after each vfork. TODO: Requires an external process 23f08c3bdfSopenharmony_ci * to send SIGCONT to goto the next vfork. <num> SIGCONT signals must be 24f08c3bdfSopenharmony_ci * received before exiting. 25f08c3bdfSopenharmony_ci * 26f08c3bdfSopenharmony_ci * We can't do anything but execve or _exit in vfork'd processes 27f08c3bdfSopenharmony_ci * so we use ptrace vfork'd processes in order to pause then during each 28f08c3bdfSopenharmony_ci * vfork. This places the parent process in "TASK_UNINTERRUPTIBLE" state 29f08c3bdfSopenharmony_ci * until vfork returns. This can delay delivery of signals to the parent 30f08c3bdfSopenharmony_ci * process, even delay or stop system suspend. 31f08c3bdfSopenharmony_ci */ 32f08c3bdfSopenharmony_ci#include <stdio.h> 33f08c3bdfSopenharmony_ci#include <stdlib.h> 34f08c3bdfSopenharmony_ci#include <string.h> 35f08c3bdfSopenharmony_ci#include <unistd.h> 36f08c3bdfSopenharmony_ci#include <errno.h> 37f08c3bdfSopenharmony_ci#include <time.h> 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci#include <sys/types.h> 40f08c3bdfSopenharmony_ci#include <sys/wait.h> 41f08c3bdfSopenharmony_ci#include <sys/socket.h> 42f08c3bdfSopenharmony_ci#include "test.h" 43f08c3bdfSopenharmony_ci#include "config.h" 44f08c3bdfSopenharmony_ci#include "../../syscalls/ptrace/ptrace.h" 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#define str_expand(s) str(s) 47f08c3bdfSopenharmony_ci#define str(s) #s 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci#define debug(s) \ 50f08c3bdfSopenharmony_ciperror("ERROR at " __FILE__ ":" str_expand(__LINE__) ": " s ) 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cichar *filename = NULL; 53f08c3bdfSopenharmony_ciFILE *fp = NULL; 54f08c3bdfSopenharmony_ciint psync[2]; 55f08c3bdfSopenharmony_cipid_t child = -1; 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ciint TST_TOTAL = 1; 58f08c3bdfSopenharmony_cichar *TCID = "vfork"; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci/* for signal handlers */ 61f08c3bdfSopenharmony_civoid parent_cleanup(void) 62f08c3bdfSopenharmony_ci{ 63f08c3bdfSopenharmony_ci close(psync[1]); 64f08c3bdfSopenharmony_ci if (fp) { 65f08c3bdfSopenharmony_ci fflush(fp); 66f08c3bdfSopenharmony_ci if (filename) { 67f08c3bdfSopenharmony_ci fclose(fp); 68f08c3bdfSopenharmony_ci (void)unlink(filename); 69f08c3bdfSopenharmony_ci } 70f08c3bdfSopenharmony_ci } 71f08c3bdfSopenharmony_ci tst_exit(); 72f08c3bdfSopenharmony_ci} 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_civoid kill_child(void) 75f08c3bdfSopenharmony_ci{ 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci /* Avoid killing all processes at the current user's level, and the 78f08c3bdfSopenharmony_ci * test app as well =]. 79f08c3bdfSopenharmony_ci */ 80f08c3bdfSopenharmony_ci if (0 < child && kill(child, 0) == 0) { 81f08c3bdfSopenharmony_ci /* Shouldn't happen, but I've seen it before... */ 82f08c3bdfSopenharmony_ci if (ptrace(PTRACE_KILL, child, NULL, NULL) < 0) { 83f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, 84f08c3bdfSopenharmony_ci "ptrace(PTRACE_KILL, %d, ..) failed", child); 85f08c3bdfSopenharmony_ci } 86f08c3bdfSopenharmony_ci (void)waitpid(child, NULL, WNOHANG); /* Zombie children are bad. */ 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci} 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_civoid child_cleanup(void) 92f08c3bdfSopenharmony_ci{ 93f08c3bdfSopenharmony_ci close(psync[0]); 94f08c3bdfSopenharmony_ci tst_exit(); 95f08c3bdfSopenharmony_ci} 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ciint do_vfork(int count) 98f08c3bdfSopenharmony_ci{ 99f08c3bdfSopenharmony_ci pid_t child; 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci while (count) { 102f08c3bdfSopenharmony_ci child = vfork(); 103f08c3bdfSopenharmony_ci if (child == 0) 104f08c3bdfSopenharmony_ci _exit(0); 105f08c3bdfSopenharmony_ci else if (child > 0) 106f08c3bdfSopenharmony_ci count--; 107f08c3bdfSopenharmony_ci else { 108f08c3bdfSopenharmony_ci tst_brkm(TFAIL | TERRNO, NULL, "vfork failed"); 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci } 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci return EXIT_SUCCESS; 113f08c3bdfSopenharmony_ci} 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci/* Options */ 116f08c3bdfSopenharmony_ciint num_vforks = 1; 117f08c3bdfSopenharmony_ciint do_pause = 0; 118f08c3bdfSopenharmony_ciint do_sleep = 0; 119f08c3bdfSopenharmony_cistruct timespec sleep_duration; 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_civoid sleepy_time(void) 122f08c3bdfSopenharmony_ci{ 123f08c3bdfSopenharmony_ci do { 124f08c3bdfSopenharmony_ci int rc = nanosleep(&sleep_duration, &sleep_duration); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci if ((rc == -1) && (errno != EINTR)) 127f08c3bdfSopenharmony_ci continue; 128f08c3bdfSopenharmony_ci break; 129f08c3bdfSopenharmony_ci } while (1); 130f08c3bdfSopenharmony_ci} 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_civoid usage(void) 133f08c3bdfSopenharmony_ci{ 134f08c3bdfSopenharmony_ci tst_resm(TBROK, "usage: %s [-f [FILE]] [-s [NUM]] [-p] [NUM]\n\n" 135f08c3bdfSopenharmony_ci "\t-f FILE\t\tFile to output trace data to.\n" 136f08c3bdfSopenharmony_ci "\t-s NUM\t\tSleep for NUM seconds. [Default: 1 second]\n" 137f08c3bdfSopenharmony_ci "\t\t\t\tSuffixes ms, us, s, m, and h correspond to\n" 138f08c3bdfSopenharmony_ci "\t\t\t\tmilliseconds, microseconds, seconds [Default],\n" 139f08c3bdfSopenharmony_ci "\t\t\t\tminutes, and hours respectively.\n\n" 140f08c3bdfSopenharmony_ci "\t-p\t\tPause.\n\n" 141f08c3bdfSopenharmony_ci "\tNUM\t\tExecute vfork NUM times.\n", TCID); 142f08c3bdfSopenharmony_ci} 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_civoid _parse_opts(int argc, char **argv) 145f08c3bdfSopenharmony_ci{ 146f08c3bdfSopenharmony_ci int opt; 147f08c3bdfSopenharmony_ci char *units; 148f08c3bdfSopenharmony_ci unsigned long long duration = 1U; 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci sleep_duration.tv_sec = 0U; 151f08c3bdfSopenharmony_ci sleep_duration.tv_nsec = 0U; 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci while ((opt = getopt(argc, argv, "f:ps::")) != -1) { 154f08c3bdfSopenharmony_ci switch (opt) { 155f08c3bdfSopenharmony_ci case 'f': 156f08c3bdfSopenharmony_ci if ((fp = fopen(optarg, "w")) != NULL) { 157f08c3bdfSopenharmony_ci filename = optarg; 158f08c3bdfSopenharmony_ci } 159f08c3bdfSopenharmony_ci break; 160f08c3bdfSopenharmony_ci case 'p': 161f08c3bdfSopenharmony_ci do_pause = 1; 162f08c3bdfSopenharmony_ci break; 163f08c3bdfSopenharmony_ci case 's': 164f08c3bdfSopenharmony_ci if (optarg == NULL) { 165f08c3bdfSopenharmony_ci sleep_duration.tv_sec = 1; 166f08c3bdfSopenharmony_ci do_sleep = 1; 167f08c3bdfSopenharmony_ci break; 168f08c3bdfSopenharmony_ci } 169f08c3bdfSopenharmony_ci opt = sscanf(optarg, "%Ld%as", &duration, &units); 170f08c3bdfSopenharmony_ci if (opt < 1) 171f08c3bdfSopenharmony_ci break; 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci if ((opt != 2) || !strcmp(units, "s")) 174f08c3bdfSopenharmony_ci sleep_duration.tv_sec = duration; 175f08c3bdfSopenharmony_ci else if (!strcmp(units, "ms")) 176f08c3bdfSopenharmony_ci sleep_duration.tv_nsec = duration * 1000000U; 177f08c3bdfSopenharmony_ci else if (!strcmp(units, "us")) 178f08c3bdfSopenharmony_ci sleep_duration.tv_nsec = duration * 1000U; 179f08c3bdfSopenharmony_ci else if (!strcmp(units, "m")) 180f08c3bdfSopenharmony_ci sleep_duration.tv_sec = duration * 60U; 181f08c3bdfSopenharmony_ci else if (!strcmp(units, "h")) 182f08c3bdfSopenharmony_ci sleep_duration.tv_sec = duration * 3600U; 183f08c3bdfSopenharmony_ci else { 184f08c3bdfSopenharmony_ci tst_resm(TBROK, "Unrecognized time units: %s", 185f08c3bdfSopenharmony_ci units); 186f08c3bdfSopenharmony_ci usage(); 187f08c3bdfSopenharmony_ci } 188f08c3bdfSopenharmony_ci do_sleep = 1; 189f08c3bdfSopenharmony_ci break; 190f08c3bdfSopenharmony_ci default: 191f08c3bdfSopenharmony_ci usage(); 192f08c3bdfSopenharmony_ci } 193f08c3bdfSopenharmony_ci } 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci if (optind >= argc) 196f08c3bdfSopenharmony_ci return; 197f08c3bdfSopenharmony_ci if (!strcmp(argv[optind], "--")) 198f08c3bdfSopenharmony_ci return; 199f08c3bdfSopenharmony_ci sscanf(argv[optind], "%d", &num_vforks); 200f08c3bdfSopenharmony_ci} 201f08c3bdfSopenharmony_ci 202f08c3bdfSopenharmony_ciint trace_grandchild(pid_t gchild) 203f08c3bdfSopenharmony_ci{ 204f08c3bdfSopenharmony_ci#if HAVE_DECL_PTRACE_GETSIGINFO 205f08c3bdfSopenharmony_ci siginfo_t info; 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci if (ptrace(PTRACE_GETSIGINFO, gchild, NULL, &info) == -1) { 208f08c3bdfSopenharmony_ci debug("ptrace(): "); 209f08c3bdfSopenharmony_ci return 0; 210f08c3bdfSopenharmony_ci } 211f08c3bdfSopenharmony_ci /*dump_siginfo(gchild, &info); */ 212f08c3bdfSopenharmony_ci if ((info.si_code != 0) || (info.si_signo != SIGSTOP)) 213f08c3bdfSopenharmony_ci return 0; 214f08c3bdfSopenharmony_ci 215f08c3bdfSopenharmony_ci tst_resm(TINFO, "Grandchild spawn's pid=%d", gchild); 216f08c3bdfSopenharmony_ci fprintf(fp, "\t%d\n", gchild); 217f08c3bdfSopenharmony_ci fflush(fp); 218f08c3bdfSopenharmony_ci if (do_pause) 219f08c3bdfSopenharmony_ci pause(); 220f08c3bdfSopenharmony_ci if (do_sleep) 221f08c3bdfSopenharmony_ci sleepy_time(); 222f08c3bdfSopenharmony_ci if (ptrace(PTRACE_DETACH, gchild, NULL, NULL) == -1) 223f08c3bdfSopenharmony_ci debug("ptrace(): "); 224f08c3bdfSopenharmony_ci return -1; /* don't wait for gchild */ 225f08c3bdfSopenharmony_ci#else 226f08c3bdfSopenharmony_ci return 0; 227f08c3bdfSopenharmony_ci#endif 228f08c3bdfSopenharmony_ci} 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_ciint do_trace(pid_t child, int num_children) 231f08c3bdfSopenharmony_ci{ 232f08c3bdfSopenharmony_ci int my_exit_status = EXIT_SUCCESS; 233f08c3bdfSopenharmony_ci int status; 234f08c3bdfSopenharmony_ci pid_t process; 235f08c3bdfSopenharmony_ci 236f08c3bdfSopenharmony_ci while (num_children > 0) { 237f08c3bdfSopenharmony_ci int died = 0; 238f08c3bdfSopenharmony_ci 239f08c3bdfSopenharmony_ci /*printf("waiting for %d processes to exit\n", num_children); */ 240f08c3bdfSopenharmony_ci process = waitpid(-1, &status, WUNTRACED); 241f08c3bdfSopenharmony_ci if (process < 1) 242f08c3bdfSopenharmony_ci continue; 243f08c3bdfSopenharmony_ci /*dump_status(process, status); */ 244f08c3bdfSopenharmony_ci died = (WIFEXITED(status) || WIFSIGNALED(status)); 245f08c3bdfSopenharmony_ci if (died) 246f08c3bdfSopenharmony_ci num_children--; 247f08c3bdfSopenharmony_ci if (process == child) 248f08c3bdfSopenharmony_ci my_exit_status = WEXITSTATUS(status); 249f08c3bdfSopenharmony_ci if (died || !WIFSTOPPED(status)) 250f08c3bdfSopenharmony_ci continue; 251f08c3bdfSopenharmony_ci 252f08c3bdfSopenharmony_ci if (process == child) { 253f08c3bdfSopenharmony_ci /* trace_child(process); */ 254f08c3bdfSopenharmony_ci if (ptrace(PTRACE_CONT, process, NULL, NULL) == -1) 255f08c3bdfSopenharmony_ci debug("ptrace(): "); 256f08c3bdfSopenharmony_ci } else 257f08c3bdfSopenharmony_ci num_children += trace_grandchild(process); 258f08c3bdfSopenharmony_ci 259f08c3bdfSopenharmony_ci } 260f08c3bdfSopenharmony_ci 261f08c3bdfSopenharmony_ci return my_exit_status; 262f08c3bdfSopenharmony_ci} 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_civoid send_mutex(int fd) 265f08c3bdfSopenharmony_ci{ 266f08c3bdfSopenharmony_ci ssize_t nbytes = 0; 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci do { 269f08c3bdfSopenharmony_ci nbytes = write(fd, "r", 1); 270f08c3bdfSopenharmony_ci if (nbytes == 1) 271f08c3bdfSopenharmony_ci break; 272f08c3bdfSopenharmony_ci if (nbytes != -1) 273f08c3bdfSopenharmony_ci continue; 274f08c3bdfSopenharmony_ci if ((errno == EAGAIN) || (errno == EINTR)) 275f08c3bdfSopenharmony_ci continue; 276f08c3bdfSopenharmony_ci else 277f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 278f08c3bdfSopenharmony_ci debug("write: "); 279f08c3bdfSopenharmony_ci } while (1); 280f08c3bdfSopenharmony_ci} 281f08c3bdfSopenharmony_ci 282f08c3bdfSopenharmony_civoid await_mutex(int fd) 283f08c3bdfSopenharmony_ci{ 284f08c3bdfSopenharmony_ci char buffer[1]; 285f08c3bdfSopenharmony_ci ssize_t nbytes = 0; 286f08c3bdfSopenharmony_ci 287f08c3bdfSopenharmony_ci do { 288f08c3bdfSopenharmony_ci nbytes = read(fd, buffer, sizeof(buffer)); 289f08c3bdfSopenharmony_ci if (nbytes == 1) 290f08c3bdfSopenharmony_ci break; 291f08c3bdfSopenharmony_ci if (nbytes != -1) 292f08c3bdfSopenharmony_ci continue; 293f08c3bdfSopenharmony_ci if ((errno == EAGAIN) || (errno == EINTR)) 294f08c3bdfSopenharmony_ci continue; 295f08c3bdfSopenharmony_ci else 296f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 297f08c3bdfSopenharmony_ci } while (1); 298f08c3bdfSopenharmony_ci} 299f08c3bdfSopenharmony_ci 300f08c3bdfSopenharmony_ciint main(int argc, char **argv) 301f08c3bdfSopenharmony_ci{ 302f08c3bdfSopenharmony_ci 303f08c3bdfSopenharmony_ci#if HAVE_DECL_PTRACE_SETOPTIONS && HAVE_DECL_PTRACE_O_TRACEVFORKDONE 304f08c3bdfSopenharmony_ci int exit_status; 305f08c3bdfSopenharmony_ci 306f08c3bdfSopenharmony_ci _parse_opts(argc, argv); 307f08c3bdfSopenharmony_ci 308f08c3bdfSopenharmony_ci if (fp == NULL) { 309f08c3bdfSopenharmony_ci fp = stderr; 310f08c3bdfSopenharmony_ci } 311f08c3bdfSopenharmony_ci 312f08c3bdfSopenharmony_ci if (socketpair(AF_UNIX, SOCK_STREAM, 0, psync) == -1) { 313f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "socketpair() failed"); 314f08c3bdfSopenharmony_ci } else { 315f08c3bdfSopenharmony_ci 316f08c3bdfSopenharmony_ci child = fork(); 317f08c3bdfSopenharmony_ci if (child == -1) { 318f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "fork() failed"); 319f08c3bdfSopenharmony_ci } else if (child == 0) { 320f08c3bdfSopenharmony_ci 321f08c3bdfSopenharmony_ci int rc = EXIT_FAILURE; 322f08c3bdfSopenharmony_ci 323f08c3bdfSopenharmony_ci tst_sig(FORK, DEF_HANDLER, child_cleanup); 324f08c3bdfSopenharmony_ci 325f08c3bdfSopenharmony_ci if (close(psync[1])) { 326f08c3bdfSopenharmony_ci tst_resm(TBROK, "close(psync[1]) failed)"); 327f08c3bdfSopenharmony_ci } else { 328f08c3bdfSopenharmony_ci /* sleep until the parent wakes us up */ 329f08c3bdfSopenharmony_ci await_mutex(psync[0]); 330f08c3bdfSopenharmony_ci rc = do_vfork(num_vforks); 331f08c3bdfSopenharmony_ci } 332f08c3bdfSopenharmony_ci _exit(rc); 333f08c3bdfSopenharmony_ci 334f08c3bdfSopenharmony_ci } else { 335f08c3bdfSopenharmony_ci 336f08c3bdfSopenharmony_ci tst_sig(FORK, kill_child, parent_cleanup); 337f08c3bdfSopenharmony_ci 338f08c3bdfSopenharmony_ci close(psync[0]); 339f08c3bdfSopenharmony_ci 340f08c3bdfSopenharmony_ci /* Set up ptrace */ 341f08c3bdfSopenharmony_ci if (ptrace(PTRACE_ATTACH, child, NULL, NULL) == -1) { 342f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, 343f08c3bdfSopenharmony_ci NULL, "ptrace(ATTACH) failed"); 344f08c3bdfSopenharmony_ci } 345f08c3bdfSopenharmony_ci if (waitpid(child, NULL, 0) != child) { 346f08c3bdfSopenharmony_ci tst_resm(TBROK | TERRNO, "waitpid(%d) failed", 347f08c3bdfSopenharmony_ci child); 348f08c3bdfSopenharmony_ci kill_child(); 349f08c3bdfSopenharmony_ci } else { 350f08c3bdfSopenharmony_ci 351f08c3bdfSopenharmony_ci if (ptrace(PTRACE_SETOPTIONS, child, NULL, 352f08c3bdfSopenharmony_ci PTRACE_O_TRACEVFORK) == -1) { 353f08c3bdfSopenharmony_ci tst_resm(TINFO | TERRNO, 354f08c3bdfSopenharmony_ci "ptrace(PTRACE_SETOPTIONS) " 355f08c3bdfSopenharmony_ci "failed."); 356f08c3bdfSopenharmony_ci } 357f08c3bdfSopenharmony_ci if (ptrace(PTRACE_CONT, child, NULL, NULL) == 358f08c3bdfSopenharmony_ci -1) { 359f08c3bdfSopenharmony_ci tst_resm(TINFO | TERRNO, 360f08c3bdfSopenharmony_ci "ptrace(PTRACE_CONT) failed."); 361f08c3bdfSopenharmony_ci } 362f08c3bdfSopenharmony_ci 363f08c3bdfSopenharmony_ci send_mutex(psync[1]); 364f08c3bdfSopenharmony_ci 365f08c3bdfSopenharmony_ci close(psync[1]); 366f08c3bdfSopenharmony_ci 367f08c3bdfSopenharmony_ci tst_resm(TINFO, "Child spawn's pid=%d", child); 368f08c3bdfSopenharmony_ci fprintf(fp, "%d\n", child); 369f08c3bdfSopenharmony_ci fflush(fp); 370f08c3bdfSopenharmony_ci 371f08c3bdfSopenharmony_ci exit_status = do_trace(child, ++num_vforks); 372f08c3bdfSopenharmony_ci 373f08c3bdfSopenharmony_ci tst_resm(exit_status == 0 ? TPASS : TFAIL, 374f08c3bdfSopenharmony_ci "do_trace %s", 375f08c3bdfSopenharmony_ci (exit_status == 376f08c3bdfSopenharmony_ci 0 ? "succeeded" : "failed")); 377f08c3bdfSopenharmony_ci 378f08c3bdfSopenharmony_ci parent_cleanup(); 379f08c3bdfSopenharmony_ci 380f08c3bdfSopenharmony_ci } 381f08c3bdfSopenharmony_ci 382f08c3bdfSopenharmony_ci } 383f08c3bdfSopenharmony_ci 384f08c3bdfSopenharmony_ci } 385f08c3bdfSopenharmony_ci 386f08c3bdfSopenharmony_ci#else 387f08c3bdfSopenharmony_ci tst_resm(TCONF, "System doesn't support have required ptrace " 388f08c3bdfSopenharmony_ci "capabilities."); 389f08c3bdfSopenharmony_ci#endif 390f08c3bdfSopenharmony_ci tst_resm(TINFO, "Exiting..."); 391f08c3bdfSopenharmony_ci tst_exit(); 392f08c3bdfSopenharmony_ci 393f08c3bdfSopenharmony_ci} 394