1 /* 2 * Copyright (c) 1980, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Robert Elz at The University of Melbourne. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)repquota.c 5.10 (Berkeley) 06/01/90"; 19 #endif /* not lint */ 20 21 /* 22 * Quota report 23 */ 24 #include <sys/param.h> 25 #include <sys/stat.h> 26 #include <ufs/quota.h> 27 #include <fstab.h> 28 #include <pwd.h> 29 #include <grp.h> 30 #include <stdio.h> 31 #include <errno.h> 32 33 struct fileusage { 34 struct fileusage *fu_next; 35 struct dqblk fu_dqblk; 36 u_long fu_id; 37 char fu_name[1]; 38 /* actually bigger */ 39 }; 40 #define FUHASH 1024 /* must be power of two */ 41 struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 42 struct fileusage *lookup(); 43 struct fileusage *addid(); 44 u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 45 46 int vflag; /* verbose */ 47 int aflag; /* all file systems */ 48 49 main(argc, argv) 50 int argc; 51 char **argv; 52 { 53 register struct fstab *fs; 54 register struct passwd *pw; 55 register struct group *gr; 56 int gflag = 0, uflag = 0, errs = 0; 57 long i, argnum, done = 0; 58 extern char *optarg; 59 extern int optind; 60 char ch, *qfnp; 61 62 while ((ch = getopt(argc, argv, "aguv")) != EOF) { 63 switch(ch) { 64 case 'a': 65 aflag++; 66 break; 67 case 'g': 68 gflag++; 69 break; 70 case 'u': 71 uflag++; 72 break; 73 case 'v': 74 vflag++; 75 break; 76 default: 77 usage(); 78 } 79 } 80 argc -= optind; 81 argv += optind; 82 if (argc == 0 && !aflag) 83 usage(); 84 if (!gflag && !uflag) { 85 if (aflag) 86 gflag++; 87 uflag++; 88 } 89 if (gflag) { 90 setgrent(); 91 while ((gr = getgrent()) != 0) 92 (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 93 endgrent(); 94 } 95 if (uflag) { 96 setpwent(); 97 while ((pw = getpwent()) != 0) 98 (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 99 endpwent(); 100 } 101 setfsent(); 102 while ((fs = getfsent()) != NULL) { 103 if (strcmp(fs->fs_vfstype, "ufs")) 104 continue; 105 if (aflag) { 106 if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) 107 errs += repquota(fs, GRPQUOTA, qfnp); 108 if (uflag && hasquota(fs, USRQUOTA, &qfnp)) 109 errs += repquota(fs, USRQUOTA, qfnp); 110 continue; 111 } 112 if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 113 (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { 114 done |= 1 << argnum; 115 if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) 116 errs += repquota(fs, GRPQUOTA, qfnp); 117 if (uflag && hasquota(fs, USRQUOTA, &qfnp)) 118 errs += repquota(fs, USRQUOTA, qfnp); 119 } 120 } 121 endfsent(); 122 for (i = 0; i < argc; i++) 123 if ((done & (1 << i)) == 0) 124 fprintf(stderr, "%s not found in fstab\n", argv[i]); 125 exit(errs); 126 } 127 128 usage() 129 { 130 fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 131 "repquota [-v] [-g] [-u] -a", 132 "repquota [-v] [-g] [-u] filesys ..."); 133 exit(1); 134 } 135 136 repquota(fs, type, qfpathname) 137 register struct fstab *fs; 138 int type; 139 char *qfpathname; 140 { 141 register struct fileusage *fup; 142 FILE *qf; 143 u_long id; 144 struct dqblk dqbuf; 145 char *timeprt(); 146 static struct dqblk zerodqblk; 147 static int warned = 0; 148 static int multiple = 0; 149 extern int errno; 150 151 if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 && 152 errno == EOPNOTSUPP && !warned && vflag) { 153 warned++; 154 fprintf(stdout, 155 "*** Warning: Quotas are not compiled into this kernel\n"); 156 } 157 if (multiple++) 158 printf("\n"); 159 if (vflag) 160 fprintf(stdout, "*** Report for %s quotas on %s (%s)\n", 161 qfextension[type], fs->fs_file, fs->fs_spec); 162 if ((qf = fopen(qfpathname, "r")) == NULL) { 163 perror(qfpathname); 164 return (1); 165 } 166 for (id = 0; ; id++) { 167 fread(&dqbuf, sizeof(struct dqblk), 1, qf); 168 if (feof(qf)) 169 break; 170 if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) 171 continue; 172 if ((fup = lookup(id, type)) == 0) 173 fup = addid(id, type, (char *)0); 174 fup->fu_dqblk = dqbuf; 175 } 176 fclose(qf); 177 printf(" Block limits File limits\n"); 178 printf("User used soft hard grace used soft hard grace\n"); 179 for (id = 0; id <= highid[type]; id++) { 180 fup = lookup(id, type); 181 if (fup == 0) 182 continue; 183 if (fup->fu_dqblk.dqb_curinodes == 0 && 184 fup->fu_dqblk.dqb_curblocks == 0) 185 continue; 186 printf("%-10s", fup->fu_name); 187 printf("%c%c%8d%8d%8d%7s", 188 fup->fu_dqblk.dqb_bsoftlimit && 189 fup->fu_dqblk.dqb_curblocks >= 190 fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-', 191 fup->fu_dqblk.dqb_isoftlimit && 192 fup->fu_dqblk.dqb_curinodes >= 193 fup->fu_dqblk.dqb_isoftlimit ? '+' : '-', 194 dbtob(fup->fu_dqblk.dqb_curblocks) / 1024, 195 dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024, 196 dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024, 197 fup->fu_dqblk.dqb_bsoftlimit && 198 fup->fu_dqblk.dqb_curblocks >= 199 fup->fu_dqblk.dqb_bsoftlimit ? 200 timeprt(fup->fu_dqblk.dqb_btime) : ""); 201 printf(" %6d%6d%6d%7s\n", 202 fup->fu_dqblk.dqb_curinodes, 203 fup->fu_dqblk.dqb_isoftlimit, 204 fup->fu_dqblk.dqb_ihardlimit, 205 fup->fu_dqblk.dqb_isoftlimit && 206 fup->fu_dqblk.dqb_curinodes >= 207 fup->fu_dqblk.dqb_isoftlimit ? 208 timeprt(fup->fu_dqblk.dqb_itime) : ""); 209 fup->fu_dqblk = zerodqblk; 210 } 211 return (0); 212 } 213 214 /* 215 * Check to see if target appears in list of size cnt. 216 */ 217 oneof(target, list, cnt) 218 register char *target, *list[]; 219 int cnt; 220 { 221 register int i; 222 223 for (i = 0; i < cnt; i++) 224 if (strcmp(target, list[i]) == 0) 225 return (i); 226 return (-1); 227 } 228 229 /* 230 * Check to see if a particular quota is to be enabled. 231 */ 232 hasquota(fs, type, qfnamep) 233 register struct fstab *fs; 234 int type; 235 char **qfnamep; 236 { 237 register char *opt; 238 char *cp, *index(), *strtok(); 239 static char initname, usrname[100], grpname[100]; 240 static char buf[BUFSIZ]; 241 242 if (!initname) { 243 sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 244 sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 245 initname = 1; 246 } 247 strcpy(buf, fs->fs_mntops); 248 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 249 if (cp = index(opt, '=')) 250 *cp++ = '\0'; 251 if (type == USRQUOTA && strcmp(opt, usrname) == 0) 252 break; 253 if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 254 break; 255 } 256 if (!opt) 257 return (0); 258 if (cp) { 259 *qfnamep = cp; 260 return (1); 261 } 262 (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 263 *qfnamep = buf; 264 return (1); 265 } 266 267 /* 268 * Routines to manage the file usage table. 269 * 270 * Lookup an id of a specific type. 271 */ 272 struct fileusage * 273 lookup(id, type) 274 u_long id; 275 int type; 276 { 277 register struct fileusage *fup; 278 279 for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 280 if (fup->fu_id == id) 281 return (fup); 282 return ((struct fileusage *)0); 283 } 284 285 /* 286 * Add a new file usage id if it does not already exist. 287 */ 288 struct fileusage * 289 addid(id, type, name) 290 u_long id; 291 int type; 292 char *name; 293 { 294 struct fileusage *fup, **fhp; 295 int len; 296 extern char *calloc(); 297 298 if (fup = lookup(id, type)) 299 return (fup); 300 if (name) 301 len = strlen(name); 302 else 303 len = 10; 304 if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { 305 fprintf(stderr, "out of memory for fileusage structures\n"); 306 exit(1); 307 } 308 fhp = &fuhead[type][id & (FUHASH - 1)]; 309 fup->fu_next = *fhp; 310 *fhp = fup; 311 fup->fu_id = id; 312 if (id > highid[type]) 313 highid[type] = id; 314 if (name) { 315 bcopy(name, fup->fu_name, len + 1); 316 } else { 317 sprintf(fup->fu_name, "%u", id); 318 } 319 return (fup); 320 } 321 322 /* 323 * Calculate the grace period and return a printable string for it. 324 */ 325 char * 326 timeprt(seconds) 327 time_t seconds; 328 { 329 time_t hours, minutes; 330 static char buf[20]; 331 static time_t now; 332 333 if (now == 0) 334 time(&now); 335 if (now > seconds) 336 return ("none"); 337 seconds -= now; 338 minutes = (seconds + 30) / 60; 339 hours = (minutes + 30) / 60; 340 if (hours >= 36) { 341 sprintf(buf, "%ddays", (hours + 12) / 24); 342 return (buf); 343 } 344 if (minutes >= 60) { 345 sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); 346 return (buf); 347 } 348 sprintf(buf, "%2d", minutes); 349 return (buf); 350 } 351