1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * Name: vfork01
22 *
23 * Test Description:
24 * Fork a process using vfork() and verify that, the attribute values like
25 * euid, ruid, suid, egid, rgid, sgid, umask, inode and device number of
26 * root and current working directories are same as that of the parent
27 * process.
28 * $
29 * Expected Result:
30 * The attribute values like euid, ruid, suid, egid, rgid, sgid, umask, inode
31 * and device number of root and current working directory of the parent and
32 * child processes should be equal.
33 *
34 * Algorithm:
35 * Setup:
36 * Setup signal handling.
37 * Pause for SIGUSR1 if option specified.
38 *
39 * Test:
40 * Loop if the proper options are given.
41 * Execute system call
42 * Check return code, if system call failed (return=-1)
43 * Log the errno and Issue a FAIL message.
44 * Otherwise,
45 * Verify the Functionality of system call
46 * if successful,
47 * Issue Functionality-Pass message.
48 * Otherwise,
49 * Issue Functionality-Fail message.
50 * Cleanup:
51 * Print errno log and/or timing stats if options given
52 *
53 * Usage: <for command-line>
54 * vfork01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
55 * where, -c n : Run n copies concurrently.
56 * -e : Turn on errno logging.
57 * -f : Turn off functionality Testing.
58 * -i n : Execute test n times.
59 * -I x : Execute test for x seconds.
60 * -P x : Pause for x seconds between iterations.
61 * -t : Turn on syscall timing.
62 *
63 * History
64 * 07/2001 John George
65 * -Ported
66 *
67 * Restrictions:
68 * None.
69 *
70 */
71
72 #define _GNU_SOURCE 1
73 #include <stdio.h>
74 #include <sys/types.h>
75 #include <errno.h>
76 #include <unistd.h>
77 #include <fcntl.h>
78 #include <string.h>
79 #include <signal.h>
80 #include <unistd.h>
81 #include <sys/stat.h>
82 #include <sys/wait.h>
83
84 #include "test.h"
85
86 char *TCID = "vfork01";
87 int TST_TOTAL = 1;
88
89 /* Variables to hold parent/child eff/real/saved uid/gid values */
90 uid_t Peuid, Ceuid, Csuid, Psuid, Pruid, Cruid;
91 gid_t Pegid, Cegid, Psgid, Csgid, Prgid, Crgid;
92 mode_t Pumask, Cumask;
93
94 char *Pcwd, *Ccwd; /*
95 * pathname of working directory of
96 * child/parent process.
97 */
98 /* stat structure to hold directory/inode information for parent/child */
99 struct stat StatPbuf;
100 struct stat StatCbuf;
101 struct stat Stat_cwd_Pbuf;
102 struct stat Stat_cwd_Cbuf;
103
104 void setup(); /* Main setup function of test */
105 void cleanup(); /* cleanup function for the test */
106
main(int ac,char ** av)107 int main(int ac, char **av)
108 {
109 int lc;
110 pid_t cpid; /* process id of the child process */
111 int exit_status; /* exit status of child process */
112
113 tst_parse_opts(ac, av, NULL, NULL);
114
115 setup();
116
117 for (lc = 0; TEST_LOOPING(lc); lc++) {
118
119 tst_count = 0;
120
121 /*
122 * Call vfork(2) to create a child process without
123 * fully copying the address space of parent.
124 */
125 TEST(vfork());
126
127 if ((cpid = TEST_RETURN) == -1) {
128 tst_resm(TFAIL, "vfork() Failed, errno=%d : %s",
129 TEST_ERRNO, strerror(TEST_ERRNO));
130 } else if (cpid == 0) { /* Child process */
131 /*
132 * Get the euid, ruid, egid, rgid, umask value
133 * and the current working directory of the
134 * child process
135 */
136 if (getresuid(&Cruid, &Ceuid, &Csuid) < 0) {
137 tst_resm(TFAIL, "getresuid() fails to "
138 "get real/eff./saved uid of "
139 "child process");
140 _exit(1);
141 }
142
143 if (getresgid(&Crgid, &Cegid, &Csgid) < 0) {
144 tst_resm(TFAIL, "getresgid() fails to "
145 "get real/eff./saved gid of "
146 "child process");
147 _exit(1);
148 }
149
150 /*
151 * Get the file mode creation mask value of
152 * child process by setting value zero and
153 * restore the previous mask value.
154 */
155 Cumask = umask(0);
156
157 /*
158 * Restore the process mask of child to
159 * previous value.
160 */
161 umask(Cumask);
162
163 /*
164 * Get the pathname of current working
165 * directory for the child process.
166 */
167 if ((Ccwd = (char *)getcwd(NULL,
168 BUFSIZ)) == NULL) {
169 tst_resm(TFAIL, "getcwd failed for the "
170 "child process");
171 _exit(1);
172 }
173
174 /*
175 * Get the device number and the inode
176 * number of "/" directory for the child
177 * process.
178 */
179 if (stat("/", &StatCbuf) < 0) {
180 tst_resm(TFAIL, "stat(2) failed to get "
181 "info. of'/' in the child "
182 "process");
183 _exit(1);
184 }
185
186 /*
187 * Get the device/inode number of "."
188 * (working directory) for the child process.
189 */
190 if (stat(Ccwd, &Stat_cwd_Cbuf) < 0) {
191 tst_resm(TFAIL, "stat(2) failed to get "
192 "info. of working irectory in "
193 "the child");
194 _exit(1);
195 }
196
197 /* Now, do the actual comparision */
198 if (Peuid != Ceuid || Pegid != Cegid ||
199 Psuid != Csuid || Psgid != Csgid ||
200 Pruid != Cruid || Prgid != Crgid ||
201 Pumask != Cumask) {
202 tst_resm(TFAIL, "Attribute values of "
203 "parent and child don't match");
204 _exit(1);
205 } else {
206 tst_resm(TINFO, "Attribute values of "
207 "parent and child match");
208 }
209
210 /* Check for the same working directories */
211 if (strcmp(Pcwd, Ccwd) != 0) {
212 tst_resm(TFAIL, "Working directories "
213 "of parent and child don't "
214 "match");
215 _exit(1);
216 } else {
217 tst_resm(TINFO, "Working directories "
218 "of parent and child match");
219 }
220
221 /*
222 * Check for the same device/inode number of
223 * '/' directory.
224 */
225 if ((StatPbuf.st_ino != StatCbuf.st_ino) ||
226 (StatPbuf.st_dev != StatCbuf.st_dev)) {
227 tst_resm(TFAIL, "Device/inode number "
228 "of parent and childs '/' "
229 " don't match");
230 _exit(1);
231 } else {
232 tst_resm(TINFO, "Device/inode number "
233 "of parent and childs '/' "
234 "match");
235 }
236
237 /*
238 * Check for the same device and inode number
239 * of "." (current working directory.
240 */
241 if ((Stat_cwd_Pbuf.st_ino !=
242 Stat_cwd_Cbuf.st_ino) ||
243 (Stat_cwd_Pbuf.st_dev !=
244 Stat_cwd_Cbuf.st_dev)) {
245 tst_resm(TFAIL, "Device/inode number "
246 "of parent and childs '.' "
247 "don't match");
248 _exit(1);
249 } else {
250 tst_resm(TINFO, "Device/inode number "
251 "of parent and childs '.' "
252 "don't match");
253 }
254
255 /*
256 * Exit with normal exit code if everything
257 * fine
258 */
259 _exit(0);
260
261 } else { /* parent process */
262 /*
263 * Let the parent process wait till child completes
264 * its execution.
265 */
266 wait(&exit_status);
267
268 /* Check for the exit status of child process */
269 if (WEXITSTATUS(exit_status) == 0) {
270 tst_resm(TPASS, "Call of vfork() successful");
271 } else if (WEXITSTATUS(exit_status) == 1) {
272 tst_resm(TFAIL,
273 "Child process exited abnormally");
274 }
275 }
276 tst_count++; /* incr. TEST_LOOP counter */
277 }
278
279 cleanup();
280 tst_exit();
281 }
282
283 /*
284 * void
285 * setup() - performs all ONE TIME setup for this test.
286 * This function gets real/effective/saved uid/gid, umask, the device/inode
287 * number of '/' and current working directory for the parent process.
288 */
setup(void)289 void setup(void)
290 {
291
292 tst_sig(FORK, DEF_HANDLER, cleanup);
293
294 TEST_PAUSE;
295
296 /*
297 * Get the euid, ruid, egid, rgid, umask value
298 * and the current working directory of the parent process.
299 */
300 if (getresuid(&Pruid, &Peuid, &Psuid) < 0) {
301 tst_brkm(TFAIL, cleanup, "getresuid() fails to get "
302 "real/eff./saved uid of parent");
303 }
304
305 if (getresgid(&Prgid, &Pegid, &Psgid) < 0) {
306 tst_brkm(TFAIL, cleanup, "getresgid() fails to get "
307 "real/eff./saved gid of parent");
308 }
309
310 /* Get the process file mode creation mask by setting value 0 */
311 Pumask = umask(0);
312 umask(Pumask); /*
313 * Restore the mask value of the
314 * process.
315 */
316 /*
317 * Get the pathname of current working directory of the parent
318 * process.
319 */
320 if ((Pcwd = (char *)getcwd(NULL, BUFSIZ)) == NULL) {
321 tst_brkm(TFAIL, cleanup,
322 "getcwd failed for the parent process");
323 }
324
325 /*
326 * Get the device and inode number of root directory for the
327 * parent process.
328 */
329 if (stat("/", &StatPbuf) == -1) {
330 tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of '/' "
331 "in parent process");
332 }
333
334 /*
335 * Get the device number and the inode number of "." (current-
336 * working directory) for the parent process.
337 */
338 if (stat(Pcwd, &Stat_cwd_Pbuf) < 0) {
339 tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of "
340 "working directory in parent process");
341 }
342 }
343
344 /*
345 * void
346 * cleanup() - performs all ONE TIME cleanup for this test at
347 * completion or premature exit.
348 */
cleanup(void)349 void cleanup(void)
350 {
351
352 }
353