1 | /* Test that spawn file action functions work without file limit. |
2 | Copyright (C) 2016-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <fcntl.h> |
21 | #include <spawn.h> |
22 | #include <stdbool.h> |
23 | #include <stdio.h> |
24 | #include <sys/resource.h> |
25 | #include <unistd.h> |
26 | |
27 | /* _SC_OPEN_MAX value. */ |
28 | static long maxfd; |
29 | |
30 | /* A positive but unused file descriptor, used for testing |
31 | purposes. */ |
32 | static int invalid_fd; |
33 | |
34 | /* Indicate that errors have been encountered. */ |
35 | static bool errors; |
36 | |
37 | static posix_spawn_file_actions_t actions; |
38 | |
39 | static void |
40 | one_test (const char *name, int (*func) (int), int fd, |
41 | bool expect_success) |
42 | { |
43 | int ret = func (fd); |
44 | if (expect_success) |
45 | { |
46 | if (ret != 0) |
47 | { |
48 | errno = ret; |
49 | printf (format: "error: posix_spawn_file_actions_%s (%d): %m\n" , name, fd); |
50 | errors = true; |
51 | } |
52 | } |
53 | else if (ret != EBADF) |
54 | { |
55 | if (ret == 0) |
56 | printf (format: "error: posix_spawn_file_actions_%s (%d):" |
57 | " unexpected success\n" , name, fd); |
58 | else |
59 | { |
60 | errno = ret; |
61 | printf (format: "error: posix_spawn_file_actions_%s (%d): %m\n" , name, fd); |
62 | } |
63 | errors = true; |
64 | } |
65 | } |
66 | |
67 | static void |
68 | all_tests (const char *name, int (*func) (int)) |
69 | { |
70 | one_test (name, func, fd: 0, true); |
71 | one_test (name, func, fd: invalid_fd, true); |
72 | one_test (name, func, fd: -1, false); |
73 | one_test (name, func, fd: -2, false); |
74 | if (maxfd >= 0) |
75 | one_test (name, func, fd: maxfd, false); |
76 | } |
77 | |
78 | static int |
79 | addopen (int fd) |
80 | { |
81 | return posix_spawn_file_actions_addopen |
82 | (file_actions: &actions, fd: fd, path: "/dev/null" , O_RDONLY, mode: 0); |
83 | } |
84 | |
85 | static int |
86 | adddup2 (int fd) |
87 | { |
88 | return posix_spawn_file_actions_adddup2 (file_actions: &actions, fd: fd, newfd: 1); |
89 | } |
90 | |
91 | static int |
92 | adddup2_reverse (int fd) |
93 | { |
94 | return posix_spawn_file_actions_adddup2 (file_actions: &actions, fd: 1, newfd: fd); |
95 | } |
96 | |
97 | static int |
98 | addclose (int fd) |
99 | { |
100 | return posix_spawn_file_actions_addclose (file_actions: &actions, fd: fd); |
101 | } |
102 | |
103 | static void |
104 | all_functions (void) |
105 | { |
106 | all_tests (name: "addopen" , func: addopen); |
107 | all_tests (name: "adddup2" , func: adddup2); |
108 | all_tests (name: "adddup2" , func: adddup2_reverse); |
109 | all_tests (name: "adddup2" , func: addclose); |
110 | } |
111 | |
112 | static int |
113 | do_test (void) |
114 | { |
115 | /* Try to eliminate the file descriptor limit. */ |
116 | { |
117 | struct rlimit limit; |
118 | if (getrlimit (RLIMIT_NOFILE, rlimits: &limit) < 0) |
119 | { |
120 | printf (format: "error: getrlimit: %m\n" ); |
121 | return 1; |
122 | } |
123 | limit.rlim_cur = RLIM_INFINITY; |
124 | if (setrlimit (RLIMIT_NOFILE, rlimits: &limit) < 0) |
125 | printf (format: "warning: setrlimit: %m\n" ); |
126 | } |
127 | |
128 | maxfd = sysconf (_SC_OPEN_MAX); |
129 | printf (format: "info: _SC_OPEN_MAX: %ld\n" , maxfd); |
130 | |
131 | invalid_fd = dup (fd: 0); |
132 | if (invalid_fd < 0) |
133 | { |
134 | printf (format: "error: dup: %m\n" ); |
135 | return 1; |
136 | } |
137 | if (close (fd: invalid_fd) < 0) |
138 | { |
139 | printf (format: "error: close: %m\n" ); |
140 | return 1; |
141 | } |
142 | |
143 | int ret = posix_spawn_file_actions_init (file_actions: &actions); |
144 | if (ret != 0) |
145 | { |
146 | errno = ret; |
147 | printf (format: "error: posix_spawn_file_actions_init: %m\n" ); |
148 | return 1; |
149 | } |
150 | |
151 | all_functions (); |
152 | |
153 | ret = posix_spawn_file_actions_destroy (file_actions: &actions); |
154 | if (ret != 0) |
155 | { |
156 | errno = ret; |
157 | printf (format: "error: posix_spawn_file_actions_destroy: %m\n" ); |
158 | return 1; |
159 | } |
160 | |
161 | return errors; |
162 | } |
163 | |
164 | #define TEST_FUNCTION do_test () |
165 | #include "../test-skeleton.c" |
166 | |