]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
flock: Introduce no-fork option.
authorTerry Burton <tez@terryburton.co.uk>
Thu, 14 Apr 2016 11:27:52 +0000 (12:27 +0100)
committerTerry Burton <tez@terryburton.co.uk>
Fri, 15 Apr 2016 22:15:22 +0000 (23:15 +0100)
When guarding a command with flock it is sometimes preferable to not leave a
flock process waiting around for the command to exit.

sys-utils/flock.1
sys-utils/flock.c

index 8e9d5c29a2890405d8b9c84eccedee61c5a2598b..c10cde5ff3de559a87c149461c28f46188e33c8f 100644 (file)
@@ -70,6 +70,14 @@ The exit code used when the \fB\-n\fP option is in use, and the
 conflicting lock exists, or the \fB\-w\fP option is in use,
 and the timeout is reached.  The default value is \fB1\fR.
 .TP
+.BR \-F , " \-\-no\-fork"
+Do not fork before executing
+.IR command .
+Upon execution the flock process is replaced by
+.IR command
+which continues to hold the lock. This option is incompatible with
+\fB\-\-close\fR as there would otherwise be nothing left to hold the lock.
+.TP
 .BR \-e , " \-x" , " \-\-exclusive"
 Obtain an exclusive lock, sometimes called a write lock.  This is the
 default.
index b5c4d918973a51eddd31f6d462689ba5880cd3e9..ac473eecddc932810bf0965455b17b1705385111 100644 (file)
@@ -67,6 +67,7 @@ static void __attribute__((__noreturn__)) usage(int ex)
        fputs(_(  " -E, --conflict-exit-code <number>  exit code after conflict or timeout\n"), stderr);
        fputs(_(  " -o, --close              close file descriptor before running command\n"), stderr);
        fputs(_(  " -c, --command <command>  run a single command string through the shell\n"), stderr);
+       fputs(_(  " -F, --no-fork            execute command without forking\n"), stderr);
        fputs(_(  "     --verbose            increase verbosity\n"), stderr);
        fprintf(stderr, USAGE_SEPARATOR);
        fprintf(stderr, USAGE_HELP);
@@ -125,6 +126,7 @@ int main(int argc, char *argv[])
        int fd = -1;
        int opt, ix;
        int do_close = 0;
+       int no_fork = 0;
        int status;
        int verbose = 0;
        struct timeval time_start, time_done;
@@ -148,6 +150,7 @@ int main(int argc, char *argv[])
                {"wait", required_argument, NULL, 'w'},
                {"conflict-exit-code", required_argument, NULL, 'E'},
                {"close", no_argument, NULL, 'o'},
+               {"no-fork", no_argument, NULL, 'F'},
                {"verbose", no_argument, NULL, OPT_VERBOSE},
                {"help", no_argument, NULL, 'h'},
                {"version", no_argument, NULL, 'V'},
@@ -166,7 +169,7 @@ int main(int argc, char *argv[])
 
        optopt = 0;
        while ((opt =
-               getopt_long(argc, argv, "+sexnouw:E:hV?", long_options,
+               getopt_long(argc, argv, "+sexnoFuw:E:hV?", long_options,
                            &ix)) != EOF) {
                switch (opt) {
                case 's':
@@ -182,6 +185,9 @@ int main(int argc, char *argv[])
                case 'o':
                        do_close = 1;
                        break;
+               case 'F':
+                       no_fork = 1;
+                       break;
                case 'n':
                        block = LOCK_NB;
                        break;
@@ -209,6 +215,10 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (no_fork && do_close)
+               errx(EX_USAGE,
+                       _("the --no-fork and --close options are incompatible"));
+
        if (argc > optind + 1) {
                /* Run command */
                if (!strcmp(argv[optind + 1], "-c") ||
@@ -320,36 +330,40 @@ int main(int argc, char *argv[])
                signal(SIGCHLD, SIG_DFL);
                if (verbose)
                        printf(_("%s: executing %s\n"), program_invocation_short_name, cmd_argv[0]);
-               f = fork();
 
-               if (f < 0) {
-                       err(EX_OSERR, _("fork failed"));
-               } else if (f == 0) {
-                       if (do_close)
-                               close(fd);
-                       execvp(cmd_argv[0], cmd_argv);
-                       /* execvp() failed */
-                       warn(_("failed to execute %s"), cmd_argv[0]);
-                       _exit((errno == ENOMEM) ? EX_OSERR : EX_UNAVAILABLE);
-               } else {
-                       do {
-                               w = waitpid(f, &status, 0);
-                               if (w == -1 && errno != EINTR)
-                                       break;
-                       } while (w != f);
+               if (!no_fork) {
+                       f = fork();
+                       if (f < 0) {
+                               err(EX_OSERR, _("fork failed"));
+                               if (f != 0) {
+                                       do {
+                                               w = waitpid(f, &status, 0);
+                                               if (w == -1 && errno != EINTR)
+                                               break;
+                                       } while (w != f);
 
-                       if (w == -1) {
-                               status = EXIT_FAILURE;
-                               warn(_("waitpid failed"));
-                       } else if (WIFEXITED(status))
-                               status = WEXITSTATUS(status);
-                       else if (WIFSIGNALED(status))
-                               status = WTERMSIG(status) + 128;
-                       else
-                               /* WTF? */
-                               status = EX_OSERR;
+                                       if (w == -1) {
+                                       status = EXIT_FAILURE;
+                                       warn(_("waitpid failed"));
+                               } else if (WIFEXITED(status))
+                                       status = WEXITSTATUS(status);
+                               else if (WIFSIGNALED(status))
+                                       status = WTERMSIG(status) + 128;
+                               else
+                                       /* WTF? */
+                                       status = EX_OSERR;
+                               }
+                               goto out;
+                       }
                }
+               if (do_close)
+                       close(fd);
+               execvp(cmd_argv[0], cmd_argv);
+               /* execvp() failed */
+               warn(_("failed to execute %s"), cmd_argv[0]);
+               _exit((errno == ENOMEM) ? EX_OSERR : EX_UNAVAILABLE);
        }
 
+out:
        return status;
 }