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