]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: improve command line option processing
authorKarel Zak <kzak@redhat.com>
Tue, 21 Oct 2025 09:45:54 +0000 (11:45 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 21 Oct 2025 09:45:54 +0000 (11:45 +0200)
The options --detach, --remove, and --set-capacity are mutually
exclusive. We can assume the device name follows the options, which is
better than assuming the device name is specified as an option's
argument. This also allows the use of the existing mutually-exclusive
check.

 # losetup --remove --detach loop0
 losetup: /dev/--detach: remove failed: Success
 losetup: /dev/loop0: remove failed: Device or resource busy

is ugly.

Reported-by: Benno Schulenberg <bensberg@telfort.nl>
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/losetup.c

index 8320d580548f5e3ddf4c5893cf69fe4b7cfcbdab..c2eec5600ba5ad417bb9012ee3058dd01be65a76 100644 (file)
@@ -691,7 +691,7 @@ int main(int argc, char **argv)
 {
        struct loopdev_cxt lc;
        int act = 0, flags = 0, no_overlap = 0, c;
-       char *file = NULL, *refname = NULL;
+       char *file = NULL, *refname = NULL, *devname = NULL;
        uint64_t offset = 0, sizelimit = 0, blocksize = 0;
        int res = 0, showdev = 0, lo_flags = 0;
        char *outarg = NULL;
@@ -709,8 +709,8 @@ int main(int argc, char **argv)
        };
        static const struct option longopts[] = {
                { "all",          no_argument,       NULL, 'a'           },
-               { "set-capacity", required_argument, NULL, 'c'           },
-               { "detach",       required_argument, NULL, 'd'           },
+               { "set-capacity", no_argument,       NULL, 'c'           },
+               { "detach",       no_argument,       NULL, 'd'           },
                { "detach-all",   no_argument,       NULL, 'D'           },
                { "find",         no_argument,       NULL, 'f'           },
                { "nooverlap",    no_argument,       NULL, 'L'           },
@@ -732,7 +732,7 @@ int main(int argc, char **argv)
                { "show",         no_argument,       NULL, OPT_SHOW      },
                { "verbose",      no_argument,       NULL, 'v'           },
                { "version",      no_argument,       NULL, 'V'           },
-               { "remove",       required_argument, NULL, OPT_REMOVE    },
+               { "remove",       no_argument,       NULL, OPT_REMOVE    },
                { NULL, 0, NULL, 0 }
        };
 
@@ -753,7 +753,7 @@ int main(int argc, char **argv)
        if (loopcxt_init(&lc, 0))
                err(EXIT_FAILURE, _("failed to initialize loopcxt"));
 
-       while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:PrvV",
+       while ((c = getopt_long(argc, argv, "ab:cdDfhj:JlLno:O:PrvV",
                                longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
@@ -768,9 +768,6 @@ int main(int argc, char **argv)
                        break;
                case 'c':
                        act = A_SET_CAPACITY;
-                       if (loopcxt_set_device(&lc, optarg))
-                               err(EXIT_FAILURE, _("%s: failed to use device"),
-                                               optarg);
                        break;
                case 'r':
                        lo_flags |= LO_FLAGS_READ_ONLY;
@@ -780,9 +777,6 @@ int main(int argc, char **argv)
                        break;
                case 'd':
                        act = A_DETACH;
-                       if (loopcxt_set_device(&lc, optarg))
-                               err(EXIT_FAILURE, _("%s: failed to use device"),
-                                               optarg);
                        break;
                case 'D':
                        act = A_DETACH_ALL;
@@ -849,9 +843,6 @@ int main(int argc, char **argv)
 
                case OPT_REMOVE:
                        act = A_REMOVE;
-                       if (loopcxt_set_device(&lc, optarg))
-                               err(EXIT_FAILURE, _("%s: failed to use device"),
-                                               optarg);
                        break;
 
                default:
@@ -902,6 +893,15 @@ int main(int argc, char **argv)
                 */
                act = A_SHOW;
 
+       if (act == A_SET_CAPACITY
+           || act == A_DETACH
+           || act == A_REMOVE) {
+
+               if (optind >= argc)
+                       errx(EXIT_FAILURE, _("no loop device specified"));
+               devname = argv[optind++];
+       }
+
        if (!act && optind + 1 == argc) {
                /*
                 * losetup [--list] <device>
@@ -916,10 +916,9 @@ int main(int argc, char **argv)
                else
                        act = A_SHOW_ONE;
 
-               if (loopcxt_set_device(&lc, argv[optind]))
-                       err(EXIT_FAILURE, _("%s: failed to use device"),
-                                       argv[optind]);
-               optind++;
+               if (optind >= argc)
+                       errx(EXIT_FAILURE, _("no loop device specified"));
+               devname = argv[optind++];
        }
        if (!act) {
                /*
@@ -929,17 +928,17 @@ int main(int argc, char **argv)
 
                if (optind >= argc)
                        errx(EXIT_FAILURE, _("no loop device specified"));
-               /* don't use is_loopdev() here, the device does not have exist yet */
-               if (loopcxt_set_device(&lc, argv[optind]))
-                       err(EXIT_FAILURE, _("%s: failed to use device"),
-                                       argv[optind]);
-               optind++;
+               devname = argv[optind++];
 
                if (optind >= argc)
                        errx(EXIT_FAILURE, _("no file specified"));
                file = argv[optind++];
        }
 
+       /* don't use is_loopdev() here, the device does not have exist yet */
+       if (devname && loopcxt_set_device(&lc, devname))
+               err(EXIT_FAILURE, _("%s: failed to use device"), devname);
+
        if (act != A_CREATE &&
            (sizelimit || lo_flags || showdev))
                errx(EXIT_FAILURE,