• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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