Fix losetup so that it A) actually works again, B) has much better error
authorRob Landley <rob@landley.net>
Tue, 29 Nov 2005 23:47:10 +0000 (23:47 -0000)
committerRob Landley <rob@landley.net>
Tue, 29 Nov 2005 23:47:10 +0000 (23:47 -0000)
messages, C) can show the current association (if any) when called
with only one argument.  Update the documentation a lot too.

Remind me to add a test suite for this thing.  I think I've figured out
how to handle root-only testsuites...

include/libbb.h
include/usage.h
libbb/loop.c
util-linux/losetup.c

index d1c6be670c20bbf7b4c5ed10edac2a49101dec03..96dc46a09b3158a88f91250d19c00ba9f219d0fd 100644 (file)
@@ -232,6 +232,7 @@ extern char *bb_askpass(int timeout, const char * prompt);
 
 extern int device_open(const char *device, int mode);
 
+extern char *query_loop(const char *device);
 extern int del_loop(const char *device);
 extern int set_loop(char **device, const char *file, int offset);
 
@@ -466,7 +467,7 @@ typedef struct {
 } procps_status_t;
 
 extern procps_status_t * procps_scan(int save_user_arg0);
-extern int compare_string_array(const char * const string_array[], const char *key);
+extern unsigned short compare_string_array(const char *string_array[], const char *key);
 
 extern int my_query_module(const char *name, int which, void **buf, size_t *bufsize, size_t *ret);
 
index 912a88f4ed7a36b6fd0ef6ec4c7fba1ca563745d..53832b9876863526ec550e919180e4d0b41f522f 100644 (file)
        "\t-f\t\toutput data as the log grows"
 
 #define losetup_trivial_usage \
-       "[OPTION]... LOOPDEVICE FILE\n" \
-       "or: losetup [OPTION]... -d LOOPDEVICE"
+       "[-od] LOOPDEVICE [FILE]\n"
 #define losetup_full_usage \
-       "Associate LOOPDEVICE with FILE.\n\n" \
+       "Associate LOOPDEVICE with FILE, or display current association.\n\n" \
        "Options:\n" \
        "\t-d\t\tDisassociate LOOPDEVICE\n" \
        "\t-o OFFSET\tStart OFFSET bytes into FILE"
+#define losetup_notes_usage \
+       "One argument (losetup /dev/loop1) will display the current association\n" \
+       "(if any), or disassociate it (with -d).  The display shows the offset\n" \
+       "and filename of the file the loop device is currently bound to.\n\n" \
+       "Two arguments (losetup /dev/loop1 file.img) create a new association,\n" \
+       "with an optional offset (-o 12345).  Encryption is not yet supported.\n\n"
 
 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
 #  define USAGE_LS_TIMESTAMPS(a) a
        "-rw-------    1 andersen andersen        0 Apr 25 17:10 /tmp/temp.mWiLjM\n"
 
 #define modprobe_trivial_usage \
-       "[-knqrsv] MODULE [symbol=value ...]"
+       "[-knqrsv] [MODULE ...]"
 #define modprobe_full_usage \
+       "Used for high level module loading and unloading.\n\n" \
        "Options:\n" \
        "\t-k\tMake module autoclean-able\n" \
        "\t-n\tJust show what would be done\n" \
        "\t-q\tQuiet output\n" \
        "\t-r\tRemove module (stacks) or do autoclean\n" \
        "\t-s\tReport via syslog instead of stderr\n" \
-       "\t-v\tVerbose output\n\n"
-#define modprobe_notes_usage \
-"modprobe can (un)load a stack of modules, passing each module options (when\n" \
-"loading). modprobe uses a configuration file to determine what option(s) to\n" \
-"pass each module it loads.\n" \
-"\n" \
-"The configuration file is searched (in order) amongst:\n" \
-"\n" \
-"    /etc/modprobe.conf (2.6 only)\n" \
-"    /etc/modules.conf\n" \
-"    /etc/conf.modules (deprecated)\n" \
-"\n" \
-"They all have the same syntax (see below). If none is present, it is\n" \
-"_not_ an error; each loaded module is then expected to load without\n" \
-"options. Once a file is found, the others are tested for.\n" \
-"\n" \
-"/etc/modules.conf entry format:\n" \
-"\n" \
-"  alias <alias_name> <mod_name>\n" \
-"    Makes it possible to modprobe alias_name, when there is no such module.\n" \
-"    It makes sense if your mod_name is long, or you want a more reprenstative\n" \
-"    name for that module (eg. 'scsi' in place of 'aha7xxx').\n" \
-"    This makes it also possible to use a different set of options (below) for\n" \
-"    the module and the alias.\n" \
-"    A module can be aliased more than once.\n" \
-"\n" \
-"  options <mod_name|alias_name> <symbol=value ...>\n" \
-"    When loading module mod_name (or the module aliased by alias_name), pass\n" \
-"    the \"symbol=value\" pairs as option to that module.\n" \
-"\n" \
-"Sample /etc/modules.conf file:\n" \
-"\n" \
-"  options tulip irq=3\n" \
-"  alias tulip tulip2\n" \
-"  options tulip2 irq=4 io=0x308\n" \
-"\n" \
-"Other functionality offered by 'classic' modprobe is not available in\n" \
-"this implementation.\n" \
-"\n" \
-"If module options are present both in the config file, and on the command line,\n" \
-"then the options from the command line will be passed to the module _after_\n" \
-"the options from the config file. That way, you can have defaults in the config\n" \
-"file, and override them for a specific usage from the command line.\n"
+       "\t-v\tVerbose output"
 #define modprobe_example_usage \
-       "(with the above /etc/modules.conf):\n\n" \
-       "$ modprobe tulip\n" \
-       "   will load the module 'tulip' with default option 'irq=3'\n\n" \
-       "$ modprobe tulip irq=5\n" \
-       "   will load the module 'tulip' with option 'irq=5', thus overriding the default\n\n" \
-       "$ modprobe tulip2\n" \
-       "   will load the module 'tulip' with default options 'irq=4 io=0x308',\n" \
-       "   which are the default for alias 'tulip2'\n\n" \
-       "$ modprobe tulip2 irq=8\n" \
-       "   will load the module 'tulip' with default options 'irq=4 io=0x308 irq=8',\n" \
-       "   which are the default for alias 'tulip2' overriden by the option 'irq=8'\n\n" \
-       "   from the command line\n\n" \
-       "$ modprobe tulip2 irq=2 io=0x210\n" \
-       "   will load the module 'tulip' with default options 'irq=4 io=0x308 irq=4 io=0x210',\n" \
-       "   which are the default for alias 'tulip2' overriden by the options 'irq=2 io=0x210'\n\n" \
-       "   from the command line\n"
+       "$ modprobe cdrom\n"
 
 #define more_trivial_usage \
        "[FILE ...]"
        "\tdev/nodev:\tAllow use of special device files / disallow them\n" \
        "\texec/noexec:\tAllow use of executable files / disallow them\n" \
        USAGE_MOUNT_LOOP( \
-       "\tloop:\t\tMounts a file via loop device\n" \
+       "\tloop:\t\t Ignored (loop devices are autodetected)\n" \
        ) \
        "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them\n" \
        "\tremount:\tRe-mount a mounted filesystem, changing its flags\n" \
        "\tro/rw:\t\tMount for read-only / read-write\n" \
-       "\tbind:\t\tUse the linux 2.4.x \"bind\" feature\n" \
+       "\tbind:\t\tBind a directory to an additional location\n" \
+       "\tmove:\t\tRelocate an existing mount point.\n" \
        "\nThere are EVEN MORE flags that are specific to each filesystem\n" \
        "You'll have to see the written documentation for those filesystems"
 #define mount_example_usage \
        "proc on /proc type proc (rw)\n" \
        "devpts on /dev/pts type devpts (rw)\n" \
        "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \
-       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
+       "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" \
+       "$ mount cd_image.iso mydir\n"
 
 #define mountpoint_trivial_usage \
        "[-q] <[-d] DIR | -x DEVICE>"
        "Telnetd listens for incoming TELNET connections on PORT.\n" \
        "Options:\n" \
        "\t-p PORT\tlisten for connections on PORT (default 23)\n" \
-       "\t-b ADDR\tlisten for connections on ADDR (default 0.0.0.0)\n"\
        "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \
        "\t-f issue_file\tDisplay issue_file instead of /etc/issue"
 #endif
index 10217931b7090d5c768b55b50a53cfe52d93fc92..00e3d6236a84801c2f536bc1e358028a88d76259 100644 (file)
@@ -51,15 +51,30 @@ typedef struct {
 } bb_loop_info;
 #endif
 
-extern int del_loop(const char *device)
+char *query_loop(const char *device)
 {
-       int fd,rc=0;
+       int fd;
+       bb_loop_info loopinfo;
+       char *dev=0;
+       
+       if ((fd = open(device, O_RDONLY)) < 0) return 0;
+       if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
+               dev=bb_xasprintf("%ld %s", (long) loopinfo.lo_offset,
+                               loopinfo.lo_file_name);
+       close(fd);
 
-       if ((fd = open(device, O_RDONLY)) < 0) rc=1;
-       else {
-               if (ioctl(fd, LOOP_CLR_FD, 0) < 0) rc=1;
-               close(fd);
-       }
+       return dev;
+}      
+
+
+int del_loop(const char *device)
+{
+       int fd, rc;
+
+       if ((fd = open(device, O_RDONLY)) < 0) return 1;
+       rc=ioctl(fd, LOOP_CLR_FD, 0);
+       close(fd);
+       
        return rc;
 }
 
@@ -69,9 +84,9 @@ extern int del_loop(const char *device)
    search will re-use an existing loop device already bound to that
    file/offset if it finds one.
  */
-extern int set_loop(char **device, const char *file, int offset)
+int set_loop(char **device, const char *file, int offset)
 {
-       char dev[20];
+       char dev[20], *try;
        bb_loop_info loopinfo;
        struct stat statbuf;
        int i, dfd, ffd, mode, rc=1;
@@ -81,20 +96,21 @@ extern int set_loop(char **device, const char *file, int offset)
                return errno;
 
        /* Find a loop device.  */
+       try=*device ? : dev;
        for(i=0;rc;i++) {
                sprintf(dev, LOOP_FORMAT, i++);
                /* Ran out of block devices, return failure.  */
-               if(stat(*device ? *device : dev, &statbuf) ||
-                               !S_ISBLK(statbuf.st_mode)) {
+               if(stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
                        rc=ENOENT;
                        break;
                }
                /* Open the sucker and check its loopiness.  */
-               if((dfd=open(dev, mode))<0 && errno==EROFS)
-                       dfd=open(dev,mode=O_RDONLY);
+               if((dfd=open(try, mode))<0 && errno==EROFS)
+                       dfd=open(try,mode=O_RDONLY);
                if(dfd<0) continue;
 
                rc=ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
+
                /* If device free, claim it.  */
                if(rc && errno==ENXIO) {
                        memset(&loopinfo, 0, sizeof(loopinfo));
@@ -110,7 +126,7 @@ extern int set_loop(char **device, const char *file, int offset)
                   without using losetup manually is problematic.)
                 */
                } else if(strcmp(file,loopinfo.lo_file_name)
-                                       || offset!=loopinfo.lo_offset) rc=1;
+                                       || offset!=loopinfo.lo_offset) rc=-1;
                close(dfd);
                if(*device) break;
        }
index 11bd66ebf31ac8dc34f5817dd24164376e3dd47d..b2af63dc0ea1c96a2960c4fbb8648b6aecfd4042 100644 (file)
@@ -24,8 +24,7 @@
 
 #include "busybox.h"
 
-int
-losetup_main (int argc, char **argv)
+int losetup_main (int argc, char **argv)
 {
   int offset = 0;
 
@@ -34,18 +33,27 @@ losetup_main (int argc, char **argv)
   switch(getopt(argc,argv, "do:")) {
     case 'd':
       /* detach takes exactly one argument */
-      if(optind+1==argc)
-        return del_loop(argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE;
-      break;
+      if(optind+1==argc && !del_loop(argv[optind])) return EXIT_SUCCESS;
+die_failed:
+      bb_perror_msg_and_die("%s",argv[optind]);
 
     case 'o':
       offset = bb_xparse_number (optarg, NULL);
       /* Fall through to do the losetup */
     case -1:
       /* losetup takes two argument:, loop_device and file */
-      if(optind+2==argc)
-        return set_loop(&argv[optind], argv[optind + 1], offset)<0
-           ? EXIT_FAILURE : EXIT_SUCCESS;
+      if(optind+2==argc) {
+        if(set_loop(&argv[optind], argv[optind + 1], offset)>=0)
+          return EXIT_SUCCESS;
+        else goto die_failed;
+      }
+      if(optind+1==argc) {
+        char *s=query_loop(argv[optind]);
+        if (!s) goto die_failed;
+        printf("%s: %s\n",argv[optind],s);
+        if(ENABLE_FEATURE_CLEAN_UP) free(s);
+        return EXIT_SUCCESS;
+      }
       break;
   }
   bb_show_usage();