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