summaryrefslogtreecommitdiff
path: root/Src/Modules
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-02-24 21:37:24 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-02-24 21:37:24 +0000
commitbec3de98dfab722b21e69a905bd83e4bfac22f72 (patch)
tree6bf8e01ac522e88cd4489a29bc44ce5a36ceea2b /Src/Modules
parent48315b019b12ad62ee2e260926db2d0167f45450 (diff)
downloadzsh-bec3de98dfab722b21e69a905bd83e4bfac22f72.tar.gz
zsh-bec3de98dfab722b21e69a905bd83e4bfac22f72.zip
27754 plus NEWS change: add "zsystem flock"
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/system.c166
1 files changed, 165 insertions, 1 deletions
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index 4af464db0..ef1ebb0b0 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -173,7 +173,7 @@ bin_sysread(char *nam, char **args, Options ops, UNUSED(int func))
select_tv.tv_usec = 0;
}
- while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds,
+ while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds,
NULL, NULL,&select_tv)) < 1) {
if (errno != EINTR || errflag || retflag || breaks || contflag)
break;
@@ -340,10 +340,174 @@ bin_syserror(char *nam, char **args, Options ops, UNUSED(int func))
return 0;
}
+/**/
+static int
+bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
+{
+ int cloexec = 1, unlock = 0, readlock = 0;
+ time_t timeout = 0;
+ char *fdvar = NULL;
+#ifdef HAVE_FCNTL_H
+ struct flock lck;
+ int flock_fd, flags;
+#endif
+
+ while (*args && **args == '-') {
+ int opt;
+ char *optptr = *args + 1, *optarg;
+ args++;
+ if (!*optptr || !strcmp(optptr, "-"))
+ break;
+ while ((opt = *optptr)) {
+ switch (opt) {
+ case 'e':
+ /* keep lock on "exec" */
+ cloexec = 0;
+ break;
+
+ case 'f':
+ /* variable for fd */
+ if (optptr[1]) {
+ fdvar = optptr + 1;
+ optptr += strlen(fdvar) - 1;
+ } else if (*args) {
+ fdvar = *args++;
+ }
+ if (fdvar == NULL || !isident(fdvar)) {
+ zwarnnam(nam, "flock: option %c requires a variable name",
+ opt);
+ return 1;
+ }
+ break;
+
+ case 'r':
+ /* read lock rather than read-write lock */
+ readlock = 1;
+ break;
+
+ case 't':
+ /* timeout in seconds */
+ if (optptr[1]) {
+ optarg = optptr + 1;
+ optptr += strlen(optarg) - 1;
+ } else if (!*args) {
+ zwarnnam(nam, "flock: option %c requires a numeric timeout",
+ opt);
+ return 1;
+ } else {
+ optarg = *args++;
+ }
+ timeout = (time_t)mathevali(optarg);
+ break;
+
+ case 'u':
+ /* unlock: argument is fd */
+ unlock = 1;
+ break;
+
+ default:
+ zwarnnam(nam, "flock: unknown option: %c", *optptr);
+ return 1;
+ }
+ optptr++;
+ }
+ }
+
+
+ if (!args[0]) {
+ zwarnnam(nam, "flock: not enough arguments");
+ return 1;
+ }
+ if (args[1]) {
+ zwarnnam(nam, "flock: too many arguments");
+ return 1;
+ }
+
+#ifdef HAVE_FCNTL_H
+ if (unlock) {
+ flock_fd = (int)mathevali(args[0]);
+ if (zcloselockfd(flock_fd) < 0) {
+ zwarnnam(nam, "flock: file descriptor %d not in use for locking",
+ flock_fd);
+ return 1;
+ }
+ return 0;
+ }
+
+ if (readlock)
+ flags = O_RDONLY | O_NOCTTY;
+ else
+ flags = O_RDWR | O_NOCTTY;
+ if ((flock_fd = open(unmeta(args[0]), flags)) < 0) {
+ zwarnnam(nam, "failed to open %s for writing: %e", args[0], errno);
+ return 1;
+ }
+ flock_fd = movefd(flock_fd);
+ if (flock_fd == -1)
+ return 1;
+#ifdef FD_CLOEXEC
+ if (cloexec)
+ {
+ long fdflags = fcntl(flock_fd, F_GETFD, 0);
+ if (fdflags != (long)-1)
+ fcntl(flock_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
+#endif
+ addlockfd(flock_fd, cloexec);
+
+ lck.l_type = readlock ? F_RDLCK : F_WRLCK;
+ lck.l_whence = SEEK_SET;
+ lck.l_start = 0;
+ lck.l_len = 0; /* lock the whole file */
+
+ if (timeout > 0) {
+ time_t end = time(NULL) + (time_t)timeout;
+ while (fcntl(flock_fd, F_SETLK, &lck) < 0) {
+ if (errno != EINTR && errno != EACCES && errno != EAGAIN) {
+ zwarnnam(nam, "failed to lock file %s: %e", args[0], errno);
+ return 1;
+ }
+ if (time(NULL) >= end)
+ return 2;
+ sleep(1);
+ }
+ } else {
+ while (fcntl(flock_fd, F_SETLKW, &lck) < 0) {
+ if (errno == EINTR)
+ continue;
+ zwarnnam(nam, "failed to lock file %s: %e", args[0], errno);
+ return 1;
+ }
+ }
+
+ if (fdvar)
+ setiparam(fdvar, flock_fd);
+
+ return 0;
+#else /* HAVE_FCNTL_H */
+ zwarnnam(nam, "flock: not implemented on this system");
+ return 255;
+#endif /* HAVE_FCNTL_H */
+}
+
+
+/**/
+static int
+bin_zsystem(char *nam, char **args, Options ops, int func)
+{
+ /* If more commands are implemented, this can be more sophisticated */
+ if (!strcmp(*args, "flock")) {
+ return bin_zsystem_flock(nam, args+1, ops, func);
+ }
+ zwarnnam(nam, "unknown subcommand: %s", *args);
+ return 1;
+}
+
static struct builtin bintab[] = {
BUILTIN("syserror", 0, bin_syserror, 0, 1, 0, "e:p:", NULL),
BUILTIN("sysread", 0, bin_sysread, 0, 1, 0, "c:i:o:s:t:", NULL),
BUILTIN("syswrite", 0, bin_syswrite, 1, 1, 0, "c:o:", NULL),
+ BUILTIN("zsystem", 0, bin_zsystem, 1, -1, 0, NULL, NULL)
};