Home | History | Annotate | Download | only in semctl
      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
     22  *	semctl04.c
     23  *
     24  * DESCRIPTION
     25  *	semctl04 - test for EPERM error
     26  *
     27  * ALGORITHM
     28  *	create a semaphore set without read or alter permissions
     29  *	get the user id for "nobody"
     30  *	fork a child process
     31  *	if child
     32  *	  set the ID of the child process to that of "nobody"
     33  *	  loop if that option was specified
     34  *	    call semctl() with two different invalid cases
     35  *	    check the errno value
     36  *	      issue a PASS message if we get EPERM
     37  *	    otherwise, the tests fails
     38  *	      issue a FAIL message
     39  *	  call cleanup
     40  *	if parent
     41  *	  wait for child to exit
     42  *	  remove the semaphore set
     43  *
     44  * USAGE:  <for command-line>
     45  *  semctl04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     46  *     where,  -c n : Run n copies concurrently.
     47  *             -e   : Turn on errno logging.
     48  *	       -i n : Execute test n times.
     49  *	       -I x : Execute test for x seconds.
     50  *	       -P x : Pause for x seconds between iterations.
     51  *	       -t   : Turn on syscall timing.
     52  *
     53  * HISTORY
     54  *	03/2001 - Written by Wayne Boyer
     55  *
     56  * RESTRICTIONS
     57  *	test must be run as root
     58  */
     59 
     60 #include "ipcsem.h"
     61 
     62 #include <pwd.h>
     63 #include <sys/wait.h>
     64 
     65 char *TCID = "semctl04";
     66 int TST_TOTAL = 2;
     67 
     68 int sem_id_1 = -1;
     69 
     70 uid_t ltp_uid;
     71 char *ltp_user = "nobody";
     72 
     73 int TC[] = { IPC_SET, IPC_RMID };
     74 
     75 int main(int ac, char **av)
     76 {
     77 	pid_t pid;
     78 	void do_child(void);
     79 
     80 	tst_parse_opts(ac, av, NULL, NULL);
     81 
     82 	setup();		/* global setup */
     83 
     84 	if ((pid = FORK_OR_VFORK()) == -1) {
     85 		tst_brkm(TBROK, cleanup, "could not fork");
     86 	}
     87 
     88 	if (pid == 0) {		/* child */
     89 		/* set the user ID of the child to the non root user */
     90 		if (setuid(ltp_uid) == -1) {
     91 			tst_resm(TBROK, "setuid() failed");
     92 			exit(1);
     93 		}
     94 
     95 		do_child();
     96 
     97 	} else {
     98 		if (waitpid(pid, NULL, 0) == -1) {
     99 			tst_resm(TBROK, "waitpid() failed");
    100 			tst_resm(TINFO, "waitpid() error = %d : %s", errno,
    101 				 strerror(errno));
    102 		}
    103 
    104 		/* if it exists, remove the semaphore resouce */
    105 		rm_sema(sem_id_1);
    106 
    107 		tst_rmdir();
    108 	}
    109 	cleanup();
    110 
    111 	tst_exit();
    112 }
    113 
    114 /*
    115  * do_child() - make the TEST call as the child process
    116  */
    117 void do_child(void)
    118 {
    119 	int lc;
    120 	int i;
    121 	union semun arg;
    122 	struct semid_ds perm;
    123 
    124 	/* The following loop checks looping state if -i option given */
    125 
    126 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    127 		/* reset tst_count in case we are looping */
    128 		tst_count = 0;
    129 
    130 		for (i = 0; i < TST_TOTAL; i++) {
    131 
    132 			if (TC[i] == IPC_SET) {
    133 				arg.buf = &perm;
    134 				memset(&perm, 0, sizeof perm);
    135 				perm.sem_perm.uid = getuid() + 1;
    136 				perm.sem_perm.gid = getgid() + 1;
    137 				perm.sem_perm.mode = 0666;
    138 			}
    139 
    140 			TEST(semctl(sem_id_1, 0, TC[i], arg));
    141 
    142 			if (TEST_RETURN != -1) {
    143 				tst_resm(TFAIL, "call succeeded unexpectedly");
    144 				continue;
    145 			}
    146 
    147 			switch (TEST_ERRNO) {
    148 			case EPERM:
    149 				tst_resm(TPASS, "expected failure - errno ="
    150 					 " %d : %s", TEST_ERRNO,
    151 					 strerror(TEST_ERRNO));
    152 				break;
    153 			default:
    154 				tst_resm(TFAIL, "unexpected error "
    155 					 "- %d : %s", TEST_ERRNO,
    156 					 strerror(TEST_ERRNO));
    157 				break;
    158 			}
    159 		}
    160 	}
    161 }
    162 
    163 /*
    164  * setup() - performs all the ONE TIME setup for this test.
    165  */
    166 void setup(void)
    167 {
    168 	tst_require_root();
    169 
    170 	tst_sig(FORK, DEF_HANDLER, cleanup);
    171 
    172 	TEST_PAUSE;
    173 
    174 	/*
    175 	 * Create a temporary directory and cd into it.
    176 	 * This helps to ensure that a unique msgkey is created.
    177 	 * See ../lib/libipc.c for more information.
    178 	 */
    179 	tst_tmpdir();
    180 
    181 	/* get an IPC resource key */
    182 	semkey = getipckey();
    183 
    184 	/* create a semaphore set without read or alter permissions */
    185 	if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) {
    186 		tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup");
    187 	}
    188 
    189 	/* get the userid for a non root user */
    190 	ltp_uid = getuserid(ltp_user);
    191 }
    192 
    193 /*
    194  * cleanup() - performs all the ONE TIME cleanup for this test at completion
    195  * 	       or premature exit.
    196  */
    197 void cleanup(void)
    198 {
    199 
    200 }
    201