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
one_test(const char * name,int (* func)(int),int fd,bool expect_success)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 ("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 ("error: posix_spawn_file_actions_%s (%d):"
57                   " unexpected success\n", name, fd);
58       else
59         {
60           errno = ret;
61           printf ("error: posix_spawn_file_actions_%s (%d): %m\n", name, fd);
62         }
63       errors = true;
64     }
65 }
66 
67 static void
all_tests(const char * name,int (* func)(int))68 all_tests (const char *name, int (*func) (int))
69 {
70   one_test (name, func, 0, true);
71   one_test (name, func, invalid_fd, true);
72   one_test (name, func, -1, false);
73   one_test (name, func, -2, false);
74   if (maxfd >= 0)
75     one_test (name, func, maxfd, false);
76 }
77 
78 static int
addopen(int fd)79 addopen (int fd)
80 {
81   return posix_spawn_file_actions_addopen
82     (&actions, fd, "/dev/null", O_RDONLY, 0);
83 }
84 
85 static int
adddup2(int fd)86 adddup2 (int fd)
87 {
88   return posix_spawn_file_actions_adddup2 (&actions, fd, 1);
89 }
90 
91 static int
adddup2_reverse(int fd)92 adddup2_reverse (int fd)
93 {
94   return posix_spawn_file_actions_adddup2 (&actions, 1, fd);
95 }
96 
97 static int
addclose(int fd)98 addclose (int fd)
99 {
100   return posix_spawn_file_actions_addclose (&actions, fd);
101 }
102 
103 static void
all_functions(void)104 all_functions (void)
105 {
106   all_tests ("addopen", addopen);
107   all_tests ("adddup2", adddup2);
108   all_tests ("adddup2", adddup2_reverse);
109   all_tests ("adddup2", addclose);
110 }
111 
112 static int
do_test(void)113 do_test (void)
114 {
115   /* Try to eliminate the file descriptor limit.  */
116   {
117     struct rlimit limit;
118     if (getrlimit (RLIMIT_NOFILE, &limit) < 0)
119       {
120         printf ("error: getrlimit: %m\n");
121         return 1;
122       }
123     limit.rlim_cur = RLIM_INFINITY;
124     if (setrlimit (RLIMIT_NOFILE, &limit) < 0)
125       printf ("warning: setrlimit: %m\n");
126   }
127 
128   maxfd = sysconf (_SC_OPEN_MAX);
129   printf ("info: _SC_OPEN_MAX: %ld\n", maxfd);
130 
131   invalid_fd = dup (0);
132   if (invalid_fd < 0)
133     {
134       printf ("error: dup: %m\n");
135       return 1;
136     }
137   if (close (invalid_fd) < 0)
138     {
139       printf ("error: close: %m\n");
140       return 1;
141     }
142 
143   int ret = posix_spawn_file_actions_init (&actions);
144   if (ret != 0)
145     {
146       errno = ret;
147       printf ("error: posix_spawn_file_actions_init: %m\n");
148       return 1;
149     }
150 
151   all_functions ();
152 
153   ret = posix_spawn_file_actions_destroy (&actions);
154   if (ret != 0)
155     {
156       errno = ret;
157       printf ("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