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 * DESCRIPTION
22 *	semop02 - test for E2BIG, EACCES, EFAULT, EINVAL and ERANGE errors
23 *
24 * HISTORY
25 *	03/2001 - Written by Wayne Boyer
26 *
27 *      10/03/2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com)
28 *      - Fix concurrency issue. The second key used for this test could
29 *        conflict with the key from another task.
30 */
31
32#define _GNU_SOURCE
33#include <pwd.h>
34#include "test.h"
35#include "safe_macros.h"
36#include "ipcsem.h"
37
38char *TCID = "semop02";
39
40static void semop_verify(int i);
41int sem_id_1 = -1;	/* a semaphore set with read & alter permissions */
42int sem_id_2 = -1;	/* a semaphore set without read & alter permissions */
43int bad_id = -1;
44
45struct sembuf s_buf[PSEMS];
46
47int badbuf = -1;
48
49#define NSOPS	5		/* a resonable number of operations */
50#define	BIGOPS	1024		/* a value that is too large for the number */
51				/* of semop operations that are permitted   */
52struct test_case_t {
53	int *semid;
54	struct sembuf *t_sbuf;
55	unsigned t_ops;
56	int error;
57} TC[] = {
58	{&sem_id_1, (struct sembuf *)&s_buf, BIGOPS, E2BIG},
59	{&sem_id_2, (struct sembuf *)&s_buf, NSOPS, EACCES},
60	{&sem_id_1, (struct sembuf *)-1, NSOPS, EFAULT},
61	{&sem_id_1, (struct sembuf *)&s_buf, 0, EINVAL},
62	{&bad_id, (struct sembuf *)&s_buf, NSOPS, EINVAL},
63	{&sem_id_1, (struct sembuf *)&s_buf, 1, ERANGE}
64};
65
66int TST_TOTAL = ARRAY_SIZE(TC);
67
68int main(int ac, char **av)
69{
70	int lc;
71	int i;
72
73	tst_parse_opts(ac, av, NULL, NULL);
74
75	setup();
76
77	for (lc = 0; TEST_LOOPING(lc); lc++) {
78		tst_count = 0;
79
80		for (i = 0; i < TST_TOTAL; i++)
81			semop_verify(i);
82	}
83
84	cleanup();
85	tst_exit();
86}
87
88void setup(void)
89{
90	char nobody_uid[] = "nobody";
91	struct passwd *ltpuser;
92	key_t semkey2;
93	struct seminfo ipc_buf;
94	union semun arr;
95
96	tst_require_root();
97
98	ltpuser = SAFE_GETPWNAM(NULL, nobody_uid);
99	SAFE_SETUID(NULL, ltpuser->pw_uid);
100
101	tst_sig(NOFORK, DEF_HANDLER, cleanup);
102
103	TEST_PAUSE;
104
105	tst_tmpdir();
106
107	/* get an IPC resource key */
108	semkey = getipckey();
109
110	/* create a semaphore set with read and alter permissions */
111	sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
112	if (sem_id_1 == -1) {
113		tst_brkm(TBROK | TERRNO, cleanup,
114			 "couldn't create semaphore in setup");
115	}
116
117	/* Get an new IPC resource key. */
118	semkey2 = getipckey();
119
120	/* create a semaphore set without read and alter permissions */
121	sem_id_2 = semget(semkey2, PSEMS, IPC_CREAT | IPC_EXCL);
122	if (sem_id_2 == -1) {
123		tst_brkm(TBROK | TERRNO, cleanup,
124			 "couldn't create semaphore in setup");
125	}
126
127	arr.__buf = &ipc_buf;
128	if (semctl(sem_id_1, 0, IPC_INFO, arr) == -1)
129		tst_brkm(TBROK | TERRNO, cleanup, "semctl() IPC_INFO failed");
130
131	/* for ERANGE errno test */
132	arr.val = 1;
133	s_buf[0].sem_op = ipc_buf.semvmx;
134	if (semctl(sem_id_1, 0, SETVAL, arr) == -1)
135		tst_brkm(TBROK | TERRNO, cleanup, "semctl() SETVAL failed");
136}
137
138static void semop_verify(int i)
139{
140	TEST(semop(*(TC[i].semid), TC[i].t_sbuf, TC[i].t_ops));
141
142	if (TEST_RETURN != -1) {
143		tst_resm(TFAIL, "call succeeded unexpectedly");
144		return;
145	}
146
147	if (TEST_ERRNO == TC[i].error) {
148		tst_resm(TPASS | TTERRNO, "semop failed as expected");
149	} else {
150		tst_resm(TFAIL | TTERRNO,
151			 "semop failed unexpectedly; expected: "
152			 "%d - %s", TC[i].error, strerror(TC[i].error));
153	}
154}
155
156void cleanup(void)
157{
158	/* if they exist, remove the semaphore resources */
159	rm_sema(sem_id_1);
160	rm_sema(sem_id_2);
161
162	tst_rmdir();
163}
164