Fix losetup so that it A) actually works again, B) has much better error

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...
This commit is contained in:
Rob Landley 2005-11-29 23:47:10 +00:00
parent 70678bc5b6
commit 1d589b2e2d
4 changed files with 65 additions and 90 deletions

View File

@ -232,6 +232,7 @@ extern char *bb_askpass(int timeout, const char * prompt);
extern int device_open(const char *device, int mode); 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 del_loop(const char *device);
extern int set_loop(char **device, const char *file, int offset); extern int set_loop(char **device, const char *file, int offset);
@ -466,7 +467,7 @@ typedef struct {
} procps_status_t; } procps_status_t;
extern procps_status_t * procps_scan(int save_user_arg0); 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); extern int my_query_module(const char *name, int which, void **buf, size_t *bufsize, size_t *ret);

View File

@ -1657,13 +1657,18 @@
"\t-f\t\toutput data as the log grows" "\t-f\t\toutput data as the log grows"
#define losetup_trivial_usage \ #define losetup_trivial_usage \
"[OPTION]... LOOPDEVICE FILE\n" \ "[-od] LOOPDEVICE [FILE]\n"
"or: losetup [OPTION]... -d LOOPDEVICE"
#define losetup_full_usage \ #define losetup_full_usage \
"Associate LOOPDEVICE with FILE.\n\n" \ "Associate LOOPDEVICE with FILE, or display current association.\n\n" \
"Options:\n" \ "Options:\n" \
"\t-d\t\tDisassociate LOOPDEVICE\n" \ "\t-d\t\tDisassociate LOOPDEVICE\n" \
"\t-o OFFSET\tStart OFFSET bytes into FILE" "\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 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
# define USAGE_LS_TIMESTAMPS(a) a # define USAGE_LS_TIMESTAMPS(a) a
@ -1946,74 +1951,18 @@
"-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n"
#define modprobe_trivial_usage \ #define modprobe_trivial_usage \
"[-knqrsv] MODULE [symbol=value ...]" "[-knqrsv] [MODULE ...]"
#define modprobe_full_usage \ #define modprobe_full_usage \
"Used for high level module loading and unloading.\n\n" \
"Options:\n" \ "Options:\n" \
"\t-k\tMake module autoclean-able\n" \ "\t-k\tMake module autoclean-able\n" \
"\t-n\tJust show what would be done\n" \ "\t-n\tJust show what would be done\n" \
"\t-q\tQuiet output\n" \ "\t-q\tQuiet output\n" \
"\t-r\tRemove module (stacks) or do autoclean\n" \ "\t-r\tRemove module (stacks) or do autoclean\n" \
"\t-s\tReport via syslog instead of stderr\n" \ "\t-s\tReport via syslog instead of stderr\n" \
"\t-v\tVerbose output\n\n" "\t-v\tVerbose output"
#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"
#define modprobe_example_usage \ #define modprobe_example_usage \
"(with the above /etc/modules.conf):\n\n" \ "$ modprobe cdrom\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"
#define more_trivial_usage \ #define more_trivial_usage \
"[FILE ...]" "[FILE ...]"
@ -2054,12 +2003,13 @@
"\tdev/nodev:\tAllow use of special device files / disallow them\n" \ "\tdev/nodev:\tAllow use of special device files / disallow them\n" \
"\texec/noexec:\tAllow use of executable files / disallow them\n" \ "\texec/noexec:\tAllow use of executable files / disallow them\n" \
USAGE_MOUNT_LOOP( \ 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" \ "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them\n" \
"\tremount:\tRe-mount a mounted filesystem, changing its flags\n" \ "\tremount:\tRe-mount a mounted filesystem, changing its flags\n" \
"\tro/rw:\t\tMount for read-only / read-write\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" \ "\nThere are EVEN MORE flags that are specific to each filesystem\n" \
"You'll have to see the written documentation for those filesystems" "You'll have to see the written documentation for those filesystems"
#define mount_example_usage \ #define mount_example_usage \
@ -2068,7 +2018,8 @@
"proc on /proc type proc (rw)\n" \ "proc on /proc type proc (rw)\n" \
"devpts on /dev/pts type devpts (rw)\n" \ "devpts on /dev/pts type devpts (rw)\n" \
"$ mount /dev/fd0 /mnt -t msdos -o ro\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 \ #define mountpoint_trivial_usage \
"[-q] <[-d] DIR | -x DEVICE>" "[-q] <[-d] DIR | -x DEVICE>"
@ -3008,7 +2959,6 @@
"Telnetd listens for incoming TELNET connections on PORT.\n" \ "Telnetd listens for incoming TELNET connections on PORT.\n" \
"Options:\n" \ "Options:\n" \
"\t-p PORT\tlisten for connections on PORT (default 23)\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-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \
"\t-f issue_file\tDisplay issue_file instead of /etc/issue" "\t-f issue_file\tDisplay issue_file instead of /etc/issue"
#endif #endif

View File

@ -51,15 +51,30 @@ typedef struct {
} bb_loop_info; } bb_loop_info;
#endif #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);
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);
if ((fd = open(device, O_RDONLY)) < 0) rc=1;
else {
if (ioctl(fd, LOOP_CLR_FD, 0) < 0) rc=1;
close(fd);
}
return rc; 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 search will re-use an existing loop device already bound to that
file/offset if it finds one. 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; bb_loop_info loopinfo;
struct stat statbuf; struct stat statbuf;
int i, dfd, ffd, mode, rc=1; int i, dfd, ffd, mode, rc=1;
@ -81,20 +96,21 @@ extern int set_loop(char **device, const char *file, int offset)
return errno; return errno;
/* Find a loop device. */ /* Find a loop device. */
try=*device ? : dev;
for(i=0;rc;i++) { for(i=0;rc;i++) {
sprintf(dev, LOOP_FORMAT, i++); sprintf(dev, LOOP_FORMAT, i++);
/* Ran out of block devices, return failure. */ /* Ran out of block devices, return failure. */
if(stat(*device ? *device : dev, &statbuf) || if(stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
!S_ISBLK(statbuf.st_mode)) {
rc=ENOENT; rc=ENOENT;
break; break;
} }
/* Open the sucker and check its loopiness. */ /* Open the sucker and check its loopiness. */
if((dfd=open(dev, mode))<0 && errno==EROFS) if((dfd=open(try, mode))<0 && errno==EROFS)
dfd=open(dev,mode=O_RDONLY); dfd=open(try,mode=O_RDONLY);
if(dfd<0) continue; if(dfd<0) continue;
rc=ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo); rc=ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
/* If device free, claim it. */ /* If device free, claim it. */
if(rc && errno==ENXIO) { if(rc && errno==ENXIO) {
memset(&loopinfo, 0, sizeof(loopinfo)); 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.) without using losetup manually is problematic.)
*/ */
} else if(strcmp(file,loopinfo.lo_file_name) } else if(strcmp(file,loopinfo.lo_file_name)
|| offset!=loopinfo.lo_offset) rc=1; || offset!=loopinfo.lo_offset) rc=-1;
close(dfd); close(dfd);
if(*device) break; if(*device) break;
} }

View File

@ -24,8 +24,7 @@
#include "busybox.h" #include "busybox.h"
int int losetup_main (int argc, char **argv)
losetup_main (int argc, char **argv)
{ {
int offset = 0; int offset = 0;
@ -34,18 +33,27 @@ losetup_main (int argc, char **argv)
switch(getopt(argc,argv, "do:")) { switch(getopt(argc,argv, "do:")) {
case 'd': case 'd':
/* detach takes exactly one argument */ /* detach takes exactly one argument */
if(optind+1==argc) if(optind+1==argc && !del_loop(argv[optind])) return EXIT_SUCCESS;
return del_loop(argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE; die_failed:
break; bb_perror_msg_and_die("%s",argv[optind]);
case 'o': case 'o':
offset = bb_xparse_number (optarg, NULL); offset = bb_xparse_number (optarg, NULL);
/* Fall through to do the losetup */ /* Fall through to do the losetup */
case -1: case -1:
/* losetup takes two argument:, loop_device and file */ /* losetup takes two argument:, loop_device and file */
if(optind+2==argc) if(optind+2==argc) {
return set_loop(&argv[optind], argv[optind + 1], offset)<0 if(set_loop(&argv[optind], argv[optind + 1], offset)>=0)
? EXIT_FAILURE : EXIT_SUCCESS; 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; break;
} }
bb_show_usage(); bb_show_usage();