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 *	fcntl18.c
23 *
24 * DESCRIPTION
25 *	Test to check the error conditions in fcntl system call
26 *
27 * USAGE
28 *	fcntl18
29 *
30 * HISTORY
31 *	07/2001 Ported by Wayne Boyer
32 *
33 * RESTRICTIONS
34 *	NONE
35 */
36
37#include <signal.h>
38#include <errno.h>
39#include <pwd.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <sys/param.h>
44#include <fcntl.h>
45#include <unistd.h>
46#include "test.h"
47
48#define INVAL_FLAG	-1
49#define INVAL_MIN	(-2147483647L-1L)
50
51int fd;
52char string[40] = "";
53
54char *TCID = "fcntl18";
55int TST_TOTAL = 1;
56struct passwd *pass;
57
58void setup(void);
59void cleanup(void);
60int fail;
61
62int main(int ac, char **av)
63{
64	int retval;
65	struct flock fl;
66	int pid, status;
67
68	tst_parse_opts(ac, av, NULL, NULL);
69
70	setup();		/* global setup */
71
72/* //block1: */
73#ifndef UCLINUX
74	/* Skip since uClinux does not implement memory protection */
75	tst_resm(TINFO, "Enter block 1");
76	fail = 0;
77	if ((fd = open("temp.dat", O_CREAT | O_RDWR, 0777)) < 0) {	//mode must be specified when O_CREATE is in the flag
78		tst_resm(TFAIL, "file opening error");
79		fail = 1;
80	}
81
82	/* Error condition if address is bad */
83	retval = fcntl(fd, F_GETLK, (struct flock *)INVAL_FLAG);
84	if (errno == EFAULT) {
85		tst_resm(TPASS, "Test F_GETLK: for errno EFAULT PASSED");
86	} else {
87		tst_resm(TFAIL, "Test F_GETLK: for errno EFAULT FAILED");
88		fail = 1;
89	}
90	if (fail) {
91		tst_resm(TINFO, "Block 1 FAILED");
92	} else {
93		tst_resm(TINFO, "Block 1 PASSED");
94	}
95	tst_resm(TINFO, "Exit block 1");
96#else
97	tst_resm(TINFO, "Skip block 1 on uClinux");
98#endif
99
100/* //block2: */
101#ifndef UCLINUX
102	/* Skip since uClinux does not implement memory protection */
103	tst_resm(TINFO, "Enter block 2");
104	fail = 0;
105	/* Error condition if address is bad */
106	retval = fcntl(fd, F_GETLK64, (struct flock *)INVAL_FLAG);
107	if (errno == EFAULT) {
108		tst_resm(TPASS, "Test F_GETLK64: for errno EFAULT PASSED");
109	} else {
110		tst_resm(TFAIL, "Test F_GETLK64: for errno EFAULT FAILED");
111		fail = 1;
112	}
113	if (fail) {
114		tst_resm(TINFO, "Block 2 FAILED");
115	} else {
116		tst_resm(TINFO, "Block 2 PASSED");
117	}
118	tst_resm(TINFO, "Exit block 2");
119#else
120	tst_resm(TINFO, "Skip block 2 on uClinux");
121#endif
122
123/* //block3: */
124	tst_resm(TINFO, "Enter block 3");
125	fail = 0;
126	if ((pid = FORK_OR_VFORK()) == 0) {	/* child */
127		fail = 0;
128		pass = getpwnam("nobody");
129		retval = setreuid(-1, pass->pw_uid);
130		if (retval < 0) {
131			tst_resm(TFAIL, "setreuid to user nobody failed, "
132				 "errno: %d", errno);
133			fail = 1;
134		}
135
136		/* Error condition: invalid cmd */
137		retval = fcntl(fd, INVAL_FLAG, &fl);
138		if (errno == EINVAL) {
139			tst_resm(TPASS, "Test for errno EINVAL PASSED");
140		} else {
141			tst_resm(TFAIL, "Test for errno EINVAL FAILED, "
142				 "got: %d", errno);
143			fail = 1;
144		}
145		exit(fail);
146	} else {		/* parent */
147		waitpid(pid, &status, 0);
148		if (WEXITSTATUS(status) != 0) {
149			tst_resm(TFAIL, "child returned bad exit status");
150			fail = 1;
151		}
152		if (fail) {
153			tst_resm(TINFO, "Block 3 FAILED");
154		} else {
155			tst_resm(TINFO, "Block 3 PASSED");
156		}
157	}
158	tst_resm(TINFO, "Exit block 3");
159
160	cleanup();
161	tst_exit();
162
163}
164
165/*
166 * setup()
167 *	performs all ONE TIME setup for this test
168 */
169void setup(void)
170{
171
172	tst_sig(FORK, DEF_HANDLER, cleanup);
173
174	tst_require_root();
175
176	umask(0);
177
178	TEST_PAUSE;
179
180	tst_tmpdir();
181
182	sprintf(string, "./fcntl18.%d.1", getpid());
183	unlink(string);
184}
185
186/*
187 * cleanup()
188 *	performs all the ONE TIME cleanup for this test at completion or
189 *	or premature exit.
190 */
191void cleanup(void)
192{
193	/*
194	 * print timing status if that option was specified.
195	 * print errno log if that option was specified
196	 */
197	close(fd);
198
199	tst_rmdir();
200
201	unlink("temp.dat");
202
203}
204