1 /* Tests for exec.
2 Copyright (C) 2000-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 <error.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <wait.h>
26
27
28 /* Nonzero if the program gets called via `exec'. */
29 static int restart;
30
31
32 #define CMDLINE_OPTIONS \
33 { "restart", no_argument, &restart, 1 },
34
35 /* Prototype for our test function. */
36 extern void do_prepare (int argc, char *argv[]);
37 extern int do_test (int argc, char *argv[]);
38
39 /* We have a preparation function. */
40 #define PREPARE do_prepare
41
42 #include "../test-skeleton.c"
43
44
45 /* Name of the temporary files. */
46 static char *name1;
47 static char *name2;
48
49 /* File descriptors for these temporary files. */
50 static int temp_fd1 = -1;
51 static int temp_fd2 = -1;
52
53 /* The contents of our files. */
54 static const char fd1string[] = "This file should get closed";
55 static const char fd2string[] = "This file should stay opened";
56
57
58 /* We have a preparation function. */
59 void
do_prepare(int argc,char * argv[])60 do_prepare (int argc, char *argv[])
61 {
62 /* We must not open any files in the restart case. */
63 if (restart)
64 return;
65
66 temp_fd1 = create_temp_file ("exec", &name1);
67 temp_fd2 = create_temp_file ("exec", &name2);
68 if (temp_fd1 < 0 || temp_fd2 < 0)
69 exit (1);
70 }
71
72
73 static int
handle_restart(const char * fd1s,const char * fd2s,const char * name)74 handle_restart (const char *fd1s, const char *fd2s, const char *name)
75 {
76 char buf[100];
77 int fd1;
78 int fd2;
79
80 /* First get the descriptors. */
81 fd1 = atol (fd1s);
82 fd2 = atol (fd2s);
83
84 /* Sanity check. */
85 if (fd1 == fd2)
86 error (EXIT_FAILURE, 0, "value of fd1 and fd2 is the same");
87
88 /* First the easy part: read from the file descriptor which is
89 supposed to be open. */
90 if (lseek (fd2, 0, SEEK_CUR) != strlen (fd2string))
91 error (EXIT_FAILURE, errno, "file 2 not in right position");
92 if (lseek (fd2, 0, SEEK_SET) != 0)
93 error (EXIT_FAILURE, 0, "cannot reset position in file 2");
94 if (read (fd2, buf, sizeof buf) != strlen (fd2string))
95 error (EXIT_FAILURE, 0, "cannot read file 2");
96 if (memcmp (fd2string, buf, strlen (fd2string)) != 0)
97 error (EXIT_FAILURE, 0, "file 2 does not match");
98
99 /* No try to read the first file. First make sure it is not opened. */
100 if (lseek (fd1, 0, SEEK_CUR) != (off_t) -1 || errno != EBADF)
101 error (EXIT_FAILURE, 0, "file 1 (%d) is not closed", fd1);
102
103 /* Now open the file and read it. */
104 fd1 = open (name, O_RDONLY);
105 if (fd1 == -1)
106 error (EXIT_FAILURE, errno,
107 "cannot open first file \"%s\" for verification", name);
108
109 if (read (fd1, buf, sizeof buf) != strlen (fd1string))
110 error (EXIT_FAILURE, errno, "cannot read file 1");
111 if (memcmp (fd1string, buf, strlen (fd1string)) != 0)
112 error (EXIT_FAILURE, 0, "file 1 does not match");
113
114 return 0;
115 }
116
117
118 int
do_test(int argc,char * argv[])119 do_test (int argc, char *argv[])
120 {
121 pid_t pid;
122 int flags;
123 int status;
124
125 /* We must have
126 - one or four parameters left if called initially
127 + path for ld.so optional
128 + "--library-path" optional
129 + the library path optional
130 + the application name
131 - three parameters left if called through re-execution
132 + file descriptor number which is supposed to be closed
133 + the open file descriptor
134 + the name of the closed desriptor
135 */
136
137 if (restart)
138 {
139 if (argc != 4)
140 error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc);
141
142 return handle_restart (argv[1], argv[2], argv[3]);
143 }
144
145 if (argc != 2 && argc != 5)
146 error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc);
147
148 /* Prepare the test. We are creating two files: one which file descriptor
149 will be marked with FD_CLOEXEC, another which is not. */
150
151 /* Set the bit. */
152 flags = fcntl (temp_fd1, F_GETFD, 0);
153 if (flags < 0)
154 error (EXIT_FAILURE, errno, "cannot get flags");
155 flags |= FD_CLOEXEC;
156 if (fcntl (temp_fd1, F_SETFD, flags) < 0)
157 error (EXIT_FAILURE, errno, "cannot set flags");
158
159 /* Write something in the files. */
160 if (write (temp_fd1, fd1string, strlen (fd1string)) != strlen (fd1string))
161 error (EXIT_FAILURE, errno, "cannot write to first file");
162 if (write (temp_fd2, fd2string, strlen (fd2string)) != strlen (fd2string))
163 error (EXIT_FAILURE, errno, "cannot write to second file");
164
165 /* We want to test the `exec' function. To do this we restart the program
166 with an additional parameter. But first create another process. */
167 pid = fork ();
168 if (pid == 0)
169 {
170 char fd1name[18];
171 char fd2name[18];
172
173 snprintf (fd1name, sizeof fd1name, "%d", temp_fd1);
174 snprintf (fd2name, sizeof fd2name, "%d", temp_fd2);
175
176 /* This is the child. Construct the command line. */
177 if (argc == 5)
178 execl (argv[1], argv[1], argv[2], argv[3], argv[4], "--direct",
179 "--restart", fd1name, fd2name, name1, NULL);
180 else
181 execl (argv[1], argv[1], "--direct",
182 "--restart", fd1name, fd2name, name1, NULL);
183
184 error (EXIT_FAILURE, errno, "cannot exec");
185 }
186 else if (pid == (pid_t) -1)
187 error (EXIT_FAILURE, errno, "cannot fork");
188
189 /* Wait for the child. */
190 if (waitpid (pid, &status, 0) != pid)
191 error (EXIT_FAILURE, errno, "wrong child");
192
193 if (WTERMSIG (status) != 0)
194 error (EXIT_FAILURE, 0, "Child terminated incorrectly");
195 status = WEXITSTATUS (status);
196
197 return status;
198 }
199