From: Karel Zak Date: Tue, 21 Oct 2025 09:45:54 +0000 (+0200) Subject: losetup: improve command line option processing X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=787f8251b539ad6c3cd1098ab155980afe611867;p=thirdparty%2Futil-linux.git 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 --- 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,