Home | History | Annotate | Download | only in acct
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     23 /*	  All Rights Reserved  	*/
     24 
     25 /*
     26  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
     27  * Use is subject to license terms.
     28  */
     29 
     30 
     31 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.8	*/
     32 /*
     33  *	acctdusg [-u file] [-p file] > dtmp-file
     34  *	-u	file for names of files not charged to anyone
     35  *	-p	get password info from file
     36  *	reads std input (normally from find / -print)
     37  *	and computes disk resource consumption by login
     38  */
     39 #include <stdio.h>
     40 #include <sys/types.h>
     41 #include <sys/stat.h>
     42 #include <pwd.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <limits.h>
     46 #include <libcmdutils.h>
     47 
     48 #include "acctdef.h"
     49 
     50 struct	disk {
     51 	struct disk *next;		/* next entry at same hash tbl index */
     52 	uid_t	dsk_uid;		/* user id of login name */
     53 	blkcnt_t	dsk_du;		/* disk usage */
     54 	char	dsk_name[NSZ+1];	/* login name */
     55 	char	validuser;		/* set if the uid exists */
     56 };
     57 
     58 static char	*pfile = NULL;
     59 static FILE	*nchrg = NULL;
     60 static avl_tree_t	*tree = NULL;
     61 
     62 static struct disk *usglist[MAXUSERS];  /* holds data on disk usg by uid */
     63 #define	HASHKEY(x)	((int)((unsigned int)(x) % MAXUSERS))
     64 
     65 static struct disk *hash_insert(uid_t);
     66 static struct disk *hash_find(uid_t);
     67 static void openerr(char *);
     68 static void output(void);
     69 static void validate_entry(struct disk *, struct passwd *);
     70 static void charge(char *);
     71 #ifdef DEBUG
     72 static void pdisk(void);
     73 #endif
     74 
     75 int
     76 main(int argc, char **argv)
     77 {
     78 	char	fbuf[PATH_MAX+1], *fb;
     79 	FILE	*pwf;
     80 	int	c;
     81 	struct passwd	*pw;
     82 	struct disk	*entry;
     83 
     84 	while ((c = getopt(argc, argv, "p:u:")) != EOF) {
     85 		switch (c) {
     86 		case 'u':
     87 			if ((nchrg = fopen(optarg, "w")) == NULL)
     88 				openerr(optarg);
     89 			(void) chmod(optarg, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
     90 			break;
     91 		case 'p':
     92 			pfile = optarg;
     93 			break;
     94 		default:
     95 			exit(1);
     96 		}
     97 	}
     98 
     99 	if (pfile) {
    100 		if ((pwf = fopen(pfile, "r")) == NULL) {
    101 			openerr(pfile);
    102 		}
    103 		/* fill usglist with the user's in the passwd file */
    104 		while ((pw = fgetpwent(pwf)) != NULL) {
    105 			if ((entry = hash_find(pw->pw_uid)) == NULL)
    106 				entry = hash_insert(pw->pw_uid);
    107 			validate_entry(entry, pw);
    108 		}
    109 		(void) fclose(pwf);
    110 	}
    111 
    112 	/* charge the files listed in names to users listed in the usglist */
    113 	while (fgets(fbuf, sizeof (fbuf), stdin) != NULL) {
    114 		if ((fb = strchr(fbuf, '\n')) != NULL) {
    115 			/*
    116 			 * replace the newline char at the end of the
    117 			 * filename with a null character
    118 			 */
    119 			*fb = '\0';
    120 		}
    121 		charge(fbuf);
    122 	}
    123 
    124 	output();
    125 
    126 	if (nchrg)
    127 		(void) fclose(nchrg);
    128 #ifdef DEBUG
    129 	pdisk();
    130 #endif
    131 	return (0);
    132 }
    133 
    134 /*
    135  * create a new entry and insert.
    136  */
    137 static struct disk *
    138 hash_insert(uid_t uid)
    139 {
    140 	struct disk *curdisk;
    141 	int key = HASHKEY(uid);
    142 
    143 	if ((curdisk = malloc(sizeof (struct disk))) == NULL) {
    144 		(void) fprintf(stderr, "acctdusg:  cannot allocate memory "
    145 			"for hash table entry\n");
    146 		exit(1);
    147 	}
    148 	curdisk->dsk_uid = uid;
    149 	curdisk->dsk_du = 0;
    150 	curdisk->validuser = 0;	/* initially invalid */
    151 	curdisk->next = usglist[key];
    152 	usglist[key] = curdisk;
    153 	return (curdisk);
    154 }
    155 
    156 /*
    157  * return the disk entry for given uid. return NULL if not found.
    158  */
    159 static struct disk *
    160 hash_find(uid_t uid)
    161 {
    162 	struct disk *curdisk;
    163 
    164 	for (curdisk = usglist[HASHKEY(uid)];
    165 	    curdisk != NULL; curdisk = curdisk->next) {
    166 		if (curdisk->dsk_uid == uid) {
    167 			return (curdisk);
    168 		}
    169 	}
    170 	return (NULL);
    171 }
    172 
    173 static void
    174 openerr(char *file)
    175 {
    176 	(void) fprintf(stderr, "Cannot open %s\n", file);
    177 	exit(1);
    178 }
    179 
    180 static void
    181 output(void)
    182 {
    183 	int	index;
    184 	struct disk *entry;
    185 
    186 	for (index = 0; index < MAXUSERS; index++) {
    187 		for (entry = usglist[index];
    188 		    entry != NULL; entry = entry->next) {
    189 			if (entry->dsk_du != 0) {
    190 				(void) printf("%ld\t%s\t%lld\n",
    191 				    entry->dsk_uid,
    192 				    entry->dsk_name,
    193 				    entry->dsk_du);
    194 			}
    195 		}
    196 	}
    197 }
    198 
    199 /*
    200  * Initialize the disk entry for a valid passwd entry.
    201  */
    202 static void
    203 validate_entry(struct disk *entry, struct passwd *pw)
    204 {
    205 	(void) strlcpy(entry->dsk_name, pw->pw_name,
    206 		sizeof (entry->dsk_name));
    207 	entry->validuser = 1;
    208 }
    209 
    210 static void
    211 charge(char *n)
    212 {
    213 	struct stat	statb;
    214 	struct disk	*entry;
    215 	struct passwd	*pw;
    216 
    217 	if (lstat(n, &statb) == -1)
    218 		return;
    219 
    220 	/*
    221 	 * do not count the duplicate entries.
    222 	 */
    223 	if (statb.st_nlink > 1) {
    224 		switch (add_tnode(&tree, statb.st_dev, statb.st_ino)) {
    225 		case 0:
    226 			/* already exist */
    227 			return;
    228 		case 1:
    229 			/* added */
    230 			break;
    231 		default:
    232 			perror("acctdusg");
    233 			exit(1);
    234 		}
    235 	}
    236 
    237 	/*
    238 	 * st_blocks is not defined for character/block special files.
    239 	 */
    240 	if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode))
    241 		statb.st_blocks = 0;
    242 
    243 	/*
    244 	 * If -p is given, we've all loaded the passwd entries.
    245 	 * Files with unknown uid should go into nchrg. Otherwise
    246 	 * (without -p), we try creating new entry for the uid.
    247 	 */
    248 	if ((entry = hash_find(statb.st_uid)) == NULL) {
    249 		if (pfile == NULL) {
    250 			pw = getpwuid(statb.st_uid);
    251 			entry = hash_insert(statb.st_uid);
    252 			if (pw != NULL) {
    253 				validate_entry(entry, pw);
    254 			}
    255 		}
    256 	}
    257 
    258 	if (entry != NULL && entry->validuser) {
    259 		entry->dsk_du += statb.st_blocks;
    260 	} else if (nchrg) {
    261 		(void) fprintf(nchrg, "%9ld\t%7llu\t%s\n",
    262 			statb.st_uid, statb.st_blocks, n);
    263 	}
    264 }
    265 
    266 #ifdef DEBUG
    267 static void
    268 pdisk()
    269 {
    270 	int	index;
    271 	struct disk *entry;
    272 
    273 	for (index = 0; index < MAXUSERS; index++) {
    274 		for (entry = usglist[index];
    275 		    entry != NULL; entry = entry->next) {
    276 			(void) fprintf(stderr,  "%.8s\t%9ld\t%7llu\n",
    277 			    entry->dsk_name,
    278 			    entry->dsk_uid,
    279 			    entry->dsk_du);
    280 		}
    281 	}
    282 
    283 }
    284 #endif
    285