1 /*
2 * This file is part of attach-f-p strace test.
3 *
4 * Copyright (c) 2016-2018 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <assert.h>
13 #include <errno.h>
14 #include <pthread.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/stat.h>
18 #include "scno.h"
19 #include <unistd.h>
20
21 #define N 3
22
23 typedef union {
24 void *ptr;
25 pid_t pid;
26 } retval_t;
27
28 static const char text_parent[] = "attach-f-p.test parent";
29 static const char *child[N] = {
30 "attach-f-p.test child 0",
31 "attach-f-p.test child 1",
32 "attach-f-p.test child 2"
33 };
34 typedef int pipefd[2];
35 static pipefd pipes[N];
36
37 static void *
38 thread(void *a)
39 {
40 unsigned int no = (long) a;
41 int i, rc;
42
43 while ((rc = read(pipes[no][0], &i, sizeof(i))) != (int) sizeof(i)) {
44 if (rc < 0 && errno == EINTR)
45 continue;
46 perror_msg_and_fail("read[%u]", no);
47 }
48 assert(chdir(child[no]) == -1);
49 retval_t retval = { .pid = syscall(__NR_gettid) };
50 return retval.ptr;
51 }
52
53 int
54 main(void)
55 {
56 pthread_t t[N];
57
58 if (write(1, "", 0) != 0)
59 perror_msg_and_fail("write");
60
61 for (unsigned int i = 0; i < N; ++i) {
62 if (pipe(pipes[i]))
63 perror_msg_and_fail("pipe");
64
65 errno = pthread_create(&t[i], NULL, thread, (void *) (long) i);
66 if (errno)
67 perror_msg_and_fail("pthread_create");
68 }
69
70 if (write(1, "\n", 1) != 1)
71 perror_msg_and_fail("write");
72
73 /* wait for the peer to write to stdout */
74 for (;;) {
75 struct stat st;
76
77 if (fstat(1, &st))
78 perror_msg_and_fail("fstat");
79 if (st.st_size >= 103)
80 break;
81 }
82
83 for (unsigned int i = 0; i < N; ++i) {
84 /* sleep a bit to let the tracer catch up */
85 sleep(1);
86 if (write(pipes[i][1], &i, sizeof(i)) != (int) sizeof(i))
87 perror_msg_and_fail("write[%u]", i);
88 retval_t retval;
89 errno = pthread_join(t[i], &retval.ptr);
90 if (errno)
91 perror_msg_and_fail("pthread_join");
92 errno = ENOENT;
93 printf("%-5d chdir(\"%s\") = %s\n"
94 "%-5d +++ exited with 0 +++\n",
95 retval.pid, child[i], sprintrc(-1), retval.pid);
96 }
97
98 /* sleep a bit more to let the tracer catch up */
99 sleep(1);
100
101 pid_t pid = getpid();
102 assert(chdir(text_parent) == -1);
103
104 printf("%-5d chdir(\"%s\") = -1 ENOENT (%m)\n"
105 "%-5d +++ exited with 0 +++\n", pid, text_parent, pid);
106
107 return 0;
108 }