1 /*
2  * Copyright (c) International Business Machines  Corp., 2002
3  * Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz>
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  * This test verifies that flock cannot unlock a file locked
22  * by another task
23  *
24  * Test Steps:
25  *
26  *  Fork a child processes The parent flocks a file with LOCK_EX Child waits
27  *  for that to happen, then checks to make sure it is locked.  Child then
28  *  tries to unlock the file. If the unlock succeeds, the child attempts to
29  *  lock the file with LOCK_EX. The test passes if the child is able to lock
30  *  the file.
31  */
32 
33 #include <stdio.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/file.h>
39 #include <sys/wait.h>
40 #include "test.h"
41 
42 #define FILE_NAME "flock03"
43 
44 static void setup(void);
45 static void cleanup(void);
46 static void childfunc(int);
47 
48 #ifdef UCLINUX
49 static int fd_uc;
childfunc_uc(void)50 static void childfunc_uc(void)
51 {
52 	childfunc(fd_uc);
53 }
54 #endif
55 
56 char *TCID = "flock03";
57 int TST_TOTAL = 3;
58 
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61 	int lc;
62 	pid_t pid;
63 	int status;
64 	int fd;
65 
66 	tst_parse_opts(argc, argv, NULL, NULL);
67 
68 #ifdef UCLINUX
69 	maybe_run_child(&childfunc_uc, "ds", &fd_uc, FILE_NAME);
70 #endif
71 
72 	setup();
73 
74 	for (lc = 0; TEST_LOOPING(lc); lc++) {
75 		tst_count = 0;
76 
77 		fd = open(FILE_NAME, O_RDWR);
78 
79 		if (fd == -1)
80 			tst_brkm(TFAIL | TERRNO, cleanup,
81 				 "parent failed to open the file");
82 
83 		pid = FORK_OR_VFORK();
84 
85 		if (pid == -1)
86 			tst_brkm(TFAIL | TERRNO, cleanup, "fork() failed");
87 		if (pid == 0) {
88 #ifdef UCLINUX
89 			if (self_exec(argv[0], "ds", fd, FILE_NAME) < 0)
90 				tst_brkm(TFAIL | TERRNO, cleanup,
91 					 "self_exec failed");
92 #else
93 			childfunc(fd);
94 #endif
95 		}
96 
97 		TEST(flock(fd, LOCK_EX | LOCK_NB));
98 
99 		if (TEST_RETURN != 0)
100 			tst_resm(TFAIL | TTERRNO,
101 				 "Parent: Initial attempt to flock() failed");
102 		else
103 			tst_resm(TPASS,
104 				 "Parent: Initial attempt to flock() passed");
105 
106 		TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
107 
108 		if ((waitpid(pid, &status, 0)) < 0) {
109 			tst_resm(TFAIL, "wait() failed");
110 			continue;
111 		}
112 		if ((WIFEXITED(status)) && (WEXITSTATUS(status) == 0))
113 			tst_resm(TPASS, "flock03 Passed");
114 		else
115 			tst_resm(TFAIL, "flock03 Failed");
116 
117 		close(fd);
118 
119 	}
120 
121 	cleanup();
122 	tst_exit();
123 }
124 
childfunc(int fd)125 static void childfunc(int fd)
126 {
127 	int fd2;
128 
129 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
130 
131 	fd2 = open(FILE_NAME, O_RDWR);
132 
133 	if (fd2 == -1) {
134 		fprintf(stderr, "CHILD: failed to open the file: %s\n",
135 		        strerror(errno));
136 		exit(1);
137 	}
138 
139 	if (flock(fd2, LOCK_EX | LOCK_NB) != -1) {
140 		fprintf(stderr, "CHILD: The file was not already locked\n");
141 		exit(1);
142 	}
143 
144 	TEST(flock(fd, LOCK_UN));
145 	/* XXX: LOCK_UN does not return an error if there was nothing to
146 	 * unlock.
147 	 */
148 	if (TEST_RETURN == -1) {
149 		fprintf(stderr, "CHILD: Unable to unlock file locked by "
150 		        "parent: %s\n", strerror(TEST_ERRNO));
151 		exit(1);
152 	} else {
153 		fprintf(stderr, "CHILD: File locked by parent unlocked\n");
154 	}
155 
156 	TEST(flock(fd2, LOCK_EX | LOCK_NB));
157 
158 	if (TEST_RETURN == -1) {
159 		fprintf(stderr, "CHILD: Unable to lock file after "
160 		        "unlocking: %s\n", strerror(TEST_ERRNO));
161 		exit(1);
162 	} else {
163 		fprintf(stderr, "CHILD: Locking after unlock passed\n");
164 	}
165 
166 	close(fd);
167 	close(fd2);
168 
169 	exit(0);
170 }
171 
setup(void)172 static void setup(void)
173 {
174 	int fd;
175 
176 	tst_sig(FORK, DEF_HANDLER, cleanup);
177 
178 	TEST_PAUSE;
179 
180 	tst_tmpdir();
181 
182 	TST_CHECKPOINT_INIT(tst_rmdir);
183 
184 	fd = open(FILE_NAME, O_CREAT | O_TRUNC | O_RDWR, 0666);
185 	if (fd < 0) {
186 		tst_resm(TBROK, "creating a new file failed");
187 		cleanup();
188 	}
189 	close(fd);
190 }
191 
cleanup(void)192 static void cleanup(void)
193 {
194 	tst_rmdir();
195 }
196