/* * * Copyright (c) International Business Machines Corp., 2001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Name: vfork01 * * Test Description: * Fork a process using vfork() and verify that, the attribute values like * euid, ruid, suid, egid, rgid, sgid, umask, inode and device number of * root and current working directories are same as that of the parent * process. * * Expected Result: * The attribute values like euid, ruid, suid, egid, rgid, sgid, umask, inode * and device number of root and current working directory of the parent and * child processes should be equal. * * Algorithm: * Setup: * Setup signal handling. * Pause for SIGUSR1 if option specified. * * Test: * Loop if the proper options are given. * Execute system call * Check return code, if system call failed (return=-1) * Log the errno and Issue a FAIL message. * Otherwise, * Verify the Functionality of system call * if successful, * Issue Functionality-Pass message. * Otherwise, * Issue Functionality-Fail message. * Cleanup: * Print errno log and/or timing stats if options given * * Usage: * vfork01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] * where, -c n : Run n copies concurrently. * -e : Turn on errno logging. * -f : Turn off functionality Testing. * -i n : Execute test n times. * -I x : Execute test for x seconds. * -P x : Pause for x seconds between iterations. * -t : Turn on syscall timing. * * History * 07/2001 John George * -Ported * * Restrictions: * None. * */ #include #include #include #include #include #include #include #include "test.h" #include "usctest.h" const char *TCID="vfork01"; /* Test program identifier. */ int TST_TOTAL=1; /* Total number of test cases. */ extern int Tst_count; /* Test Case counter for tst_* routines */ int exp_enos[]={0}; /* Variables to hold parent/child eff/real/saved uid/gid values */ uid_t Peuid, Ceuid, Csuid, Psuid, Pruid, Cruid; gid_t Pegid, Cegid, Psgid, Csgid, Prgid, Crgid; mode_t Pumask,Cumask; char Pcwd_buf [PATH_MAX], Ccwd_buf [PATH_MAX]; char *Pcwd, *Ccwd; /* * pathname of working directory of * child/parent process. */ /* stat structure to hold directory/inode information for parent/child */ struct stat StatPbuf; struct stat StatCbuf; struct stat Stat_cwd_Pbuf; struct stat Stat_cwd_Cbuf; void setup(); /* Main setup function of test */ void cleanup() __attribute__((noreturn));/* cleanup function for the test */ int main(int ac, char **av) { int lc; /* loop counter */ const char *msg; /* message returned from parse_opts */ pid_t cpid; /* process id of the child process */ int exit_status; /* exit status of child process */ /* Parse standard options given to run the test. */ msg = parse_opts(ac, av, (option_t *) NULL, NULL); if (msg != (char *) NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); tst_exit(); } /* Perform global setup for test */ setup(); /* set the expected errnos... */ TEST_EXP_ENOS(exp_enos); /* Check looping state if -i option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { /* Reset Tst_count in case we are looping. */ Tst_count=0; /* * Call vfork(2) to create a child process without * fully copying the address space of parent. */ TEST(vfork()); /* check return code of vfork() */ if ((cpid = TEST_RETURN) == -1) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "vfork() Failed, errno=%d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); } else if (cpid == 0) { /* Child process */ /* * Perform functional verification if test * executed without (-f) option. */ if (STD_FUNCTIONAL_TEST) { /* * Get the euid, ruid, egid, rgid, umask value * and the current working directory of the * child process */ #if (linux) if (getresuid(&Cruid, &Ceuid, &Csuid) < 0) { tst_resm(TFAIL, "getresuid() fails to " "get real/eff./saved uid of " "child process"); _exit(1); } if (getresgid(&Crgid, &Cegid, &Csgid) < 0) { tst_resm(TFAIL, "getresgid() fails to " "get real/eff./saved gid of " "child process"); _exit(1); } #else Cruid = getuid (); Ceuid = geteuid (); Csuid = 0; Crgid = getgid (); Cegid = getegid (); Csgid = 0; #endif /* * Get the file mode creation mask value of * child process by setting value zero and * restore the previous mask value. */ Cumask = umask(0); /* * Restore the process mask of child to * previous value. */ umask(Cumask); /* * Get the pathname of current working * directory for the child process. */ if ((Ccwd = (char *)getcwd(Ccwd_buf, \ BUFSIZ)) == NULL) { tst_resm(TFAIL, "getcwd failed for the " "child process"); _exit(1); } /* * Get the device number and the inode * number of "/" directory for the child * process. */ if (stat("/", &StatCbuf) < 0) { tst_resm(TFAIL, "stat(2) failed to get " "info. of'/' in the child " "process"); _exit(1); } /* * Get the device/inode number of "." * (working directory) for the child process. */ if (stat(Ccwd, &Stat_cwd_Cbuf) < 0) { tst_resm(TFAIL, "stat(2) failed to get " "info. of working irectory in " "the child"); _exit(1); } /* Now, do the actual comparision */ if (Peuid != Ceuid || Pegid != Cegid || \ Psuid != Csuid || Psgid != Csgid || \ Pruid != Cruid || Prgid != Crgid || \ Pumask != Cumask) { tst_resm(TFAIL, "Arribute values of " "parent and child don't match"); _exit(1); } else { tst_resm(TINFO, "Arribute values of " "parent and child match"); } /* Check for the same working directories */ if (strcmp(Pcwd, Ccwd) != 0) { tst_resm(TFAIL, "Working directories " "of parent and child don't " "match"); _exit(1); } else { tst_resm(TINFO, "Working directories " "of parent and child match"); } /* * Check for the same device/inode number of * '/' directory. */ if ((StatPbuf.st_ino != StatCbuf.st_ino) || \ (StatPbuf.st_dev != StatCbuf.st_dev)) { tst_resm(TFAIL, "Device/inode number " "of parent and childs '/' " " don't match"); _exit(1); } else { tst_resm(TINFO, "Device/inode number " "of parent and childs '/' " "match"); } /* * Check for the same device and inode number * of "." (current working directory. */ if ((Stat_cwd_Pbuf.st_ino != \ Stat_cwd_Cbuf.st_ino) || \ (Stat_cwd_Pbuf.st_dev != \ Stat_cwd_Cbuf.st_dev)) { tst_resm(TFAIL, "Device/inode number " "of parent and childs '.' " "don't match"); _exit(1); } else { tst_resm(TINFO, "Device/inode number " "of parent and childs '.' " "match"); } /* * Exit with normal exit code if everything * fine */ _exit(0); } } else { /* parent process */ /* * Let the parent process wait till child completes * its execution. */ wait(&exit_status); /* Check for the exit status of child process */ if (WEXITSTATUS(exit_status) == 0) { tst_resm(TPASS, \ "Call of vfork() successful"); } else if (WEXITSTATUS(exit_status) == 1) { tst_resm(TFAIL, \ "Child process exited abnormally"); } } Tst_count++; /* incr. TEST_LOOP counter */ } /* End for TEST_LOOPING */ /* Call cleanup() to undo setup done for the test. */ cleanup(); /*NOTREACHED*/ } /* End main */ /* * void * setup() - performs all ONE TIME setup for this test. * This function gets real/effective/saved uid/gid, umask, the device/inode * number of '/' and current working directory for the parent process. */ void setup() { /* capture signals */ tst_sig(FORK, DEF_HANDLER, cleanup); /* Pause if that option was specified */ TEST_PAUSE; /* * Get the euid, ruid, egid, rgid, umask value * and the current working directory of the parent process. */ #if (linux) if (getresuid(&Pruid, &Peuid, &Psuid) < 0) { tst_brkm(TFAIL, cleanup, "getresuid() fails to get " "real/eff./saved uid of parent"); } if (getresgid(&Prgid, &Pegid, &Psgid) < 0) { tst_brkm(TFAIL, cleanup, "getresgid() fails to get " "real/eff./saved gid of parent"); } #else Pruid = getuid (); Peuid = geteuid (); Psuid = 0; Prgid = getgid (); Pegid = getegid (); Psgid = 0; #endif /* Get the process file mode creation mask by setting value 0 */ Pumask = umask(0); umask(Pumask); /* * Restore the mask value of the * process. */ /* * Get the pathname of current working directory of the parent * process. */ if ((Pcwd = (char *) getcwd(Pcwd_buf, BUFSIZ)) == NULL) { tst_brkm(TFAIL, cleanup, "getcwd failed for the parent process"); } /* * Get the device and inode number of root directory for the * parent process. */ if (stat("/", &StatPbuf) == -1) { tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of '/' " "in parent process"); } /* * Get the device number and the inode number of "." (current- * working directory) for the parent process. */ if (stat(Pcwd, &Stat_cwd_Pbuf) < 0) { tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of " "working directory in parent process"); } } /* End setup() */ /* * void * cleanup() - performs all ONE TIME cleanup for this test at * completion or premature exit. */ void cleanup() { /* * print timing stats if that option was specified. * print errno log if that option was specified. */ TEST_CLEANUP; /* exit with return code appropriate for results */ tst_exit(); } /* End cleanup() */