#include #include #include #include #include "builtins.h" #include "shell.h" #include "bashgetopt.h" #include "common.h" #include "filecntl.h" static int lock_file(const char *fname, int operation, int verbose) { int fd; #ifdef O_DIRECTORY if ((fd = open(fname, O_RDONLY | O_NONBLOCK | O_DIRECTORY)) < 0) #endif if ((fd = open(fname, O_RDONLY | O_NONBLOCK | O_CREAT, 0666)) < 0) { builtin_error("Failed to open lock file %s: %m", fname); return -1; } fd = move_to_high_fd(fd, 1, -1); SET_CLOSE_ON_EXEC(fd); if (flock(fd, operation) == 0) return 0; if (verbose) builtin_error("Failed to place a lock on lock file %s: %m", fname); close(fd); return -1; } static int lockf_builtin (WORD_LIST *list) { int opt, operation = LOCK_EX, nonblock = 0, verbose = 0; reset_internal_getopt(); while ((opt = internal_getopt(list, "ensvx")) != -1) { switch (opt) { case 'e': case 'x': operation = LOCK_EX; break; case 's': operation = LOCK_SH; break; case 'n': nonblock = LOCK_NB; break; case 'v': verbose = 1; break; default: builtin_usage(); return EX_USAGE; } } list = loptend; if (!list || list->next) { builtin_usage(); return EX_USAGE; } return lock_file(list->word->word, operation | nonblock, verbose) ? EXECUTION_FAILURE : EXECUTION_SUCCESS; } static char *lockf_doc[] = { "Locks a specified file, which is created if it does not already exist.", "File descriptor of the opened file has the close-on-exec flag set.", "Options have the following meanings:", "", " -s obtain a shared lock, sometimes called a read lock", " -e, -x obtain an exclusive lock, sometimes called a write lock", " (this is the default)", " -n fail rather than wait if the lock cannot be immediately acquired", " -v complain when lock attempt fails", NULL }; struct builtin lockf_struct = { "lockf", /* builtin name */ lockf_builtin, /* function implementing the builtin */ BUILTIN_ENABLED, /* initial flags for builtin */ lockf_doc, /* array of long documentation strings. */ "lockf [-ensx] file", /* usage synopsis; becomes short_doc */ 0 /* reserved for internal use */ };