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