diff options
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/dmesg.c | 95 | ||||
-rw-r--r-- | util-linux/fdflush.c | 36 | ||||
-rw-r--r-- | util-linux/mkswap.c | 253 | ||||
-rw-r--r-- | util-linux/more.c | 110 | ||||
-rw-r--r-- | util-linux/mount.c | 430 | ||||
-rw-r--r-- | util-linux/umount.c | 135 |
6 files changed, 1059 insertions, 0 deletions
diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c new file mode 100644 index 0000000..a63fa3d --- /dev/null +++ b/util-linux/dmesg.c @@ -0,0 +1,95 @@ +#include "internal.h" +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +/* dmesg.c -- Print out the contents of the kernel ring buffer + * Created: Sat Oct 9 16:19:47 1993 + * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu + * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu) + * This program comes with ABSOLUTELY NO WARRANTY. + * Modifications by Rick Sladkey (jrs@world.std.com) + * from util-linux; adapted for busybox + */ + +#include <linux/unistd.h> +#include <stdio.h> +#include <getopt.h> + +#define __NR_klog __NR_syslog + +#if defined(__GLIBC__) +#include <sys/klog.h> +#define klog klogctl +#else +static inline _syscall3(int,klog,int,type,char *,b,int,len) +#endif /* __GLIBC__ */ + +const char dmesg_usage[] = "dmesg"; + +int +dmesg_main(struct FileInfo * info, int argc, char * * argv) +{ + + char buf[4096]; + int i; + int n; + int c; + int level = 0; + int lastc; + int cmd = 3; + + while ((c = getopt( argc, argv, "cn:" )) != EOF) { + switch (c) { + case 'c': + cmd = 4; + break; + case 'n': + cmd = 8; + level = atoi(optarg); + break; + case '?': + default: + usage(dmesg_usage); + exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc > 1) { + usage(dmesg_usage); + exit(1); + } + + if (cmd == 8) { + n = klog( cmd, NULL, level ); + if (n < 0) { + perror( "klog" ); + exit( 1 ); + } + exit( 0 ); + } + + n = klog( cmd, buf, sizeof( buf ) ); + if (n < 0) { + perror( "klog" ); + exit( 1 ); + } + + lastc = '\n'; + for (i = 0; i < n; i++) { + if ((i == 0 || buf[i - 1] == '\n') && buf[i] == '<') { + i++; + while (buf[i] >= '0' && buf[i] <= '9') + i++; + if (buf[i] == '>') + i++; + } + lastc = buf[i]; + putchar( lastc ); + } + if (lastc != '\n') + putchar( '\n' ); + return 0; +} diff --git a/util-linux/fdflush.c b/util-linux/fdflush.c new file mode 100644 index 0000000..a15e9b3 --- /dev/null +++ b/util-linux/fdflush.c @@ -0,0 +1,36 @@ +#include "internal.h" +#include <sys/ioctl.h> +#include <linux/fd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +const char fdflush_usage[] = "fdflush device"; + +int +fdflush(const char *filename) +{ + int status; + int fd = open(filename, 0); + + if ( fd < 0 ) { + name_and_error(filename); + return 1; + } + + status = ioctl(fd, FDFLUSH, 0); + close(fd); + + if ( status != 0 ) { + name_and_error(filename); + return 1; + } + return 0; +} + + +int +fdflush_fn(const struct FileInfo * i) +{ + return fdflush(i->source); +} diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c new file mode 100644 index 0000000..f797d13 --- /dev/null +++ b/util-linux/mkswap.c @@ -0,0 +1,253 @@ +#include "internal.h" +/* + * mkswap.c - set up a linux swap device + * + * (C) 1991 Linus Torvalds. This file may be redistributed as per + * the Linux copyright. + */ + +/* + * 20.12.91 - time began. Got VM working yesterday by doing this by hand. + * + * Usage: mkswap [-c] device [size-in-blocks] + * + * -c for readablility checking (use it unless you are SURE!) + * + * The device may be a block device or a image of one, but this isn't + * enforced (but it's not much fun on a character device :-). + * + * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the + * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <asm/page.h> +#include <linux/fs.h> + +#ifndef __linux__ +# define volatile +#endif + +#define TEST_BUFFER_PAGES 8 + +const char mkswap_usage[] = "mkswap [-c] partition [block-count]\n" +"\n" +"\tPrepare a disk partition to be used as a swap partition.\n" +"\tThe default block count is the size of the entire partition.\n" +"\n" +"\t-c:\tCheck for read-ability.\n" +"\tblock-count\tUse only this many blocks.\n"; + +static const char * program_name = "mkswap"; +static const char * device_name = NULL; +static int DEV = -1; +static long PAGES = 0; +static int do_check = 0; +static int badpages = 0; + + +static long bit_test_and_set (unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + *addr = r | m; + return (r & m) != 0; +} + +static int bit_test_and_clear (unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + *addr = r & ~m; + return (r & m) != 0; +} + +/* + * Volatile to let gcc know that this doesn't return. When trying + * to compile this under minix, volatile gives a warning, as + * exit() isn't defined as volatile under minix. + */ +volatile void fatal_error(const char * fmt_string) +{ + fprintf(stderr,fmt_string,program_name,device_name); + exit(1); +} + +#define die(str) fatal_error("%s: " str "\n") + +static void check_blocks(int * signature_page) +{ + unsigned int current_page; + int do_seek = 1; + char buffer[PAGE_SIZE]; + + current_page = 0; + while (current_page < PAGES) { + if (!do_check) { + bit_test_and_set(signature_page,current_page++); + continue; + } else { + printf("\r%d", current_page); + } + if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != + current_page*PAGE_SIZE) + die("seek failed in check_blocks"); + if ( (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) ) { + bit_test_and_clear(signature_page,current_page++); + badpages++; + continue; + } + bit_test_and_set(signature_page,current_page++); + } + if (do_check) + printf("\n"); + if (badpages) + printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); +} + +static long valid_offset (int fd, int offset) +{ + char ch; + + if (lseek (fd, offset, 0) < 0) + return 0; + if (read (fd, &ch, 1) < 1) + return 0; + return 1; +} + +static int count_blocks (int fd) +{ + int high, low; + + low = 0; + for (high = 1; valid_offset (fd, high); high *= 2) + low = high; + while (low < high - 1) + { + const int mid = (low + high) / 2; + + if (valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + valid_offset (fd, 0); + return (low + 1); +} + +static int get_size(const char *file) +{ + int fd; + int size; + + fd = open(file, O_RDWR); + if (fd < 0) { + perror(file); + exit(1); + } + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + close(fd); + return (size * 512); + } + + size = count_blocks(fd); + close(fd); + return size; +} + +int +mkswap(char *device_name, int pages, int check) + { + struct stat statbuf; + int goodpages; + int signature_page[PAGE_SIZE/sizeof(int)]; + + PAGES = pages; + do_check = check; + + memset(signature_page,0,PAGE_SIZE); + + if (device_name && !PAGES) { + PAGES = get_size(device_name) / PAGE_SIZE; + } + if (!device_name || PAGES<10) { + fprintf(stderr, + "%s: error: swap area needs to be at least %ldkB\n", + program_name, 10 * PAGE_SIZE / 1024); + /* usage(mkswap_usage); */ + exit(1); + } + if (PAGES > 8 * (PAGE_SIZE - 10)) { + PAGES = 8 * (PAGE_SIZE - 10); + fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", + program_name, PAGES * PAGE_SIZE / 1024); + } + DEV = open(device_name,O_RDWR); + if (DEV < 0 || fstat(DEV, &statbuf) < 0) { + perror(device_name); + exit(1); + } + if (!S_ISBLK(statbuf.st_mode)) + do_check=0; + else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) + die("Will not try to make swapdevice on '%s'"); + check_blocks(signature_page); + if (!bit_test_and_clear(signature_page,0)) + die("fatal: first page unreadable"); + goodpages = PAGES - badpages - 1; + if (goodpages <= 0) + die("Unable to set up swap-space: unreadable"); + printf("Setting up swapspace, size = %ld bytes\n",goodpages*PAGE_SIZE); + strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); + if (lseek(DEV, 0, SEEK_SET)) + die("unable to rewind swap-device"); + if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) + die("unable to write signature page"); + + close(DEV); + return 0; +} + +int mkswap_main(struct FileInfo * unnecessary, int argc, char ** argv) +{ + char * tmp; + long int pages=0; + int check=0; + + if (argc && *argv) + program_name = *argv; + while (argc > 1) { + argv++; + argc--; + if (argv[0][0] != '-') + if (device_name) { + pages = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10); + if (*tmp) { + usage(mkswap_usage); + exit(1); + } + } else + device_name = argv[0]; + else while (*++argv[0]) + switch (argv[0][0]) { + case 'c': check=1; break; + default: usage(mkswap_usage); + exit(1); + } + } + return mkswap(device_name, pages, check); +} diff --git a/util-linux/more.c b/util-linux/more.c new file mode 100644 index 0000000..6540999 --- /dev/null +++ b/util-linux/more.c @@ -0,0 +1,110 @@ +#include "internal.h" +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#define BB_MORE_TERM + +#ifdef BB_MORE_TERM + #include <termios.h> + #include <signal.h> + + FILE *cin; + struct termios initial_settings, new_settings; + + void gotsig(int sig) { + tcsetattr(fileno(cin), TCSANOW, &initial_settings); + exit(0); + } +#endif + +const char more_usage[] = "more [file]\n" +"\n" +"\tDisplays a file, one page at a time.\n" +"\tIf there are no arguments, the standard input is displayed.\n"; + +extern int +more_fn(const struct FileInfo * i) +{ + FILE * f = stdin; + int c; + int lines = 0, tlines = 0; + int next_page = 0; + int rows = 24, cols = 79; +#ifdef BB_MORE_TERM + long sizeb = 0; + struct stat st; + struct winsize win; +#endif + + if ( i ) { + if (! (f = fopen(i->source, "r") )) { + name_and_error(i->source); + return 1; + } + fstat(fileno(f), &st); + sizeb = st.st_size / 100; + } + +#ifdef BB_MORE_TERM + cin = fopen("/dev/tty", "r"); + tcgetattr(fileno(cin),&initial_settings); + new_settings = initial_settings; + new_settings.c_lflag &= ~ICANON; + new_settings.c_lflag &= ~ECHO; + tcsetattr(fileno(cin), TCSANOW, &new_settings); + + (void) signal(SIGINT, gotsig); + + ioctl(STDOUT_FILENO, TIOCGWINSZ, &win); + if (win.ws_row > 4) rows = win.ws_row - 2; + if (win.ws_col > 0) cols = win.ws_col - 1; + + +#endif + + while ( (c = getc(f)) != EOF ) { + if ( next_page ) { + char garbage; + int len; + tlines += lines; + lines = 0; + next_page = 0; //Percentage is based on bytes, not lines. + if ( i && i->source ) //It is not very acurate, but still useful. + len = printf("%s - %%%2ld - line: %d", i->source, (ftell(f) - sizeb - sizeb) / sizeb, tlines); + else + len = printf("line: %d", tlines); + + fflush(stdout); +#ifndef BB_MORE_TERM + read(2, &garbage, 1); +#else + do { + fread(&garbage, 1, 1, cin); + } while ((garbage != ' ') && (garbage != '\n')); + + if (garbage == '\n') { + lines = rows; + tlines -= rows; + } + garbage = 0; + //clear line, since tabs don't overwrite. + while(len-- > 0) putchar('\b'); + while(len++ < cols) putchar(' '); + while(len-- > 0) putchar('\b'); + fflush(stdout); +#endif + } + putchar(c); + if ( c == '\n' && ++lines == (rows + 1) ) + next_page = 1; + } + if ( f != stdin ) + fclose(f); +#ifdef BB_MORE_TERM + gotsig(0); +#endif + return 0; +} diff --git a/util-linux/mount.c b/util-linux/mount.c new file mode 100644 index 0000000..010757d --- /dev/null +++ b/util-linux/mount.c @@ -0,0 +1,430 @@ +/* + 3/21/1999 Charles P. Wright <cpwright@cpwright.com> + searches through fstab when -a is passed + will try mounting stuff with all fses when passed -t auto + + 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. +*/ + +#include "internal.h" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <mntent.h> +#include <sys/mount.h> +#include <ctype.h> + +const char mount_usage[] = "mount\n" +"\t\tmount [flags] special-device directory\n" +"\n" +"Flags:\n" +"\t-a:\tMount all file systems in fstab.\n" +"\t-f:\t\"Fake\" mount. Add entry to mount table but don't mount it.\n" +"\t-n:\tDon't write a mount table entry.\n" +"\t-o option:\tOne of many filesystem options, listed below.\n" +"\t-r:\tMount the filesystem read-only.\n" +"\t-t filesystem-type:\tSpecify the filesystem type.\n" +"\t-w:\tMount for reading and writing (default).\n" +"\n" +"Options for use with the \"-o\" flag:\n" +"\tasync / sync:\tWrites are asynchronous / synchronous.\n" +"\tdev / nodev:\tAllow use of special device files / disallow them.\n" +"\texec / noexec:\tAllow use of executable files / disallow them.\n" +"\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n" +"\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n" +"\tro / rw: Mount for read-only / read-write.\n" +"\t" +"There are EVEN MORE flags that are specific to each filesystem.\n" +"You'll have to see the written documentation for those.\n"; + +struct mount_options { + const char * name; + unsigned long and; + unsigned long or; +}; + +static const struct mount_options mount_options[] = { + { "async", ~MS_SYNCHRONOUS,0 }, + { "defaults", ~0, 0 }, + { "dev", ~MS_NODEV, 0 }, + { "exec", ~MS_NOEXEC, 0 }, + { "nodev", ~0, MS_NODEV }, + { "noexec", ~0, MS_NOEXEC }, + { "nosuid", ~0, MS_NOSUID }, + { "remount", ~0, MS_REMOUNT }, + { "ro", ~0, MS_RDONLY }, + { "rw", ~MS_RDONLY, 0 }, + { "suid", ~MS_NOSUID, 0 }, + { "sync", ~0, MS_SYNCHRONOUS }, + { 0, 0, 0 } +}; + +static void +show_flags(unsigned long flags, char * buffer) +{ + const struct mount_options * f = mount_options; + while ( f->name ) { + if ( flags & f->and ) { + int length = strlen(f->name); + memcpy(buffer, f->name, length); + buffer += length; + *buffer++ = ','; + *buffer = '\0'; + } + f++; + } +} + +static void +one_option( + char * option +,unsigned long * flags +,char * data) +{ + const struct mount_options * f = mount_options; + + while ( f->name != 0 ) { + if ( strcasecmp(f->name, option) == 0 ) { + *flags &= f->and; + *flags |= f->or; + return; + } + f++; + } + if ( *data ) { + data += strlen(data); + *data++ = ','; + } + strcpy(data, option); +} + +static void +parse_mount_options( + char * options +,unsigned long * flags +,char * data) +{ + while ( *options ) { + char * comma = strchr(options, ','); + if ( comma ) + *comma = '\0'; + one_option(options, flags, data); + if ( comma ) { + *comma = ','; + options = ++comma; + } + else + break; + } +} + +int +mount_one( + char * blockDevice +,char * directory +,char * filesystemType +,unsigned long flags +,char * string_flags +,int noMtab +,int fake) +{ + int error = 0; + int status = 0; + + char buf[255]; + + if (!fake) { + if (*filesystemType == 'a') { //Will fail on real FS starting with 'a' + + FILE *f = fopen("/proc/filesystems", "r"); + + if (f == NULL) return 1; + + while (fgets(buf, sizeof(buf), f) != NULL) { + filesystemType = buf; + if (*filesystemType == '\t') { // Not a nodev filesystem + + while (*filesystemType && *filesystemType != '\n') filesystemType++; + *filesystemType = '\0'; + + filesystemType = buf; + filesystemType++; //hop past tab + + status = mount(blockDevice, directory, filesystemType, + flags|MS_MGC_VAL ,string_flags); + error = errno; + + if (status == 0) break; + } + } + fclose(f); + } else { + + status = mount( blockDevice, directory, filesystemType, + flags|MS_MGC_VAL ,string_flags); + error = errno; + } + } + + if ( status == 0 ) { + char * s = &string_flags[strlen(string_flags)]; + FILE * mountTable; + if ( s != string_flags ) { + *s++ = ','; + show_flags(flags, s); + } + if ( !noMtab && (mountTable = setmntent("/etc/mtab", "a+")) ) { + int length = strlen(directory); + struct mntent m; + + if ( length > 1 && directory[length - 1] == '/' ) + directory[length - 1] = '\0'; + + if ( filesystemType == 0 ) { + struct mntent * p + = findMountPoint(blockDevice, "/proc/mounts"); + + if ( p && p->mnt_type ) + filesystemType = p->mnt_type; + } + m.mnt_fsname = blockDevice; + m.mnt_dir = directory; + m.mnt_type = filesystemType ? filesystemType : "default"; + + if (*string_flags) { + m.mnt_opts = string_flags; + } else { + if ( (flags | MS_RDONLY) == flags ) + m.mnt_opts = "ro"; + else + m.mnt_opts = "rw"; + } + + m.mnt_freq = 0; + m.mnt_passno = 0; + addmntent(mountTable, &m); + endmntent(mountTable); + } + return 0; + } else { + fprintf(stderr, "Mount %s", blockDevice); + if ( filesystemType && *filesystemType ) + fprintf(stderr, " (type %s)", filesystemType); + + fprintf( + stderr + ," on %s: " + ,directory); + + switch ( error ) { + case EPERM: + if (geteuid() == 0) + fprintf( + stderr + ,"mount point %s is not a directory" + ,blockDevice); + else + fprintf( + stderr + ,"must be superuser to use mount"); + break; + case EBUSY: + fprintf( + stderr + ,"%s already mounted or %s busy" + ,blockDevice + ,directory); + break; + case ENOENT: + { + struct stat statbuf; + if ( stat(directory, &statbuf) != 0 ) + fprintf( + stderr + ,"directory %s does not exist" + ,directory); + else if ( stat(blockDevice, &statbuf) != 0 ) + fprintf( + stderr + ,"block device %s does not exist" + ,blockDevice); + else + fprintf( + stderr + ,"%s is not mounted on %s, but the mount table says it is." + ,blockDevice + ,directory); + break; + } + case ENOTDIR: + fprintf( + stderr + ,"%s is not a directory" + ,directory); + break; + case EINVAL: + fprintf( + stderr + ,"wrong filesystem type, or bad superblock on %s" + ,blockDevice); + break; + case EMFILE: + fprintf(stderr, "mount table full"); + break; + case EIO: + fprintf( + stderr + ,"I/O error reading %s" + ,blockDevice); + break; + case ENODEV: + { + FILE * f = fopen("/proc/filesystems", "r"); + + fprintf( + stderr + ,"filesystem type %s not in kernel.\n" + ,filesystemType); + fprintf(stderr, "Do you need to load a module?\n"); + if ( f ) { + char buf[100]; + + fprintf( + stderr + ,"Here are the filesystem types the kernel" + " can mount:\n"); + while ( fgets(buf, sizeof(buf), f) != 0 ) + fprintf(stderr, "\t%s", buf); + fclose(f); + } + break; + } + case ENOTBLK: + fprintf( + stderr + ,"%s is not a block device" + ,blockDevice); + break; + case ENXIO: + fprintf( + stderr + ,"%s is not a valid block device" + ,blockDevice); + break; + default: + fputs(strerror(errno), stderr); + } + putc('\n', stderr); + return -1; + } +} + +extern int +mount_main(struct FileInfo * i, int argc, char * * argv) +{ + char string_flags[1024]; + unsigned long flags = 0; + char * filesystemType = "auto"; + int fake = 0; + int noMtab = 0; + int all = 0; + + *string_flags = '\0'; + + if ( argc == 1 ) { + FILE * mountTable; + if ( (mountTable = setmntent("/etc/mtab", "r")) ) { + struct mntent * m; + while ( (m = getmntent(mountTable)) != 0 ) { + printf( + "%s on %s type %s (%s)\n" + ,m->mnt_fsname + ,m->mnt_dir + ,m->mnt_type + ,m->mnt_opts); + } + endmntent(mountTable); + } + return 0; + } + + while ( argc >= 2 && argv[1][0] == '-' ) { + switch ( argv[1][1] ) { + case 'f': + fake = 1; + break; + case 'n': + noMtab = 1; + break; + case 'o': + if ( argc < 3 ) { + usage(mount_usage); + return 1; + } + parse_mount_options(argv[2], &flags, string_flags); + argc--; + argv++; + break; + case 'r': + flags |= MS_RDONLY; + break; + case 't': + if ( argc < 3 ) { + usage(mount_usage); + return 1; + } + filesystemType = argv[2]; + argc--; + argv++; + break; + case 'v': + break; + case 'w': + flags &= ~MS_RDONLY; + break; + case 'a': + all = 1; + break; + default: + usage(mount_usage); + return 1; + } + argc--; + argv++; + } + + if (all == 1) { + struct mntent *m; + FILE *f = setmntent("/etc/fstab", "r"); + + if (f == NULL) { + return 1; + } + + // FIXME: Combine read routine (make new function) with unmount_all to save space. + + while ((m = getmntent(f)) != NULL) { + // If the file system isn't noauto, and isn't mounted on /, mount it + if ((!strstr(m->mnt_opts, "noauto")) && (m->mnt_dir[1] != '\0') + && !((m->mnt_type[0] == 's') && (m->mnt_type[1] == 'w')) + && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) { + mount_one(m->mnt_fsname, m->mnt_dir, m->mnt_type, flags, m->mnt_opts, noMtab, fake); + } + } + + endmntent(f); + } else { + if ( argc >= 3 ) { + if ( mount_one( argv[1], argv[2], filesystemType, flags, string_flags, noMtab, fake) == 0 ) + return 0; + else + return 1; + } else { + usage(mount_usage); + return 1; + } + } + return 0; +} diff --git a/util-linux/umount.c b/util-linux/umount.c new file mode 100644 index 0000000..4efc9f9 --- /dev/null +++ b/util-linux/umount.c @@ -0,0 +1,135 @@ +#include "internal.h" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <mntent.h> +#include <sys/mount.h> + +const char umount_usage[] = "umount {filesystem|directory}\n" +"\tumount -a\n" +"\n" +"\tUnmount a filesystem.\n" +"\t-a:\tUnmounts all mounted filesystems.\n"; + +static char * +stralloc(const char * string) +{ + int length = strlen(string) + 1; + char * n = malloc(length); + memcpy(n, string, length); + return n; +} + +extern void +erase_mtab(const char * name) +{ + struct mntent entries[100]; + int count = 0; + FILE * mountTable = setmntent("/etc/mtab", "r"); + struct mntent * m; + + if ( mountTable == 0 + && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) { + name_and_error("/etc/mtab"); + return; + } + + while ( (m = getmntent(mountTable)) != 0 ) { + entries[count].mnt_fsname = stralloc(m->mnt_fsname); + entries[count].mnt_dir = stralloc(m->mnt_dir); + entries[count].mnt_type = stralloc(m->mnt_type); + entries[count].mnt_opts = stralloc(m->mnt_opts); + entries[count].mnt_freq = m->mnt_freq; + entries[count].mnt_passno = m->mnt_passno; + count++; + } + endmntent(mountTable); + if ( (mountTable = setmntent("/etc/mtab", "w")) ) { + int i; + for ( i = 0; i < count; i++ ) { + int result = ( strcmp(entries[i].mnt_fsname, name) == 0 + || strcmp(entries[i].mnt_dir, name) == 0 ); + + if ( result ) + continue; + else + addmntent(mountTable, &entries[i]); + } + endmntent(mountTable); + } + else if ( errno != EROFS ) + name_and_error("/etc/mtab"); +} + +static int +umount_all(int noMtab) +{ + struct mntent entries[100]; + int count = 0; + FILE * mountTable = setmntent("/etc/mtab", "r"); + struct mntent * m; + int status = 0; + + if ( mountTable == 0 + && (mountTable = setmntent("/proc/mounts", "r")) == 0 ) { + name_and_error("/etc/mtab"); + return 1; + } + + while ( (m = getmntent(mountTable)) != 0 ) { + entries[count].mnt_fsname = stralloc(m->mnt_fsname); + count++; + } + endmntent(mountTable); + + while ( count > 0 ) { + int result = umount(entries[--count].mnt_fsname) == 0; + /* free(entries[count].mnt_fsname); */ + if ( result ) { + if ( !noMtab ) + erase_mtab(entries[count].mnt_fsname); + } + else { + status = 1; + name_and_error(entries[count].mnt_fsname); + } + } + return status; +} + +extern int +do_umount(const char * name, int noMtab) +{ + if ( umount(name) == 0 ) { + if ( !noMtab ) + erase_mtab(name); + return 0; + } + return 1; +} + +extern int +umount_main(struct FileInfo * i, int argc, char * * argv) +{ + int noMtab = 0; + + if ( argv[1][0] == '-' ) { + switch ( argv[1][1] ) { + case 'a': + return umount_all(noMtab); + case 'n': + noMtab = 1; + break; + default: + usage(umount_usage); + return 1; + } + } + if ( do_umount(argv[1],noMtab) != 0 ) { + fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno)); + return 1; + } + return 0; +} |