From 5cbdd712f5320ffc109053a94b7cf36c82292cf6 Mon Sep 17 00:00:00 2001 From: Erik Andersen Date: Wed, 26 Jan 2000 20:06:48 +0000 Subject: mount and umount could leak loop device allocations causing the system to quickly run out. Also disable init's SIGHUP handler during shutdown. -Erik --- Changelog | 5 ++ init.c | 4 ++ init/init.c | 4 ++ internal.h | 4 ++ mount.c | 165 ++++++++++++++++++++++++++++------------------------ networking/ping.c | 9 +-- ping.c | 9 +-- umount.c | 70 ++++++---------------- util-linux/mount.c | 165 ++++++++++++++++++++++++++++------------------------ util-linux/umount.c | 70 ++++++---------------- utility.c | 25 ++++++++ 11 files changed, 266 insertions(+), 264 deletions(-) diff --git a/Changelog b/Changelog index 4dbb46e..46b2a1f 100644 --- a/Changelog +++ b/Changelog @@ -32,6 +32,11 @@ tail -f work only with a single file. This reduced tail from 6k to 2.4k. The bigger/more featured tail can still be had by disabling BB_FEATURE_SIMPLE_TAIL in dusybox.defs.h + * Ping now falls back to doing the right thing if /etc/protocols + turns up missing. + * Fixed mount and umount. Previously they could leak loop device + allocations, causing the system to quickly run out. Fix for umount + by Ben Collins , and mount was fixed by me. -Erik Andersen diff --git a/init.c b/init.c index 5b80cc5..09540ff 100644 --- a/init.c +++ b/init.c @@ -359,6 +359,7 @@ static pid_t run(char* command, signal(SIGUSR2, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); if ((fd = device_open(terminal, O_RDWR)) < 0) { message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal); @@ -458,6 +459,9 @@ goodnight: #ifndef DEBUG_INIT static void shutdown_system(void) { + /* first disable our SIGHUP signal */ + signal(SIGHUP, SIG_DFL); + /* Allow Ctrl-Alt-Del to reboot system. */ reboot(RB_ENABLE_CAD); message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); diff --git a/init/init.c b/init/init.c index 5b80cc5..09540ff 100644 --- a/init/init.c +++ b/init/init.c @@ -359,6 +359,7 @@ static pid_t run(char* command, signal(SIGUSR2, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); if ((fd = device_open(terminal, O_RDWR)) < 0) { message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal); @@ -458,6 +459,9 @@ goodnight: #ifndef DEBUG_INIT static void shutdown_system(void) { + /* first disable our SIGHUP signal */ + signal(SIGHUP, SIG_DFL); + /* Allow Ctrl-Alt-Del to reboot system. */ reboot(RB_ENABLE_CAD); message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); diff --git a/internal.h b/internal.h index 500a63e..9611c19 100644 --- a/internal.h +++ b/internal.h @@ -175,6 +175,10 @@ extern int check_wildcard_match(const char* text, const char* pattern); extern long getNum (const char *cp); extern pid_t findInitPid(); +#if defined BB_FEATURE_MOUNT_LOOP +extern int del_loop(const char *device); +#endif + #if defined BB_GUNZIP || defined BB_GZIP || defined BB_PRINTF || defined BB_TAIL extern void *xmalloc (size_t size); extern void error(char *msg); diff --git a/mount.c b/mount.c index 709c7fc..3c1568a 100644 --- a/mount.c +++ b/mount.c @@ -127,11 +127,11 @@ do_mount(char* specialfile, char* dir, char* filesystemtype, specialfile = find_unused_loop_device(); if (specialfile == NULL) { fprintf(stderr, "Could not find a spare loop device\n"); - exit(1); + return( FALSE); } if (set_loop (specialfile, lofile, 0, &loro)) { fprintf(stderr, "Could not setup loop device\n"); - exit(1); + return( FALSE); } if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ fprintf(stderr, "WARNING: loop device is read-only\n"); @@ -141,15 +141,26 @@ do_mount(char* specialfile, char* dir, char* filesystemtype, #endif status=mount(specialfile, dir, filesystemtype, flags, string_flags); } -#if defined BB_MTAB + + + /* If the mount was sucessful, do anything needed, then return TRUE */ if (status == 0) { - if (useMtab==TRUE) + +#if defined BB_MTAB + if (useMtab==TRUE) { write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); - return 0; + } +#endif + return( TRUE); + } + + /* Bummer. mount failed. Clean up */ +#if defined BB_FEATURE_MOUNT_LOOP + if (specialfile != NULL) { + del_loop(specialfile); } - else #endif - return(status); + return( FALSE); } @@ -166,6 +177,75 @@ extern void whine_if_fstab_is_missing() #endif +#if defined BB_FEATURE_MOUNT_LOOP +static int set_loop(const char *device, const char *file, int offset, int *loopro) +{ + struct loop_info loopinfo; + int fd, ffd, mode; + + mode = *loopro ? O_RDONLY : O_RDWR; + if ((ffd = open (file, mode)) < 0 && !*loopro + && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { + perror (file); + return 1; + } + if ((fd = open (device, mode)) < 0) { + close(ffd); + perror (device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE-1] = 0; + + loopinfo.lo_offset = offset; + + loopinfo.lo_encrypt_key_size = 0; + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + close(fd); + close(ffd); + return 1; + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror("ioctl: LOOP_SET_STATUS"); + close(fd); + close(ffd); + return 1; + } + close(fd); + close(ffd); + return 0; +} + +char *find_unused_loop_device (void) +{ + char dev[20]; + int i, fd; + struct stat statbuf; + struct loop_info loopinfo; + + for(i = 0; i <= 7; i++) { + sprintf(dev, "/dev/loop%d", i); + if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { + if ((fd = open (dev, O_RDONLY)) >= 0) { + if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1) { + if (errno == ENXIO) { /* probably free */ + close (fd); + return strdup(dev); + } + } + close (fd); + } + } + } + return NULL; +} +#endif /* BB_FEATURE_MOUNT_LOOP */ + /* Seperate standard mount options from the nonstandard string options */ static void parse_mount_options ( char *options, unsigned long *flags, char *strflags) @@ -240,7 +320,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, status = do_mount (blockDevice, directory, filesystemType, flags | MS_MGC_VAL, string_flags, useMtab, fakeIt, mtab_opts); - if (status == 0) + if (status == TRUE) break; } } @@ -253,7 +333,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, fakeIt, mtab_opts); } - if (status) { + if (status==FALSE) { fprintf (stderr, "Mounting %s on %s failed: %s\n", blockDevice, directory, strerror(errno)); return (FALSE); @@ -400,70 +480,3 @@ goodbye: usage( mount_usage); } -#if defined BB_FEATURE_MOUNT_LOOP -static int set_loop(const char *device, const char *file, int offset, int *loopro) -{ - struct loop_info loopinfo; - int fd, ffd, mode; - - mode = *loopro ? O_RDONLY : O_RDWR; - if ((ffd = open (file, mode)) < 0 && !*loopro - && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { - perror (file); - return 1; - } - if ((fd = open (device, mode)) < 0) { - close(ffd); - perror (device); - return 1; - } - *loopro = (mode == O_RDONLY); - - memset(&loopinfo, 0, sizeof(loopinfo)); - strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); - loopinfo.lo_name[LO_NAME_SIZE-1] = 0; - - loopinfo.lo_offset = offset; - - loopinfo.lo_encrypt_key_size = 0; - if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { - perror("ioctl: LOOP_SET_FD"); - close(fd); - close(ffd); - return 1; - } - if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { - (void) ioctl(fd, LOOP_CLR_FD, 0); - perror("ioctl: LOOP_SET_STATUS"); - close(fd); - close(ffd); - return 1; - } - close(fd); - close(ffd); - return 0; -} - -char *find_unused_loop_device (void) -{ - char dev[20]; - int i, fd; - struct stat statbuf; - struct loop_info loopinfo; - - for(i = 0; i <= 7; i++) { - sprintf(dev, "/dev/loop%d", i); - if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { - if ((fd = open (dev, O_RDONLY)) >= 0) { - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1 && - errno == ENXIO) { /* probably free */ - close (fd); - return strdup(dev); - } - close (fd); - } - } - } - return NULL; -} -#endif /* BB_FEATURE_MOUNT_LOOP */ diff --git a/networking/ping.c b/networking/ping.c index 92b62de..2b6e7f5 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -1,5 +1,5 @@ /* - * $Id: ping.c,v 1.6 1999/12/11 08:41:28 andersen Exp $ + * $Id: ping.c,v 1.7 2000/01/26 20:06:48 erik Exp $ * Mini ping implementation for busybox * * Copyright (C) 1999 by Randolph Chung @@ -319,10 +319,11 @@ static void ping(char *host) int sockopt; if (!(proto = getprotobyname("icmp"))) { - fprintf(stderr, "ping: unknown protocol icmp\n"); - exit(1); + /* getprotobyname failed, so just silently force + * proto->p_proto to have the correct value for "icmp" */ + proto->p_proto = 1; } - if ((pingsock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { + if ((pingsock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { /* 1 == ICMP */ if (errno == EPERM) { fprintf(stderr, "ping: permission denied. (are you root?)\n"); } else { diff --git a/ping.c b/ping.c index 92b62de..2b6e7f5 100644 --- a/ping.c +++ b/ping.c @@ -1,5 +1,5 @@ /* - * $Id: ping.c,v 1.6 1999/12/11 08:41:28 andersen Exp $ + * $Id: ping.c,v 1.7 2000/01/26 20:06:48 erik Exp $ * Mini ping implementation for busybox * * Copyright (C) 1999 by Randolph Chung @@ -319,10 +319,11 @@ static void ping(char *host) int sockopt; if (!(proto = getprotobyname("icmp"))) { - fprintf(stderr, "ping: unknown protocol icmp\n"); - exit(1); + /* getprotobyname failed, so just silently force + * proto->p_proto to have the correct value for "icmp" */ + proto->p_proto = 1; } - if ((pingsock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { + if ((pingsock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { /* 1 == ICMP */ if (errno == EPERM) { fprintf(stderr, "ping: permission denied. (are you root?)\n"); } else { diff --git a/umount.c b/umount.c index 9ad6f26..68b27e3 100644 --- a/umount.c +++ b/umount.c @@ -28,14 +28,6 @@ #include #include -#if defined BB_FEATURE_MOUNT_LOOP -#include -#include -#include - -static int del_loop(const char *device); -#endif - static const char umount_usage[] = "umount [flags] filesystem|directory\n\n" "Flags:\n" @@ -52,43 +44,34 @@ static int useMtab = TRUE; static int umountAll = FALSE; extern const char mtab_file[]; /* Defined in utility.c */ +#define MIN(x,y) (x > y ? x : y) + static int do_umount(const char* name, int useMtab) { int status; - -#if defined BB_FEATURE_MOUNT_LOOP - /* check to see if this is a loop device */ - struct stat fst; - char dev[20]; - const char *oldname = NULL; - int i; - - if (stat(name, &fst)) { - fprintf(stderr, "umount: %s: %s\n", name, strerror(errno)); - exit(1); - } - for (i = 0 ; i <= 7 ; i++) { - struct stat lst; - sprintf(dev, "/dev/loop%d", i); - if (stat(dev, &lst)) - continue; - if (lst.st_dev == fst.st_dev) { - oldname = name; - name = dev; - break; + struct mntent *m; + FILE *mountTable; + const char *blockDevice = NULL; + + if ((mountTable = setmntent (mtab_file, "r"))) { + while ((m = getmntent (mountTable)) != 0) { + if (strncmp(m->mnt_dir, name, + MIN(strlen(m->mnt_dir),strlen(name))) == 0) + blockDevice = m->mnt_fsname; + else if (strcmp(m->mnt_fsname, name) == 0) { + blockDevice = name; + name = m->mnt_dir; + } } } -#endif status = umount(name); #if defined BB_FEATURE_MOUNT_LOOP - if (!strncmp("/dev/loop", name, 9)) { /* this was a loop device, delete it */ - del_loop(name); - if (oldname != NULL) - name = oldname; - } + if (blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) + /* this was a loop device, delete it */ + del_loop(blockDevice); #endif #if defined BB_MTAB if ( status == 0 ) { @@ -178,20 +161,3 @@ umount_main(int argc, char** argv) } } -#if defined BB_FEATURE_MOUNT_LOOP -static int del_loop(const char *device) -{ - int fd; - - if ((fd = open(device, O_RDONLY)) < 0) { - perror(device); - exit(1); - } - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - perror("ioctl: LOOP_CLR_FD"); - exit(1); - } - close(fd); - return(0); -} -#endif diff --git a/util-linux/mount.c b/util-linux/mount.c index 709c7fc..3c1568a 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -127,11 +127,11 @@ do_mount(char* specialfile, char* dir, char* filesystemtype, specialfile = find_unused_loop_device(); if (specialfile == NULL) { fprintf(stderr, "Could not find a spare loop device\n"); - exit(1); + return( FALSE); } if (set_loop (specialfile, lofile, 0, &loro)) { fprintf(stderr, "Could not setup loop device\n"); - exit(1); + return( FALSE); } if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ fprintf(stderr, "WARNING: loop device is read-only\n"); @@ -141,15 +141,26 @@ do_mount(char* specialfile, char* dir, char* filesystemtype, #endif status=mount(specialfile, dir, filesystemtype, flags, string_flags); } -#if defined BB_MTAB + + + /* If the mount was sucessful, do anything needed, then return TRUE */ if (status == 0) { - if (useMtab==TRUE) + +#if defined BB_MTAB + if (useMtab==TRUE) { write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); - return 0; + } +#endif + return( TRUE); + } + + /* Bummer. mount failed. Clean up */ +#if defined BB_FEATURE_MOUNT_LOOP + if (specialfile != NULL) { + del_loop(specialfile); } - else #endif - return(status); + return( FALSE); } @@ -166,6 +177,75 @@ extern void whine_if_fstab_is_missing() #endif +#if defined BB_FEATURE_MOUNT_LOOP +static int set_loop(const char *device, const char *file, int offset, int *loopro) +{ + struct loop_info loopinfo; + int fd, ffd, mode; + + mode = *loopro ? O_RDONLY : O_RDWR; + if ((ffd = open (file, mode)) < 0 && !*loopro + && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { + perror (file); + return 1; + } + if ((fd = open (device, mode)) < 0) { + close(ffd); + perror (device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE-1] = 0; + + loopinfo.lo_offset = offset; + + loopinfo.lo_encrypt_key_size = 0; + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + close(fd); + close(ffd); + return 1; + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror("ioctl: LOOP_SET_STATUS"); + close(fd); + close(ffd); + return 1; + } + close(fd); + close(ffd); + return 0; +} + +char *find_unused_loop_device (void) +{ + char dev[20]; + int i, fd; + struct stat statbuf; + struct loop_info loopinfo; + + for(i = 0; i <= 7; i++) { + sprintf(dev, "/dev/loop%d", i); + if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { + if ((fd = open (dev, O_RDONLY)) >= 0) { + if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1) { + if (errno == ENXIO) { /* probably free */ + close (fd); + return strdup(dev); + } + } + close (fd); + } + } + } + return NULL; +} +#endif /* BB_FEATURE_MOUNT_LOOP */ + /* Seperate standard mount options from the nonstandard string options */ static void parse_mount_options ( char *options, unsigned long *flags, char *strflags) @@ -240,7 +320,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, status = do_mount (blockDevice, directory, filesystemType, flags | MS_MGC_VAL, string_flags, useMtab, fakeIt, mtab_opts); - if (status == 0) + if (status == TRUE) break; } } @@ -253,7 +333,7 @@ mount_one(char *blockDevice, char *directory, char *filesystemType, fakeIt, mtab_opts); } - if (status) { + if (status==FALSE) { fprintf (stderr, "Mounting %s on %s failed: %s\n", blockDevice, directory, strerror(errno)); return (FALSE); @@ -400,70 +480,3 @@ goodbye: usage( mount_usage); } -#if defined BB_FEATURE_MOUNT_LOOP -static int set_loop(const char *device, const char *file, int offset, int *loopro) -{ - struct loop_info loopinfo; - int fd, ffd, mode; - - mode = *loopro ? O_RDONLY : O_RDWR; - if ((ffd = open (file, mode)) < 0 && !*loopro - && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { - perror (file); - return 1; - } - if ((fd = open (device, mode)) < 0) { - close(ffd); - perror (device); - return 1; - } - *loopro = (mode == O_RDONLY); - - memset(&loopinfo, 0, sizeof(loopinfo)); - strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); - loopinfo.lo_name[LO_NAME_SIZE-1] = 0; - - loopinfo.lo_offset = offset; - - loopinfo.lo_encrypt_key_size = 0; - if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { - perror("ioctl: LOOP_SET_FD"); - close(fd); - close(ffd); - return 1; - } - if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { - (void) ioctl(fd, LOOP_CLR_FD, 0); - perror("ioctl: LOOP_SET_STATUS"); - close(fd); - close(ffd); - return 1; - } - close(fd); - close(ffd); - return 0; -} - -char *find_unused_loop_device (void) -{ - char dev[20]; - int i, fd; - struct stat statbuf; - struct loop_info loopinfo; - - for(i = 0; i <= 7; i++) { - sprintf(dev, "/dev/loop%d", i); - if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { - if ((fd = open (dev, O_RDONLY)) >= 0) { - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1 && - errno == ENXIO) { /* probably free */ - close (fd); - return strdup(dev); - } - close (fd); - } - } - } - return NULL; -} -#endif /* BB_FEATURE_MOUNT_LOOP */ diff --git a/util-linux/umount.c b/util-linux/umount.c index 9ad6f26..68b27e3 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -28,14 +28,6 @@ #include #include -#if defined BB_FEATURE_MOUNT_LOOP -#include -#include -#include - -static int del_loop(const char *device); -#endif - static const char umount_usage[] = "umount [flags] filesystem|directory\n\n" "Flags:\n" @@ -52,43 +44,34 @@ static int useMtab = TRUE; static int umountAll = FALSE; extern const char mtab_file[]; /* Defined in utility.c */ +#define MIN(x,y) (x > y ? x : y) + static int do_umount(const char* name, int useMtab) { int status; - -#if defined BB_FEATURE_MOUNT_LOOP - /* check to see if this is a loop device */ - struct stat fst; - char dev[20]; - const char *oldname = NULL; - int i; - - if (stat(name, &fst)) { - fprintf(stderr, "umount: %s: %s\n", name, strerror(errno)); - exit(1); - } - for (i = 0 ; i <= 7 ; i++) { - struct stat lst; - sprintf(dev, "/dev/loop%d", i); - if (stat(dev, &lst)) - continue; - if (lst.st_dev == fst.st_dev) { - oldname = name; - name = dev; - break; + struct mntent *m; + FILE *mountTable; + const char *blockDevice = NULL; + + if ((mountTable = setmntent (mtab_file, "r"))) { + while ((m = getmntent (mountTable)) != 0) { + if (strncmp(m->mnt_dir, name, + MIN(strlen(m->mnt_dir),strlen(name))) == 0) + blockDevice = m->mnt_fsname; + else if (strcmp(m->mnt_fsname, name) == 0) { + blockDevice = name; + name = m->mnt_dir; + } } } -#endif status = umount(name); #if defined BB_FEATURE_MOUNT_LOOP - if (!strncmp("/dev/loop", name, 9)) { /* this was a loop device, delete it */ - del_loop(name); - if (oldname != NULL) - name = oldname; - } + if (blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) + /* this was a loop device, delete it */ + del_loop(blockDevice); #endif #if defined BB_MTAB if ( status == 0 ) { @@ -178,20 +161,3 @@ umount_main(int argc, char** argv) } } -#if defined BB_FEATURE_MOUNT_LOOP -static int del_loop(const char *device) -{ - int fd; - - if ((fd = open(device, O_RDONLY)) < 0) { - perror(device); - exit(1); - } - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - perror("ioctl: LOOP_CLR_FD"); - exit(1); - } - close(fd); - return(0); -} -#endif diff --git a/utility.c b/utility.c index 8139f38..643c3b5 100644 --- a/utility.c +++ b/utility.c @@ -36,6 +36,13 @@ #include #include +#if defined BB_FEATURE_MOUNT_LOOP +#include +#include +#include +#endif + + #if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF # if defined BB_FEATURE_USE_PROCFS const char mtab_file[] = "/proc/mounts"; @@ -1146,4 +1153,22 @@ extern int vdprintf(int d, const char *format, va_list ap) } #endif +#if defined BB_FEATURE_MOUNT_LOOP +extern int del_loop(const char *device) +{ + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) { + perror(device); + return( FALSE); + } + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + perror("ioctl: LOOP_CLR_FD"); + return( FALSE); + } + close(fd); + return( TRUE); +} +#endif + /* END CODE */ -- cgit v1.1