1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. 4 * Copyright (c) 2014 Cyril Hrubis <chrubis (at) suse.cz> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 /* 22 * Test to check the error and trivial conditions in setpgid system call 23 * 24 * EPERM - The calling process, process specified by pid and the target 25 * process group must be in the same session. 26 * 27 * EACCESS - Proccess cannot change process group ID of a child after child 28 * has performed exec() 29 */ 30 31 #include <wait.h> 32 #include <limits.h> 33 #include <signal.h> 34 #include <errno.h> 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <unistd.h> 39 #include "test.h" 40 41 #define TEST_APP "setpgid03_child" 42 43 char *TCID = "setpgid03"; 44 int TST_TOTAL = 1; 45 46 static void do_child(void); 47 static void setup(void); 48 static void cleanup(void); 49 50 int main(int ac, char **av) 51 { 52 int child_pid; 53 int status; 54 int rval; 55 int lc; 56 57 tst_parse_opts(ac, av, NULL, NULL); 58 #ifdef UCLINUX 59 maybe_run_child(&do_child, ""); 60 #endif 61 62 setup(); 63 64 for (lc = 0; TEST_LOOPING(lc); lc++) { 65 66 tst_count = 0; 67 68 /* Child is in new session we are not alowed to change pgid */ 69 if ((child_pid = FORK_OR_VFORK()) == -1) 70 tst_brkm(TBROK, cleanup, "fork() failed"); 71 72 if (child_pid == 0) { 73 #ifdef UCLINUX 74 if (self_exec(av[0], "") < 0) 75 tst_brkm(TBROK, cleanup, "self_exec failed"); 76 #else 77 do_child(); 78 #endif 79 } 80 81 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 82 rval = setpgid(child_pid, getppid()); 83 if (rval == -1 && errno == EPERM) { 84 tst_resm(TPASS, "setpgid failed with EPERM"); 85 } else { 86 tst_resm(TFAIL, 87 "retval %d, errno %d, expected errno %d", 88 rval, errno, EPERM); 89 } 90 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 91 92 if (wait(&status) < 0) 93 tst_resm(TFAIL | TERRNO, "wait() for child 1 failed"); 94 95 if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) 96 tst_resm(TFAIL, "child 1 failed with status %d", 97 WEXITSTATUS(status)); 98 99 /* Child after exec() we are no longer allowed to set pgid */ 100 if ((child_pid = FORK_OR_VFORK()) == -1) 101 tst_resm(TFAIL, "Fork failed"); 102 103 if (child_pid == 0) { 104 if (execlp(TEST_APP, TEST_APP, NULL) < 0) 105 perror("exec failed"); 106 107 exit(127); 108 } 109 110 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 111 rval = setpgid(child_pid, getppid()); 112 if (rval == -1 && errno == EACCES) { 113 tst_resm(TPASS, "setpgid failed with EACCES"); 114 } else { 115 tst_resm(TFAIL, 116 "retval %d, errno %d, expected errno %d", 117 rval, errno, EACCES); 118 } 119 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 120 121 if (wait(&status) < 0) 122 tst_resm(TFAIL | TERRNO, "wait() for child 2 failed"); 123 124 if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) 125 tst_resm(TFAIL, "child 2 failed with status %d", 126 WEXITSTATUS(status)); 127 } 128 129 cleanup(); 130 tst_exit(); 131 } 132 133 static void do_child(void) 134 { 135 if (setsid() < 0) { 136 printf("CHILD: setsid() failed, errno: %d\n", errno); 137 exit(2); 138 } 139 140 TST_SAFE_CHECKPOINT_WAKE(NULL, 0); 141 142 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 143 144 exit(0); 145 } 146 147 static void setup(void) 148 { 149 tst_sig(FORK, DEF_HANDLER, cleanup); 150 151 tst_tmpdir(); 152 153 TST_CHECKPOINT_INIT(tst_rmdir); 154 155 umask(0); 156 157 TEST_PAUSE; 158 } 159 160 static void cleanup(void) 161 { 162 tst_rmdir(); 163 } 164