From 787f8251b539ad6c3cd1098ab155980afe611867 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 21 Oct 2025 11:45:54 +0200 Subject: [PATCH] losetup: improve command line option processing 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 Signed-off-by: Karel Zak --- sys-utils/losetup.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 8320d5805..c2eec5600 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -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] @@ -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, -- 2.47.3