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