Home | History | Annotate | Download | only in flock
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2002
      3  * Copyright (c) 2012 Cyril Hrubis <chrubis (at) 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;
     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 
     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 
    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 
    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 
    192 static void cleanup(void)
    193 {
    194 	tst_rmdir();
    195 }
    196