1 /*
2 * Test --syscall-limit option.
3 *
4 * Copyright (c) 2023 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20
21 #ifndef PRINT_VALID
22 # define PRINT_VALID 1
23 #endif
24 #ifndef PRINT_INVALID
25 # define PRINT_INVALID 1
26 #endif
27 #ifndef PRINT_STATS
28 # define PRINT_STATS 0
29 #endif
30 #ifndef UNLINKAT_CNT
31 # define UNLINKAT_CNT 1
32 #endif
33 #ifndef TOTAL_CNT
34 # define TOTAL_CNT 3
35 #endif
36
37 static int
38 write_status(const char *name, int value)
39 {
40 FILE *fp = fopen(name, "w");
41 if (!fp)
42 perror_msg_and_fail("fopen: %s", name);
43 if (fprintf(fp, "%d\n", value) <= 0)
44 perror_msg_and_fail("fprintf: %s", name);
45 if (fclose(fp))
46 perror_msg_and_fail("fclose: %s", name);
47 fflush(stdout);
48 return value;
49 }
50
51 static const char valid_path[] = ".";
52 static const char invalid_path[] = "invalid.dir";
53
54 static void
55 test_chdir(int pid, bool print)
56 {
57 if (chdir(valid_path))
58 perror_msg_and_fail("chdir: %s", valid_path);
59
60 if (print) {
61 #if PRINT_VALID
62 printf("%-5u chdir(\"%s\") = 0\n", pid, valid_path);
63 #else /* !PRINT_VALID */
64 if (chdir(invalid_path) == 0)
65 error_msg_and_fail("chdir: %s", invalid_path);
66 # if PRINT_INVALID
67 printf("%-5u chdir(\"%s\") = %s\n", pid, invalid_path, sprintrc(-1));
68 # endif
69 #endif /* PRINT_VALID */
70 } else {
71 if (chdir(invalid_path) == 0)
72 error_msg_and_fail("chdir: %s", invalid_path);
73 }
74 }
75
76 static void
77 test_rmdir(int pid, bool print)
78 {
79 #ifndef AT_FDCWD
80 # define AT_FDCWD -100
81 #endif
82 #ifndef AT_REMOVEDIR
83 # define AT_REMOVEDIR 0x200
84 #endif
85 if (syscall(__NR_unlinkat, AT_FDCWD, "invalid.dir", AT_REMOVEDIR) == 0)
86 error_msg_and_fail("unlinkat: %s", invalid_path);
87 #if PRINT_INVALID
88 if (print)
89 printf("%-5u unlinkat(AT_FDCWD, \"%s\", AT_REMOVEDIR) = %s\n",
90 pid, invalid_path, sprintrc(-1));
91 #endif
92 }
93
94 int
95 main(void)
96 {
97 int pid = getpid();
98
99 test_chdir(pid, /* print */ true);
100
101 fflush(stdout);
102 pid_t child = fork();
103 if (child < 0)
104 perror_msg_and_fail("fork");
105
106 if (child == 0) {
107 int pid = getpid();
108
109 test_rmdir(pid, /* print */ true);
110 test_chdir(pid, /* print */ true);
111
112 /*
113 * the tracer is expected to detach at this point
114 * if TOTAL_CNT < 4.
115 */
116
117 test_rmdir(pid, /* print */ TOTAL_CNT > 3);
118
119 exit(0);
120 }
121
122 int status;
123 while ((waitpid(child, &status, 0)) != child) {
124 if (errno == EINTR)
125 continue;
126 perror_msg_and_fail("waitpid: %d", child);
127 }
128
129 /* the tracer is expected to detach at this point */
130
131 test_chdir(pid, /* print */ false);
132
133 #if PRINT_STATS
134 # if defined MPERS_IS_m32
135 printf("System call usage summary for 32 bit mode:\n");
136 # endif
137 # if defined MPERS_IS_mx32
138 printf("System call usage summary for x32 mode:\n");
139 # endif
140 printf("%9s %s\n", "calls", "syscall");
141 printf("--------- ----------------\n");
142 printf("%9d %s\n", 2, "chdir");
143 printf("%9d %s\n", UNLINKAT_CNT, "unlinkat");
144 printf("--------- ----------------\n");
145 printf("%9d %s\n", TOTAL_CNT, "total");
146 #endif /* PRINT_STATS */
147
148 return write_status("parent_status",
149 WIFEXITED(status) ? WEXITSTATUS(status) : 1);
150 }