• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *	fcntl11.c
23  *
24  * DESCRIPTION
25  *	Testcase to check locking of regions of a file
26  *
27  * ALGORITHM
28  *	Test changing lock sections around a write lock
29  *
30  * USAGE
31  *	fcntl11
32  *
33  * HISTORY
34  *	07/2001 Ported by Wayne Boyer
35  *
36  * RESTRICTIONS
37  *	None
38  */
39 
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/wait.h>
46 #include <inttypes.h>
47 #include "test.h"
48 #include "safe_macros.h"
49 
50 #define STRINGSIZE	27
51 #define STRING		"abcdefghijklmnopqrstuvwxyz\n"
52 #define STOP		0xFFF0
53 
54 int parent_pipe[2];
55 int child_pipe[2];
56 int fd;
57 pid_t parent_pid, child_pid;
58 
59 void parent_put();
60 void parent_get();
61 void child_put();
62 void child_get();
63 void stop_child();
64 void compare_lock(struct flock *, short, short, int, int, pid_t);
65 void unlock_file();
66 void do_test(struct flock *, short, short, int, int);
67 void catch_child();
68 char *str_type();
69 int do_lock(int, short, short, int, int);
70 
71 char *TCID = "fcntl11";
72 int TST_TOTAL = 1;
73 
74 int fail;
75 
cleanup(void)76 void cleanup(void)
77 {
78 	tst_rmdir();
79 
80 }
81 
setup(void)82 void setup(void)
83 {
84 	char *buf = STRING;
85 	char template[PATH_MAX];
86 	struct sigaction act;
87 
88 	tst_sig(FORK, DEF_HANDLER, cleanup);
89 	tst_tmpdir();
90 
91 	umask(0);
92 
93 	TEST_PAUSE;
94 
95 	SAFE_PIPE(cleanup, parent_pipe);
96 	SAFE_PIPE(cleanup, child_pipe);
97 	parent_pid = getpid();
98 	snprintf(template, PATH_MAX, "fcntl11XXXXXX");
99 
100 	if ((fd = mkstemp(template)) < 0)
101 		tst_resm(TFAIL, "Couldn't open temp file! errno = %d", errno);
102 
103 	SAFE_WRITE(cleanup, 0, fd, buf, STRINGSIZE);
104 
105 	memset(&act, 0, sizeof(act));
106 	act.sa_handler = catch_child;
107 	sigemptyset(&act.sa_mask);
108 	sigaddset(&act.sa_mask, SIGCHLD);
109 	if ((sigaction(SIGCHLD, &act, NULL)) < 0)
110 		tst_brkm(TBROK | TERRNO, cleanup,
111 			 "sigaction(SIGCHLD, ..) failed");
112 }
113 
do_child(void)114 void do_child(void)
115 {
116 	struct flock fl;
117 
118 	close(parent_pipe[1]);
119 	close(child_pipe[0]);
120 	while (1) {
121 		child_get(&fl);
122 		if (fcntl(fd, F_GETLK, &fl) < 0)
123 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
124 		child_put(&fl);
125 	}
126 }
127 
do_lock(int cmd,short type,short whence,int start,int len)128 int do_lock(int cmd, short type, short whence, int start, int len)
129 {
130 	struct flock fl;
131 
132 	fl.l_type = type;
133 	fl.l_whence = whence;
134 	fl.l_start = start;
135 	fl.l_len = len;
136 	return (fcntl(fd, cmd, &fl));
137 }
138 
do_test(struct flock * fl,short type,short whence,int start,int len)139 void do_test(struct flock *fl, short type, short whence, int start, int len)
140 {
141 	fl->l_type = type;
142 	fl->l_whence = whence;
143 	fl->l_start = start;
144 	fl->l_len = len;
145 	fl->l_pid = (short)0;
146 
147 	parent_put(fl);
148 	parent_get(fl);
149 }
150 
151 void
compare_lock(struct flock * fl,short type,short whence,int start,int len,pid_t pid)152 compare_lock(struct flock *fl, short type, short whence, int start, int len,
153 	     pid_t pid)
154 {
155 	if (fl->l_type != type)
156 		tst_resm(TFAIL, "lock type is wrong should be %s is %s",
157 			 str_type(type), str_type(fl->l_type));
158 
159 	if (fl->l_whence != whence)
160 		tst_resm(TFAIL, "lock whence is wrong should be %d is %d",
161 			 whence, fl->l_whence);
162 
163 	if (fl->l_start != start)
164 		tst_resm(TFAIL, "region starts in wrong place, should be "
165 			 "%d is %" PRId64, start, (int64_t) fl->l_start);
166 
167 	if (fl->l_len != len)
168 		tst_resm(TFAIL,
169 			 "region length is wrong, should be %d is %" PRId64,
170 			 len, (int64_t) fl->l_len);
171 
172 	if (fl->l_pid != pid)
173 		tst_resm(TFAIL, "locking pid is wrong, should be %d is %d",
174 			 pid, fl->l_pid);
175 }
176 
unlock_file(void)177 void unlock_file(void)
178 {
179 	struct flock fl;
180 
181 	if (do_lock(F_SETLK, (short)F_UNLCK, (short)0, 0, 0) < 0)
182 		tst_resm(TFAIL | TERRNO, "fcntl on file failed");
183 	do_test(&fl, F_WRLCK, 0, 0, 0);
184 	compare_lock(&fl, (short)F_UNLCK, (short)0, 0, 0, (pid_t) 0);
185 }
186 
str_type(int type)187 char *str_type(int type)
188 {
189 	static char buf[20];
190 
191 	switch (type) {
192 	case 0:
193 		return ("F_RDLCK");
194 	case 1:
195 		return ("F_WRLCK");
196 	case 2:
197 		return ("F_UNLCK");
198 	default:
199 		sprintf(buf, "BAD VALUE: %d", type);
200 		return (buf);
201 	}
202 }
203 
parent_put(struct flock * l)204 void parent_put(struct flock *l)
205 {
206 	SAFE_WRITE(cleanup, 1, parent_pipe[1], l, sizeof(*l));
207 }
208 
parent_get(struct flock * l)209 void parent_get(struct flock *l)
210 {
211 	SAFE_READ(cleanup, 1, child_pipe[0], l, sizeof(*l));
212 }
213 
child_put(struct flock * l)214 void child_put(struct flock *l)
215 {
216 	SAFE_WRITE(NULL, 1, child_pipe[1], l, sizeof(*l));
217 }
218 
child_get(struct flock * l)219 void child_get(struct flock *l)
220 {
221 	SAFE_READ(NULL, 1, parent_pipe[0], l, sizeof(*l));
222 	if (l->l_type == (short)STOP)
223 		exit(0);
224 }
225 
stop_child(void)226 void stop_child(void)
227 {
228 	struct flock fl;
229 
230 	signal(SIGCHLD, SIG_DFL);
231 	fl.l_type = STOP;
232 	parent_put(&fl);
233 	wait(0);
234 }
235 
catch_child(void)236 void catch_child(void)
237 {
238 	tst_brkm(TFAIL, cleanup, "Unexpected death of child process");
239 }
240 
main(int ac,char ** av)241 int main(int ac, char **av)
242 {
243 	struct flock tl;
244 
245 	int lc;
246 
247 	tst_parse_opts(ac, av, NULL, NULL);
248 #ifdef UCLINUX
249 	maybe_run_child(&do_child, "ddddd", &parent_pipe[0],
250 			&parent_pipe[1], &child_pipe[0], &child_pipe[1], &fd);
251 #endif
252 
253 	setup();		/* global setup */
254 
255 	/* Check for looping state if -i option is given */
256 	for (lc = 0; TEST_LOOPING(lc); lc++) {
257 		/* reset tst_count in case we are looping */
258 		tst_count = 0;
259 
260 		if ((child_pid = FORK_OR_VFORK()) == 0) {	/* parent */
261 #ifdef UCLINUX
262 			if (self_exec(av[0], "ddddd", parent_pipe[0],
263 				      parent_pipe[1], child_pipe[0],
264 				      child_pipe[1], fd) < 0)
265 				tst_brkm(TBROK | TERRNO, cleanup,
266 					 "self_exec failed");
267 #else
268 			do_child();
269 #endif
270 		} else if (child_pid == -1)
271 			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
272 
273 		SAFE_CLOSE(cleanup, parent_pipe[0]);
274 		SAFE_CLOSE(cleanup, child_pipe[1]);
275 
276 /* //block1: */
277 		tst_resm(TINFO, "Enter block 1");
278 
279 		/*
280 		 * Add a write lock to the middle of the file and a read
281 		 * at the begining
282 		 */
283 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
284 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
285 
286 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 1, 5) < 0)
287 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
288 
289 		/*
290 		 * Test read lock
291 		 */
292 		do_test(&tl, F_WRLCK, 0, 0, 0);
293 		compare_lock(&tl, (short)F_RDLCK, (short)0, 1, 5, parent_pid);
294 
295 		/*
296 		 * Test write lock
297 		 */
298 		do_test(&tl, F_WRLCK, 0, 6, 0);
299 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
300 
301 		/*
302 		 * Test that the rest of the file is unlocked
303 		 */
304 		do_test(&tl, F_WRLCK, 0, 15, 0);
305 		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
306 
307 		/*
308 		 * remove all the locks set above
309 		 */
310 		unlock_file();
311 
312 		tst_resm(TINFO, "Exit block 1");
313 
314 /* //block2: */
315 		tst_resm(TINFO, "Enter block 2");
316 
317 		/*
318 		 * Set a write lock at the middle of the file and a
319 		 * read lock just before
320 		 */
321 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
322 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
323 
324 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 5) < 0)
325 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
326 
327 		/*
328 		 * Test the read lock
329 		 */
330 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
331 		compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 5, parent_pid);
332 
333 		/*
334 		 * Test the write lock.
335 		 */
336 		do_test(&tl, (short)F_WRLCK, (short)0, 10, 0);
337 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
338 
339 		/*
340 		 * Test to make sure the rest of the file is unlocked.
341 		 */
342 		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
343 		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
344 
345 		/*
346 		 * remove all the locks set above
347 		 */
348 		unlock_file();
349 
350 		tst_resm(TINFO, "Exit block 2");
351 
352 /* //block3: */
353 		tst_resm(TINFO, "Enter block 3");
354 
355 		/*
356 		 * Set a write lock in the middle and a read lock that
357 		 * ends at the first byte of the write lock
358 		 */
359 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
360 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
361 
362 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 6) < 0)
363 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
364 
365 		/*
366 		 * Test read lock
367 		 */
368 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
369 		compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 6, parent_pid);
370 
371 		/*
372 		 * Test write lock
373 		 */
374 		do_test(&tl, (short)F_WRLCK, (short)0, 11, 0);
375 		compare_lock(&tl, (short)F_WRLCK, (short)0, 11, 4, parent_pid);
376 
377 		/*
378 		 * Test to make sure the rest of the file is unlocked.
379 		 */
380 		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
381 		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
382 
383 		/*
384 		 * remove all the locks set above
385 		 */
386 		unlock_file();
387 
388 		tst_resm(TINFO, "Exit block 3");
389 
390 /* //block4: */
391 		tst_resm(TINFO, "Enter block 4");
392 
393 		/*
394 		 * Set a write lock on the middle of the file and a read
395 		 * lock that overlaps the front of the write.
396 		 */
397 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
398 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
399 
400 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 5, 8) < 0)
401 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
402 
403 		/*
404 		 * Test the read lock
405 		 */
406 		do_test(&tl, (short)F_WRLCK, (short)0, 5, 0);
407 		compare_lock(&tl, (short)F_RDLCK, (short)0, 5, 8, parent_pid);
408 
409 		/*
410 		 * Test the write lock
411 		 */
412 		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
413 		compare_lock(&tl, (short)F_WRLCK, (short)0, 13, 2, parent_pid);
414 
415 		/*
416 		 * Test to make sure the rest of the file is unlocked.
417 		 */
418 		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
419 		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 0, 0);
420 
421 		/*
422 		 * remove all the locks set above
423 		 */
424 		unlock_file();
425 
426 		tst_resm(TINFO, "Exit block 4");
427 
428 /* //block5: */
429 		tst_resm(TINFO, "Enter block 5");
430 
431 		/*
432 		 * Set a write lock in the middle of a file and a read
433 		 * lock in the middle of it
434 		 */
435 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 10) < 0)
436 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
437 
438 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 13, 5) < 0)
439 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
440 
441 		/*
442 		 * Test the first write lock
443 		 */
444 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
445 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 3, parent_pid);
446 
447 		/*
448 		 * Test the read lock
449 		 */
450 		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
451 		compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 5, parent_pid);
452 
453 		/*
454 		 * Test the second write lock
455 		 */
456 		do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
457 		compare_lock(&tl, (short)F_WRLCK, (short)0, 18, 2, parent_pid);
458 
459 		/*
460 		 * Test to make sure the rest of the file is unlocked
461 		 */
462 		do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
463 		compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
464 
465 		/*
466 		 * remove all the locks set above.
467 		 */
468 		unlock_file();
469 		tst_resm(TINFO, "Exit block 5");
470 
471 /* //block6: */
472 		tst_resm(TINFO, "Enter block 6");
473 		/*
474 		 * Set a write lock in the middle of the file and a read
475 		 * lock that overlaps the end
476 		 */
477 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
478 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
479 
480 		/*
481 		 * Set a read lock on the whole file
482 		 */
483 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 13, 5) < 0)
484 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
485 
486 		/*
487 		 * Test the write lock
488 		 */
489 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
490 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 3, parent_pid);
491 
492 		/*
493 		 * Test the read lock
494 		 */
495 		do_test(&tl, (short)F_WRLCK, (short)0, 13, 0);
496 		compare_lock(&tl, (short)F_RDLCK, (short)0, 13, 5, parent_pid);
497 
498 		/*
499 		 * Test to make sure the rest of the file is unlocked
500 		 */
501 		do_test(&tl, (short)F_WRLCK, (short)0, 18, 0);
502 		compare_lock(&tl, (short)F_UNLCK, (short)0, 18, 0, 0);
503 
504 		/*
505 		 * remove all the locks set above
506 		 */
507 		unlock_file();
508 
509 		tst_resm(TINFO, "Exit block 6");
510 
511 /* //block7: */
512 		tst_resm(TINFO, "Enter block 7");
513 
514 		/*
515 		 * Set a write lock in the middle of the file and a read
516 		 * lock starting at the last byte of the write lock
517 		 */
518 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
519 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
520 
521 		/*
522 		 * Set a read lock on the whole file.
523 		 */
524 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 14, 5) < 0)
525 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
526 
527 		/*
528 		 * Test write lock
529 		 */
530 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
531 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 4, parent_pid);
532 
533 		/*
534 		 * Test the read lock
535 		 */
536 		do_test(&tl, (short)F_WRLCK, (short)0, 14, 0);
537 		compare_lock(&tl, (short)F_RDLCK, (short)0, 14, 5, parent_pid);
538 
539 		/*
540 		 * Test to make sure the end of the file is unlocked
541 		 */
542 		do_test(&tl, (short)F_WRLCK, (short)0, 19, 0);
543 		compare_lock(&tl, (short)F_UNLCK, (short)0, 19, 0, 0);
544 
545 		/*
546 		 * remove all the locks set above
547 		 */
548 		unlock_file();
549 
550 		tst_resm(TINFO, "Exit block 7");
551 
552 /* //block8: */
553 		tst_resm(TINFO, "Enter block 8");
554 
555 		/*
556 		 * Set a write lock in the middle of the file and a read
557 		 * lock that starts just after the last byte of the
558 		 * write lock.
559 		 */
560 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
561 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
562 
563 		/*
564 		 * Set a read lock on the whole file
565 		 */
566 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 15, 5) < 0)
567 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
568 
569 		/*
570 		 * Test the write lock
571 		 */
572 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
573 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
574 
575 		/*
576 		 * Test the read lock
577 		 */
578 		do_test(&tl, (short)F_WRLCK, (short)0, 15, 0);
579 		compare_lock(&tl, (short)F_RDLCK, (short)0, 15, 5, parent_pid);
580 
581 		/*
582 		 * Test to make sure the rest of the file is unlocked
583 		 */
584 		do_test(&tl, (short)F_WRLCK, (short)0, 20, 0);
585 		compare_lock(&tl, (short)F_UNLCK, (short)0, 20, 0, 0);
586 
587 		/*
588 		 * remove all the locks set above
589 		 */
590 		unlock_file();
591 
592 		tst_resm(TINFO, "Exit block 8");
593 
594 /* //block9: */
595 		tst_resm(TINFO, "Enter block 9");
596 
597 		/*
598 		 * Set a write lock at the middle of the file and a read
599 		 * lock that starts past the end of the write lock.
600 		 */
601 		if (do_lock(F_SETLK, (short)F_WRLCK, (short)0, 10, 5) < 0)
602 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
603 
604 		if (do_lock(F_SETLK, (short)F_RDLCK, (short)0, 16, 5) < 0)
605 			tst_resm(TFAIL | TERRNO, "fcntl on file failed");
606 
607 		/*
608 		 * Test the write lock
609 		 */
610 		do_test(&tl, (short)F_WRLCK, (short)0, 0, 0);
611 		compare_lock(&tl, (short)F_WRLCK, (short)0, 10, 5, parent_pid);
612 
613 		/*
614 		 * Test that byte in between is unlocked
615 		 */
616 		do_test(&tl, (short)F_WRLCK, (short)0, 15, 1);
617 		compare_lock(&tl, (short)F_UNLCK, (short)0, 15, 1, 0);
618 
619 		/*
620 		 * Test the read lock
621 		 */
622 		do_test(&tl, (short)F_WRLCK, (short)0, 16, 0);
623 		compare_lock(&tl, (short)F_RDLCK, (short)0, 16, 5, parent_pid);
624 
625 		/*
626 		 * Test to make sure the rest of the file is unlocked
627 		 */
628 		do_test(&tl, (short)F_WRLCK, (short)0, 21, 0);
629 		compare_lock(&tl, (short)F_UNLCK, (short)0, 21, 0, 0);
630 
631 		/*
632 		 * remove all the locks set above
633 		 */
634 		unlock_file();
635 
636 		tst_resm(TINFO, "Exit block 9");
637 
638 		stop_child();
639 		SAFE_CLOSE(cleanup, fd);
640 	}
641 	cleanup();
642 	tst_exit();
643 }
644