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@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 <sys/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
main(int ac,char ** av)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
do_child(void)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
setup(void)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
cleanup(void)160 static void cleanup(void)
161 {
162 tst_rmdir();
163 }
164