./ChangeLog 2016-05-23 Svante Signell * Makefile: Add sub-directory libfshelp-tests. libfshelp-tests/ChangeLog 2018-12-07 Svante Signell * Update copyright years. * locks.c(cmd_lock): Call fshelp_rlock_tweak() with new last argument rendezvous = MACH_PORT_NULL. 2017-01-05 Svante Signell * Update copyright years and headers. 2016-12-28 Svante Signell * Makefile: test-flock.c, test-lockf.c and test-fcntl.c * test-lockf.c: New file * Rename set-flock.c, set-fcntl.c to test-flock.c test-fcntl.c * TODO: Update README 2016-05-23 Svante Signell * Makefile: Link with pthread, add build of set-flock.c and set-fcntl.c * define temporary CPP_FLAGS until glibc is updated * set-flock.c, set-fcntl.c: New files. * Fix typos in README 2001-04-11 Neal H Walfield * ChangeLog: New file, mentioning itself in this sentence. * Makefile: New file. * README: Likewise. * fork.c: Likewise. * locks: Likewise. * locks-tests: Likewise. * locks.c: Likewise. * race.c: Likewise. Index: hurd-0.9.git20181030-3.3/Makefile =================================================================== --- hurd-0.9.git20181030-3.3.orig/Makefile +++ hurd-0.9.git20181030-3.3/Makefile @@ -1,6 +1,6 @@ # -# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2004, -# 2006, 2009, 2011, 2012, 2013 Free Software Foundation, Inc. +# Copyright (C) 1993-1999, 2001, 2002, 2004, 2006, 2009, +# 2011-2013, 2015-2018 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -46,7 +46,7 @@ prog-subdirs = auth proc exec term \ storeio pflocal pfinet defpager mach-defpager \ login daemons boot console \ hostmux usermux ftpfs trans \ - console-client utils sutils \ + console-client utils sutils libfshelp-tests \ benchmarks fstests \ procfs \ startup \ Index: hurd-0.9.git20181030-3.3/libfshelp-tests/Makefile =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/Makefile @@ -0,0 +1,52 @@ +# Makefile libfshelp test cases +# +# Copyright (C) 2001, 2015-2017 Free Software Foundation, Inc. +# +# Written by Neal H Walfield +# +# This file is part of the GNU Hurd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the GNU Hurd. If not, see . + +dir := libfshelp-tests +makemode := utilities + +targets = race locks fork test-flock test-lockf test-fcntl +SRCS = race.c locks.c fork.c test-flock.c test-lockf.c test-fcntl.c + +MIGSTUBS = fsUser.o ioUser.o +OBJS = $(SRCS:.c=.o) $(MIGSTUBS) +HURDLIBS = fshelp ports +LDLIBS += -lpthread + +race: race.o fsUser.o ioUser.o +fork: fork.o fsUser.o +locks: locks.o +test-flock: test-flock.o +test-lockf: test-lockf.o +test-fcntl: test-fcntl.o ../libfshelp/libfshelp.a + +race locks: ../libfshelp/libfshelp.a ../libports/libports.a ../libshouldbeinlibc/libshouldbeinlibc.a + +# Define the 64 bit versions of the second argument to fcntl() +# Can safely be removed when glibc is updated +EXTRA_CPP_FLAGS= -DF_GETLK64=10 -DF_SETLK64=11 -DF_SETLKW64=12 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 +fork-CPPFLAGS += $(EXTRA_CPP_FLAGS) +locks-CPPFLAGS += $(EXTRA_CPP_FLAGS) +race-CPPFLAGS += $(EXTRA_CPP_FLAGS) +test-flock-CPPFLAGS += $(EXTRA_CPP_FLAGS) +test-lockf-CPPFLAGS += $(EXTRA_CPP_FLAGS) +test-fcntl-CPPFLAGS += $(EXTRA_CPP_FLAGS) + +include ../Makeconf Index: hurd-0.9.git20181030-3.3/libfshelp-tests/README =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/README @@ -0,0 +1,102 @@ +These programs are used to help test the algorithms in the libfshelp +library. + +Record Locking +============== + +Race +---- + +Race locks a file, reads an integer, increments it, writes the result to +the file and then unlocks the file -- 10,000 times. It is intended that +multiple instances of this program be run at the same time. Race takes +three arguments: the file to use, the start of the lock and the length. +For obvious reasons, it is important that all instances of race have +locks that overlap. For example: + + # rm -f foo && ( ./race foo 2 0 & ./race foo 2 3 & \ + > ./race foo 0 3 ) + Was blocked 5482 times + Was blocked 5485 times + Was blocked 5479 times + # cat foo + 30000 + +We see here that each process was blocked several thousand times and that +the result in the file foo is 30000. Perfect. + +Locks +----- + +Locks is an interactive shell that has one ``file'' and ten open file +descriptors. Using some simple commands, one can test to see if locks +are established, cleared, and enforced. The principal command is +`lock,' which takes four parameters. The first is the file descriptor +to lock, the second is the start of the lock, the third is the length of +the lock (0 = until EOF) and the last is the type of lock to establish +from the set {0: F_UNLCK, 1: F_RDLCK, 2: F_WRLCK}. Help on the other +commands can be gotten using the `help' command. + +A small run: + + # ./locks + > lock 0 10 0 1 + 0: Start = 10; Length = 0; Type = F_RDLCK + +Lock from byte 10 through the EOF. + + > lock 0 20 0 0 + 0: Start = 10; Length = 10; Type = F_RDLCK + +Unlock from byte 20 through the EOF. + + > lock 0 11 8 2 + 0: Start = 10; Length = 1; Type = F_RDLCK + Start = 11; Length = 8; Type = F_WRLCK + Start = 19; Length = 1; Type = F_RDLCK + +Upgrade bytes 11 through 19 to a write lock. + + > lock 0 9 10 1 + 0: Start = 9; Length = 2; Type = F_RDLCK + Start = 11; Length = 8; Type = F_WRLCK + Start = 19; Length = 1; Type = F_RDLCK + +Add a read lock to byte 9. + + > lock 1 0 10 1 + 1: Start = 0; Length = 10; Type = F_RDLCK + +Read lock the first ten bytes of the file through file descriptor 1. + + > lock 1 10 0 1 + Resource temporarily unavailable + +Attempts to read lock the rest of the file. This, however, fails as +there are outstanding write locks held through file descriptor 1. + + > lock 1 10 0 0 + 1: Start = 0; Length = 10; Type = F_RDLCK + +What happens when file descriptor tries to unlock the blocked range? + + > lock 1 10 0 2 + Resource temporarily unavailable + +Nothing. + +A bunch of tests live in locks-tests. One can run them through the test +program using: `./locks < ./locks-test 2>&1 | less'. If it core dumps or +triggers an assertion, that is a bug. Report it. + +Fork +---- + +Tests to see if the a child inherits the locks across a fork. According +to POSIX, the child should not. + + # ./fork foo + Parent has a write lock; Others have a write lock. + Child has a write lock; Others have a write lock. + +We are not POSIX compliant. Index: hurd-0.9.git20181030-3.3/libfshelp-tests/fork.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/fork.c @@ -0,0 +1,80 @@ +/* Test is a process inherits locks after a fork. + + Copyright (C) 2001 Free Software Foundation, Inc. + + Written by Neal H Walfield + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include "fs_U.h" +#include + +char *lock2str (int type) +{ + if (type & LOCK_SH) + return "read"; + if (type & LOCK_EX) + return "write"; + if (type & LOCK_UN) + return "unlocked"; + assert (! "Invalid"); + return NULL; +} + +int main (int argc, char **argv) +{ + error_t err; + struct flock64 lock; + mach_port_t rendezvous = MACH_PORT_NULL; + int fd; + pid_t pid; + int mine, others; + + if (argc != 2) + error (1, 0, "Usage: %s file", argv[0]); + + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_type = F_WRLCK; + + fd = file_name_lookup (argv[1], O_READ | O_WRITE | O_CREAT, 0666); + if (fd == MACH_PORT_NULL) + error (1, errno, "file_name_lookup"); + + err = file_record_lock (fd, F_SETLK64, &lock, rendezvous, MACH_MSG_TYPE_MAKE_SEND); + if (err) + error (1, err, "file_record_lock"); + + pid = fork (); + if (pid == -1) + error (1, errno, "fork"); + + err = file_lock_stat (fd, &mine, &others); + if (err) + error (1, err, "file_lock_stat"); + + printf ("%s has a %s lock; Others have a %s lock.\n", + pid ? "Parent" : "Child", lock2str (mine), lock2str (others)); + + mach_port_deallocate (mach_task_self (), fd); + + return 0; +} Index: hurd-0.9.git20181030-3.3/libfshelp-tests/locks.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/locks.c @@ -0,0 +1,328 @@ +/* Test record locking. + + Copyright (C) 2001, 2018 Free Software Foundation, Inc. + + Written by Neal H Walfield + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#include "../libfshelp/fshelp.h" +#include "../libfshelp/rlock.h" +#include +#include +#include +#include + +#include "fs_U.h" + +#ifndef PEROPENS +#define PEROPENS 10 +#endif + +struct rlock_box box; +struct rlock_peropen peropens[PEROPENS]; +loff_t pointers[PEROPENS]; +loff_t file_size; + +struct command +{ + char *name; + int (*func)(char *cmds); + char *doc; +}; + +error_t cmd_help (char *); +error_t cmd_comment (char *); +error_t cmd_echo (char *); +error_t cmd_lock (char *); +error_t cmd_list (char *); +error_t cmd_seek (char *); +error_t cmd_exec (char *); + +struct command commands [] = + { + { "help", cmd_help, "Print this screen" }, + { "#", cmd_comment, "Comment (Must _start_ the line)." }, + { "echo", cmd_echo, "Echo the line." }, + { "lock", cmd_lock, + "po start length type\n" + "\ttype = { F_UNLCK=0, F_RDLCK,=1, F_WRLCK=2 }" }, + { "list", cmd_list, "list all locks' status" }, + { "seek", cmd_seek, "PO1 ... Print the position of the given po.\n" + "\tPO1=N ... Seek a given po." }, + { "exec", cmd_exec, "Execute a built in echoing the command."} + }; + +error_t +cmd_help (char *args) +{ + int i; + printf ("Commands:\n"); + for (i = 0; i < sizeof (commands) / sizeof (struct command); i ++) + printf ("%s\t%s\n", commands[i].name, commands[i].doc); + return 0; +} + +error_t +cmd_comment (char *args) +{ + return 0; +} + +error_t +cmd_echo (char *args) +{ + printf ("%s", args); + return 0; +} + +error_t +cmd_lock (char *args) +{ + int po, type; + loff_t start, len; + struct flock64 lock; + mach_port_t rendezvous = MACH_PORT_NULL; + error_t err; + + if (4 != sscanf (args, "%d %ld %ld %d", &po, (long*)&start, (long*)&len, &type)) + { + printf ("Syntax error.\n"); + return 0; + } + + lock.l_type = type; + lock.l_whence = SEEK_CUR; + lock.l_start = (long)start; + lock.l_len = (long)len; + + if (po < 0 || po >= PEROPENS) + { + printf ("Unknown peropen: %d.\n", po); + return 0; + } + + switch (type) + { + case 0: lock.l_type = F_UNLCK; break; + case 1: lock.l_type = F_RDLCK; break; + case 2: lock.l_type = F_WRLCK; break; + default: printf ("Unknown type.\n"); return 0; + } + + err= fshelp_rlock_tweak (&box, NULL, &peropens[po], O_RDWR, + file_size, pointers[po], F_SETLK64, + &lock, rendezvous); + if (! err) + { + char buf[10]; + sprintf (buf, "%d\n", po); + cmd_list (buf); + } + return err; +} + +error_t +cmd_list (char *args) +{ + char *end; + + void dump (int i) + { + struct rlock_list *l; + + printf ("%3d:", i); + for (l = *peropens[i].locks; l; l = l->po.next) + { + printf ("\tStart = %4ld; Length = %4ld; Type = ", (long)l->start, (long)l->len); + switch (l->type) + { + case F_RDLCK: printf ("F_RDLCK"); break; + case F_WRLCK: printf ("F_WRLCK"); break; + case F_UNLCK: printf ("F_UNLCK"); break; + default: printf ("UNKNOWN"); break; + } + printf ("\n"); + } + + if (*peropens[i].locks == NULL) + printf ("\n"); + } + + while (*args == ' ') + args ++; + + if (*args == '\n' || *args == '\0') + { + int i; + + for (i = 0; i < PEROPENS; i ++) + dump (i); + return 0; + } + + while (1) + { + long int p = strtoll (args, &end, 0); + if (end == args) + { + printf ("Syntax error.\n"); + return 0; + } + + if (p < 0 || p > PEROPENS) + printf ("%3ld:\tOut of range.", p); + else + dump (p); + + while (*end == ' ') + end ++; + + if (*end == '\n' || *end == '\0') + return 0; + args = end; + } +} + +error_t +cmd_seek (char *args) +{ + char *end; + int p; + + while (*args == ' ') + args ++; + + if (*args == '\n' || *args == '\0') + { + int i; + for (i = 0; i < PEROPENS; i ++) + printf ("%3d: %ld\n", i, (long)pointers[i]); + return 0; + } + + while (1) + { + int set = 0; + long seek_to = 0; + + p = strtol (args, &end, 0); + if (end == args) + { + printf ("Syntax error.\n"); + return 0; + } + + if (*end == '=') + { + set = 1; + args = end + 1; + seek_to = strtol (args, &end, 0); + if (end == args) + { + printf ("Syntax error.\n"); + return 0; + } + } + + if (p < 0 || p > PEROPENS) + printf ("%3d: unknown peropen\n", p); + else + { + printf ("%3d: %ld", p, (long)pointers[p]); + if (set) + printf (" => %ld\n", (long)(pointers[p] = seek_to)); + else + printf ("\n"); + } + + while (*end == ' ') + end ++; + if (*end == '\0' || *end == '\n') + return 0; + args = end; + } +} + +error_t +interpret (char *buffer) +{ + int i; + + while (*buffer == ' ') + buffer ++; + + if (*buffer == '\n') + return 0; + + for (i = 0; i < sizeof (commands) / sizeof (struct command); i ++) + if (strncmp (commands[i].name, buffer, strlen (commands[i].name)) == 0) + { + error_t err; + err = commands[i].func (buffer + strlen (commands[i].name) + 1); + if (err) + printf ("%s\n", strerror (err)); + return err; + } + + printf ("Unknown command.\n"); + return 0; +} + +error_t +cmd_exec (char *arg) +{ + printf ("%s", arg); + interpret (arg); + return 0; +} + +int main (int argc, char *argv[]) +{ + int i; + + if (argc != 1) + { + printf ("Usage: %s\n" + "\tType `help' at the prompt.\n" + "\tUsed to test the record locking functions in libfshelp\n", + argv[0]); + return 1; + } + + fshelp_rlock_init (&box); + for (i = 0; i < PEROPENS; i ++) + fshelp_rlock_po_init (&peropens[i]); + + while (! feof (stdin)) + { + char b[1024]; + + printf ("> "); + fflush (stdout); + + if (! fgets (b, sizeof (b), stdin)) + { + if (feof (stdin)) + break; + else + continue; + } + + interpret (b); + } + + printf ("\n"); + return 0; +} Index: hurd-0.9.git20181030-3.3/libfshelp-tests/locks-tests =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/locks-tests @@ -0,0 +1,585 @@ +echo Legend: +echo + => Shared region +echo x => Exclusive region +echo ' ' => Unlocked region +echo . => Clearing region +echo [] => Start/End of a region +echo After each lock command, the proposed region is shown followed +echo by the result of applying it. +echo * Established region wraps new region +echo ** Both boundaries align +echo [ +exec lock 0 1 10 1 +echo [+++++++++++++] +echo [ [+++++++++++++] +exec lock 0 1 10 1 +echo [+++++++++++++] +echo [ [+++++++++++++] +exec lock 0 1 10 2 +echo [xxxxxxxxxxxxx] +echo [ [xxxxxxxxxxxxx] +exec lock 0 1 10 1 +echo [+++++++++++++] +echo [ [xxxxxxxxxxxxx] +exec lock 0 1 10 2 +echo [xxxxxxxxxxxxx] +echo [ [xxxxxxxxxxxxx] +exec lock 0 1 10 0 +echo [.............] +echo [ +exec lock 0 10 0 1 +echo [++++++++ +echo [ [++++++++ +exec lock 0 10 0 1 +echo [++++++++ +echo [ [++++++++ +exec lock 0 10 0 2 +echo [xxxxxxxx +echo [ [xxxxxxxx +exec lock 0 10 0 2 +echo [xxxxxxxx +echo [ [xxxxxxxx +exec lock 0 10 0 1 +echo [++++++++ +echo [ [xxxxxxxx +exec lock 0 10 0 0 +echo [........ +echo [ +echo ** Left boundaries align +exec lock 0 1 10 1 +echo [+++++++++++] +echo [ [+++++++++++] +exec lock 0 1 5 1 +echo [+++++] +echo [ [+++++++++++] +exec lock 0 1 5 2 +echo [xxxxx] +echo [ [xxxxx][++++] +exec lock 0 1 3 1 +echo [++] +echo [ [xxxxx][++++] +exec lock 0 1 10 0 +echo [............ +echo [ +exec lock 0 1 10 1 +echo [+++++++++++] +echo [ [+++++++++++] +exec lock 0 1 9 2 +echo [xxxxxxxx] +echo [ [xxxxxxxx][+] +exec lock 0 1 5 0 +echo [...] +echo [ [***][+] +exec lock 0 6 3 0 +echo [.] +echo [ [*][+] +exec lock 0 9 1 0 +echo [.] +echo [ [+] +exec lock 0 10 1 0 +echo [.] +echo [ +exec lock 0 1 0 1 +echo [++++++++++++ +echo [ [++++++++++++ +exec lock 0 1 5 1 +echo [++++] +echo [ [++++++++++++ +exec lock 0 1 5 2 +echo [xxxx] +echo [ [xxxx][++++++ +exec lock 0 1 0 0 +echo [............ +echo [ +exec lock 0 5 0 2 +echo [xxxxxxxxxx +echo [ [xxxxxxxxxx +exec lock 0 5 5 1 +echo [++++] +echo [ [xxxxxxxxxx +exec lock 0 5 0 1 +echo [++++++++++ +echo [ [xxxxxxxxxx +exec lock 0 0 0 0 +echo [.............. +echo [ +echo ** Common right side +exec lock 0 5 5 1 +echo [+++++] +echo [ [+++++] +exec lock 0 9 1 1 +echo [+] +echo [ [+++++] +exec lock 0 9 1 2 +echo [x] +echo [ [++][x] +exec lock 0 5 4 2 +echo [xx] +echo [ [xxxxx] +exec lock 0 8 2 2 +echo [x] +echo [ [xxxxx] +exec lock 0 9 1 0 +echo [.] +echo [ [xxx] +exec lock 0 5 4 0 +echo [...] +echo [ +exec lock 0 5 0 1 +echo [++++++++++ +echo [ [++++++++++ +exec lock 0 10 0 1 +echo [+++++ +echo [ [++++++++++ +exec lock 0 10 0 2 +echo [xxxxx +echo [ [+++][xxxxx +exec lock 0 5 0 0 +echo [.......... +echo [ +echo ** Completely interior +exec lock 0 5 10 1 +echo [++++++++] +echo [ [++++++++] +exec lock 0 6 8 1 +echo [++++++] +echo [ [++++++++] +exec lock 0 8 3 1 +echo [+] +echo [ [++++++++] +exec lock 0 8 3 2 +echo [x] +echo [ [+][x][++] +exec lock 0 12 1 2 +echo x +echo [ [++xxx+x+] +exec lock 0 6 8 0 +echo [......] +echo [ [+] [+] +exec lock 0 0 0 0 +echo [.............. +echo [ +exec lock 0 5 0 1 +echo [+++++++++ +echo [ [+++++++++ +exec lock 0 10 0 1 +echo [++++ +echo [ [+++++++++ +exec lock 0 10 0 2 +echo [xxxx +echo [ [+++][xxxx +exec lock 0 11 0 0 +echo [.. +echo [ [+++][x] +exec lock 0 6 0 0 +echo [....... +echo [ [+] +exec lock 0 5 0 0 +echo [......... +echo [ +exec lock 0 10 0 1 +echo [+++++ +echo [ [+++++ +exec lock 0 11 0 1 +echo [+] +echo [ [+++++ +exec lock 0 11 0 1 +echo [+] +echo [ [+++++ +exec lock 0 11 1 2 +echo [x] +echo [ [+x+++ +exec lock 0 13 0 1 +echo [+] +echo [ [+x+++ +exec lock 0 10 0 0 +echo [..... +echo [ +echo * We wrap the locked region +echo ** Left boundaries align +exec lock 0 1 10 1 +echo [++++] +echo [[++++] +exec lock 0 1 15 1 +echo [++++++++] +echo [[++++++++] +exec lock 0 1 16 1 +echo [+++++++++] +echo [[+++++++++] +exec lock 0 1 20 2 +echo [xxxxxxxxxxxxx] +echo [[xxxxxxxxxxxxx] +exec lock 0 1 30 1 +echo [+++++++++++++++++++] +echo [[xxxxxxxxxxxxx][++++] +exec lock 0 22 11 2 +echo [xxx] +echo [[xxxxxxxxxxxxx][+][xx] +exec lock 0 1 40 0 +echo [.........................] +echo [ +exec lock 0 1 0 1 +echo [++++++++++ +echo [[++++++++++ +exec lock 0 1 0 1 +echo [++++++++++ +echo [[++++++++++ +exec lock 0 1 0 2 +echo [xxxxxxxxxx +echo [[xxxxxxxxxx +exec lock 0 0 0 0 +echo [........... +echo [ +exec lock 0 1 0 1 +echo [++++++++++ +echo [[++++++++++ +exec lock 0 10 0 1 +echo [+++++ +echo [[++++++++++ +exec lock 0 10 0 2 +echo [xxxxx +echo [[+++][xxxxx +exec lock 0 0 0 0 +echo [........... +echo [ +echo ** Right boundaries align +exec lock 0 5 10 1 +echo [++++++++] +echo [ [++++++++] +exec lock 0 4 11 1 +echo [+++++++++] +echo [ [+++++++++] +exec lock 0 3 12 2 +echo [xxxxxxxxxx] +echo [ [xxxxxxxxxx] +exec lock 0 0 15 2 +echo [xxxxxxxxxxxx] +echo [xxxxxxxxxxxx] +exec lock 0 0 0 0 +echo [............. +echo [ +exec lock 0 5 0 1 +echo [++++++++ +echo [ [++++++++ +exec lock 0 4 0 1 +echo [+++++++++ +echo [ [+++++++++ +exec lock 0 3 0 2 +echo [xxxxxxxxxx +echo [ [xxxxxxxxxx +exec lock 0 2 0 2 +echo [xxxxxxxxxxx +echo [ [xxxxxxxxxxx +exec lock 0 0 0 2 +echo [xxxxxxxxxxxxx +echo [xxxxxxxxxxxxx +exec lock 0 0 0 0 +echo [............. +echo [ +echo ** Consume locked region +exec lock 0 5 10 1 +echo [++++++++] +echo [ [++++++++] +exec lock 0 4 12 1 +echo [++++++++++] +echo [ [++++++++++] +exec lock 0 2 16 1 +echo [++++++++++++++] +echo [ [++++++++++++++] +exec lock 0 1 18 2 +echo [xxxxxxxxxxxxxxxx] +echo [[xxxxxxxxxxxxxxxx] +exec lock 0 0 24 2 +echo [xxxxxxxxxxxxxxxxxxxxx] +echo [xxxxxxxxxxxxxxxxxxxxx] +exec lock 0 0 30 0 +echo [.........................] +echo [ +exec lock 0 5 3 1 +echo [++] +echo [ [++] +exec lock 0 10 5 1 +echo [++++] +echo [ [++] [++++] +exec lock 0 20 5 2 +echo [xxxx] +echo [ [++] [++++] [xxxx] +exec lock 0 4 30 2 +echo [xxxxxxxxxxxxxxxxxxxxxxxxxx] +echo [ [xxxxxxxxxxxxxxxxxxxxxxxxxx] +exec lock 0 1 35 1 +echo [++++++++++++++++++++++++++++++] +echo [ [+[xxxxxxxxxxxxxxxxxxxxxxxxxx]+] +exec lock 0 0 40 1 +echo [+++++++++++++++++++++++++++++++++++] +echo [++][xxxxxxxxxxxxxxxxxxxxxxxxxx][+++] +exec lock 0 0 0 0 +echo [.................................... +echo [ +exec lock 0 5 5 1 +echo [+++] +echo [ [+++] +exec lock 0 4 0 1 +echo [++++++] +echo [ [++++++] +exec lock 0 4 0 0 +echo [.......... +echo [ +exec lock 0 5 3 1 +echo [++] +echo [ [++] +exec lock 0 10 5 1 +echo [++++] +echo [ [++] [++++] +exec lock 0 0 0 1 +echo [++++++++++++++++++++ +echo [++++++++++++++++++++ +exec lock 0 0 0 0 +echo [.................... +echo [ +exec lock 0 5 3 1 +echo [++] +echo [ [++] +exec lock 0 10 3 1 +echo [++] +echo [ [++] [++] +exec lock 0 4 0 1 +echo [++++++++++++++ +echo [ [++++++++++++++ +exec lock 0 10 3 2 +echo [**] +echo [ [++++++][**][++ +exec lock 0 0 0 2 +echo [xxxxxxxxxxxxxxxxxx +echo [xxxxxxxxxxxxxxxxxx +exec lock 0 0 0 0 +echo [.................. +echo [ +echo * Our start is within the locked region or one byte after and our +echo end is after the end of the locked region. +echo ** The regions are the same type: Merge into a single large region +exec lock 0 5 5 1 +echo [+++] +echo [ [+++] +exec lock 0 6 5 1 +echo [+++] +echo [ [++++] +exec lock 0 8 8 1 +echo [++++++] +echo [ [+++++++++] +exec lock 0 16 4 1 +echo [++] +echo [ [+++++++++++++] +exec lock 0 20 0 1 +echo [+++ +echo [ [++++++++++++++++++ +exec lock 0 5 16 0 +echo [..............] +echo [ [+++ +exec lock 0 20 0 0 +echo [... +echo [ +exec lock 0 6 6 2 +echo [xxxx] +echo [ [xxxx] +exec lock 0 7 7 2 +echo [xxxxx] +echo [ [xxxxxx] +exec lock 0 14 7 2 +echo [xxxxx] +echo [ [xxxxxxxxxxxxx] +exec lock 0 21 0 2 +echo [xx +echo [ [xxxxxxxxxxxxxxxxx +exec lock 0 6 0 0 +echo [................. +echo [ +echo ** Different types just after the end of the locked region +exec lock 0 1 3 1 +echo [++] +echo [[++] +exec lock 0 4 3 2 +echo [xx] +echo [[++][xx] +exec lock 0 7 3 1 +echo [++] +echo [[++][xx][++] +exec lock 0 10 0 2 +echo [xxx +echo [[++][xx][++][xxx +exec lock 0 5 0 0 +echo [......... +echo [[++]x +exec lock 0 5 0 1 +echo [+++ +echo [[++]x[+++ +exec lock 0 1 0 0 +echo [... +echo [ +echo ** New region consumes the intersection. +exec lock 0 5 5 1 +echo [+++] +echo [ [+++] +exec lock 0 8 6 2 +echo [xxx] +echo [ [++][xxx] +exec lock 0 6 0 2 +echo [xxxxxx +echo [ [+][xxxxxx +exec lock 0 5 0 0 +echo [......... +echo [ +echo ** New region is dominated +exec lock 0 5 5 2 +echo [xxx] +echo [ [xxx] +exec lock 0 8 6 1 +echo [++++] +echo [ [xxx][++] +exec lock 0 6 0 1 +echo [++++++ +echo [ [xxx][+++ +exec lock 0 5 0 0 +echo [........ +echo [ +echo * Our start falls before the locked region. Our end falls just +echo before or with in the region (although we do not consume it) +echo ** The regions are the same type: Merge into a single large region +exec lock 0 10 5 1 +echo [+++] +echo [ [+++] +exec lock 0 5 5 1 +echo [+++] +echo [ [++++++++] +exec lock 0 4 4 1 +echo [++] +echo [ [+++++++++] +exec lock 0 0 10 1 +echo [+++++++++] +echo [+++++++++++++] +exec lock 0 0 15 0 +echo [...............] +echo [ +exec lock 0 10 0 1 +echo [++++ +echo [ [++++ +exec lock 0 5 5 1 +echo [+++] +echo [ [+++++++++ +exec lock 0 4 1 1 +echo + +echo [ [++++++++++ +exec lock 0 0 0 1 +echo [++++++++++++++ +echo [++++++++++++++ +exec lock 0 0 0 0 +echo [.... +echo [ +exec lock 0 10 5 2 +echo [xxx] +echo [ [xxx] +exec lock 0 5 5 2 +echo [xxx] +echo [ [xxxxxxxx] +exec lock 0 4 4 2 +echo [xx] +echo [ [xxxxxxxxx] +exec lock 0 0 10 2 +echo [xxxxxxxxx] +echo [xxxxxxxxxxxxx] +exec lock 0 0 15 0 +echo [...............] +echo [ +exec lock 0 10 0 2 +echo [xxxx +echo [ [xxxx +exec lock 0 5 5 2 +echo [xxx] +echo [ [xxxxxxxxx +exec lock 0 4 1 2 +echo x +echo [ [xxxxxxxxxx +exec lock 0 0 0 2 +echo [xxxxxxxxxxxxxx +echo [xxxxxxxxxxxxxx +exec lock 0 0 0 0 +echo [.... +echo [ +echo ** Different types just before the start of the locked region +exec lock 0 5 5 1 +echo [+++] +echo [ [+++] +exec lock 0 3 2 2 +echo [x] +echo [ [x][+++] +exec lock 0 2 1 1 +echo + +echo [ +[x][+++] +exec lock 0 1 0 2 +echo [xxxx +echo [[xxxx +exec lock 0 0 1 1 +echo + +echo +[xxxx +exec lock 0 0 0 0 +echo [.... +echo [.... +exec lock 0 5 0 1 +echo [++++ +echo [ [++++ +exec lock 0 0 5 2 +echo [xxxxxxxxx +echo [xxxxxxxxx +exec lock 0 0 0 0 +echo [.... +echo [ +echo ** New region consumes the intersection. +exec lock 0 5 5 1 +echo [+++] +echo [ [+++] +exec lock 0 4 3 2 +echo [x] +echo [ [x][+] +exec lock 0 2 0 2 +echo [xxxxxx +echo [ [xxxxxx +exec lock 0 0 0 0 +echo [.... +echo [ +exec lock 0 5 0 1 +echo [++++++ +echo [ [++++++ +exec lock 0 4 5 2 +echo [xxx] +echo [ [xxx][++ +exec lock 0 4 0 0 +echo [.... +echo [ +exec lock 0 5 0 1 +echo [++++ +echo [ [++++ +exec lock 0 0 0 2 +echo [xxxxxxxxxx +echo [xxxxxxxxxx +exec lock 0 0 0 0 +echo [.... +echo [ +echo ** New region is dominated +exec lock 0 5 5 2 +echo [xxx] +echo [ [xxx] +exec lock 0 4 5 1 +echo [+++] +echo [ +[xxx] +exec lock 0 0 0 0 +echo [... +echo [ +exec lock 0 5 0 2 +echo [xxxx +echo [ [xxxx +exec lock 0 0 0 1 +echo [++++++++ +echo [+++[xxxx +exec lock 0 0 0 0 +echo [.... +echo [ Index: hurd-0.9.git20181030-3.3/libfshelp-tests/race.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/race.c @@ -0,0 +1,83 @@ +/* Test races in the record locking code. + + Copyright (C) 2001 Free Software Foundation, Inc. + + Written by Neal H Walfield + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#include +#include +#include +#include +#include "fs_U.h" +#include +#include "io_U.h" + +int main (int argc, char **argv) +{ + error_t err; + struct flock64 lock; + mach_port_t rendezvous = MACH_PORT_NULL; + int fd; + int i; + uint v; + int blocked = 0; + char buf[10] = ""; + char *bufp; + + if (argc != 4) + error (1, 0, "Usage: %s file start len", argv[0]); + + lock.l_whence = SEEK_SET; + lock.l_start = atoi (argv[2]); + lock.l_len = atoi (argv[3]); + + fd = file_name_lookup (argv[1], O_READ | O_WRITE | O_CREAT, 0666); + if (fd == MACH_PORT_NULL) + error (1, errno, "file_name_lookup"); + + for (i = 0; i < 10000; i ++) + { + lock.l_type = F_WRLCK; + err = file_record_lock (fd, F_SETLK64, &lock, rendezvous, MACH_MSG_TYPE_MAKE_SEND); + if (err) + { + blocked ++; + err = file_record_lock (fd, F_SETLKW64, &lock, rendezvous, MACH_MSG_TYPE_MAKE_SEND); + } + if (err) + error (1, err, "file_record_lock"); + + v = sizeof (buf); + bufp = buf; + io_read (fd, &bufp, &v, 0, v); + + v = atoi (bufp); + sprintf (buf, "%d\n", v + 1); + + v = 10; + io_write (fd, buf, sizeof (buf), 0, &v); + if (v == 0) + error (1, errno, "write (%d)", i); + + lock.l_type = F_UNLCK; + file_record_lock (fd, F_SETLK64, &lock, rendezvous, MACH_MSG_TYPE_MAKE_SEND); + } + + mach_port_deallocate (mach_task_self (), fd); + + printf ("Was blocked %d times\n", blocked); + return 0; +} Index: hurd-0.9.git20181030-3.3/libfshelp-tests/test-flock.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/test-flock.c @@ -0,0 +1,181 @@ +/* test-flock.c: Test advisory open file locks, see flock(2) + Options: + file : file name/device name + flags : r (O_RDONLY) | w (O_WRONLY) | rw (O_RDWR) + operation : s (LOCK_SH), x (LOCK_EX), u (LOCK_UN), + sn (LOCK_SH | LOCK_UN), xn (LOCK_EX | LOCK_UN) + sleep_time : st [10] + + Copyright (C) 2016-2018 Free Software Foundation, Inc. + + Written by Svante Signell + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* Parse args */ +int parse_args (int argc, char **argv, char **file_name, + int *flags, char **flagsc, + int *op, char **opc, + int *sleep_time) +{ + int i, tmp; + char *str, *endptr; + + if (argc < 2) + error (1, 0, "Usage: %s file [flags] [operation] [sleep_time]\n \ + file : file name/device name\n \ + flags : r (O_RDONLY) | w [O_WRONLY] | rw (O_RDWR)\n \ + operation : s [LOCK_SH], x (LOCK_EX), u (LOCK_UN),\n \ + sn (LOCK_SH | LOCK_UN), xn (LOCK_EX | LOCK_UN)\n \ + sleep_time : st [10]\n", + argv[0]); + + *file_name = argv[1]; + for (i = 2; i < argc; i++) + { + str = argv[i]; + if (strncmp (str, "r", 2) == 0) + { + *flags = O_RDONLY; + *flagsc = "O_RDONLY"; + continue; + } + if (strncmp (str, "w", 2) == 0) + { + *flags = O_WRONLY; + *flagsc = "O_WRONLY"; + continue; + } + if (strncmp (str, "rw", 2) == 0) + { + *flags = O_RDWR; + *flagsc = "O_RDWR"; + continue; + } + if (strncmp (str, "s", 2) == 0) + { + *op = LOCK_SH; + *opc = "LOCK_SH"; + continue; + } + if (strncmp (str, "sn", 2) == 0) + { + *op = LOCK_SH | LOCK_NB; + *opc = "LOCK_SH | LOCK_NB"; + continue; + } + if (strncmp (str, "x", 2) == 0) + { + *op = LOCK_EX; + *opc = "LOCK_EX"; + continue; + } + if (strncmp (str, "xn", 2) == 0) + { + *op = LOCK_EX | LOCK_NB; + *opc = "LOCK_EX | LOCK_NB"; + continue; + } + if (strncmp (str, "u", 2) == 0) + { + *op = LOCK_UN; + *opc = "LOCK_UN"; + continue; + } + if (strncmp (str, "st", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + *sleep_time = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + error (1, EINVAL, "%s", str); + } + + return 0; +} + +int main (int argc, char **argv) +{ +#ifdef __GNU__ + error_t err; +#else + int err; +#endif + int fd, ret = -1; + char *file_name = NULL; + int flags = O_RDONLY; + char *flagsc = "O_RDONLY"; + int op = LOCK_SH; + char *opc = "LOCK_SH"; + char *opc1 = NULL; + int sleep_time = 10; + + ret = parse_args (argc, argv, &file_name, + &flags, &flagsc, + &op, &opc, + &sleep_time); + +#ifdef __GNU__ + printf ("test-lockf.c: GNU/Hurd\n"); +#else + printf ("test-lockf.c: GNU/Linux\n"); +#endif + + printf ("Opening file = '%s', flags = %s\n", file_name, flagsc); + fd = open (file_name, flags); + if (!fd) + error (1, errno, "open"); + printf ("'%s' opened: fd = %d, ", file_name, fd); + + opc1 = malloc (strlen (opc) + 1); + strcpy (opc1, opc); + + printf ("operation = %s\n", opc1); + + printf ("Requesting lock\n"); + err = flock (fd, op); + if (err) + error (1, errno, "flock"); + + printf ("Sleeping %d seconds\n", sleep_time); + sleep (sleep_time); + + printf ("Closing fd = %d\n", fd); + close (fd); + + return ret; +} Index: hurd-0.9.git20181030-3.3/libfshelp-tests/test-lockf.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/test-lockf.c @@ -0,0 +1,198 @@ +/* test-lockf.c: Test advisory open file record locks: + lockf(3) is an interface on top of fcntl(2) locking. + Options: + file : file name/device name + flags : r (O_RDONLY) | w (O_WRONLY) | rw (O_RDWR) + cmd : x (F_LOCK), xt (F_TLOCK), u (F_ULOCK), t (F_TEST) + len : l [0] + sleep_time : st [10] + + Copyright (C) 2016-2018 Free Software Foundation, Inc. + + Written by Svante Signell + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* Parse args */ +int parse_args(int argc, char **argv, char **file_name, + int *flags, char **flagsc, + int *cmd, char **cmdc, + off_t *len, int *sleep_time) +{ + int i, tmp; + char *str, *endptr; + + if (argc < 2) + error (1, 0, "Usage: %s file [flags] [cmd] [len] [sleep_time]\n \ + file : file name/device name\n \ + flags : r (O_RDONLY) | w [O_WRONLY] | rw (O_RDWR)\n \ + cmd : x [F_LOCK], xt (F_TLOCK), u (F_ULOCK),\n \ + t (F_TEST)\n \ + len : l [0]\n \ + sleep_time : st [10]\n", + argv[0]); + + *file_name = argv[1]; + for (i = 2; i < argc; i++) + { + str = argv[i]; + if (strncmp (str, "r", 2) == 0) + { + *flags = O_RDONLY; + *flagsc = "O_RDONLY"; + continue; + } + if (strncmp (str, "w", 2) == 0) + { + *flags = O_WRONLY; + *flagsc = "O_WRONLY"; + continue; + } + if (strncmp (str, "rw", 2) == 0) + { + *flags = O_RDWR; + *flagsc = "O_RDWR"; + continue; + } + if (strncmp (str, "x", 2) == 0) + { + *cmd = F_LOCK; + *cmdc = "F_LOCK"; + continue; + } + if (strncmp (str, "xt", 2) == 0) + { + *cmd = F_TLOCK; + *cmdc = "F_TLOCK"; + continue; + } + if (strncmp (str, "u", 2) == 0) + { + *cmd = F_ULOCK; + *cmdc = "F_LOCK"; + continue; + } + if (strncmp (str, "t", 2) == 0) + { + *cmd = F_TEST; + *cmdc = "F_TEST"; + continue; + } + if (strncmp (str, "l", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + *len = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + if (strncmp (str, "st", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + *sleep_time = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + error (1, EINVAL, "%s", str); + } + + return 0; +} + +int main (int argc, char **argv) +{ +#ifdef __GNU__ + error_t err; +#else + int err; +#endif + int fd, ret = -1; + char *file_name = NULL; + int flags = O_WRONLY; + char *flagsc = "O_WRONLY"; + int cmd = F_LOCK; + char *cmdc = "F_LOCK"; + char *cmdc1 = NULL; + off_t len = 0; + int sleep_time = 10; + + ret = parse_args (argc, argv, &file_name, + &flags, &flagsc, + &cmd, &cmdc, + &len, &sleep_time); + +#ifdef __GNU__ + printf ("test-lockf.c: GNU/Hurd\n"); +#else + printf ("test-lockf.c: GNU/Linux\n"); +#endif + + printf ("Opening file = '%s', flags = %s\n", file_name, flagsc); + fd = open (file_name, flags); + if (!fd) + error (1, errno, "open"); + printf ("'%s' opened: fd = %d, ", file_name, fd); + + cmdc1 = malloc (strlen (cmdc) + 1); + strcpy (cmdc1, cmdc); + +#ifdef __GNU__ + printf ("cmd = %s, len = %lld\n", cmdc1, len); +#else + printf ("cmd = %s, len = %ld\n", cmdc1, len); +#endif + printf ("Requesting lock\n"); + err = lockf (fd, cmd, len); + if (err) + error (1, errno, "lockf"); + + printf ("Sleeping %d seconds\n", sleep_time); + sleep (sleep_time); + + printf ("Closing fd = %d\n", fd); + close (fd); + + return ret; +} Index: hurd-0.9.git20181030-3.3/libfshelp-tests/test-fcntl.c =================================================================== --- /dev/null +++ hurd-0.9.git20181030-3.3/libfshelp-tests/test-fcntl.c @@ -0,0 +1,308 @@ +/* test-fcntl.c: Test advisory open file record locks, see fcntl(2) + Options: + file : file name/device name + flags : r (O_RDONLY) | w (O_WRONLY) | rw (O_RDWR) + cmd : g (F_GETLK), s (F_SETLK), sw (F_SETLKW) + l_type : rl (F_RDLCK), wl (F_WRLCK), ul (F_UNLCK) + l_whence : ss (SEEK_SET), sc (SEEK_CUR), se (SEEK_END) + l_start : b [0] + l_len : l [0] + sleep_time : st [10] + + Copyright (C) 2016-2018 Free Software Foundation, Inc. + + Written by Svante Signell + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd. If not, see . */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* Parse args */ +int parse_args(int argc, char **argv, char **file_name, + int *flags, char **flagsc, + int *cmd, char **cmdc, + struct flock *lock, + char **l_typec, char **l_whencec, + int *sleep_time) +{ + int i, tmp; + char *str, *endptr; + + if (argc < 2) + error (1, 0, "Usage: %s file [flags] [cmd] [len] [sleep_time]\n \ + file : file name/device name\n \ + flags : r (O_RDONLY) | w (O_WRONLY) | rw [O_RDWR]\n \ + cmd : g (F_GETLK), s [F_SETLK], sw (F_SETLKW)\n \ + lock.l_type : rl (F_RDLCK), wl (F_WRLCK), ul [F_UNLCK]\n \ + lock.l_whence : ss [SEEK_SET], sc (SEEK_CUR), se (SEEK_END)\n \ + lock.l_start : b [0]\n \ + lock.l_len : l [0]\n \ + sleep_time : st [10]\n", + argv[0]); + + *file_name = argv[1]; + for (i = 2; i < argc; i++) + { + str = argv[i]; + if (strncmp (str, "r", 2) == 0) + { + *flags = O_RDONLY; + *flagsc = "O_RDONLY"; + continue; + } + if (strncmp (str, "w", 2) == 0) + { + *flags = O_WRONLY; + *flagsc = "O_WRONLY"; + continue; + } + if (strncmp (str, "rw", 2) == 0) + { + *flags = O_RDWR; + *flagsc = "O_RDWR"; + continue; + } + if (strncmp (str, "s", 2) == 0) + { + *cmd = F_SETLK; + *cmdc = "F_SETLK"; + continue; + } + if (strncmp (str, "sw", 2) == 0) + { + *cmd = F_SETLKW; + *cmdc = "F_SETLKW"; + continue; + } + if (strncmp (str, "g", 2) == 0) + { + *cmd = F_GETLK; + *cmdc = "F_GETLK"; + continue; + } + if (strncmp (str, "rl", 2) == 0) + { + lock->l_type = F_RDLCK; + *l_typec = "F_RDLCK"; + continue; + } + if (strncmp (str, "wl", 2) == 0) + { + lock->l_type = F_WRLCK; + *l_typec = "F_WRLCK"; + continue; + } + if (strncmp (str, "ul", 2) == 0) + { + lock->l_type = F_UNLCK; + *l_typec = "F_UNLCK"; + continue; + } + if (strncmp (str, "ss", 2) == 0) + { + lock->l_whence = SEEK_SET; + *l_whencec = "SEEK_SET"; + continue; + } + if (strncmp (str, "sc", 2) == 0) + { + lock->l_whence = SEEK_CUR; + *l_whencec = "SEEK_CUR"; + continue; + } + if (strncmp (str, "se", 2) == 0) + { + lock->l_whence = SEEK_END; + *l_whencec = "SEEK_END"; + continue; + } + if (strncmp (str, "b", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + lock->l_start = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + if (strncmp (str, "l", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + lock->l_len = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + if (strncmp (str, "st", 2) == 0) + { + str = argv[++i]; + if (str) + { + errno = 0; + tmp = strtol (str, &endptr, 10); + if (tmp == 0 && errno != 0) + error (1, errno, "%s", str); + if (endptr == str) + error (1, EINVAL, "%s", str); + *sleep_time = tmp; + } + else + error (1, EINVAL, "%s", str); + continue; + } + error (1, EINVAL, "%s", str); + } + + return 0; +} + +int main (int argc, char **argv) +{ +#ifdef __GNU__ + error_t err; +#else + int err; +#endif + int fd, ret = -1; + char *file_name = NULL; + int flags = O_RDWR; + char *flagsc = "O_RDWR"; + char *old_l_typec; + int old_l_type, old_l_pid; + int cmd = F_SETLK; + char *cmdc = "F_SETLK"; + char *cmdc1 = NULL; + struct flock lock = { + F_UNLCK, + SEEK_SET, + 0, + 0, + 123456}; + char *l_typec = "F_UNLCK"; + char *l_whencec = "SEEK_SET"; + int sleep_time = 10; + + ret = parse_args (argc, argv, &file_name, + &flags, &flagsc, + &cmd, &cmdc, + &lock, + &l_typec, &l_whencec, + &sleep_time); + +#ifdef __GNU__ + printf ("GNU/Hurd\n"); +#else + printf ("GNU/Linux\n"); +#endif + printf ("test-fcntl.c:[PID]=%d\n", getpid()); + + file_name = "x.txt"; + printf ("Opening file = '%s', flags = %s\n", file_name, flagsc); + fd = open (file_name, flags); + if (!fd) + error (1, errno, "open"); + printf ("'%s' opened: fd = %d, ", file_name, fd); + + cmdc1 = malloc (strlen (cmdc) + 1); + strcpy (cmdc1, cmdc); + + printf ("cmd = %s\n", cmdc1); + printf("lock = {l_type, l_whence, l_start, l_len, l_pid} =\n"); +#ifdef __GNU__ + printf (" {%s, %s, %lld, %lld, %d}\n", +#else + printf (" {%s, %s, %ld, %ld, %d}\n", +#endif + l_typec, l_whencec, lock.l_start, lock.l_len, lock.l_pid); + + old_l_type = lock.l_type; + old_l_typec = l_typec; + old_l_pid = lock.l_pid; + + printf ("Requesting lock\n"); + err = fcntl (fd, cmd, &lock); + if (err) + error (1, errno, "fcntl"); + + if (old_l_type != lock.l_type) + if (lock.l_type == F_UNLCK) + { + l_typec = "F_UNLCK"; + printf("[PID=%ld] Lock can be placed\n", (long) getpid()); + printf ("old_l_typec = %s, l_type = %s\n", old_l_typec, l_typec); + return ret; + } + if (old_l_pid != lock.l_pid) + { + printf("[PID=%ld] Denied by %s lock on %lld:%lld " + "(held by PID %ld)\n", (long) getpid(), + (lock.l_type == F_RDLCK) ? "READ" : "WRITE", + (long long) lock.l_start, + (long long) lock.l_len, (long) lock.l_pid); + return ret; + } + printf ("Sleeping %d seconds\n", sleep_time); + sleep (sleep_time); + + printf ("Closing fd = %d\n", fd); + close (fd); + + return ret; +} +/* +Specific test cases: +T1: ./test-fcntl x.txt s rl +T2: ./test-fcntl x.txt g rl +[PID=9134] Lock can be placed +old_l_typec = F_RDLCK, l_type = F_UNLCK + +T1: ./test-fcntl x.txt s rl +T2: ./test-fcntl x.txt g wl +[PID=9161] Denied by READ lock on 0:0 (held by PID 9159) + +T1: ./test-fcntl x.txt s rl +T2: ./test-fcntl x.txt s wl +./test-fcntl: fcntl: Resource temporarily unavailable + +T1: ./test-fcntl x.txt s rl +T2: /test-fcntl x.txt sw wl +lock obtained after timeout in T1 +*/