dal@syntel.UUCP (Dale Schumacher) (06/25/89)
This version of 'df' uses the '/etc/mtab' file (as Minix-PC v1.4?) to keep track of what is mounted, and assumes '/etc/mount' and '/etc/umount' will update that file properly. In addition, something like the following should be in your '/etc/rc' file. echo "/dev/hd3 is mounted on /" > /etc/mtab chmod 644 /etc/mtab This allows 'df' to display stats on all mounted devices if it is run with no parameters, all of which is no surprise to Minix-PC users. What is new in this version of 'df' is that it radically alters the output format to start with a single header line (describing the fields) and adds two new fields. One showing percent of disk blocks used, and the other showing the mount point for each device. Here is some sample output: device inodes: used free blocks: used free %use mount point /dev/hd3 106 222 354 606 36% / /dev/hd4 2392 5749 14909 9491 61% /usr /dev/ram 6 35 93 7 93% /rbin /dev/dd0 37 211 708 12 98% /user The context diffs were almost as big as the whole source, so I'm posting the new source directly. PS. I'll be incommunicado from 6/26 to 6/30, but I'll answer mail as soon after that as possible. ---------------------------------------------------------------------------- /* df - disk free block printout Author: Andy Tanenbaum */ #include <minix/const.h> #include <minix/type.h> #include <fs/const.h> #include <fs/type.h> #include <fs/super.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> extern char *itoa(); char *mtab = "/etc/mtab"; main(argc, argv) int argc; char *argv[]; { register int i; sync(); /* have to make sure disk is up-to-date */ prints( "device inodes: used free blocks: used free %use mount point\n"); defaults((argc > 1) ? argv[1] : ((char *) 0)); exit(0); /* redundant, defaults() doesn't return */ } df(name, mountpoint) char *name, *mountpoint; { register int fd; int i_count, z_count, totblocks, busyblocks, i; long freepercent; char buf[BLOCK_SIZE]; struct super_block super, *sp; struct stat statbuf; if ( (fd = open(name,0)) < 0) { perror(name); return; } /* Is it a block special file? */ if (fstat(fd, &statbuf) < 0) { stderr2(name, ": Cannot stat\n"); return; } if ( (statbuf.st_mode & S_IFMT) != S_IFBLK) { stderr2(name, ": not a block special file\n"); return; } lseek(fd, (long)BLOCK_SIZE, 0); /* skip boot block */ if (read(fd, &super, SUPER_SIZE) != SUPER_SIZE) { stderr2(name, ": Can't read super block\n"); close(fd); return; } lseek(fd, (long) BLOCK_SIZE * 2L, 0); /* skip rest of super block */ sp = &super; if (sp->s_magic != SUPER_MAGIC) { stderr2(name, ": Not a valid file system\n"); close(fd); return; } i_count = bit_count(sp->s_imap_blocks, sp->s_ninodes+1, fd); if (i_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } z_count = bit_count(sp->s_zmap_blocks, sp->s_nzones, fd); if (z_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } totblocks = sp->s_nzones << sp->s_log_zone_size; busyblocks = z_count << sp->s_log_zone_size; /* Print results. */ sfield(name, -14); sfield(itoa(i_count - 1), 7); sfield(itoa(sp->s_ninodes + 1 - i_count), 7); prints(" "); sfield(itoa(busyblocks), 7); sfield(itoa(totblocks - busyblocks), 7); freepercent = ((long) busyblocks) * 100L; freepercent /= (long) totblocks; sfield(itoa((int) freepercent), 4); prints("% "); prints(mountpoint); prints("\n"); close(fd); } bit_count(blocks, bits, fd) int blocks; int bits; int fd; { register int i, b; int busy, count, w; int *wptr, *wlim; int buf[BLOCK_SIZE/sizeof(int)]; /* Loop on blocks, reading one at a time and counting bits. */ busy = 0; count = 0; for (i = 0; i < blocks; i++) { if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) return(-1); wptr = &buf[0]; wlim = &buf[BLOCK_SIZE/sizeof(int)]; /* Loop on the words of a block */ while (wptr != wlim) { w = *wptr++; /* Loop on the bits of a word. */ for (b = 0; b < 8*sizeof(int); b++) { if ( (w>>b) & 1) busy++; if (++count == bits) return(busy); } } } return(0); } stderr2(s1, s2) char *s1, *s2; { std_err(s1); std_err(s2); } sfield(s, n) char *s; int n; { char pad[128], *p; int m, x; m = strlen(s); /* compute and create padding string */ for(p=pad, x=((n<0)?-n:n); (m < x); ++m) *p++ = ' '; *p = '\0'; if(n > 0) /* right justification */ prints(pad); prints(s); if(n < 0) /* left justification */ prints(pad); return(m); /* characters printed */ } defaults(device) char *device; { /* Use the root file system and all mounted file systems. */ /* If a device is specified, only display that device. */ char mdev[256], *mdir, *getname(); close(0); if (open(mtab, 0) < 0) { std_err("df: cannot open "); std_err(mtab); std_err("\n"); exit(1); } /* Read /etc/mtab and iterate on the lines. */ while (1) { mdir = getname(mdev); /* getname exits upon hitting EOF */ if(!device || (strcmp(device, mdev) == 0)) df(mdev, mdir); } } char *getname(p) char *p; { int c; while (1) { c = getchar(); if (c == EOF) exit(0); if (c == ' ') c = 0; if (c == '\n') { *p = '\0'; while(*--p) ; return(++p); } *p++ = (char)c; } } ---------------------------------------------------------------------------- -- Dale Schumacher 399 Beacon Ave. (alias: Dalnefre') St. Paul, MN 55104-3527 ...bungia!midgard.mn.org!syntel!dal United States of America "I may be competitive, but I'm never ruthless"