blob: 17cecbaf5d39728eff5253c753b09336ee50a8f0 [file] [log] [blame]
/*
* Copyright (c) International Business Machines Corp., 2001
* Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
* Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Test to check the error and trivial conditions in setpgid system call
*
* EPERM - The calling process, process specified by pid and the target
* process group must be in the same session.
*
* EACCESS - Proccess cannot change process group ID of a child after child
* has performed exec()
*/
#include <wait.h>
#include <limits.h>
#include <signal.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "test.h"
#define TEST_APP "setpgid03_child"
char *TCID = "setpgid03";
int TST_TOTAL = 1;
static struct tst_checkpoint checkpoint;
static void do_child(void);
static void setup(void);
static void cleanup(void);
int main(int ac, char **av)
{
int child_pid;
int status;
int rval;
int lc;
const char *msg;
if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
#ifdef UCLINUX
maybe_run_child(&do_child, "");
#endif
setup();
for (lc = 0; TEST_LOOPING(lc); lc++) {
tst_count = 0;
/* Child is in new session we are not alowed to change pgid */
if ((child_pid = FORK_OR_VFORK()) == -1)
tst_brkm(TBROK, cleanup, "fork() failed");
if (child_pid == 0) {
#ifdef UCLINUX
if (self_exec(av[0], "") < 0)
tst_brkm(TBROK, cleanup, "self_exec failed");
#else
do_child();
#endif
}
TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint);
rval = setpgid(child_pid, getppid());
if (rval == -1 && errno == EPERM) {
tst_resm(TPASS, "setpgid failed with EPERM");
} else {
tst_resm(TFAIL,
"retval %d, errno %d, expected errno %d",
rval, errno, EPERM);
}
TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint);
if (wait(&status) < 0)
tst_resm(TFAIL | TERRNO, "wait() for child 1 failed");
if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0))
tst_resm(TFAIL, "child 1 failed with status %d",
WEXITSTATUS(status));
/* Child after exec() we are no longer allowed to set pgid */
if ((child_pid = FORK_OR_VFORK()) == -1)
tst_resm(TFAIL, "Fork failed");
if (child_pid == 0) {
if (execlp(TEST_APP, TEST_APP, NULL) < 0)
perror("exec failed");
exit(127);
}
TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint);
rval = setpgid(child_pid, getppid());
if (rval == -1 && errno == EACCES) {
tst_resm(TPASS, "setpgid failed with EACCES");
} else {
tst_resm(TFAIL,
"retval %d, errno %d, expected errno %d",
rval, errno, EACCES);
}
TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint);
if (wait(&status) < 0)
tst_resm(TFAIL | TERRNO, "wait() for child 2 failed");
if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0))
tst_resm(TFAIL, "child 2 failed with status %d",
WEXITSTATUS(status));
}
cleanup();
tst_exit();
}
static void do_child(void)
{
if (setsid() < 0) {
printf("CHILD: setsid() failed, errno: %d\n", errno);
exit(2);
}
TST_CHECKPOINT_SIGNAL_PARENT(&checkpoint);
TST_CHECKPOINT_CHILD_WAIT(&checkpoint);
exit(0);
}
static void setup(void)
{
tst_sig(FORK, DEF_HANDLER, cleanup);
tst_tmpdir();
TST_CHECKPOINT_CREATE(&checkpoint);
checkpoint.timeout = 10000;
umask(0);
TEST_PAUSE;
}
static void cleanup(void)
{
tst_rmdir();
}