du.c revision 1.17.2.1       1  1.17.2.1    grant /*	$NetBSD: du.c,v 1.17.2.1 2003/06/19 00:21:50 grant Exp $	*/
      2       1.9    glass 
      3       1.1      cgd /*
      4       1.9    glass  * Copyright (c) 1989, 1993, 1994
      5       1.9    glass  *	The Regents of the University of California.  All rights reserved.
      6       1.1      cgd  *
      7       1.1      cgd  * This code is derived from software contributed to Berkeley by
      8       1.1      cgd  * Chris Newcomb.
      9       1.1      cgd  *
     10       1.1      cgd  * Redistribution and use in source and binary forms, with or without
     11       1.1      cgd  * modification, are permitted provided that the following conditions
     12       1.1      cgd  * are met:
     13       1.1      cgd  * 1. Redistributions of source code must retain the above copyright
     14       1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     15       1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     17       1.1      cgd  *    documentation and/or other materials provided with the distribution.
     18       1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     19       1.1      cgd  *    must display the following acknowledgement:
     20       1.1      cgd  *	This product includes software developed by the University of
     21       1.1      cgd  *	California, Berkeley and its contributors.
     22       1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     23       1.1      cgd  *    may be used to endorse or promote products derived from this software
     24       1.1      cgd  *    without specific prior written permission.
     25       1.1      cgd  *
     26       1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27       1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28       1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29       1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30       1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31       1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32       1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33       1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34       1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35       1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36       1.1      cgd  * SUCH DAMAGE.
     37       1.1      cgd  */
     38       1.1      cgd 
     39      1.12    lukem #include <sys/cdefs.h>
     40       1.1      cgd #ifndef lint
     41      1.12    lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
     42      1.12    lukem 	The Regents of the University of California.  All rights reserved.\n");
     43       1.1      cgd #endif /* not lint */
     44       1.1      cgd 
     45       1.1      cgd #ifndef lint
     46       1.9    glass #if 0
     47      1.10    perry static char sccsid[] = "@(#)du.c	8.5 (Berkeley) 5/4/95";
     48       1.9    glass #else
     49  1.17.2.1    grant __RCSID("$NetBSD: du.c,v 1.17.2.1 2003/06/19 00:21:50 grant Exp $");
     50       1.9    glass #endif
     51       1.1      cgd #endif /* not lint */
     52       1.1      cgd 
     53       1.9    glass #include <sys/types.h>
     54       1.9    glass #include <sys/stat.h>
     55       1.9    glass 
     56       1.9    glass #include <dirent.h>
     57       1.9    glass #include <err.h>
     58       1.9    glass #include <errno.h>
     59       1.9    glass #include <fts.h>
     60       1.5      jtc #include <stdio.h>
     61       1.5      jtc #include <stdlib.h>
     62       1.5      jtc #include <string.h>
     63       1.5      jtc #include <unistd.h>
     64       1.1      cgd 
     65      1.12    lukem int	linkchk __P((FTSENT *));
     66      1.12    lukem int	main __P((int, char **));
     67      1.12    lukem void	usage __P((void));
     68       1.4  mycroft 
     69       1.9    glass int
     70       1.1      cgd main(argc, argv)
     71       1.1      cgd 	int argc;
     72       1.4  mycroft 	char *argv[];
     73       1.1      cgd {
     74       1.9    glass 	FTS *fts;
     75       1.9    glass 	FTSENT *p;
     76      1.11  thorpej 	long blocksize, totalblocks;
     77  1.17.2.1    grant 	int ftsoptions, listdirs, listfiles, notused;
     78  1.17.2.1    grant 	int Hflag, Lflag, Pflag, aflag, ch, cflag, kmflag, rval, sflag;
     79  1.17.2.1    grant 	char *noargv[2];
     80       1.1      cgd 
     81      1.16  hubertf 	Hflag = Lflag = Pflag = aflag = cflag = kmflag = sflag = 0;
     82      1.11  thorpej 	totalblocks = 0;
     83       1.1      cgd 	ftsoptions = FTS_PHYSICAL;
     84      1.16  hubertf 	while ((ch = getopt(argc, argv, "HLPackmrsx")) != -1)
     85       1.9    glass 		switch (ch) {
     86       1.9    glass 		case 'H':
     87       1.9    glass 			Hflag = 1;
     88       1.9    glass 			Lflag = Pflag = 0;
     89       1.9    glass 			break;
     90       1.9    glass 		case 'L':
     91       1.9    glass 			Lflag = 1;
     92       1.9    glass 			Hflag = Pflag = 0;
     93       1.9    glass 			break;
     94       1.9    glass 		case 'P':
     95       1.9    glass 			Pflag = 1;
     96       1.9    glass 			Hflag = Lflag = 0;
     97       1.9    glass 			break;
     98       1.1      cgd 		case 'a':
     99       1.1      cgd 			aflag = 1;
    100       1.1      cgd 			break;
    101      1.11  thorpej 		case 'c':
    102      1.11  thorpej 			cflag = 1;
    103      1.11  thorpej 			break;
    104       1.1      cgd 		case 'k':
    105       1.4  mycroft 			blocksize = 1024;
    106      1.16  hubertf 			kmflag = 1;
    107      1.14   kleink 			break;
    108      1.16  hubertf 		case 'm':
    109      1.16  hubertf 			blocksize = 1024 * 1024;
    110      1.16  hubertf 			kmflag = 1;
    111      1.16  hubertf 			break;
    112      1.14   kleink 		case 'r':
    113       1.1      cgd 			break;
    114       1.1      cgd 		case 's':
    115       1.1      cgd 			sflag = 1;
    116       1.1      cgd 			break;
    117       1.1      cgd 		case 'x':
    118       1.1      cgd 			ftsoptions |= FTS_XDEV;
    119       1.1      cgd 			break;
    120       1.1      cgd 		case '?':
    121       1.1      cgd 		default:
    122       1.1      cgd 			usage();
    123       1.1      cgd 		}
    124       1.9    glass 	argc -= optind;
    125       1.1      cgd 	argv += optind;
    126       1.1      cgd 
    127       1.9    glass 	/*
    128       1.9    glass 	 * XXX
    129       1.9    glass 	 * Because of the way that fts(3) works, logical walks will not count
    130       1.9    glass 	 * the blocks actually used by symbolic links.  We rationalize this by
    131       1.9    glass 	 * noting that users computing logical sizes are likely to do logical
    132       1.9    glass 	 * copies, so not counting the links is correct.  The real reason is
    133       1.9    glass 	 * that we'd have to re-implement the kernel's symbolic link traversing
    134       1.9    glass 	 * algorithm to get this right.  If, for example, you have relative
    135       1.9    glass 	 * symbolic links referencing other relative symbolic links, it gets
    136       1.9    glass 	 * very nasty, very fast.  The bottom line is that it's documented in
    137       1.9    glass 	 * the man page, so it's a feature.
    138       1.9    glass 	 */
    139       1.9    glass 	if (Hflag)
    140       1.9    glass 		ftsoptions |= FTS_COMFOLLOW;
    141       1.9    glass 	if (Lflag) {
    142       1.9    glass 		ftsoptions &= ~FTS_PHYSICAL;
    143       1.9    glass 		ftsoptions |= FTS_LOGICAL;
    144       1.9    glass 	}
    145       1.9    glass 
    146       1.1      cgd 	if (aflag) {
    147       1.1      cgd 		if (sflag)
    148       1.1      cgd 			usage();
    149       1.1      cgd 		listdirs = listfiles = 1;
    150       1.1      cgd 	} else if (sflag)
    151       1.1      cgd 		listdirs = listfiles = 0;
    152       1.1      cgd 	else {
    153       1.1      cgd 		listfiles = 0;
    154       1.1      cgd 		listdirs = 1;
    155       1.1      cgd 	}
    156       1.1      cgd 
    157       1.1      cgd 	if (!*argv) {
    158  1.17.2.1    grant 		noargv[0] = ".";
    159  1.17.2.1    grant 		noargv[1] = NULL;
    160  1.17.2.1    grant 		argv = noargv;
    161       1.1      cgd 	}
    162       1.1      cgd 
    163      1.16  hubertf 	if (!kmflag)
    164       1.6      cgd 		(void)getbsize(¬used, &blocksize);
    165       1.4  mycroft 	blocksize /= 512;
    166       1.4  mycroft 
    167       1.4  mycroft 	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
    168      1.12    lukem 		err(1, "fts_open `%s'", *argv);
    169       1.1      cgd 
    170      1.10    perry 	for (rval = 0; (p = fts_read(fts)) != NULL;)
    171       1.9    glass 		switch (p->fts_info) {
    172       1.9    glass 		case FTS_D:			/* Ignore. */
    173       1.1      cgd 			break;
    174       1.1      cgd 		case FTS_DP:
    175       1.1      cgd 			p->fts_parent->fts_number +=
    176       1.3  deraadt 			    p->fts_number += p->fts_statp->st_blocks;
    177      1.11  thorpej 			if (cflag)
    178      1.11  thorpej 				totalblocks += p->fts_statp->st_blocks;
    179       1.1      cgd 			/*
    180       1.1      cgd 			 * If listing each directory, or not listing files
    181       1.1      cgd 			 * or directories and this is post-order of the
    182       1.1      cgd 			 * root of a traversal, display the total.
    183       1.1      cgd 			 */
    184      1.12    lukem 			if (listdirs || (!listfiles && !p->fts_level))
    185       1.4  mycroft 				(void)printf("%ld\t%s\n",
    186       1.4  mycroft 				    howmany(p->fts_number, blocksize),
    187       1.4  mycroft 				    p->fts_path);
    188       1.1      cgd 			break;
    189       1.9    glass 		case FTS_DC:			/* Ignore. */
    190       1.9    glass 			break;
    191       1.9    glass 		case FTS_DNR:			/* Warn, continue. */
    192       1.1      cgd 		case FTS_ERR:
    193       1.1      cgd 		case FTS_NS:
    194      1.10    perry 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
    195      1.10    perry 			rval = 1;
    196       1.1      cgd 			break;
    197       1.1      cgd 		default:
    198       1.3  deraadt 			if (p->fts_statp->st_nlink > 1 && linkchk(p))
    199       1.1      cgd 				break;
    200       1.1      cgd 			/*
    201       1.1      cgd 			 * If listing each file, or a non-directory file was
    202       1.1      cgd 			 * the root of a traversal, display the total.
    203       1.1      cgd 			 */
    204       1.1      cgd 			if (listfiles || !p->fts_level)
    205      1.17    lukem 				(void)printf("%lld\t%s\n", (long long)
    206       1.4  mycroft 				    howmany(p->fts_statp->st_blocks, blocksize),
    207       1.4  mycroft 				    p->fts_path);
    208       1.3  deraadt 			p->fts_parent->fts_number += p->fts_statp->st_blocks;
    209      1.11  thorpej 			if (cflag)
    210      1.11  thorpej 				totalblocks += p->fts_statp->st_blocks;
    211       1.1      cgd 		}
    212       1.4  mycroft 	if (errno)
    213       1.9    glass 		err(1, "fts_read");
    214      1.11  thorpej 	if (cflag)
    215      1.11  thorpej 		(void)printf("%ld\ttotal\n",
    216      1.11  thorpej 		    howmany(totalblocks, blocksize));
    217       1.1      cgd 	exit(0);
    218       1.1      cgd }
    219       1.1      cgd 
    220       1.1      cgd typedef struct _ID {
    221       1.1      cgd 	dev_t	dev;
    222       1.1      cgd 	ino_t	inode;
    223       1.1      cgd } ID;
    224       1.1      cgd 
    225       1.4  mycroft int
    226       1.1      cgd linkchk(p)
    227       1.9    glass 	FTSENT *p;
    228       1.1      cgd {
    229       1.1      cgd 	static ID *files;
    230       1.1      cgd 	static int maxfiles, nfiles;
    231       1.9    glass 	ID *fp, *start;
    232       1.9    glass 	ino_t ino;
    233       1.9    glass 	dev_t dev;
    234       1.1      cgd 
    235       1.3  deraadt 	ino = p->fts_statp->st_ino;
    236       1.3  deraadt 	dev = p->fts_statp->st_dev;
    237       1.9    glass 	if ((start = files) != NULL)
    238       1.1      cgd 		for (fp = start + nfiles - 1; fp >= start; --fp)
    239       1.1      cgd 			if (ino == fp->inode && dev == fp->dev)
    240       1.9    glass 				return (1);
    241       1.1      cgd 
    242       1.4  mycroft 	if (nfiles == maxfiles && (files = realloc((char *)files,
    243       1.4  mycroft 	    (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
    244      1.12    lukem 		err(1, "realloc");
    245       1.1      cgd 	files[nfiles].inode = ino;
    246       1.1      cgd 	files[nfiles].dev = dev;
    247       1.1      cgd 	++nfiles;
    248       1.9    glass 	return (0);
    249       1.1      cgd }
    250       1.1      cgd 
    251       1.4  mycroft void
    252       1.1      cgd usage()
    253       1.1      cgd {
    254       1.9    glass 
    255       1.9    glass 	(void)fprintf(stderr,
    256      1.16  hubertf 		"usage: du [-H | -L | -P] [-a | -s] [-ckmrx] [file ...]\n");
    257       1.4  mycroft 	exit(1);
    258       1.1      cgd }
    259