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'. */
29static int restart;
30
31
32#define CMDLINE_OPTIONS \
33 { "restart", no_argument, &restart, 1 },
34
35/* Prototype for our test function. */
36extern void do_prepare (int argc, char *argv[]);
37extern 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. */
46static char *name1;
47static char *name2;
48
49/* File descriptors for these temporary files. */
50static int temp_fd1 = -1;
51static int temp_fd2 = -1;
52
53/* The contents of our files. */
54static const char fd1string[] = "This file should get closed";
55static const char fd2string[] = "This file should stay opened";
56
57
58/* We have a preparation function. */
59void
60do_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 (base: "exec", filename: &name1);
67 temp_fd2 = create_temp_file (base: "exec", filename: &name2);
68 if (temp_fd1 < 0 || temp_fd2 < 0)
69 exit (1);
70}
71
72
73static int
74handle_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 (nptr: fd1s);
82 fd2 = atol (nptr: fd2s);
83
84 /* Sanity check. */
85 if (fd1 == fd2)
86 error (EXIT_FAILURE, errnum: 0, format: "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 (fd: fd2, offset: 0, SEEK_CUR) != strlen (fd2string))
91 error (EXIT_FAILURE, errno, format: "file 2 not in right position");
92 if (lseek (fd: fd2, offset: 0, SEEK_SET) != 0)
93 error (EXIT_FAILURE, errnum: 0, format: "cannot reset position in file 2");
94 if (read (fd2, buf, sizeof buf) != strlen (fd2string))
95 error (EXIT_FAILURE, errnum: 0, format: "cannot read file 2");
96 if (memcmp (fd2string, buf, strlen (fd2string)) != 0)
97 error (EXIT_FAILURE, errnum: 0, format: "file 2 does not match");
98
99 /* No try to read the first file. First make sure it is not opened. */
100 if (lseek (fd: fd1, offset: 0, SEEK_CUR) != (off_t) -1 || errno != EBADF)
101 error (EXIT_FAILURE, errnum: 0, format: "file 1 (%d) is not closed", fd1);
102
103 /* Now open the file and read it. */
104 fd1 = open (file: name, O_RDONLY);
105 if (fd1 == -1)
106 error (EXIT_FAILURE, errno,
107 format: "cannot open first file \"%s\" for verification", name);
108
109 if (read (fd1, buf, sizeof buf) != strlen (fd1string))
110 error (EXIT_FAILURE, errno, format: "cannot read file 1");
111 if (memcmp (fd1string, buf, strlen (fd1string)) != 0)
112 error (EXIT_FAILURE, errnum: 0, format: "file 1 does not match");
113
114 return 0;
115}
116
117
118int
119do_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, errnum: 0, format: "wrong number of arguments (%d)", argc);
141
142 return handle_restart (fd1s: argv[1], fd2s: argv[2], name: argv[3]);
143 }
144
145 if (argc != 2 && argc != 5)
146 error (EXIT_FAILURE, errnum: 0, format: "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 (fd: temp_fd1, F_GETFD, 0);
153 if (flags < 0)
154 error (EXIT_FAILURE, errno, format: "cannot get flags");
155 flags |= FD_CLOEXEC;
156 if (fcntl (fd: temp_fd1, F_SETFD, flags) < 0)
157 error (EXIT_FAILURE, errno, format: "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, format: "cannot write to first file");
162 if (write (temp_fd2, fd2string, strlen (fd2string)) != strlen (fd2string))
163 error (EXIT_FAILURE, errno, format: "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 (s: fd1name, maxlen: sizeof fd1name, format: "%d", temp_fd1);
174 snprintf (s: fd2name, maxlen: sizeof fd2name, format: "%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, format: "cannot exec");
185 }
186 else if (pid == (pid_t) -1)
187 error (EXIT_FAILURE, errno, format: "cannot fork");
188
189 /* Wait for the child. */
190 if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid)
191 error (EXIT_FAILURE, errno, format: "wrong child");
192
193 if (WTERMSIG (status) != 0)
194 error (EXIT_FAILURE, errnum: 0, format: "Child terminated incorrectly");
195 status = WEXITSTATUS (status);
196
197 return status;
198}
199

source code of glibc/posix/tst-exec.c