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