fix silly indirect-through-zero bug
[unix-history] / usr / src / usr.sbin / repquota / repquota.c
CommitLineData
2a18434a 1/*
09f77423 2 * Copyright (c) 1980, 1990 Regents of the University of California.
f9ac90b4
KB
3 * All rights reserved.
4 *
cdb4efdf
KM
5 * This code is derived from software contributed to Berkeley by
6 * Robert Elz at The University of Melbourne.
7 *
417f7a11 8 * %sccs.include.redist.c%
2a18434a
KM
9 */
10
11#ifndef lint
12char copyright[] =
09f77423 13"@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\
2a18434a 14 All rights reserved.\n";
f9ac90b4 15#endif /* not lint */
2a18434a 16
fe35ac74 17#ifndef lint
1032f6ad 18static char sccsid[] = "@(#)repquota.c 5.12 (Berkeley) %G%";
f9ac90b4 19#endif /* not lint */
fe35ac74
KM
20
21/*
22 * Quota report
23 */
fe35ac74 24#include <sys/param.h>
6c299bfc 25#include <sys/stat.h>
1032f6ad 26#include <ufs/ufs/quota.h>
6c299bfc
KM
27#include <fstab.h>
28#include <pwd.h>
cdb4efdf 29#include <grp.h>
aed516fd
KB
30#include <stdio.h>
31#include <errno.h>
fe35ac74 32
78b244e9
KM
33char *qfname = QUOTAFILENAME;
34char *qfextension[] = INITQFNAMES;
35
6c299bfc 36struct fileusage {
cdb4efdf
KM
37 struct fileusage *fu_next;
38 struct dqblk fu_dqblk;
39 u_long fu_id;
40 char fu_name[1];
41 /* actually bigger */
6c299bfc 42};
cdb4efdf
KM
43#define FUHASH 1024 /* must be power of two */
44struct fileusage *fuhead[MAXQUOTAS][FUHASH];
6c299bfc 45struct fileusage *lookup();
cdb4efdf
KM
46struct fileusage *addid();
47u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
fe35ac74 48
cdb4efdf
KM
49int vflag; /* verbose */
50int aflag; /* all file systems */
fe35ac74
KM
51
52main(argc, argv)
6c299bfc 53 int argc;
fe35ac74
KM
54 char **argv;
55{
6c299bfc
KM
56 register struct fstab *fs;
57 register struct passwd *pw;
cdb4efdf
KM
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;
09f77423 63 char ch, *qfnp;
cdb4efdf
KM
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 }
6c299bfc 82 }
cdb4efdf
KM
83 argc -= optind;
84 argv += optind;
85 if (argc == 0 && !aflag)
86 usage();
87 if (!gflag && !uflag) {
88 if (aflag)
89 gflag++;
90 uflag++;
6c299bfc 91 }
cdb4efdf
KM
92 if (gflag) {
93 setgrent();
94 while ((gr = getgrent()) != 0)
95 (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
96 endgrent();
fe35ac74 97 }
cdb4efdf
KM
98 if (uflag) {
99 setpwent();
100 while ((pw = getpwent()) != 0)
101 (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
102 endpwent();
6c299bfc 103 }
6c299bfc
KM
104 setfsent();
105 while ((fs = getfsent()) != NULL) {
09f77423
KM
106 if (strcmp(fs->fs_vfstype, "ufs"))
107 continue;
cdb4efdf 108 if (aflag) {
09f77423
KM
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);
fe35ac74 113 continue;
cdb4efdf
KM
114 }
115 if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
116 (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
117 done |= 1 << argnum;
09f77423
KM
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);
cdb4efdf 122 }
fe35ac74 123 }
6c299bfc
KM
124 endfsent();
125 for (i = 0; i < argc; i++)
126 if ((done & (1 << i)) == 0)
cdb4efdf 127 fprintf(stderr, "%s not found in fstab\n", argv[i]);
6c299bfc
KM
128 exit(errs);
129}
fe35ac74 130
cdb4efdf
KM
131usage()
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
09f77423 139repquota(fs, type, qfpathname)
cdb4efdf
KM
140 register struct fstab *fs;
141 int type;
09f77423 142 char *qfpathname;
6c299bfc
KM
143{
144 register struct fileusage *fup;
145 FILE *qf;
cdb4efdf 146 u_long id;
6c299bfc 147 struct dqblk dqbuf;
09f77423 148 char *timeprt();
cdb4efdf 149 static struct dqblk zerodqblk;
824e2e71 150 static int warned = 0;
cdb4efdf 151 static int multiple = 0;
824e2e71 152 extern int errno;
fe35ac74 153
cdb4efdf
KM
154 if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
155 errno == EOPNOTSUPP && !warned && vflag) {
824e2e71
KM
156 warned++;
157 fprintf(stdout,
158 "*** Warning: Quotas are not compiled into this kernel\n");
159 }
cdb4efdf
KM
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);
09f77423
KM
165 if ((qf = fopen(qfpathname, "r")) == NULL) {
166 perror(qfpathname);
cdb4efdf
KM
167 return (1);
168 }
169 for (id = 0; ; id++) {
6c299bfc
KM
170 fread(&dqbuf, sizeof(struct dqblk), 1, qf);
171 if (feof(qf))
172 break;
cdb4efdf 173 if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
2dd469d2 174 continue;
cdb4efdf
KM
175 if ((fup = lookup(id, type)) == 0)
176 fup = addid(id, type, (char *)0);
6c299bfc
KM
177 fup->fu_dqblk = dqbuf;
178 }
cdb4efdf 179 fclose(qf);
6c299bfc 180 printf(" Block limits File limits\n");
cdb4efdf
KM
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);
6c299bfc
KM
184 if (fup == 0)
185 continue;
3e5a0658 186 if (fup->fu_dqblk.dqb_curinodes == 0 &&
6c299bfc 187 fup->fu_dqblk.dqb_curblocks == 0)
fe35ac74 188 continue;
cdb4efdf
KM
189 printf("%-10s", fup->fu_name);
190 printf("%c%c%8d%8d%8d%7s",
6c299bfc
KM
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 ? '+' : '-',
285a6d40
JB
197 dbtob(fup->fu_dqblk.dqb_curblocks) / 1024,
198 dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024,
199 dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024,
cdb4efdf
KM
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",
6c299bfc
KM
205 fup->fu_dqblk.dqb_curinodes,
206 fup->fu_dqblk.dqb_isoftlimit,
207 fup->fu_dqblk.dqb_ihardlimit,
cdb4efdf
KM
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) : "");
6c299bfc 212 fup->fu_dqblk = zerodqblk;
fe35ac74 213 }
6c299bfc
KM
214 return (0);
215}
216
cdb4efdf
KM
217/*
218 * Check to see if target appears in list of size cnt.
219 */
220oneof(target, list, cnt)
221 register char *target, *list[];
222 int cnt;
6c299bfc
KM
223{
224 register int i;
225
cdb4efdf
KM
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 */
09f77423
KM
235hasquota(fs, type, qfnamep)
236 register struct fstab *fs;
cdb4efdf 237 int type;
09f77423 238 char **qfnamep;
cdb4efdf
KM
239{
240 register char *opt;
09f77423 241 char *cp, *index(), *strtok();
cdb4efdf 242 static char initname, usrname[100], grpname[100];
09f77423 243 static char buf[BUFSIZ];
cdb4efdf
KM
244
245 if (!initname) {
246 sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
247 sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
248 initname = 1;
249 }
09f77423 250 strcpy(buf, fs->fs_mntops);
cdb4efdf 251 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
09f77423
KM
252 if (cp = index(opt, '='))
253 *cp++ = '\0';
cdb4efdf 254 if (type == USRQUOTA && strcmp(opt, usrname) == 0)
09f77423 255 break;
cdb4efdf 256 if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
09f77423 257 break;
cdb4efdf 258 }
09f77423
KM
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);
fe35ac74
KM
268}
269
cdb4efdf
KM
270/*
271 * Routines to manage the file usage table.
272 *
273 * Lookup an id of a specific type.
274 */
6c299bfc 275struct fileusage *
cdb4efdf
KM
276lookup(id, type)
277 u_long id;
278 int type;
fe35ac74 279{
6c299bfc 280 register struct fileusage *fup;
fe35ac74 281
cdb4efdf
KM
282 for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
283 if (fup->fu_id == id)
6c299bfc
KM
284 return (fup);
285 return ((struct fileusage *)0);
286}
287
cdb4efdf
KM
288/*
289 * Add a new file usage id if it does not already exist.
290 */
6c299bfc 291struct fileusage *
cdb4efdf
KM
292addid(id, type, name)
293 u_long id;
294 int type;
295 char *name;
6c299bfc
KM
296{
297 struct fileusage *fup, **fhp;
cdb4efdf 298 int len;
2dd469d2 299 extern char *calloc();
6c299bfc 300
cdb4efdf 301 if (fup = lookup(id, type))
6c299bfc 302 return (fup);
cdb4efdf
KM
303 if (name)
304 len = strlen(name);
305 else
306 len = 10;
307 if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
6c299bfc
KM
308 fprintf(stderr, "out of memory for fileusage structures\n");
309 exit(1);
310 }
cdb4efdf 311 fhp = &fuhead[type][id & (FUHASH - 1)];
6c299bfc
KM
312 fup->fu_next = *fhp;
313 *fhp = fup;
cdb4efdf
KM
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 }
6c299bfc 322 return (fup);
fe35ac74 323}
cdb4efdf
KM
324
325/*
326 * Calculate the grace period and return a printable string for it.
327 */
328char *
329timeprt(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}