Home | History | Annotate | Download | only in vfork
      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 
    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  */
    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  */
    349 void cleanup(void)
    350 {
    351 
    352 }
    353