From 37b302046a62ddfe0524f7bd8c725d4ddc5184b1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 26 May 2020 17:21:04 +0200 Subject: [PATCH] lib/blkdev: add support for --lock and LOCK_BLOCK_DEVICE All simple function to parse --lock and $LOCK_BLOCK_DEVICE, and to flock the fd. The supported is: "1" or "yes" - LOCK_EX "0" or "no" - do nothing "nonblock" - LOCK_EX | LOCK_NB The function tries LOCK_NB before the solo LOCK_EX and prints inform user that it will wait, for example: session A: # sfdisk --lock /dev/sdc session B: # sfdisk --lock /dev/sdc sfdisk: /dev/sdc: device already locked, waiting to get lock ... ^C # sfdisk --lock=nonblock /dev/sdc sfdisk: /dev/sdc: device already locked Addresses: https://github.com/karelzak/util-linux/issues/921 Signed-off-by: Karel Zak --- include/blkdev.h | 1 + lib/blkdev.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/include/blkdev.h b/include/blkdev.h index 62eda82af..6cbecbb65 100644 --- a/include/blkdev.h +++ b/include/blkdev.h @@ -146,5 +146,6 @@ int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s); /* convert scsi type code to name */ const char *blkdev_scsi_type_to_name(int type); +int blkdev_lock(int fd, const char *devname, const char *lockmode); #endif /* BLKDEV_H */ diff --git a/lib/blkdev.c b/lib/blkdev.c index c71550e63..c22853ddc 100644 --- a/lib/blkdev.c +++ b/lib/blkdev.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -361,6 +362,57 @@ const char *blkdev_scsi_type_to_name(int type) return NULL; } +/* return 0 on success */ +int blkdev_lock(int fd, const char *devname, const char *lockmode) +{ + int oper, rc, msg = 0; + + if (!lockmode) + lockmode = getenv("LOCK_BLOCK_DEVICE"); + if (!lockmode) + return 0; + + if (strcasecmp(lockmode, "yes") == 0 || + strcmp(lockmode, "1") == 0) + oper = LOCK_EX; + + else if (strcasecmp(lockmode, "nonblock") == 0) + oper = LOCK_EX | LOCK_NB; + + else if (strcasecmp(lockmode, "no") == 0 || + strcmp(lockmode, "0") == 0) + return 0; + else { + warnx(_("unsupported lock mode: %s"), lockmode); + return -EINVAL; + } + + if (!(oper & LOCK_NB)) { + /* Try non-block first to provide message */ + rc = flock(fd, oper | LOCK_NB); + if (rc == 0) + return 0; + if (rc != 0 && errno == EWOULDBLOCK) { + fprintf(stderr, _("%s: %s: device already locked, waiting to get lock ... "), + program_invocation_short_name, devname); + msg = 1; + } + } + rc = flock(fd, oper); + if (rc != 0) { + switch (errno) { + case EWOULDBLOCK: /* LOCK_NB */ + warnx(_("%s: device already locked"), devname); + break; + default: + warn(_("%s: failed to get lock"), devname); + } + } else if (msg) + fprintf(stderr, _("OK\n")); + return rc; +} + + #ifdef TEST_PROGRAM_BLKDEV #include #include