busybox/util-linux/flock.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Timo Teras <timo.teras@iki.fi>
   3 *
   4 * This is free software, licensed under the GNU General Public License v2.
   5 */
   6//config:config FLOCK
   7//config:       bool "flock (6.3 kb)"
   8//config:       default y
   9//config:       help
  10//config:       Manage locks from shell scripts
  11
  12//applet:IF_FLOCK(APPLET(flock, BB_DIR_USR_BIN, BB_SUID_DROP))
  13
  14//kbuild:lib-$(CONFIG_FLOCK) += flock.o
  15
  16//usage:#define flock_trivial_usage
  17//usage:       "[-sxun] FD|{FILE [-c] PROG ARGS}"
  18//usage:#define flock_full_usage "\n\n"
  19//usage:       "[Un]lock file descriptor, or lock FILE, run PROG\n"
  20//usage:     "\n        -s      Shared lock"
  21//usage:     "\n        -x      Exclusive lock (default)"
  22//usage:     "\n        -u      Unlock FD"
  23//usage:     "\n        -n      Fail rather than wait"
  24
  25#include <sys/file.h>
  26#include "libbb.h"
  27
  28int flock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  29int flock_main(int argc UNUSED_PARAM, char **argv)
  30{
  31        int mode, opt, fd;
  32        enum {
  33                OPT_s = (1 << 0),
  34                OPT_x = (1 << 1),
  35                OPT_n = (1 << 2),
  36                OPT_u = (1 << 3),
  37                OPT_c = (1 << 4),
  38        };
  39
  40#if ENABLE_LONG_OPTS
  41        static const char flock_longopts[] ALIGN1 =
  42                "shared\0"      No_argument       "s"
  43                "exclusive\0"   No_argument       "x"
  44                "unlock\0"      No_argument       "u"
  45                "nonblock\0"    No_argument       "n"
  46                ;
  47#endif
  48
  49        opt = getopt32long(argv, "^+" "sxnu" "\0" "-1", flock_longopts);
  50        argv += optind;
  51
  52        if (argv[1]) {
  53                fd = open(argv[0], O_RDONLY|O_NOCTTY|O_CREAT, 0666);
  54                if (fd < 0 && errno == EISDIR)
  55                        fd = open(argv[0], O_RDONLY|O_NOCTTY);
  56                if (fd < 0)
  57                        bb_perror_msg_and_die("can't open '%s'", argv[0]);
  58                //TODO? close_on_exec_on(fd);
  59        } else {
  60                fd = xatoi_positive(argv[0]);
  61        }
  62        argv++;
  63
  64        /* If it is "flock FILE -c PROG", then -c isn't caught by getopt32:
  65         * we use "+" in order to support "flock -opt FILE PROG -with-opts",
  66         * we need to remove -c by hand.
  67         */
  68        if (argv[0]
  69         && argv[0][0] == '-'
  70         && (  (argv[0][1] == 'c' && !argv[0][2])
  71            || (ENABLE_LONG_OPTS && strcmp(argv[0] + 1, "-command") == 0)
  72            )
  73        ) {
  74                argv++;
  75                if (argv[1])
  76                        bb_error_msg_and_die("-c takes only one argument");
  77                opt |= OPT_c;
  78        }
  79
  80        if (OPT_s == LOCK_SH && OPT_x == LOCK_EX && OPT_n == LOCK_NB && OPT_u == LOCK_UN) {
  81                /* With suitably matched constants, mode setting is much simpler */
  82                mode = opt & (LOCK_SH + LOCK_EX + LOCK_NB + LOCK_UN);
  83                if (!(mode & ~LOCK_NB))
  84                        mode |= LOCK_EX;
  85        } else {
  86                if (opt & OPT_u)
  87                        mode = LOCK_UN;
  88                else if (opt & OPT_s)
  89                        mode = LOCK_SH;
  90                else
  91                        mode = LOCK_EX;
  92                if (opt & OPT_n)
  93                        mode |= LOCK_NB;
  94        }
  95
  96        if (flock(fd, mode) != 0) {
  97                if (errno == EWOULDBLOCK)
  98                        return EXIT_FAILURE;
  99                bb_perror_nomsg_and_die();
 100        }
 101
 102        if (argv[0]) {
 103                int rc;
 104                if (opt & OPT_c) {
 105                        /* -c 'PROG ARGS' means "run sh -c 'PROG ARGS'" */
 106                        argv -= 2;
 107                        argv[0] = (char*)get_shell_name();
 108                        argv[1] = (char*)"-c";
 109                        /* argv[2] = "PROG ARGS"; */
 110                        /* argv[3] = NULL; */
 111                }
 112                rc = spawn_and_wait(argv);
 113                if (rc < 0)
 114                        bb_simple_perror_msg(argv[0]);
 115                return rc;
 116        }
 117
 118        return EXIT_SUCCESS;
 119}
 120