446 lines
8.6 KiB
C
446 lines
8.6 KiB
C
/* Copyright (c) 1984 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "$Revision: 1.15 $"
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/syssgi.h>
|
|
#include <sys/fs/efs.h>
|
|
#include <sys/fs/xfs_itable.h>
|
|
#include <pwd.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <diskinfo.h>
|
|
#include "acctdef.h"
|
|
|
|
#define UNUSED -1
|
|
#define FAIL -1
|
|
#define MAXNAME 8
|
|
#define SUCCEED 0
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
union sblock {
|
|
struct efs fs ;
|
|
char data[BBTOB(BTOBB(sizeof(struct efs)))] ;
|
|
} sblock ;
|
|
|
|
struct efs *fs ; /* pointer to sblock.fs */
|
|
|
|
struct efs_dinode *dinode;
|
|
|
|
int VERBOSE = 0;
|
|
FILE *ufd = 0;
|
|
extern int _pw_stayopen;
|
|
unsigned nfiles;
|
|
ino_t ino ;
|
|
|
|
struct dacct {
|
|
long long usage; /* daveh note 2 Jul 91: now BBs */
|
|
int uid;
|
|
char name[MAXNAME+1];
|
|
};
|
|
struct dacct *userlist;
|
|
int maxusers;
|
|
|
|
char **ignlist;
|
|
int maxign;
|
|
int igncnt = {0}; /* why makes it part of .data? */
|
|
|
|
char *cmd;
|
|
|
|
|
|
void adduser(FILE *);
|
|
void bread(int, unsigned, union sblock *, int);
|
|
int count(void);
|
|
struct efs_dinode *efs_iget(int, ino_t);
|
|
void error(void);
|
|
unsigned hash(unsigned);
|
|
void hashinit(void);
|
|
void ignore(char *);
|
|
void ilist(char *, int);
|
|
void output(void);
|
|
void setup(char *);
|
|
char *skip(char *);
|
|
int todo(char *);
|
|
int xfs_count(xfs_bstat_t *);
|
|
void xfs_ilist(char *file, int fd);
|
|
|
|
main(int argc, char **argv)
|
|
{
|
|
extern int optind;
|
|
extern char *optarg;
|
|
register c;
|
|
register FILE *fd;
|
|
register rfd;
|
|
struct stat sb;
|
|
int sflg = {FALSE};
|
|
char *pfile = {"/etc/passwd"};
|
|
int errfl = {FALSE};
|
|
char *str;
|
|
|
|
/* allocate memory for userlist */
|
|
str = getenv(ACCT_MAXUSERS);
|
|
if (str == NULL)
|
|
maxusers = MAXUSERS;
|
|
else {
|
|
maxusers = strtol(str, (char **)0, 0);
|
|
if (errno == ERANGE || maxusers < MAXUSERS)
|
|
maxusers = MAXUSERS;
|
|
}
|
|
userlist = (struct dacct *)calloc(maxusers, sizeof(struct dacct));
|
|
if (userlist == (struct dacct *)NULL) {
|
|
fprintf(stderr, "%s: Cannot allocate memory\n", argv[0]);
|
|
exit(5);
|
|
}
|
|
/* allocate memory for ignore list */
|
|
str = getenv(ACCT_MAXIGN);
|
|
if (str == NULL)
|
|
maxign = MAXIGN;
|
|
else {
|
|
maxign = strtol(str, (char **)0, 0);
|
|
if (errno == ERANGE || maxign < MAXIGN)
|
|
maxign = MAXIGN;
|
|
}
|
|
ignlist = (char **)calloc(maxign, sizeof(char *));
|
|
if (ignlist == (char **)NULL) {
|
|
fprintf(stderr, "%s: Cannot allocate memory\n", argv[0]);
|
|
exit(5);
|
|
}
|
|
|
|
cmd = argv[0];
|
|
while((c = getopt(argc, argv, "vu:p:si:")) != EOF) switch(c) {
|
|
case 's':
|
|
sflg = TRUE;
|
|
break;
|
|
case 'v':
|
|
VERBOSE = 1;
|
|
break;
|
|
case 'i':
|
|
ignore(optarg);
|
|
break;
|
|
case 'u':
|
|
ufd = fopen(optarg, "a");
|
|
break;
|
|
case '?':
|
|
errfl++;
|
|
break;
|
|
}
|
|
if(errfl) {
|
|
fprintf(stderr, "Usage: %s [-sv] [-u file] [-i ignlist] [file ...]\n", cmd);
|
|
exit(10);
|
|
}
|
|
|
|
hashinit();
|
|
if(sflg == TRUE) {
|
|
if(optind == argc){
|
|
adduser(stdin);
|
|
} else {
|
|
for( ; optind < argc; optind++) {
|
|
if( (fd = fopen(argv[optind], "r")) == NULL) {
|
|
fprintf(stderr, "%s: Cannot open %s\n", cmd, argv[optind]);
|
|
continue;
|
|
}
|
|
adduser(fd);
|
|
fclose(fd);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
setup(pfile);
|
|
for( ; optind < argc; optind++) {
|
|
if( (rfd = open(argv[optind], O_RDONLY)) < 0) {
|
|
fprintf(stderr, "%s: Cannot open %s\n", cmd, argv[optind]);
|
|
continue;
|
|
}
|
|
if(fstat(rfd, &sb) >= 0){
|
|
if ( (sb.st_mode & S_IFMT) == S_IFCHR ||
|
|
(sb.st_mode & S_IFMT) == S_IFBLK ) {
|
|
ilist(argv[optind], rfd);
|
|
} else {
|
|
fprintf(stderr, "%s: %s is not a special file -- ignored\n", cmd, argv[optind]);
|
|
}
|
|
} else {
|
|
fprintf(stderr, "%s: Cannot stat %s\n", cmd, argv[optind]);
|
|
}
|
|
close(rfd);
|
|
}
|
|
}
|
|
output();
|
|
exit(0);
|
|
}
|
|
|
|
void
|
|
adduser(FILE *fd)
|
|
{
|
|
int usrid, index;
|
|
long long blcks;
|
|
char login[MAXNAME+10];
|
|
|
|
while(fscanf(fd, "%d %s %lld\n", &usrid, login, &blcks) == 3) {
|
|
if( (index = hash(usrid)) == FAIL) return;
|
|
if(userlist[index].uid == UNUSED) {
|
|
userlist[index].uid = usrid;
|
|
strncpy(userlist[index].name, login, MAXNAME);
|
|
}
|
|
userlist[index].usage += blcks;
|
|
}
|
|
}
|
|
|
|
void
|
|
ilist(char *file, int fd)
|
|
{
|
|
register dev_t dev;
|
|
register i, j;
|
|
char *rawpath;
|
|
int rawfd = 0;
|
|
|
|
struct efs_dinode *efs_iget() ;
|
|
|
|
if (fd < 0 ) {
|
|
return;
|
|
}
|
|
|
|
/* sync(); daveh 2/7/91: irrelevent due to mounted fs -> char dev hack */
|
|
|
|
/* Read in super-block of filesystem */
|
|
bread(fd, 1, &sblock, sizeof(sblock) );
|
|
|
|
fs = &sblock.fs ;
|
|
|
|
/* daveh 2 7 91: a *little* sanity chacking, for God's sake... */
|
|
|
|
if (!IS_EFS_MAGIC(fs->fs_magic)) {
|
|
xfs_ilist(file, fd);
|
|
return;
|
|
}
|
|
fs->fs_ipcg = EFS_COMPUTE_IPCG(fs);
|
|
|
|
/* Check for filesystem names to ignore */
|
|
if(!todo(fs->fs_fname))
|
|
return;
|
|
|
|
if ((rawpath = findrawpath(file)) == NULL)
|
|
return;
|
|
|
|
if ((rawfd = open(rawpath, O_RDONLY)) < 0)
|
|
return;
|
|
|
|
nfiles = (fs->fs_cgisize * EFS_INOPBB) * fs->fs_ncg ;
|
|
|
|
/* Start at physical block 2, inode list */
|
|
for (ino = 2; ino < nfiles; ino++ ) {
|
|
dinode = efs_iget(rawfd, ino ) ;
|
|
if (dinode->di_mode & S_IFMT) {
|
|
if(count() == FAIL) {
|
|
if(VERBOSE)
|
|
fprintf(stderr,"BAD UID: file system = %s, inode = %u, uid = %u\n",
|
|
file, ino, dinode->di_uid);
|
|
if(ufd)
|
|
fprintf(ufd, "%s %u %u\n", file, ino, dinode->di_uid);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
ignore(char *str)
|
|
{
|
|
char *skip();
|
|
|
|
for( ; *str && igncnt < maxign; str = skip(str), igncnt++)
|
|
ignlist[igncnt] = str;
|
|
if(igncnt == maxign) {
|
|
fprintf(stderr, "%s: ignore list overflow. Increase the size of the environment variable ACCT_MAXIGN\n", cmd);
|
|
}
|
|
}
|
|
|
|
/* daveh 2/7/91: now uses readb for fs > 2 gig */
|
|
|
|
struct efs_dinode *
|
|
efs_iget(int rawfd, ino_t ino)
|
|
{
|
|
int inobb;
|
|
static struct efs_dinode inos[EFS_INOPBB];
|
|
|
|
if ( (ino % EFS_INOPBB) != 0 ) {
|
|
return &inos[ino % EFS_INOPBB];
|
|
}
|
|
|
|
inobb = EFS_ITOBB(fs, ino);
|
|
if (readb(rawfd, (char *) &inos[0], inobb, 1) != 1)
|
|
error();
|
|
return &inos[ino % EFS_INOPBB];
|
|
}
|
|
|
|
void
|
|
bread(int fd, unsigned bno, union sblock *buf, int cnt)
|
|
{
|
|
int debug ;
|
|
|
|
lseek(fd, BBTOB(bno), 0);
|
|
if ((debug=read(fd, buf, cnt) ) != cnt)
|
|
{
|
|
fprintf(stderr, "read error %u %d %d\n", bno,debug,cnt);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
int
|
|
count(void)
|
|
{
|
|
int index;
|
|
|
|
if ( dinode->di_nlink == 0 || dinode->di_mode == 0 )
|
|
return(SUCCEED);
|
|
if( (index = hash(dinode->di_uid)) == FAIL || userlist[index].uid == UNUSED )
|
|
return (FAIL);
|
|
userlist[index].usage += ((dinode->di_size + BBSIZE - 1) / BBSIZE);
|
|
return (SUCCEED);
|
|
}
|
|
|
|
void
|
|
output(void)
|
|
{
|
|
int index;
|
|
|
|
for (index=0; index < maxusers ; index++)
|
|
if ( userlist[index].uid != UNUSED && userlist[index].usage != 0 )
|
|
printf("%u %s %lld\n",
|
|
userlist[index].uid,
|
|
userlist[index].name,
|
|
userlist[index].usage);
|
|
}
|
|
|
|
unsigned
|
|
hash(unsigned j)
|
|
{
|
|
register unsigned start;
|
|
register unsigned circle;
|
|
circle = start = j % maxusers;
|
|
do
|
|
{
|
|
if ( userlist[circle].uid == j || userlist[circle].uid == UNUSED )
|
|
return (circle);
|
|
circle = (circle + 1) % maxusers;
|
|
} while ( circle != start);
|
|
return (FAIL);
|
|
}
|
|
|
|
void
|
|
hashinit(void)
|
|
{
|
|
int index;
|
|
|
|
for(index=0; index < maxusers ; index++)
|
|
{
|
|
userlist[index].uid = UNUSED;
|
|
userlist[index].usage = 0;
|
|
userlist[index].name[0] = '\0';
|
|
}
|
|
}
|
|
|
|
void
|
|
setup(char *pfile)
|
|
{
|
|
register struct passwd *pw;
|
|
int index;
|
|
|
|
_pw_stayopen = 1;
|
|
setpwent();
|
|
while ( (pw=getpwent()) != NULL )
|
|
{
|
|
if ( (index=hash(pw->pw_uid)) == FAIL )
|
|
{
|
|
fprintf(stderr,"diskacct: INCREASE THE VALUE OF THE ENVIRONMENT VARIABLE ACCT_MAXUSERS\n");
|
|
return;
|
|
}
|
|
if ( userlist[index].uid == UNUSED )
|
|
{
|
|
userlist[index].uid = pw->pw_uid;
|
|
strncpy( userlist[index].name, pw->pw_name, MAXNAME);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
todo(char *fname)
|
|
{
|
|
register i;
|
|
|
|
for(i = 0; i < igncnt; i++) {
|
|
if(strncmp(fname, ignlist[i], 6) == 0) return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
char *
|
|
skip(char *str)
|
|
{
|
|
while(*str) {
|
|
if(*str == ' ' ||
|
|
*str == ',') {
|
|
*str = '\0';
|
|
str++;
|
|
break;
|
|
}
|
|
str++;
|
|
}
|
|
return(str);
|
|
}
|
|
|
|
void
|
|
error(void)
|
|
{
|
|
fprintf(stderr, "%s: i/o error\n", cmd);
|
|
exit(-1);
|
|
}
|
|
|
|
void
|
|
xfs_ilist(char *file, int fd)
|
|
{
|
|
ino64_t last;
|
|
int index, i, c, n = 1000;
|
|
xfs_bstat_t *t;
|
|
|
|
t = malloc(n * sizeof(*t));
|
|
last = 0;
|
|
while (syssgi(SGI_FS_BULKSTAT, fd, &last, n, t, &c) == 0) {
|
|
if (c == 0)
|
|
break;
|
|
for (i = 0; i < c; i++) {
|
|
if (xfs_count(&t[i]) == FAIL) {
|
|
if(VERBOSE)
|
|
fprintf(stderr,"BAD UID: file system = %s, inode = %llu, uid = %u\n",
|
|
file, t[i].bs_ino, t[i].bs_uid);
|
|
if(ufd)
|
|
fprintf(ufd, "%s %llu %u\n",
|
|
file, t[i].bs_ino, t[i].bs_uid);
|
|
}
|
|
}
|
|
}
|
|
free(t);
|
|
}
|
|
|
|
int
|
|
xfs_count(xfs_bstat_t *tp)
|
|
{
|
|
int index;
|
|
|
|
if( (index = hash(tp->bs_uid)) == FAIL || userlist[index].uid == UNUSED )
|
|
return (FAIL);
|
|
userlist[index].usage += (tp->bs_blocks * tp->bs_blksize) / BBSIZE;
|
|
return (SUCCEED);
|
|
}
|