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