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