diff options
Diffstat (limited to 'postgresql-prep/src/testlock')
-rw-r--r-- | postgresql-prep/src/testlock/.gitignore | 1 | ||||
-rw-r--r-- | postgresql-prep/src/testlock/makefile | 56 | ||||
-rw-r--r-- | postgresql-prep/src/testlock/testlock.1 | 38 | ||||
-rw-r--r-- | postgresql-prep/src/testlock/testlock.c | 110 | ||||
-rw-r--r-- | postgresql-prep/src/testlock/testlock.md | 27 |
5 files changed, 232 insertions, 0 deletions
diff --git a/postgresql-prep/src/testlock/.gitignore b/postgresql-prep/src/testlock/.gitignore new file mode 100644 index 0000000..0618485 --- /dev/null +++ b/postgresql-prep/src/testlock/.gitignore @@ -0,0 +1 @@ +testlock diff --git a/postgresql-prep/src/testlock/makefile b/postgresql-prep/src/testlock/makefile new file mode 100644 index 0000000..c3bbb7a --- /dev/null +++ b/postgresql-prep/src/testlock/makefile @@ -0,0 +1,56 @@ +# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this code except in compliance +# with the License. You may obtain a copy of the License +# at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. + + +all: testlock + +TESTLOCK=./testlock + +ttestlock: testlock + @echo;echo should print usage list + -$(TESTLOCK) + @echo;echo should print usage list + -$(TESTLOCK) -? + @echo;echo should print missing lock filename + -$(TESTLOCK) -t 0 + @echo;echo should print missing command + -$(TESTLOCK) -t 0 /var/tmp/tl + @echo;echo should run immediately + $(TESTLOCK) -t 0 /var/tmp/tl /bin/echo hello + @echo;echo grab lock, done SHOULD run after lock becomes available + date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) /var/tmp/tl /bin/echo done;date + $(TESTLOCK) /var/tmp/tl true # cleanup + @echo;echo grab lock, not waiting should NOT run + date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 0 /var/tmp/tl /bin/echo not waiting;date + $(TESTLOCK) /var/tmp/tl true # cleanup + @echo;echo grab lock, echo should NOT run because lock does not become available in 4 seconds + date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 3 /var/tmp/tl /bin/echo waiting up to 3 seconds;date + $(TESTLOCK) /var/tmp/tl true # cleanup + @echo;echo grab lock, echo should SILENTLY NOT run because lock does not become available in 4 seconds + date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 3 -s /var/tmp/tl /bin/echo waiting up to 3 seconds;date + $(TESTLOCK) /var/tmp/tl true # cleanup + @echo;echo grab lock, echo SHOULD run after lock becomes available in 5 seconds + date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 10 /var/tmp/tl /bin/echo waiting up to 10 seconds;date + $(TESTLOCK) /var/tmp/tl true # cleanup + +testlock: testlock.c + gcc -o testlock testlock.c + +clean: + rm -f *~ + +clobber: clean + rm -f testlock + +stage: testlock + cp -p testlock ../postgresql-prep/Linux/dist_files/opt/app/postgresql-prep/bin/ diff --git a/postgresql-prep/src/testlock/testlock.1 b/postgresql-prep/src/testlock/testlock.1 new file mode 100644 index 0000000..12dbb9d --- /dev/null +++ b/postgresql-prep/src/testlock/testlock.1 @@ -0,0 +1,38 @@ +'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +'\" +'\" Licensed under the Apache License, Version 2.0 (the "License"); +'\" you may not use this code except in compliance +'\" with the License. You may obtain a copy of the License +'\" at http://www.apache.org/licenses/LICENSE-2.0 +'\" +'\" Unless required by applicable law or agreed to in writing, software +'\" distributed under the License is distributed on an "AS IS" BASIS, +'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +'\" implied. See the License for the specific language governing +'\" permissions and limitations under the License. +.TH testlock 1 "April 26 2006" "" "" +.SH NAME +testlock \- lock a file and run a command with the lock held +.SH SYNOPSIS +testlock [-v] [-t timeout] [-s] [-r exittcode] filename command args ... +.SH DESCRIPTION +.PP +Testlock will acquire a file lock and then execute a command while the lock is held. +If no timeout is provided, testlock will wait indefinitely until the file can be locked, +and then execute the command. +If a timeout is given, it will stop waiting after that many seconds have passed. +.SS Options +.IP -t +Abort if the lock cannot be acquired after +.I timeout +seconds. +If +.I timeout +is 0, the lock will be totally non-blocking. +.IP -s +Silently ignore errors with locking. +(Other errors will still be reported.) +.IP -r exitcode +If the lock cannot be acquired, use this exit code instead of the default exit code of 99. +.SH AUTHOR +Tony Hansen. diff --git a/postgresql-prep/src/testlock/testlock.c b/postgresql-prep/src/testlock/testlock.c new file mode 100644 index 0000000..41bea59 --- /dev/null +++ b/postgresql-prep/src/testlock/testlock.c @@ -0,0 +1,110 @@ +/* + Usage: testlock [-t timeout] [-s] filename command args ... + + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this code except in compliance + with the License. You may obtain a copy of the License + at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + +*/ + +#include <sys/file.h> +#include <stdio.h> +#include <unistd.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdbool.h> +#include <errno.h> +#include <string.h> + +void usage(const char *prog0, const char *msg) +{ + if (msg) fprintf(stderr, "%s\n", msg); + fprintf(stderr, "Usage: %s [-v] [-t timeout] [-s] [-r retcode] lock-filename command args ...\n", prog0); + fprintf(stderr, "-t ##\thow long to wait for a lock to be freed. 0 means exit immediately\n"); + fprintf(stderr, "-s\tsilently ignore errors with locking\n"); + fprintf(stderr, "-r ##\texit with this code when the lock fails\n"); + fprintf(stderr, "-v\tbe verbose\n"); + fprintf(stderr, "Note:\tlock-filename is created (if it does not exist) and truncated before locking.\n"); + fprintf(stderr, "\tlock-filename is not removed after the command finishes\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *prog0 = argv[0]; + + int c; + int timeout = -1; + bool silent = false; + bool verbose = false; + int nolockret = 99; + + while ((c = getopt(argc, argv, "t:r:sv?")) != -1) { + switch (c) { + case 's': silent = true; break; + case 't': timeout = atoi(optarg); break; + case 'r': nolockret = atoi(optarg); break; + case 'v': verbose = true; break; + default: usage(prog0, NULL); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(prog0, "Missing lock filename"); + } else if (argc < 2) { + usage(prog0, "Missing command to run"); + } + + const char *lockFilename = *argv++; + if (verbose) printf("lockfilename=%s\n", lockFilename); + + int lockfd = creat(lockFilename, 0666); + if (lockfd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", lockFilename, strerror(errno)); + exit(2); + } + + if (timeout < 0) { + /* wait forever */ + lockf(lockfd, F_LOCK, 0); + } else { + /* try each second (for up to timeout seconds) to get the lock */ + int lockret = lockf(lockfd, F_TLOCK, 0); + int count = 0; + while ((lockret < 0) && (count++ < timeout)) { + sleep(1); + lockret = lockf(lockfd, F_TLOCK, 0); + } + if (lockret < 0) { + if (!silent) { + fprintf(stderr, "Cannot lock %s: %s\n", lockFilename, strerror(errno)); + } + exit(nolockret); + } + } + + /* now execute the given command */ + if (verbose) { + char **a = argv; + printf("calling program '%s'\n", *a); + while (*++a) { + printf("with argument '%s'\n", *a); + } + } + execvp(argv[0], argv); +} diff --git a/postgresql-prep/src/testlock/testlock.md b/postgresql-prep/src/testlock/testlock.md new file mode 100644 index 0000000..8ec2a48 --- /dev/null +++ b/postgresql-prep/src/testlock/testlock.md @@ -0,0 +1,27 @@ +# testlock 1 "April 26 2006" "" "" +## NAME +testlock \- lock a file and run a command with the lock held +## SYNOPSIS +testlock [-v] [-t timeout] [-s] [-r exittcode] filename command args ... +## DESCRIPTION + +Testlock will acquire a file lock and then execute a command while the lock is held. +If no timeout is provided, testlock will wait indefinitely until the file can be locked, +and then execute the command. +If a timeout is given, it will stop waiting after that many seconds have passed. + +### Options + +-t +Abort if the lock cannot be acquired after _timeout_ seconds. +If _timeout_ is 0, the lock will be totally non-blocking. + +-s +Silently ignore errors with locking. +(Other errors will still be reported.) + +-r exitcode +If the lock cannot be acquired, use this exit code instead of the default exit code of 99. + +## AUTHOR +Tony Hansen. |