ast@cs.vu.nl (Andy Tanenbaum) (05/13/88)
Although I do not intend to post the 1.3 stuff in batches this small, nor as full files (rather than diffs), I will post this batch separately because it requires a little bit of special attention. I have changed mount/umount/df to maintain a log of currently mounted file systems, as does UNIX. The log is on /etc/mtab, and I have modified /etc/rc to initialize it at boot time. The files are all enclosed. Note that "mount" typed without an arg lists /etc/mtab. In addition, just after posting file.c, I realized that it did not detect directories and special files. This version does. Andy Tanenbaum (ast@cs.vu.nl) : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'mount.c' sed 's/^X//' > 'mount.c' << '+ END-OF-FILE ''mount.c' X/* mount - mount a file system Author: Andy Tanenbaum */ X X#include <errno.h> X X#define BUFSIZE 1024 X Xextern int errno; Xchar *mounttable = "/etc/mtab"; Xchar buffer[BUFSIZE]; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int ro, fd; X X if (argc == 1) list(); X if (argc < 3 || argc > 4) usage(); X if (argc == 4 && *argv[3] != '-' && *(argv[3]+1) != 'r') usage(); X ro = (argc == 4 ? 1 : 0); X if (mount(argv[1], argv[2], ro) < 0) { X if (errno == EINVAL) { X std_err("mount: "); X std_err(argv[1]); X std_err(" is not a valid file system.\n"); X } else { X perror("mount"); X } X exit(1); X } X std_err(argv[1]); X std_err(" mounted\n"); X if ((fd = open("/etc/mtab", 2)) < 0) exit(1); X lseek(fd, 0L, 2); /* seek to EOF */ X write(fd, argv[1], strlen(argv[1])); X write(fd, " is mounted on ", 15); X write(fd, argv[2], strlen(argv[2])); X write(fd, "\n", 1); X exit(0); X} X X Xlist() X{ X int fd, n; X X fd = open(mounttable, 0); X if (fd < 0) { X std_err("mount: cannot open "); X std_err(mounttable); X std_err("\n"); X exit(1); X } X n = read(fd, buffer, BUFSIZE); X write(1, buffer, n); X exit(0); X} X X Xusage() X{ X std_err("Usage: mount special name [-r]\n"); X exit(1); X} + END-OF-FILE mount.c chmod 'u=rw,g=r,o=r' 'mount.c' set `wc -c 'mount.c'` count=$1 case $count in 1164) :;; *) echo 'Bad character count in ''mount.c' >&2 echo 'Count should be 1164' >&2 esac echo Extracting 'umount.c' sed 's/^X//' > 'umount.c' << '+ END-OF-FILE ''umount.c' X/* umount - unmount a file system Author: Andy Tanenbaum */ X X#include <errno.h> X X#define BUFSIZE 1024 X Xextern int errno; Xchar *mounttable = "/etc/mtab"; Xchar buffer[BUFSIZE], *p = &buffer[0], *q; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X X if (argc != 2) usage(); X if (umount(argv[1]) < 0) { X if (errno == EINVAL) X std_err("Device not mounted\n"); X else X perror("umount"); X exit(1); X } X std_err(argv[1]); X std_err(" unmounted\n"); X do_mtab(argv[1]); X exit(0); X} X Xdo_mtab(devname) Xchar *devname; X{ X/* Remove an entry from mtab. */ X int n, fd; X char line[256]; X X /* Read in the mount table and then overwrite the file. */ X fd = open(mounttable, 2); X n = read(fd, buffer, BUFSIZE); X close(fd); X q = &buffer[n]; X fd = creat(mounttable, 0554); X X n = strlen(devname); X while (getline(line) != 0) { X if (strncmp(line, devname, n) == 0) continue; X write(fd, line, strlen(line)); X } X} X Xint getline(ptr) Xchar *ptr; X{ X char c; X X while (p < q) { X c = *p++; X *ptr++ = c; X if (c == '\n') { X *ptr++ = 0; X return(1); X } X } X return(0); X} X X Xusage() X{ X std_err("Usage: umount special\n"); X exit(1); X} + END-OF-FILE umount.c chmod 'u=rw,g=r,o=r' 'umount.c' set `wc -c 'umount.c'` count=$1 case $count in 1114) :;; *) echo 'Bad character count in ''umount.c' >&2 echo 'Count should be 1114' >&2 esac echo Extracting 'df.c' sed 's/^X//' > 'df.c' << '+ END-OF-FILE ''df.c' X/* df - disk free block printout Author: Andy Tanenbaum */ X X#include <minix/const.h> X#include <minix/type.h> X#include <fs/const.h> X#include <fs/type.h> X#include <fs/super.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X Xchar *mtab = "/etc/mtab"; X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register int i; X X sync(); /* have to make sure disk is up-to-date */ X if (argc == 1) defaults(); X X for (i = 1; i < argc; i++) df(argv[i]); X exit(0); X} X X Xdf(name) Xchar *name; X{ X register int fd; X int i_count, z_count, totblocks, busyblocks, i; X char buf[BLOCK_SIZE], *s0; X struct super_block super, *sp; X struct stat statbuf; X X if ( (fd = open(name,0)) < 0) { X perror(name); X return; X } X X /* Is it a block special file? */ X if (fstat(fd, &statbuf) < 0) { X stderr2(name, ": Cannot stat\n"); X return; X } X if ( (statbuf.st_mode & S_IFMT) != S_IFBLK) { X stderr2(name, ": not a block special file\n"); X return; X } X X lseek(fd, (long)BLOCK_SIZE, 0); /* skip boot block */ X if (read(fd, &super, SUPER_SIZE) != SUPER_SIZE) { X stderr2(name, ": Can't read super block\n"); X close(fd); X return; X } X X X lseek(fd, (long) BLOCK_SIZE * 2L, 0); /* skip rest of super block */ X sp = &super; X if (sp->s_magic != SUPER_MAGIC) { X stderr2(name, ": Not a valid file system\n"); X close(fd); X return; X } X X i_count = bit_count(sp->s_imap_blocks, sp->s_ninodes+1, fd); X if (i_count < 0) { X stderr2(name, ": can't find bit maps\n"); X close(fd); X return; X } X X z_count = bit_count(sp->s_zmap_blocks, sp->s_nzones, fd); X if (z_count < 0) { X stderr2(name, ": can't find bit maps\n"); X close(fd); X return; X } X totblocks = sp->s_nzones << sp->s_log_zone_size; X busyblocks = z_count << sp->s_log_zone_size; X X /* Print results. */ X prints("%s",name); X s0 = name; X while (*s0) s0++; X i = 12 - (s0 - name); X while (i--) prints(" "); X prints("i-nodes: "); X num3(i_count - 1); X prints(" used "); X num3(sp->s_ninodes + 1 - i_count); X prints(" free blocks: "); X num3(busyblocks); X prints(" used "); X num3(totblocks - busyblocks); X prints(" free\n"); X close(fd); X} X Xbit_count(blocks, bits, fd) Xint blocks; Xint bits; Xint fd; X{ X register int i, b; X int busy, count, w; X int *wptr, *wlim; X int buf[BLOCK_SIZE/sizeof(int)]; X X /* Loop on blocks, reading one at a time and counting bits. */ X busy = 0; X count = 0; X for (i = 0; i < blocks; i++) { X if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) return(-1); X X wptr = &buf[0]; X wlim = &buf[BLOCK_SIZE/sizeof(int)]; X X /* Loop on the words of a block */ X while (wptr != wlim) { X w = *wptr++; X X /* Loop on the bits of a word. */ X for (b = 0; b < 8*sizeof(int); b++) { X if ( (w>>b) & 1) busy++; X if (++count == bits) return(busy); X } X } X } X return(0); X} X X Xstderr2(s1, s2) Xchar *s1, *s2; X{ X std_err(s1); X std_err(s2); X} X Xnum3(n) Xint n; X{ X extern char *itoa(); X if (n < 10) prints(" %s", itoa(n)); X else if (n < 100) prints(" %s", itoa(n)); X else if (n < 1000) prints(" %s", itoa(n)); X else if (n < 10000) prints(" %s", itoa(n)); X else prints("%s", itoa(n)); X} X Xdefaults() X{ X/* Use the root file system and all mounted file systems. */ X X char buf[256]; X X close(0); X if (open(mtab, 0) < 0) { X std_err("df: cannot open "); X std_err(mtab); X std_err("\n"); X exit(1); X } X X /* Read /etc/mtab and iterate on the lines. */ X while (1) { X getname(buf); /* getname exits upon hitting EOF */ X df(buf); X } X X} X Xgetname(p) Xchar *p; X{ X char c; X X while (1) { X c = getchar(); X if (c < 0) exit(0); X if (c == ' ') c = 0; X *p++ = c; X if (c == '\n') return; X } X} + END-OF-FILE df.c chmod 'u=rw,g=r,o=r' 'df.c' set `wc -c 'df.c'` count=$1 case $count in 3545) :;; *) echo 'Bad character count in ''df.c' >&2 echo 'Count should be 3545' >&2 esac echo Extracting 'etcrc' sed 's/^X//' > 'etcrc' << '+ END-OF-FILE ''etcrc' Xecho "/dev/ram is root device" >/etc/mtab X/etc/mount /dev/hd1 /usr X/usr/bin/date -q </dev/tty X/etc/update & + END-OF-FILE etcrc chmod 'u=rw,g=r,o=r' 'etcrc' set `wc -c 'etcrc'` count=$1 case $count in 109) :;; *) echo 'Bad character count in ''etcrc' >&2 echo 'Count should be 109' >&2 esac echo Extracting 'file.c' sed 's/^X//' > 'file.c' << '+ END-OF-FILE ''file.c' X/* file - report on file type. Author: Andy Tanenbaum */ X X#include <minix/blocksize.h> X#include <ar.h> X#include <sys/stat.h> X X#define A_OUT 001401 /* magic number for executables */ X#define SPLIT 002040 /* second word on split I/D binaries */ X#define XBITS 00111 /* rwXrwXrwX (x bits in the mode) */ X#define ENGLISH 25 /* cutoff for determining if text is Eng.*/ Xchar buf[BLOCK_SIZE]; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X/* This program uses some heuristics to try to guess about a file type by X * looking at its contents. X */ X X int i; X X if (argc < 2) usage(); X for (i = 1; i < argc; i++) file(argv[i]); X} X Xfile(name) Xchar *name; X{ X int i, fd, n, magic, second, mode, nonascii, special, funnypct, etaoins; X long engpct; X char c; X struct stat st_buf; X X printf("%s: ", name); X X /* Open the file, stat it, and read in 1 block. */ X fd = open(name, 0); X if (fd < 0) { X printf("cannot open\n"); X return; X } X X n = fstat(fd, &st_buf); X if (n < 0) { X printf("cannot stat\n"); X close(fd); X return; X } X mode = st_buf.st_mode; X X /* Check for directories and special files. */ X if ( (mode & S_IFMT) == S_IFDIR) { X printf("directory\n"); X close(fd); X return; X } X X if ( (mode & S_IFMT) == S_IFCHR) { X printf("character special file\n"); X close(fd); X return; X } X X if ( (mode & S_IFMT) == S_IFBLK) { X printf("block special file\n"); X close(fd); X return; X } X X n = read(fd, buf, BLOCK_SIZE); X if (n < 0) { X printf("cannot read\n"); X close(fd); X return; X } X X /* Check to see if file is an archive. */ X magic = (buf[1]<<8) | (buf[0]&0377); X if (magic == ARMAG) { X printf("archive\n"); X close(fd); X return; X } X X /* Check to see if file is an executable binary. */ X if (magic == A_OUT) { X /* File is executable. Check for split I/D. */ X printf("executable "); X second = (buf[3]<<8) | (buf[2]&0377); X if (second == SPLIT) X printf(" separate I & D space\n"); X else X printf(" combined I & D space\n"); X close(fd); X return; X } X X /* Check to see if file is a shell script. */ X if (mode & XBITS) { X /* Not a binary, but executable. Probably a shell script. */ X printf("shell script\n"); X close(fd); X return; X } X X /* Check for ASCII data and certain punctuation. */ X nonascii = 0; X special = 0; X etaoins = 0; X for (i = 0; i < n; i++) { X c = buf[i]; X if (c & 0200) nonascii++; X if (c == ';' || c == '{' || c == '}' || c == '#') special++; X if (c == '*' || c == '<' || c == '>' || c == '/') special++; X if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; X if (c == 'e' || c == 't' || c == 'a' || c == 'o') etaoins++; X if (c == 'i' || c == 'n' || c == 's') etaoins++; X } X X if (nonascii == 0) { X /* File only contains ASCII characters. Continue processing. */ X funnypct = 100 * special/n; X engpct = 100L * (long) etaoins/n; X if (funnypct > 1) { X printf("C program\n"); X } else { X if (engpct > (long) ENGLISH) X printf("English text\n"); X else X printf("ASCII text\n", engpct); X } X close(fd); X return; X } X X /* Give up. Call it data. */ X printf("data\n"); X close(fd); X return; X} X Xusage() X{ X printf("Usage: file name ...\n"); X exit(1); X} X + END-OF-FILE file.c chmod 'u=rw,g=r,o=r' 'file.c' set `wc -c 'file.c'` count=$1 case $count in 3073) :;; *) echo 'Bad character count in ''file.c' >&2 echo 'Count should be 3073' >&2 esac exit 0