Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

339 lines
6.9 KiB
C

static char sccsid[] = "@(#)90 1.32 src/bos/usr/bin/du/du.c, cmdfiles, bos412, 9446C 11/14/94 16:45:56";
/*
* COMPONENT_NAME: (CMDFILES) commands that manipulate files
*
* FUNCTIONS: du
*
* ORIGINS: 3, 27, 71
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* (c) Copyright 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*
* OSF/1 1.1
*
* du -- summarize disk usage
* du [-a | -s] [-rlkx] [name ...]
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <dirent.h>
#ifndef NAME_MAX
#define NAME_MAX MAXNAMLEN
#endif
/* return the number of DEV_BSIZE sized blocks */
#define UBLOCKS(n) (n.st_blocks)
/* DEV_BSIZE is always 512 for AIX 3.2/4.1, however, prepare for */
/* different DEV_BSIZE values. */
#if DEV_BSIZE == 512
#define OUTPUT_BLOCKS(n) (kflag ? (n+1) >> 1 : n)
#else
#define OUTPUT_BLOCKS(n) ((n*DEV_BSIZE + block_size - 1 ) / block_size)
static int block_size = 512; /* default block size is 512 bytes. */
/* if -k flag is specified, use 1024 */
#endif
#include <locale.h>
#include <nl_types.h>
#include "du_msg.h"
static nl_catd catd;
#define MSGSTR(Num,Str) catgets(catd,MS_DU,Num,Str)
static char path[PATH_MAX];
#define EQ(x,y) (strcmp(x,y)==0)
#define ISDIR() ((Statb.st_mode&S_IFMT)==S_IFDIR)
#define ML 2000
struct ml {
struct ml *next;
dev_t dev[ML];
ino_t ino[ML];
};
static struct ml *curptr; /* pointer to current structure */
static struct ml firststrct; /* first structure */
static int linkc;
static struct stat Statb;
static dev_t current_device; /* current device of file system for -x flag use */
static int errcode;
static char aflag = 0;
static char sflag = 0;
static char lflag = 0;
static char xflag = 0;
static char kflag = 0;
static char nodotdot[] = "du: fatal error - can't cd to .. (%s)\n";
static long descend();
main(argc, argv)
int argc;
char **argv;
{
long blocks = 0;
char userdir[PATH_MAX+2];
struct ml *p, *tmpp;
int c;
(void) setlocale (LC_ALL,"");
catd = catopen((char *)MF_DU, NL_CAT_LOCALE);
while((c=getopt(argc, argv, "arslkx")) != EOF)
switch(c) {
case 'a':
aflag++;
continue;
case 'r':
continue;
case 's':
sflag++;
continue;
case 'l':
lflag++;
continue;
case 'k':
kflag++;
#if DEV_BSIZE != 512
block_size = 1024;
#endif
continue;
case 'x':
xflag++;
continue;
default:
fprintf(stderr,MSGSTR(USAGE,"Usage: du [-a | -s] [-rlkx] [name ...]\n"));
exit(2);
}
if (aflag && sflag) {
fprintf(stderr,MSGSTR(USAGE,"Usage: du [-a | -s] [-rlkx] [name ...]\n"));
exit(2);
}
argv = &argv[optind-1];
argc -= optind;
if(argc == 0) {
argc = 1;
argv[1] = ".";
}
if ((char *)getcwd(userdir,PATH_MAX+2) == NULL) {
fprintf(stderr,MSGSTR(CANTFIND,"du: can't find current directory\n"));
exit(2);
}
curptr = &firststrct;
curptr->next = NULL;
while(argc--) {
int len;
linkc = 0;
if ((len = strlen(*++argv)) >= sizeof(path)) {
fprintf(stderr,MSGSTR(NAMETOOLONG,"du: %s: name too long\n"), *argv);
continue;
}
strcpy(path, *argv);
if(lstat(path,&Statb)<0) {
error(path);
continue;
}
if (!ISDIR()) {
blocks = UBLOCKS(Statb);
if(Statb.st_nlink > 1) {
if (lflag) {
blocks += Statb.st_nlink - 1;
blocks /= Statb.st_nlink;
}
}
printf("%ld\t%s\n",OUTPUT_BLOCKS(blocks),path);
continue;
}
if (chdir(path) < 0) {
error(path);
continue;
}
current_device = Statb.st_dev;
blocks = descend(path + len);
curptr = &firststrct;
if(sflag)
printf("%ld\t%s\n", OUTPUT_BLOCKS(blocks), path);
if (chdir(userdir)) {
error(userdir);
exit(2);
}
}
exit(errcode ? 2 : 0);
}
/* On entry, endofname points to the NUL at the end of path and
* Statb contains a stat of the file whose full name is in path.
* If path is a directory, it is the working directory.
*/
static long
descend(endofname)
char *endofname;
{
register struct dirent *dp;
register char *c1, *c2;
long blocks = 0;
struct dirent dentry;
struct ml *p;
DIR *dir = NULL; /* open directory */
long offset = 0;
int i, count;
if (xflag && Statb.st_dev != current_device)
return (0);
blocks = UBLOCKS(Statb);
if (!ISDIR()) {
if(Statb.st_nlink > 1) {
if (lflag) {
blocks += Statb.st_nlink - 1;
blocks /= Statb.st_nlink;
} else {
if (linkc == ML) {
if (curptr->next == NULL) {
p = curptr;
curptr = (struct ml *) malloc(sizeof(struct ml));
if (!curptr) {
perror("du");
exit(2);
}
p->next = curptr;
curptr->next = NULL;
} else curptr = curptr->next;
linkc = 0;
}
for (p=&firststrct;p!=curptr->next;p=p->next) {
count = p == curptr ? linkc : ML;
for(i = 0; i < count; ++i)
if(p->ino[i]==Statb.st_ino &&
p->dev[i]==Statb.st_dev)
return 0;
}
curptr->dev[linkc] = Statb.st_dev;
curptr->ino[linkc] = Statb.st_ino;
++linkc;
}
}
if(aflag)
printf("%ld\t%s\n", OUTPUT_BLOCKS(blocks), path);
return(blocks);
}
if (endofname + (NAME_MAX+1) >= &path[sizeof(path)]) {
fprintf(stderr,MSGSTR(TOODEEP,"du: %s: TOO DEEP!\n"), path);
errcode++;
return(blocks);
}
if ((dir=opendir(".")) == NULL) {
error(path);
return(0);
}
while ((dp=readdir(dir)) != NULL) {
if(dp->d_ino==0 || EQ(dp->d_name, ".") || EQ(dp->d_name, "..")
|| dp->d_name[0] == 0) /* ?? */
continue;
if(dir->dd_fd > 10) {
offset = telldir(dir);
/* save dp because closedir free's the storage */
bcopy(dp,&dentry,sizeof(dentry));
closedir(dir);
dp = &dentry;
dir = NULL;
}
/* each directory entry */
c1 = endofname;
*c1++ = '/';
c2 = c1;
c1 = strncpy(c1, dp->d_name, (size_t)NAME_MAX);
c1 += strlen(dp->d_name);
if(lstat(c2, &Statb) < 0) {
error(path);
return(0);
}
if (ISDIR()) {
if (chdir(c2)) {
error(path);
}
else {
blocks += descend(c1);
*endofname = '\0';
if (chdir("..")) {
fprintf(stderr,
MSGSTR(NODOTDOT,nodotdot), path);
exit(2);
}
}
}
else blocks += descend(c1);
if (dir == NULL) {
if ((dir=opendir(".")) == NULL) {
error(path);
return(0);
}
if (offset > 0)
seekdir(dir,offset);
}
} /* End of loop over entries in a directory */
if(dir != NULL)
closedir(dir);
*endofname = '\0';
if(!sflag)
printf("%ld\t%s\n", OUTPUT_BLOCKS(blocks), path);
return(blocks);
}
static
error(s)
char *s;
{
fputs("du: ",stderr);
errcode++;
perror(s);
}