du.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* du -- summarize disk usage
*/
#include <fcntl.h>
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <libcmdutils.h>
static int aflg = 0;
static int rflg = 0;
static int sflg = 0;
static int kflg = 0;
static int oflg = 0;
static int dflg = 0;
static int hflg = 0;
static int Hflg = 0;
static int Lflg = 0;
static int cmdarg = 0; /* Command line argument */
static char *dot = ".";
static int level = 0; /* Level of recursion */
static char *base;
static char *name;
#define NUMBER_WIDTH 64
typedef char numbuf_t[NUMBER_WIDTH];
/*
* convert DEV_BSIZE blocks to K blocks
*/
#define DEV_BSIZE 512
#define DEV_KSHIFT 1
long wait();
int
{
int c;
extern int optind;
char *np;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
#ifdef XPG4
rflg++; /* "-r" is not an option but ON always */
#endif
#ifdef XPG4
#else
#endif
switch (c) {
case 'a':
aflg++;
continue;
case 'h':
hflg++;
continue;
case 'r':
rflg++;
continue;
case 's':
sflg++;
continue;
case 'k':
kflg++;
continue;
case 'o':
oflg++;
continue;
case 'd':
dflg++;
continue;
case 'x':
dflg++;
continue;
case 'H':
Hflg++;
/* -H and -L are mutually exclusive */
Lflg = 0;
cmdarg++;
continue;
case 'L':
Lflg++;
/* -H and -L are mutually exclusive */
Hflg = 0;
cmdarg = 0;
continue;
#ifdef XPG4
case '?':
"usage: du [-a] [-h|-k] [-r] [-s] [-x] [-H|-L]"
" [file ...]\n"));
exit(2);
#else
case '?':
"usage: du [-a] [-d] [-h|-k] [-r] [-o|-s] [-H|-L]"
" [file ...]\n"));
exit(2);
#endif
}
argc = 1;
optind = 0;
}
/* "-o" and "-s" don't make any sense together. */
oflg = 0;
perror("du");
exit(1);
}
perror("du");
exit(1);
}
do {
exitdu(1);
}
if (pid != 0) {
;
retcode = 1;
}
}
sizeof (char))) == NULL) {
if (rflg) {
"du: can't process %s"),
perror("");
}
exitdu(1);
}
}
sizeof (char))) == NULL) {
if (rflg) {
"du: can't process %s"),
perror("");
}
exitdu(1);
}
}
*np++ = '\0';
if (rflg) {
exitdu(1);
}
exitdu(0);
}
} else
(dev_t)0);
if (sflg)
}
optind++;
return (retcode);
}
/*
* descend recursively, adding up the allocated blocks.
* If curname is NULL, curfd is used.
*/
static u_longlong_t
{
ebase--;
if (curname)
/*
* If neither a -L or a -H was specified, don't follow symlinks.
* If a -H was specified, don't follow symlinks if the file is
* not a command line argument.
*/
j = 0;
} else {
/*
* Make sure any files encountered while traversing the
* hierarchy are not considered command line arguments.
*/
if (Hflg) {
cmdarg = 0;
}
}
if ((i < 0) || (j < 0)) {
if (rflg) {
}
/*
* POSIX states that non-zero status codes are only set
* when an error message is printed out on stderr
*/
*ebase0 = 0;
return (0);
}
if (device) {
*ebase0 = 0;
return (0);
}
}
else
/*
* If following links (-L) we need to keep track of all inodes
* are avoided. Otherwise, only keep track of files which are
* hard links so they only get reported once, and of directories
* so we don't report a directory and its hierarchy more than
* once in the special case in which it lies under the
* hierarchy of a directory which is a hard link.
* Note: Files with multiple links should only be counted
* once. Since each inode could possibly be referenced by a
* symbolic link, we need to keep track of all inodes when -L
* is specified.
*/
int rc;
if (rc == 0) {
/*
* This hierarchy, or file with multiple
*/
return (0);
} else {
/*
* An error occurred while trying to add the
* node to the tree.
*/
if (rflg) {
perror("du");
}
exitdu(1);
}
}
}
/*
* If there are extended attributes on the current file, add their
* block usage onto the block count.
*/
if (rflg)
"du: can't access extended attributes"));
}
else
{
sflg = 1;
}
}
/*
* Don't print twice: if sflg, file will get printed in main().
* Otherwise, level == 0 means this file is listed on the
* command line, so print here; aflg means print all files.
*/
return (blocks);
}
/*
* Close the parent directory descriptor, we will reopen
* the directory when we pop up from this level of the
* recursion.
*/
else
if (rflg) {
}
*retcode = 1;
*ebase0 = 0;
return (0);
}
level++;
if (rflg) {
}
exitdu(1);
}
}
if (rflg) {
}
*retcode = 1;
*ebase0 = 0;
level--;
return (0);
}
continue;
/*
* we're about to append "/" + dp->d_name
* onto end of base; make sure there's enough
* space
*/
if (rflg) {
perror("du");
}
exitdu(1);
}
}
/* LINTED - unbounded string specifier */
/* base may have been moved via realloc in descend() */
*ebase = 0;
if (rflg) {
gettext("du: Can't reopen in "));
}
*retcode = 1;
level--;
return (0);
}
}
}
level--;
if (sflg == 0)
else
if (ret < 0) {
if (rflg) {
gettext("du: Can't change dir to '..' in "));
}
exitdu(1);
}
*ebase0 = 0;
if (oflg)
return (0);
else
return (blocks);
}
/*
* Convert an unsigned long long to a string representation and place the
* result in the caller-supplied buffer.
* The given number is in units of "unit_from" size,
* this will first be converted to a number in 1024 or 1000 byte size,
* depending on the scaling factor.
* Then the number is scaled down until it is small enough to be in a good
* human readable format i.e. in the range 0 thru scale-1.
* If it's smaller than 10 there's room enough to provide one decimal place.
* The value "(unsigned long long)-1" is a special case and is always
* converted to "-1".
* Returns a pointer to the caller-supplied buffer.
*/
static char *
unsigned long long number, /* convert this number */
unsigned long long unit_from, /* number of bytes per input unit */
unsigned long long scale) /* 1024 (-h) or 1000 (-H) */
{
unsigned long long save = 0;
char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */
char *uom = M; /* unit of measurement, initially 'K' (=M[0]) */
if ((long long)number == (long long)-1) {
return (buf);
}
/*
* Convert number from unit_from to given scale (1024 or 1000)
* This means multiply number with unit_from and divide by scale.
* if number is large enough, we first divide and then multiply
* to avoid an overflow
* (large enough here means 100 (rather arbitrary value)
* times scale in order to reduce rounding errors)
* otherwise, we first multiply and then divide
* to avoid an underflow
*/
} else {
}
/*
* Now we have number as a count of scale units.
* Stop scaling when we reached exa bytes, then something is
* probably wrong with our number.
*/
uom++; /* next unit of measurement */
}
/* check if we should output a decimal place after the point */
/* sprintf() will round for us */
} else {
}
return (buf);
}
static void
{
if (hflg) {
unsigned long long scale = 1024L;
#ifdef XPG4
(void) printf("%s %s\n",
path);
#else
(void) printf("%s\t%s\n",
path);
#endif
} else if (kflg) {
#ifdef XPG4
#else
#endif
} else {
#ifdef XPG4
#else
#endif
}
}
static void
{
}