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