]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/blkdev: add support for --lock and LOCK_BLOCK_DEVICE
authorKarel Zak <kzak@redhat.com>
Tue, 26 May 2020 15:21:04 +0000 (17:21 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 26 May 2020 15:30:39 +0000 (17:30 +0200)
All simple function to parse --lock <mode> and $LOCK_BLOCK_DEVICE,
and to flock the fd.

The supported <mode> 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 <kzak@redhat.com>
include/blkdev.h
lib/blkdev.c

index 62eda82af919de19ba187cafad0aa31c75af52aa..6cbecbb65f8221f2f289e7c21bf883cf1484d666 100644 (file)
@@ -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 */
index c71550e63ef8a02b9ccee0d18986c8f665cfeb8b..c22853ddcbb0f604092a824f8566c1694667d2e2 100644 (file)
@@ -6,6 +6,7 @@
  */
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/file.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <stdint.h>
@@ -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 <stdio.h>
 #include <stdlib.h>