static char *sccsid = "@(#)df.c 4.6 (Berkeley) 7/8/81"; #include <stdio.h> #include <fstab.h> #include <sys/param.h> #include <sys/filsys.h> #include <sys/fblk.h> #include <sys/stat.h> /* * df */ #define NFS 32 /* Max number of filesystems */ #define KBYTE 1024 struct mtab { char path[FSNMLG]; char spec[FSNMLG]; } mtab[NFS]; struct stat stb; int dev; #define L10BS 6 #define L10IS 5 #define PCTFW 3 int DEVNMLG; /* length of longest device name */ int DIRNMLG; /* length of longest mount point name */ char *mpath(); daddr_t blkno = 1; int lflag; int iflag; struct filsys sblock; int fi; daddr_t alloc(); main(argc, argv) register int argc; register char **argv; { register int i; register int r = 0; while (argc > 1 && argv[1][0]=='-') { switch(argv[1][1]) { case 'l': lflag++; break; case 'i': iflag++; break; default: fprintf(stderr, "usage: df [-i] [-l] [filsys...]\n"); exit(0); } argc--, argv++; } if ((i=open("/etc/mtab", 0)) >= 0) { r = read(i, mtab, sizeof mtab); /* Probably returns short */ (void) close(i); r /= sizeof mtab[0]; } devlen(r); /* reads in all of /etc/fstab, too */ printf("%-*.*s %-*.*s %*.*s %*.*s %*.*s", DIRNMLG, DIRNMLG, "dir", DEVNMLG, DEVNMLG, "dev", L10BS, L10BS, "kbytes", L10BS, L10BS, "used", L10BS, L10BS, "free"); if (lflag) printf(" %*.*s", L10BS, L10BS, "hardway"); printf(" %*.*s", PCTFW + 1, PCTFW + 1, "%use"); if (iflag) printf(" %*.*s %*.*s %*.*s", L10IS, L10IS, "iused", L10IS, L10IS, "ifree", PCTFW + 1, PCTFW + 1, "%ino"); putchar('\n'); if(argc <= 1) { for (i = 0; i < NFS && mtab[i].spec[0]; ++i) dfree(mtab[i].path); return (0); } for(i=1; i<argc; i++) dfree(argv[i]); return (0); } dfree(file) char *file; { register daddr_t i; register char *mp; long blocks; long free; long used; long hardway; struct stat stbuf; static char specbuf[FSNMLG + sizeof "/dev/"] = "/dev/"; if(stat(file, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR) { struct stat mstbuf; for (i = 0; i < NFS && mtab[i].spec[0]; ++i) { strcpy(&specbuf[5], mtab[i].spec); if(!stat(specbuf, &mstbuf) && mstbuf.st_rdev == stbuf.st_dev) { file = specbuf; break; } } if (i == NFS || mtab[i].spec[0] == '\0') { fprintf(stderr, "%s mounted on unknown device\n", file); return; } } else if (strncmp("/dev/", file, sizeof "/dev/" - 1) != 0) strcpy(&specbuf[5], file), file = specbuf; fi = open(file, 0); if(fi < 0) { fprintf(stderr,"cannot open %s\n", file); return; } fstat(fi, &stb); dev = stb.st_rdev; if (lflag) sync(); bread(1L, (char *)&sblock, sizeof(sblock)); blocks = (long) sblock.s_fsize - (long)sblock.s_isize; free = sblock.s_tfree; used = blocks - free; blocks *= BSIZE(dev) / KBYTE; free *= BSIZE(dev) / KBYTE; used *= BSIZE(dev) / KBYTE; printf("%-*.*s %-*.*s %*ld %*ld %*ld", DIRNMLG, DIRNMLG, mp = mpath(file), DEVNMLG, DEVNMLG, file + sizeof "/dev", L10BS, blocks, L10BS, used, L10BS, free); if (lflag) { hardway = 0; if(BITFS(dev)) hardway = alloc(); else while(alloc()) hardway++; hardway *= BSIZE(dev) / KBYTE; printf(" %*ld", L10BS, free = hardway); } printf(" %*.0f%%", PCTFW, blocks == 0 ? 0.0 : (double) used / (double) blocks * 100.0); if (iflag) { int inodes = (sblock.s_isize - 2) * INOPB(dev); used = inodes - sblock.s_tinode; printf(" %*ld %*ld %*.0f%%", L10IS, used, L10IS, sblock.s_tinode, PCTFW, inodes == 0 ? 0.0 : (double) used / (double) inodes * 100.0); } printf("\n"); close(fi); } daddr_t alloc() { int i, j, n; daddr_t b; struct fblk buf; if(!BITFS(dev)) { i = --sblock.s_nfree; if(i<0 || i>=NICFREE) { printf("bad free count, b=%D\n", blkno); return(0); } b = sblock.s_free[i]; if(b == 0) return(0); if(b<sblock.s_isize || b>=sblock.s_fsize) { printf("bad free block (%D)\n", b); return(0); } if(sblock.s_nfree <= 0) { bread(b, (char *)&buf, sizeof(buf)); blkno = b; sblock.s_nfree = buf.df_nfree; for(i=0; i<NICFREE; i++) sblock.s_free[i] = buf.df_free[i]; } return(b); } n = 0; for(i = 0; i < BITMAP; i++) for(j = 0; j < 32; j++) /* 32: bits per int */ if(sblock.s_bfree[i] & (1 << j)) n++; return(n); } bread(bno, buf, cnt) daddr_t bno; char *buf; { register int n; extern errno; lseek(fi, bno<<BSHIFT(dev), 0); if((n=read(fi, buf, cnt)) != cnt) { printf("\nread error bno = %ld\n", bno); printf("count = %d; errno = %d\n", n, errno); exit(0); } } /* * Given a name like /dev/rrp0h, returns the mounted path, like /usr. */ char *mpath(file) char *file; { register int i; for (i=0; i<NFS; i++) if (eq(file, mtab[i].spec)) return mtab[i].path; return ""; } eq(f1, f2) char *f1, *f2; { if (strncmp(f1, "/dev/", 5) == 0) f1 += 5; if (strncmp(f2, "/dev/", 5) == 0) f2 += 5; if (strcmp(f1, f2) == 0) return 1; if (*f1 == 'r' && strcmp(f1+1, f2) == 0) return 1; if (*f2 == 'r' && strcmp(f1, f2+1) == 0) return 1; if (*f1 == 'r' && *f2 == 'r' && strcmp(f1+1, f2+1) == 0) return 1; return 0; } mtabcmp(mp0, mp1) struct mtab *mp0; struct mtab *mp1; { /* * don't let empty mtab slots sort to the front * as dfree will break * the wrong way to fix it: the whole algorithm is wrong */ if (mp0->path[0] == 0) return (1); if (mp1->path[0] == 0) return (-1); return (strncmp(mp0->path, mp1->path, sizeof (mp0->path))); } devlen(r) register int r; { register struct fstab *fsp; register int i; DEVNMLG = 0; DIRNMLG = 0; if (setfsent() == 0) perror(FSTAB), exit(1); while( (fsp = getfsent()) != 0){ if ( (strcmp(fsp->fs_type, FSTAB_RW) != 0) &&(strcmp(fsp->fs_type, FSTAB_RO) != 0) ) continue; for (i = 0; mtab[i].spec[0]; ++i) { if (strncmp(mtab[i].spec, fsp->fs_spec + 5, sizeof fsp->fs_spec - 5) == 0) break; } if (i == r && i < NFS) { strncpy(mtab[r].spec, fsp->fs_spec + 5, sizeof fsp->fs_spec - 5); strncpy(mtab[r].path, fsp->fs_file, sizeof fsp->fs_file); ++r; } if (DEVNMLG < (i = strlen(fsp->fs_spec))) DEVNMLG = i; if (DIRNMLG < (i = strlen(fsp->fs_file))) DIRNMLG = i; } endfsent(); DEVNMLG -= sizeof "/dev"; if (DEVNMLG < sizeof "dev" - 1) DEVNMLG = sizeof "dev" - 1; if (DIRNMLG < sizeof "dir" - 1) DIRNMLG = sizeof "dir" - 1; qsort(&mtab[0], r, sizeof mtab[0], mtabcmp); }