aboutsummaryrefslogtreecommitdiffstats
path: root/postgresql-prep/src/testlock
diff options
context:
space:
mode:
Diffstat (limited to 'postgresql-prep/src/testlock')
-rw-r--r--postgresql-prep/src/testlock/.gitignore1
-rw-r--r--postgresql-prep/src/testlock/makefile56
-rw-r--r--postgresql-prep/src/testlock/testlock.138
-rw-r--r--postgresql-prep/src/testlock/testlock.c110
-rw-r--r--postgresql-prep/src/testlock/testlock.md27
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.