/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* (C) COPYRIGHT International Business Machines Corp. 2002,2006 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ /*==================================================================== * * tsgetusage command: get a summary of each user's disk usage * * Syntax: tsgetusage [ options ] fsPath * * fsPath: the directory where the root of the filesystem is found. * *==================================================================*/ #include #include #include #include #include #include #include #include #include #include /* Define globals */ static int Verbose = 1; static int GroupStats = 0; static int DiskUsgFormat = 0; static char* ProgNameP = NULL; /* Define stat structure */ typedef struct uStat_struct { struct uStat_struct *nextP; unsigned int id; gpfs_off64_t blockCount; gpfs_off64_t inodeCount; } uStat; /* Define hash table for collecting stats */ static uStat **HashPP = NULL; static int HashSize = 1027; #define HASH(_id) (_id % HashSize) /* Print usage statement and exit. */ static void Usage() { fprintf(stderr, "Usage: %s [-g][-h][-q][-v][-u][-H hashTableSize] fsPath\n" "\twhere:\tfsPath\tpath to file system\n" "\t\t-u\toutputs data in diskusg format for acctdisk\n" "\t\t-g\tcollect stats for groups\n" "\t\t-H\tsets the hash table size (default %d)\n" "\t\t-h\tprints this message\n" "\t\t-q\toutputs only the resulting stats\n" "\t\t-v\tprint information about each file\n", ProgNameP, HashSize); fflush(stderr); exit(1); } /* Initialize hash table for collecting statistics */ static int InitHash() { int hashTableSize = HashSize * sizeof(uStat *); HashPP = (uStat **)malloc(hashTableSize); if (HashPP == NULL) { fprintf(stderr, "No space to allocate hash table (%d bytes)\n", hashTableSize); return ENOMEM; } memset(HashPP, '\0', hashTableSize); return 0; } /* Find and increment an user/group's stat entry. Create the entry, if it is not found. */ static int IncStats(unsigned int id, gpfs_off64_t nBlocks, gpfs_off64_t nInodes) { uStat *uP, *prevP; int hashVal; /* Locate stat entry in hash table */ prevP = NULL; hashVal = HASH(id); for (uP = HashPP[ hashVal ]; uP != NULL; uP = uP->nextP) { if (uP->id == id) { /* Entry found. Update its counters */ uP->blockCount += nBlocks; uP->inodeCount += nInodes; /* Move entry to head of hash list */ if (prevP != NULL) { prevP->nextP = uP->nextP; uP->nextP = HashPP[ hashVal ]; HashPP[ hashVal ] = uP; } return 0; } prevP = uP; } /* Entry not found. Create a new one. */ uP = (uStat *)malloc(sizeof(*uP)); if (uP == NULL) { fprintf(stderr, "No space to allocate stat entry (%d bytes)\n", sizeof(*uP)); return ENOMEM; } /* Initialize new entry & insert at head of hash list */ uP->id = id; uP->blockCount = nBlocks; uP->inodeCount = nInodes; uP->nextP = HashPP[ hashVal ]; HashPP[ hashVal ] = uP; return 0; } /* Traverse has table and print each entry */ static int PrintStats(const char* fsPathP) { int i; uStat *uP; char *nameP; struct group *grpP; struct passwd *usrP; if (Verbose > 0) { printf("%s statistics for file system %s:\n", (GroupStats != 0) ? "Group" : "User", fsPathP); printf("%10s %32s %12s %12s\n", (GroupStats != 0) ? "gid" : "uid", "name", "KB", "inodes"); } /* Traverse the hash table */ for (i = 0; i < HashSize; i++) { /* Traverse each hash list */ for (uP = HashPP[i]; uP != NULL; uP = uP->nextP) { /* Convert ids into readable names */ if (GroupStats != 0) { grpP = getgrgid((gid_t) uP->id); if (grpP == NULL) nameP = "n/a"; else nameP = grpP->gr_name; } else { usrP = getpwuid((uid_t) uP->id); if (usrP == NULL) nameP = "n/a"; else nameP = usrP->pw_name; } /* Print stats on stdout */ if (DiskUsgFormat) printf("%u\t%s\t%lld\n", uP->id, nameP, (uP->blockCount+1)/2); else printf("%10u %32s %12lld %12lld\n", uP->id, nameP, (uP->blockCount+1)/2, uP->inodeCount); } } if (Verbose > 0) printf("%s statistics for file system %s complete.\n", (GroupStats != 0) ? "Group" : "User", fsPathP); return 0; } /* Scan the file system to collect the requested stats */ int scanFileSystem(const char *fsPathP) { int rc = 0; gpfs_iscan_t *iscanP = NULL; gpfs_fssnap_handle_t *fsP = NULL; const gpfs_iattr_t *iattrP; gpfs_ino_t lastInodeNum = 0; gpfs_ino_t maxInodeNum; char modeBuf[32]; if (Verbose > 1) fprintf(stderr, "Scanning %s...\n", fsPathP); else if (Verbose > 0) printf("Scanning %s...\n", fsPathP); /* Open inode scan */ fsP = gpfs_get_fssnaphandle_by_path(fsPathP); if (fsP == NULL) { rc = errno; fprintf(stderr, "%s: gpfs_get_fssnaphandle_by_path(%s): %s\n", ProgNameP, fsPathP, strerror(rc)); goto done; } iscanP = gpfs_open_inodescan(fsP, NULL, &maxInodeNum); if (iscanP == NULL) { rc = errno; fprintf(stderr, "%s: gpfs_open_inodescan(%s): %s\n", ProgNameP, fsPathP, strerror(rc)); goto done; } /* Loop over inodes in the file system */ while (1) { rc = gpfs_next_inode(iscanP, maxInodeNum, &iattrP); if (rc != 0) { rc = errno; fprintf(stderr, "%s: gpfs_next_inode(%s,%d): %s\n", ProgNameP, fsPathP, lastInodeNum, strerror(rc)); goto done; } /* A null ptr indicates end of scan */ if (iattrP == NULL) break; /* Save inode number */ lastInodeNum = iattrP->ia_inode; /* Skip over deleted files. */ if (iattrP->ia_nlink == 0) continue; if (Verbose > 1) fprintf(stderr, "inode %9d uid %6d gid %6d bytes %10lld blks %10lld\n", iattrP->ia_inode, iattrP->ia_uid, iattrP->ia_gid, iattrP->ia_size, iattrP->ia_blocks); if (GroupStats != 0) rc = IncStats((unsigned int) iattrP->ia_gid, iattrP->ia_blocks, 1); else rc = IncStats((unsigned int) iattrP->ia_uid, iattrP->ia_blocks, 1); if (rc != 0) goto done; } done: if (iscanP != NULL) gpfs_close_inodescan(iscanP); if (fsP != NULL) gpfs_free_fssnaphandle(fsP); if (Verbose > 1) if (rc != 0) fprintf(stderr, "Scan %s complete: %s\n", fsPathP, strerror(rc)); else fprintf(stderr, "Scan %s complete\n", fsPathP); return rc; } /* main */ int main(int argc, char *argv[]) { int i, rc; const char* fsPathP; /* Save program name for usage statement */ ProgNameP = argv[0]; fsPathP = NULL; /* parse options */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-v") == 0) Verbose = 2; else if (strcmp(argv[i], "-q") == 0) Verbose = 0; else if (strcmp(argv[i], "-u") == 0) { DiskUsgFormat = 1; Verbose = 0; } else if (strcmp(argv[i], "-g") == 0) GroupStats = 1; else if (strcmp(argv[i], "-H") == 0) { i++; if (i < argc) { HashSize = atoi(argv[i]); if (HashSize <= 0) { fprintf(stderr, "%s: Invalid value for -H (%d)\n", ProgNameP, HashSize); exit(2); } } else { fprintf(stderr, "%s: Missing arg for -H\n", ProgNameP); Usage(); } } else if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-?") == 0)) Usage(); else if (fsPathP == NULL) fsPathP = argv[i]; else { fprintf(stderr, "%s: Unknown arg \"%s\"\n", ProgNameP, argv[i]); Usage(); } } if (fsPathP == NULL) { fprintf(stderr, "%s: Missing fsPath arg\n", ProgNameP); Usage(); } /* Initialize hash tables */ rc = InitHash(); if (rc != 0) goto done; /* Scan the file system to collect the requested stats */ rc = scanFileSystem(fsPathP); if (rc != 0) goto done; /* Display results */ rc = PrintStats(fsPathP); done: return rc; }