diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /bin/df/df.c |
initial import of NetBSD tree
Diffstat (limited to 'bin/df/df.c')
-rw-r--r-- | bin/df/df.c | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/bin/df/df.c b/bin/df/df.c new file mode 100644 index 00000000000..ec571d2f4f2 --- /dev/null +++ b/bin/df/df.c @@ -0,0 +1,425 @@ +/* $NetBSD: df.c,v 1.21 1995/08/11 00:38:15 jtc Exp $ */ + +/* + * Copyright (c) 1980, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)df.c 8.7 (Berkeley) 4/2/94"; +#else +static char rcsid[] = "$NetBSD: df.c,v 1.21 1995/08/11 00:38:15 jtc Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/mount.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int bread __P((off_t, void *, int)); +char *getmntpt __P((char *)); +void prtstat __P((struct statfs *, int)); +int ufs_df __P((char *, struct statfs *)); +int selected __P((const char *)); +void maketypelist __P((char *)); +long regetmntinfo __P((struct statfs **, long)); +void usage __P((void)); + +int iflag, kflag, lflag, nflag; +char **typelist = NULL; +struct ufs_args mdev; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat stbuf; + struct statfs *mntbuf; + long mntsize; + int ch, i, maxwidth, width; + char *mntpt; + + while ((ch = getopt(argc, argv, "iklnt:")) != -1) + switch (ch) { + case 'i': + iflag = 1; + break; + case 'k': + kflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'n': + nflag = 1; + break; + case 't': + if (typelist != NULL) + errx(1, "only one -t option may be specified."); + maketypelist(optarg); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (*argv && (lflag || typelist != NULL)) + errx(1, "-l or -t does not make sense with list of mount points"); + + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + if (mntsize == 0) + err(1, "retrieving information on mounted file systems"); + + if (!*argv) { + mntsize = regetmntinfo(&mntbuf, mntsize); + } else { + mntbuf = malloc(argc * sizeof(struct statfs)); + mntsize = 0; + for (; *argv; argv++) { + if (stat(*argv, &stbuf) < 0) { + if ((mntpt = getmntpt(*argv)) == 0) { + warn("%s", *argv); + continue; + } + } else if (S_ISCHR(stbuf.st_mode)) { + if (!ufs_df(*argv, &mntbuf[mntsize])) + ++mntsize; + continue; + } else if (S_ISBLK(stbuf.st_mode)) { + if ((mntpt = getmntpt(*argv)) == 0) { + mntpt = mktemp(strdup("/tmp/df.XXXXXX")); + mdev.fspec = *argv; + if (mkdir(mntpt, DEFFILEMODE) != 0) { + warn("%s", mntpt); + continue; + } + if (mount(MOUNT_UFS, mntpt, MNT_RDONLY, + &mdev) != 0) { + (void)rmdir(mntpt); + if (!ufs_df(*argv, &mntbuf[mntsize])) + ++mntsize; + continue; + } else if (!statfs(mntpt, &mntbuf[mntsize])) { + mntbuf[mntsize].f_mntonname[0] = '\0'; + ++mntsize; + } else + warn("%s", *argv); + (void)unmount(mntpt, 0); + (void)rmdir(mntpt); + continue; + } + } else + mntpt = *argv; + /* + * Statfs does not take a `wait' flag, so we cannot + * implement nflag here. + */ + if (!statfs(mntpt, &mntbuf[mntsize])) + ++mntsize; + else + warn("%s", *argv); + } + } + + maxwidth = 0; + for (i = 0; i < mntsize; i++) { + width = strlen(mntbuf[i].f_mntfromname); + if (width > maxwidth) + maxwidth = width; + } + for (i = 0; i < mntsize; i++) + prtstat(&mntbuf[i], maxwidth); + exit(0); +} + +char * +getmntpt(name) + char *name; +{ + long mntsize, i; + struct statfs *mntbuf; + + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + for (i = 0; i < mntsize; i++) { + if (!strcmp(mntbuf[i].f_mntfromname, name)) + return (mntbuf[i].f_mntonname); + } + return (0); +} + +static enum { IN_LIST, NOT_IN_LIST } which; + +int +selected(type) + const char *type; +{ + char **av; + + /* If no type specified, it's always selected. */ + if (typelist == NULL) + return (1); + for (av = typelist; *av != NULL; ++av) + if (!strncmp(type, *av, MFSNAMELEN)) + return (which == IN_LIST ? 1 : 0); + return (which == IN_LIST ? 0 : 1); +} + +void +maketypelist(fslist) + char *fslist; +{ + int i; + char *nextcp, **av; + + if ((fslist == NULL) || (fslist[0] == '\0')) + errx(1, "empty type list"); + + /* + * XXX + * Note: the syntax is "noxxx,yyy" for no xxx's and + * no yyy's, not the more intuitive "noyyy,noyyy". + */ + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + which = NOT_IN_LIST; + } else + which = IN_LIST; + + /* Count the number of types. */ + for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++) + ++nextcp; + + /* Build an array of that many types. */ + if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL) + err(1, NULL); + av[0] = fslist; + for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++) { + *nextcp = '\0'; + av[i] = ++nextcp; + } + /* Terminate the array. */ + av[i] = NULL; +} + +/* + * Make a pass over the filesystem info in ``mntbuf'' filtering out + * filesystem types not in ``fsmask'' and possibly re-stating to get + * current (not cached) info. Returns the new count of valid statfs bufs. + */ +long +regetmntinfo(mntbufp, mntsize) + struct statfs **mntbufp; + long mntsize; +{ + int i, j; + struct statfs *mntbuf; + + if (!lflag && typelist == NULL) + return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT)); + + mntbuf = *mntbufp; + j = 0; + for (i = 0; i < mntsize; i++) { + if (lflag && (mntbuf[i].f_flags & MNT_LOCAL) == 0) + continue; + if (!selected(mntbuf[i].f_fstypename)) + continue; + if (nflag) + mntbuf[j] = mntbuf[i]; + else + (void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]); + j++; + } + return (j); +} + +/* + * Convert statfs returned filesystem size into BLOCKSIZE units. + * Attempts to avoid overflow for large filesystems. + */ +#define fsbtoblk(num, fsbs, bs) \ + (((fsbs) != 0 && (fsbs) < (bs)) ? \ + (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) + +/* + * Print out status about a filesystem. + */ +void +prtstat(sfsp, maxwidth) + struct statfs *sfsp; + int maxwidth; +{ + static long blocksize; + static int headerlen, timesthrough; + static char *header; + long used, availblks, inodes; + + if (maxwidth < 11) + maxwidth = 11; + if (++timesthrough == 1) { + if (kflag) { + blocksize = 1024; + header = "1K-blocks"; + headerlen = strlen(header); + } else + header = getbsize(&headerlen, &blocksize); + (void)printf("%-*.*s %s Used Avail Capacity", + maxwidth, maxwidth, "Filesystem", header); + if (iflag) + (void)printf(" iused ifree %%iused"); + (void)printf(" Mounted on\n"); + } + (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname); + used = sfsp->f_blocks - sfsp->f_bfree; + availblks = sfsp->f_bavail + used; + (void)printf(" %*ld %8ld %8ld", headerlen, + fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), + fsbtoblk(used, sfsp->f_bsize, blocksize), + fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize)); + (void)printf(" %5.0f%%", + availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); + if (iflag) { + inodes = sfsp->f_files; + used = inodes - sfsp->f_ffree; + (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree, + inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); + } else + (void)printf(" "); + (void)printf(" %s\n", sfsp->f_mntonname); +} + +/* + * This code constitutes the pre-system call Berkeley df code for extracting + * information from filesystem superblocks. + */ +#include <ufs/ffs/fs.h> +#include <errno.h> +#include <fstab.h> + +union { + struct fs iu_fs; + char dummy[SBSIZE]; +} sb; +#define sblock sb.iu_fs + +int rfd; + +int +ufs_df(file, sfsp) + char *file; + struct statfs *sfsp; +{ + char *mntpt; + static int synced; + + if (synced++ == 0) + sync(); + + if ((rfd = open(file, O_RDONLY)) < 0) { + warn("%s", file); + return (-1); + } + if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { + (void)close(rfd); + return (-1); + } + sfsp->f_type = 0; + sfsp->f_flags = 0; + sfsp->f_bsize = sblock.fs_fsize; + sfsp->f_iosize = sblock.fs_bsize; + sfsp->f_blocks = sblock.fs_dsize; + sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + + sblock.fs_cstotal.cs_nffree; + sfsp->f_bavail = (sblock.fs_dsize * (100 - sblock.fs_minfree) / 100) - + (sblock.fs_dsize - sfsp->f_bfree); + if (sfsp->f_bavail < 0) + sfsp->f_bavail = 0; + sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; + sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; + sfsp->f_fsid.val[0] = 0; + sfsp->f_fsid.val[1] = 0; + if ((mntpt = getmntpt(file)) == 0) + mntpt = ""; + memmove(&sfsp->f_mntonname[0], mntpt, MNAMELEN); + memmove(&sfsp->f_mntfromname[0], file, MNAMELEN); + strncpy(sfsp->f_fstypename, MOUNT_UFS, MFSNAMELEN); + (void)close(rfd); + return (0); +} + +int +bread(off, buf, cnt) + off_t off; + void *buf; + int cnt; +{ + int nr; + + (void)lseek(rfd, off, SEEK_SET); + if ((nr = read(rfd, buf, cnt)) != cnt) { + /* Probably a dismounted disk if errno == EIO. */ + if (errno != EIO) + (void)fprintf(stderr, "\ndf: %qd: %s\n", + off, strerror(nr > 0 ? EIO : errno)); + return (0); + } + return (1); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: df [-ikln] [-t type] [file | file_system ...]\n"); + exit(1); +} |