[comp.os.minix] Use of /etc/mtab for logging mount/umount

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