repquota.c revision 1.26 1 1.1 cgd /*
2 1.4 mycroft * Copyright (c) 1980, 1990, 1993
3 1.4 mycroft * The Regents of the University of California. All rights reserved.
4 1.1 cgd *
5 1.1 cgd * This code is derived from software contributed to Berkeley by
6 1.1 cgd * Robert Elz at The University of Melbourne.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.20 agc * 3. Neither the name of the University nor the names of its contributors
17 1.1 cgd * may be used to endorse or promote products derived from this software
18 1.1 cgd * without specific prior written permission.
19 1.1 cgd *
20 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.1 cgd * SUCH DAMAGE.
31 1.1 cgd */
32 1.1 cgd
33 1.10 mrg #include <sys/cdefs.h>
34 1.1 cgd #ifndef lint
35 1.23 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
36 1.23 lukem The Regents of the University of California. All rights reserved.");
37 1.1 cgd #endif /* not lint */
38 1.1 cgd
39 1.1 cgd #ifndef lint
40 1.10 mrg #if 0
41 1.10 mrg static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94";
42 1.10 mrg #else
43 1.26 bouyer __RCSID("$NetBSD: repquota.c,v 1.26 2011/03/06 17:08:43 bouyer Exp $");
44 1.10 mrg #endif
45 1.1 cgd #endif /* not lint */
46 1.1 cgd
47 1.1 cgd /*
48 1.1 cgd * Quota report
49 1.1 cgd */
50 1.1 cgd #include <sys/param.h>
51 1.1 cgd #include <sys/stat.h>
52 1.26 bouyer #include <sys/types.h>
53 1.26 bouyer #include <sys/statvfs.h>
54 1.26 bouyer #include <prop/proplib.h>
55 1.26 bouyer #include <sys/quota.h>
56 1.26 bouyer
57 1.11 lukem #include <errno.h>
58 1.26 bouyer #include <err.h>
59 1.1 cgd #include <fstab.h>
60 1.11 lukem #include <grp.h>
61 1.1 cgd #include <pwd.h>
62 1.1 cgd #include <stdio.h>
63 1.11 lukem #include <stdlib.h>
64 1.6 cgd #include <string.h>
65 1.11 lukem #include <unistd.h>
66 1.1 cgd
67 1.26 bouyer #include <ufs/ufs/quota2_prop.h>
68 1.26 bouyer #include <ufs/ufs/quota1.h>
69 1.26 bouyer
70 1.26 bouyer #include <printquota.h>
71 1.26 bouyer
72 1.26 bouyer const char *qfextension[] = INITQFNAMES;
73 1.24 lukem const char *qfname = QUOTAFILENAME;
74 1.1 cgd
75 1.1 cgd struct fileusage {
76 1.1 cgd struct fileusage *fu_next;
77 1.26 bouyer struct quota2_entry fu_q2e;
78 1.1 cgd u_long fu_id;
79 1.1 cgd char fu_name[1];
80 1.1 cgd /* actually bigger */
81 1.1 cgd };
82 1.1 cgd #define FUHASH 1024 /* must be power of two */
83 1.1 cgd struct fileusage *fuhead[MAXQUOTAS][FUHASH];
84 1.1 cgd u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
85 1.26 bouyer int valid[MAXQUOTAS];
86 1.26 bouyer struct quota2_entry defaultq2e[MAXQUOTAS];
87 1.1 cgd
88 1.26 bouyer int vflag = 0; /* verbose */
89 1.26 bouyer int aflag = 0; /* all file systems */
90 1.26 bouyer int Dflag = 0; /* debug */
91 1.26 bouyer int hflag = 0; /* humanize */
92 1.26 bouyer int xflag = 0; /* export */
93 1.26 bouyer
94 1.26 bouyer
95 1.26 bouyer struct fileusage *addid(u_long, int, const char *);
96 1.26 bouyer int hasquota(struct fstab *, int, char **);
97 1.26 bouyer struct fileusage *lookup(u_long, int);
98 1.26 bouyer struct fileusage *qremove(u_long, int);
99 1.26 bouyer int main(int, char **);
100 1.26 bouyer int oneof(const char *, char **, int);
101 1.26 bouyer int repquota(const struct statvfs *, int);
102 1.26 bouyer int repquota2(const struct statvfs *, int);
103 1.26 bouyer int repquota1(const struct statvfs *, int);
104 1.26 bouyer void usage(void);
105 1.26 bouyer void printquotas(int, const struct statvfs *, int);
106 1.26 bouyer void exportquotas(void);
107 1.26 bouyer void dqblk2q2e(const struct dqblk *, struct quota2_entry *);
108 1.11 lukem
109 1.11 lukem int
110 1.1 cgd main(argc, argv)
111 1.1 cgd int argc;
112 1.1 cgd char **argv;
113 1.1 cgd {
114 1.1 cgd int gflag = 0, uflag = 0, errs = 0;
115 1.1 cgd long i, argnum, done = 0;
116 1.9 mark int ch;
117 1.26 bouyer struct statvfs *fst;
118 1.26 bouyer int nfst;
119 1.1 cgd
120 1.26 bouyer while ((ch = getopt(argc, argv, "Daguhvx")) != -1) {
121 1.1 cgd switch(ch) {
122 1.1 cgd case 'a':
123 1.1 cgd aflag++;
124 1.1 cgd break;
125 1.1 cgd case 'g':
126 1.1 cgd gflag++;
127 1.1 cgd break;
128 1.1 cgd case 'u':
129 1.1 cgd uflag++;
130 1.1 cgd break;
131 1.26 bouyer case 'h':
132 1.26 bouyer hflag++;
133 1.26 bouyer break;
134 1.1 cgd case 'v':
135 1.1 cgd vflag++;
136 1.1 cgd break;
137 1.26 bouyer case 'D':
138 1.26 bouyer Dflag++;
139 1.26 bouyer break;
140 1.26 bouyer case 'x':
141 1.26 bouyer xflag++;
142 1.26 bouyer break;
143 1.1 cgd default:
144 1.1 cgd usage();
145 1.1 cgd }
146 1.1 cgd }
147 1.1 cgd argc -= optind;
148 1.1 cgd argv += optind;
149 1.26 bouyer if (xflag && (argc != 1 || aflag))
150 1.26 bouyer usage();
151 1.1 cgd if (argc == 0 && !aflag)
152 1.1 cgd usage();
153 1.1 cgd if (!gflag && !uflag) {
154 1.1 cgd if (aflag)
155 1.1 cgd gflag++;
156 1.1 cgd uflag++;
157 1.1 cgd }
158 1.26 bouyer
159 1.26 bouyer nfst = getmntinfo(&fst, MNT_WAIT);
160 1.26 bouyer if (nfst == 0)
161 1.26 bouyer errx(2, "no filesystems mounted!");
162 1.26 bouyer for (i = 0; i < nfst; i++) {
163 1.26 bouyer if ((fst[i].f_flag & ST_QUOTA) == 0)
164 1.1 cgd continue;
165 1.1 cgd if (aflag) {
166 1.26 bouyer if (gflag)
167 1.26 bouyer errs += repquota(&fst[i], GRPQUOTA);
168 1.26 bouyer if (uflag)
169 1.26 bouyer errs += repquota(&fst[i], USRQUOTA);
170 1.1 cgd continue;
171 1.1 cgd }
172 1.26 bouyer if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
173 1.26 bouyer (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) {
174 1.1 cgd done |= 1 << argnum;
175 1.26 bouyer if (gflag)
176 1.26 bouyer errs += repquota(&fst[i], GRPQUOTA);
177 1.26 bouyer if (uflag)
178 1.26 bouyer errs += repquota(&fst[i], USRQUOTA);
179 1.1 cgd }
180 1.1 cgd }
181 1.26 bouyer if (xflag)
182 1.26 bouyer exportquotas();
183 1.1 cgd for (i = 0; i < argc; i++)
184 1.1 cgd if ((done & (1 << i)) == 0)
185 1.26 bouyer fprintf(stderr, "%s not mounted\n", argv[i]);
186 1.1 cgd exit(errs);
187 1.1 cgd }
188 1.1 cgd
189 1.11 lukem void
190 1.1 cgd usage()
191 1.1 cgd {
192 1.26 bouyer fprintf(stderr, "usage:\n"
193 1.26 bouyer "\trepquota [-D] [-v] [-g] [-u] -a\n"
194 1.26 bouyer "\trepquota [-D] [-v] [-g] [-u] filesys ...\n"
195 1.26 bouyer "\trepquota -x [-D] [-g] [-u] filesys\n");
196 1.1 cgd exit(1);
197 1.1 cgd }
198 1.1 cgd
199 1.11 lukem int
200 1.26 bouyer repquota(const struct statvfs *vfs, int type)
201 1.26 bouyer {
202 1.26 bouyer if (repquota2(vfs, type) != 0)
203 1.26 bouyer return (repquota1(vfs, type));
204 1.26 bouyer return 0;
205 1.26 bouyer }
206 1.26 bouyer
207 1.26 bouyer int
208 1.26 bouyer repquota2(const struct statvfs *vfs, int type)
209 1.26 bouyer {
210 1.26 bouyer prop_dictionary_t dict, data, cmd;
211 1.26 bouyer prop_array_t cmds, datas;
212 1.26 bouyer struct plistref pref;
213 1.26 bouyer int error;
214 1.26 bouyer int8_t error8, version = 0;
215 1.26 bouyer prop_object_iterator_t cmditer, dataiter;
216 1.26 bouyer struct quota2_entry *q2ep;
217 1.26 bouyer struct fileusage *fup;
218 1.26 bouyer const char *strid;
219 1.26 bouyer uint32_t id;
220 1.26 bouyer
221 1.26 bouyer dict = quota2_prop_create();
222 1.26 bouyer cmds = prop_array_create();
223 1.26 bouyer datas = prop_array_create();
224 1.26 bouyer
225 1.26 bouyer if (dict == NULL || cmds == NULL || datas == NULL)
226 1.26 bouyer errx(1, "can't allocate proplist");
227 1.26 bouyer if (!quota2_prop_add_command(cmds, "getall", qfextension[type], datas))
228 1.26 bouyer err(1, "prop_add_command");
229 1.26 bouyer if (!quota2_prop_add_command(cmds, "get version", qfextension[type],
230 1.26 bouyer prop_array_create()))
231 1.26 bouyer err(1, "prop_add_command");
232 1.26 bouyer if (!prop_dictionary_set(dict, "commands", cmds))
233 1.26 bouyer err(1, "prop_dictionary_set(command)");
234 1.26 bouyer if (Dflag)
235 1.26 bouyer printf("message to kernel:\n%s\n",
236 1.26 bouyer prop_dictionary_externalize(dict));
237 1.26 bouyer if (!prop_dictionary_send_syscall(dict, &pref))
238 1.26 bouyer err(1, "prop_dictionary_send_syscall");
239 1.26 bouyer prop_object_release(dict);
240 1.26 bouyer
241 1.26 bouyer if (quotactl(vfs->f_mntonname, &pref) != 0)
242 1.26 bouyer err(1, "quotactl");
243 1.26 bouyer
244 1.26 bouyer if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
245 1.26 bouyer errx(1, "prop_dictionary_recv_syscall: %s\n",
246 1.26 bouyer strerror(error));
247 1.26 bouyer }
248 1.26 bouyer if (Dflag)
249 1.26 bouyer printf("reply from kernel:\n%s\n",
250 1.26 bouyer prop_dictionary_externalize(dict));
251 1.26 bouyer if ((error = quota2_get_cmds(dict, &cmds)) != 0) {
252 1.26 bouyer errx(1, "quota2_get_cmds: %s\n",
253 1.26 bouyer strerror(error));
254 1.26 bouyer }
255 1.26 bouyer cmditer = prop_array_iterator(cmds);
256 1.26 bouyer if (cmditer == NULL)
257 1.26 bouyer err(1, "prop_array_iterator(cmds)");
258 1.26 bouyer
259 1.26 bouyer while ((cmd = prop_object_iterator_next(cmditer)) != NULL) {
260 1.26 bouyer const char *cmdstr;
261 1.26 bouyer if (!prop_dictionary_get_cstring_nocopy(cmd, "command",
262 1.26 bouyer &cmdstr))
263 1.26 bouyer err(1, "prop_get(command)");
264 1.26 bouyer
265 1.26 bouyer if (!prop_dictionary_get_int8(cmd, "return", &error8))
266 1.26 bouyer err(1, "prop_get(return)");
267 1.26 bouyer
268 1.26 bouyer if (error8) {
269 1.26 bouyer prop_object_release(dict);
270 1.26 bouyer if (error8 != EOPNOTSUPP) {
271 1.26 bouyer fprintf(stderr, "get %s quotas: %s\n",
272 1.26 bouyer qfextension[type], strerror(error8));
273 1.26 bouyer }
274 1.26 bouyer return (error8);
275 1.26 bouyer }
276 1.26 bouyer datas = prop_dictionary_get(cmd, "data");
277 1.26 bouyer if (datas == NULL)
278 1.26 bouyer err(1, "prop_dict_get(datas)");
279 1.26 bouyer
280 1.26 bouyer if (strcmp("get version", cmdstr) == 0) {
281 1.26 bouyer data = prop_array_get(datas, 0);
282 1.26 bouyer if (data == NULL)
283 1.26 bouyer err(1, "prop_array_get(version)");
284 1.26 bouyer if (!prop_dictionary_get_int8(data, "version",
285 1.26 bouyer &version))
286 1.26 bouyer err(1, "prop_get_int8(version)");
287 1.26 bouyer continue;
288 1.26 bouyer }
289 1.26 bouyer dataiter = prop_array_iterator(datas);
290 1.26 bouyer if (dataiter == NULL)
291 1.26 bouyer err(1, "prop_array_iterator");
292 1.26 bouyer
293 1.26 bouyer valid[type] = 1;
294 1.26 bouyer while ((data = prop_object_iterator_next(dataiter)) != NULL) {
295 1.26 bouyer strid = NULL;
296 1.26 bouyer if (!prop_dictionary_get_uint32(data, "id", &id)) {
297 1.26 bouyer if (!prop_dictionary_get_cstring_nocopy(data,
298 1.26 bouyer "id", &strid))
299 1.26 bouyer errx(1, "can't find id in quota entry");
300 1.26 bouyer if (strcmp(strid, "default") != 0) {
301 1.26 bouyer errx(1,
302 1.26 bouyer "wrong id string %s in quota entry",
303 1.26 bouyer strid);
304 1.26 bouyer }
305 1.26 bouyer q2ep = &defaultq2e[type];
306 1.26 bouyer } else {
307 1.26 bouyer if ((fup = lookup(id, type)) == 0)
308 1.26 bouyer fup = addid(id, type, (char *)0);
309 1.26 bouyer q2ep = &fup->fu_q2e;
310 1.26 bouyer q2ep->q2e_uid = id;
311 1.26 bouyer }
312 1.26 bouyer
313 1.26 bouyer error = quota2_dict_get_q2e_usage(data, q2ep);
314 1.26 bouyer if (error) {
315 1.26 bouyer errx(1, "quota2_dict_get_q2e_usage: %s\n",
316 1.26 bouyer strerror(error));
317 1.26 bouyer }
318 1.26 bouyer }
319 1.26 bouyer prop_object_iterator_release(dataiter);
320 1.26 bouyer }
321 1.26 bouyer prop_object_iterator_release(cmditer);
322 1.26 bouyer prop_object_release(dict);
323 1.26 bouyer if (xflag == 0)
324 1.26 bouyer printquotas(type, vfs, version);
325 1.26 bouyer return (0);
326 1.26 bouyer }
327 1.26 bouyer
328 1.26 bouyer int repquota1(const struct statvfs *vfs, int type)
329 1.26 bouyer {
330 1.26 bouyer char *qfpathname;
331 1.11 lukem struct fstab *fs;
332 1.11 lukem struct fileusage *fup;
333 1.1 cgd FILE *qf;
334 1.1 cgd u_long id;
335 1.1 cgd struct dqblk dqbuf;
336 1.26 bouyer time_t bgrace = MAX_DQ_TIME, igrace = MAX_DQ_TIME;
337 1.1 cgd
338 1.26 bouyer setfsent();
339 1.26 bouyer while ((fs = getfsent()) != NULL) {
340 1.26 bouyer if (strcmp(fs->fs_vfstype, "ffs") == 0 &&
341 1.26 bouyer strcmp(fs->fs_file, vfs->f_mntonname) == 0)
342 1.26 bouyer break;
343 1.1 cgd }
344 1.26 bouyer endfsent();
345 1.26 bouyer if (fs == NULL) {
346 1.26 bouyer fprintf(stderr, "%s not found in fstab\n", vfs->f_mntonname);
347 1.26 bouyer return 1;
348 1.26 bouyer }
349 1.26 bouyer if (!hasquota(fs, type, &qfpathname))
350 1.26 bouyer return 0;
351 1.26 bouyer
352 1.1 cgd if ((qf = fopen(qfpathname, "r")) == NULL) {
353 1.1 cgd perror(qfpathname);
354 1.1 cgd return (1);
355 1.1 cgd }
356 1.1 cgd for (id = 0; ; id++) {
357 1.1 cgd fread(&dqbuf, sizeof(struct dqblk), 1, qf);
358 1.1 cgd if (feof(qf))
359 1.1 cgd break;
360 1.26 bouyer if (id == 0) {
361 1.26 bouyer if (dqbuf.dqb_btime > 0)
362 1.26 bouyer bgrace = dqbuf.dqb_btime;
363 1.26 bouyer if (dqbuf.dqb_itime > 0)
364 1.26 bouyer igrace = dqbuf.dqb_itime;
365 1.26 bouyer }
366 1.26 bouyer if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0 &&
367 1.26 bouyer dqbuf.dqb_bsoftlimit == 0 && dqbuf.dqb_bhardlimit == 0 &&
368 1.26 bouyer dqbuf.dqb_isoftlimit == 0 && dqbuf.dqb_ihardlimit == 0)
369 1.1 cgd continue;
370 1.1 cgd if ((fup = lookup(id, type)) == 0)
371 1.1 cgd fup = addid(id, type, (char *)0);
372 1.26 bouyer dqblk2q2e(&dqbuf, &fup->fu_q2e);
373 1.26 bouyer fup->fu_q2e.q2e_val[QL_BLOCK].q2v_grace = bgrace;
374 1.26 bouyer fup->fu_q2e.q2e_val[QL_FILE].q2v_grace = igrace;
375 1.26 bouyer }
376 1.26 bouyer defaultq2e[type].q2e_val[QL_BLOCK].q2v_grace = bgrace;
377 1.26 bouyer defaultq2e[type].q2e_val[QL_FILE].q2v_grace = igrace;
378 1.26 bouyer defaultq2e[type].q2e_val[QL_BLOCK].q2v_softlimit =
379 1.26 bouyer defaultq2e[type].q2e_val[QL_BLOCK].q2v_hardlimit =
380 1.26 bouyer defaultq2e[type].q2e_val[QL_FILE].q2v_softlimit =
381 1.26 bouyer defaultq2e[type].q2e_val[QL_FILE].q2v_hardlimit = UQUAD_MAX;
382 1.26 bouyer fclose(qf);
383 1.26 bouyer valid[type] = 1;
384 1.26 bouyer if (xflag == 0)
385 1.26 bouyer printquotas(type, vfs, 1);
386 1.26 bouyer return (0);
387 1.26 bouyer }
388 1.26 bouyer
389 1.26 bouyer void
390 1.26 bouyer printquotas(int type, const struct statvfs *vfs, int version)
391 1.26 bouyer {
392 1.26 bouyer static int multiple = 0;
393 1.26 bouyer u_long id;
394 1.26 bouyer int i;
395 1.26 bouyer struct fileusage *fup;
396 1.26 bouyer const char *timemsg[N_QL];
397 1.26 bouyer char overchar[N_QL];
398 1.26 bouyer static time_t now;
399 1.26 bouyer
400 1.26 bouyer switch(type) {
401 1.26 bouyer case GRPQUOTA:
402 1.26 bouyer {
403 1.26 bouyer struct group *gr;
404 1.26 bouyer setgrent();
405 1.26 bouyer while ((gr = getgrent()) != 0)
406 1.26 bouyer (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
407 1.26 bouyer endgrent();
408 1.26 bouyer break;
409 1.26 bouyer }
410 1.26 bouyer case USRQUOTA:
411 1.26 bouyer {
412 1.26 bouyer struct passwd *pw;
413 1.26 bouyer setpwent();
414 1.26 bouyer while ((pw = getpwent()) != 0)
415 1.26 bouyer (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
416 1.26 bouyer endpwent();
417 1.26 bouyer break;
418 1.26 bouyer }
419 1.26 bouyer default:
420 1.26 bouyer errx(1, "unknown quota type %d\n", type);
421 1.1 cgd }
422 1.26 bouyer
423 1.26 bouyer if (now == 0)
424 1.26 bouyer time(&now);
425 1.26 bouyer
426 1.26 bouyer if (multiple++)
427 1.26 bouyer printf("\n");
428 1.26 bouyer if (vflag)
429 1.26 bouyer fprintf(stdout,
430 1.26 bouyer "*** Report for %s quotas on %s (%s, version %d)\n",
431 1.26 bouyer qfextension[type], vfs->f_mntonname, vfs->f_mntfromname,
432 1.26 bouyer version);
433 1.1 cgd printf(" Block limits File limits\n");
434 1.15 ad printf(type == USRQUOTA ? "User " : "Group");
435 1.25 bouyer printf(" used soft hard grace used soft hard grace\n");
436 1.1 cgd for (id = 0; id <= highid[type]; id++) {
437 1.26 bouyer fup = qremove(id, type);
438 1.1 cgd if (fup == 0)
439 1.1 cgd continue;
440 1.26 bouyer for (i = 0; i < N_QL; i++) {
441 1.26 bouyer switch (QL_STATUS(quota2_check_limit(
442 1.26 bouyer &fup->fu_q2e.q2e_val[i], 1, now))) {
443 1.26 bouyer case QL_S_DENY_HARD:
444 1.26 bouyer case QL_S_DENY_GRACE:
445 1.26 bouyer case QL_S_ALLOW_SOFT:
446 1.26 bouyer timemsg[i] = timeprt(now,
447 1.26 bouyer fup->fu_q2e.q2e_val[i].q2v_time, 7);
448 1.26 bouyer overchar[i] = '+';
449 1.26 bouyer break;
450 1.26 bouyer default:
451 1.26 bouyer timemsg[i] = (vflag && version == 2) ?
452 1.26 bouyer timeprt(0,
453 1.26 bouyer fup->fu_q2e.q2e_val[i].q2v_grace, 7):
454 1.26 bouyer "";
455 1.26 bouyer overchar[i] = '-';
456 1.26 bouyer break;
457 1.26 bouyer }
458 1.26 bouyer }
459 1.26 bouyer
460 1.26 bouyer if (fup->fu_q2e.q2e_val[QL_BLOCK].q2v_cur == 0 &&
461 1.26 bouyer fup->fu_q2e.q2e_val[QL_FILE].q2v_cur == 0 && vflag == 0 &&
462 1.26 bouyer overchar[QL_BLOCK] == '-' && overchar[QL_FILE] == '-')
463 1.1 cgd continue;
464 1.22 jdolecek if (strlen(fup->fu_name) > 9)
465 1.22 jdolecek printf("%s ", fup->fu_name);
466 1.22 jdolecek else
467 1.22 jdolecek printf("%-10s", fup->fu_name);
468 1.26 bouyer printf("%c%c%9s%9s%9s%7s",
469 1.26 bouyer overchar[QL_BLOCK], overchar[QL_FILE],
470 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_BLOCK].q2v_cur,
471 1.26 bouyer HN_B, hflag, 9),
472 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_BLOCK].q2v_softlimit,
473 1.26 bouyer HN_B, hflag, 9),
474 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_BLOCK].q2v_hardlimit,
475 1.26 bouyer HN_B, hflag, 9),
476 1.26 bouyer timemsg[QL_BLOCK]);
477 1.26 bouyer printf(" %8s%8s%8s%7s\n",
478 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_FILE].q2v_cur,
479 1.26 bouyer 0, hflag, 8),
480 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_FILE].q2v_softlimit,
481 1.26 bouyer 0, hflag, 8),
482 1.26 bouyer intprt(fup->fu_q2e.q2e_val[QL_FILE].q2v_hardlimit,
483 1.26 bouyer 0, hflag, 8),
484 1.26 bouyer timemsg[QL_FILE]);
485 1.26 bouyer free(fup);
486 1.26 bouyer }
487 1.26 bouyer }
488 1.26 bouyer
489 1.26 bouyer void
490 1.26 bouyer exportquotas()
491 1.26 bouyer {
492 1.26 bouyer u_long id;
493 1.26 bouyer struct fileusage *fup;
494 1.26 bouyer prop_dictionary_t dict, data;
495 1.26 bouyer prop_array_t cmds, datas;
496 1.26 bouyer int type;
497 1.26 bouyer
498 1.26 bouyer dict = quota2_prop_create();
499 1.26 bouyer cmds = prop_array_create();
500 1.26 bouyer
501 1.26 bouyer if (dict == NULL || cmds == NULL) {
502 1.26 bouyer errx(1, "can't allocate proplist");
503 1.26 bouyer }
504 1.26 bouyer
505 1.26 bouyer
506 1.26 bouyer for (type = 0; type < MAXQUOTAS; type++) {
507 1.26 bouyer if (valid[type] == 0)
508 1.26 bouyer continue;
509 1.26 bouyer datas = prop_array_create();
510 1.26 bouyer if (datas == NULL)
511 1.26 bouyer errx(1, "can't allocate proplist");
512 1.26 bouyer data = q2etoprop(&defaultq2e[type], 1);
513 1.26 bouyer if (data == NULL)
514 1.26 bouyer err(1, "q2etoprop(default)");
515 1.26 bouyer if (!prop_array_add_and_rel(datas, data))
516 1.26 bouyer err(1, "prop_array_add(data)");
517 1.26 bouyer
518 1.26 bouyer for (id = 0; id <= highid[type]; id++) {
519 1.26 bouyer fup = qremove(id, type);
520 1.26 bouyer if (fup == 0)
521 1.26 bouyer continue;
522 1.26 bouyer fup->fu_q2e.q2e_uid = id;
523 1.26 bouyer data = q2etoprop(&fup->fu_q2e, 0);
524 1.26 bouyer if (data == NULL)
525 1.26 bouyer err(1, "q2etoprop(default)");
526 1.26 bouyer if (!prop_array_add_and_rel(datas, data))
527 1.26 bouyer err(1, "prop_array_add(data)");
528 1.26 bouyer free(fup);
529 1.26 bouyer }
530 1.26 bouyer
531 1.26 bouyer if (!quota2_prop_add_command(cmds, "set",
532 1.26 bouyer qfextension[type], datas))
533 1.26 bouyer err(1, "prop_add_command");
534 1.1 cgd }
535 1.26 bouyer
536 1.26 bouyer if (!prop_dictionary_set(dict, "commands", cmds))
537 1.26 bouyer err(1, "prop_dictionary_set(command)");
538 1.26 bouyer
539 1.26 bouyer printf("%s\n", prop_dictionary_externalize(dict));
540 1.26 bouyer return;
541 1.1 cgd }
542 1.1 cgd
543 1.1 cgd /*
544 1.1 cgd * Check to see if target appears in list of size cnt.
545 1.1 cgd */
546 1.11 lukem int
547 1.1 cgd oneof(target, list, cnt)
548 1.14 mycroft const char *target;
549 1.14 mycroft char *list[];
550 1.1 cgd int cnt;
551 1.1 cgd {
552 1.11 lukem int i;
553 1.1 cgd
554 1.1 cgd for (i = 0; i < cnt; i++)
555 1.1 cgd if (strcmp(target, list[i]) == 0)
556 1.1 cgd return (i);
557 1.1 cgd return (-1);
558 1.1 cgd }
559 1.1 cgd
560 1.1 cgd /*
561 1.1 cgd * Check to see if a particular quota is to be enabled.
562 1.1 cgd */
563 1.11 lukem int
564 1.1 cgd hasquota(fs, type, qfnamep)
565 1.11 lukem struct fstab *fs;
566 1.1 cgd int type;
567 1.1 cgd char **qfnamep;
568 1.1 cgd {
569 1.11 lukem char *opt;
570 1.13 fair char *cp = NULL;
571 1.1 cgd static char initname, usrname[100], grpname[100];
572 1.1 cgd static char buf[BUFSIZ];
573 1.1 cgd
574 1.1 cgd if (!initname) {
575 1.1 cgd sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
576 1.1 cgd sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
577 1.1 cgd initname = 1;
578 1.1 cgd }
579 1.1 cgd strcpy(buf, fs->fs_mntops);
580 1.1 cgd for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
581 1.11 lukem if ((cp = strchr(opt, '=')) != NULL)
582 1.1 cgd *cp++ = '\0';
583 1.1 cgd if (type == USRQUOTA && strcmp(opt, usrname) == 0)
584 1.1 cgd break;
585 1.1 cgd if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
586 1.1 cgd break;
587 1.1 cgd }
588 1.1 cgd if (!opt)
589 1.1 cgd return (0);
590 1.1 cgd if (cp) {
591 1.1 cgd *qfnamep = cp;
592 1.1 cgd return (1);
593 1.1 cgd }
594 1.1 cgd (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
595 1.1 cgd *qfnamep = buf;
596 1.1 cgd return (1);
597 1.1 cgd }
598 1.1 cgd
599 1.1 cgd /*
600 1.1 cgd * Routines to manage the file usage table.
601 1.1 cgd *
602 1.1 cgd * Lookup an id of a specific type.
603 1.1 cgd */
604 1.1 cgd struct fileusage *
605 1.1 cgd lookup(id, type)
606 1.1 cgd u_long id;
607 1.1 cgd int type;
608 1.1 cgd {
609 1.11 lukem struct fileusage *fup;
610 1.1 cgd
611 1.1 cgd for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
612 1.1 cgd if (fup->fu_id == id)
613 1.1 cgd return (fup);
614 1.1 cgd return ((struct fileusage *)0);
615 1.1 cgd }
616 1.26 bouyer /*
617 1.26 bouyer * Lookup and remove an id of a specific type.
618 1.26 bouyer */
619 1.26 bouyer struct fileusage *
620 1.26 bouyer qremove(id, type)
621 1.26 bouyer u_long id;
622 1.26 bouyer int type;
623 1.26 bouyer {
624 1.26 bouyer struct fileusage *fup, **fupp;
625 1.26 bouyer
626 1.26 bouyer for (fupp = &fuhead[type][id & (FUHASH-1)]; *fupp != 0;) {
627 1.26 bouyer fup = *fupp;
628 1.26 bouyer if (fup->fu_id == id) {
629 1.26 bouyer *fupp = fup->fu_next;
630 1.26 bouyer return (fup);
631 1.26 bouyer }
632 1.26 bouyer fupp = &fup->fu_next;
633 1.26 bouyer }
634 1.26 bouyer return ((struct fileusage *)0);
635 1.26 bouyer }
636 1.1 cgd
637 1.1 cgd /*
638 1.1 cgd * Add a new file usage id if it does not already exist.
639 1.1 cgd */
640 1.1 cgd struct fileusage *
641 1.1 cgd addid(id, type, name)
642 1.1 cgd u_long id;
643 1.1 cgd int type;
644 1.14 mycroft const char *name;
645 1.1 cgd {
646 1.1 cgd struct fileusage *fup, **fhp;
647 1.26 bouyer struct group *gr = NULL;
648 1.26 bouyer struct passwd *pw = NULL;
649 1.1 cgd int len;
650 1.1 cgd
651 1.26 bouyer if ((fup = lookup(id, type)) != NULL) {
652 1.1 cgd return (fup);
653 1.26 bouyer }
654 1.26 bouyer if (name == NULL) {
655 1.26 bouyer switch(type) {
656 1.26 bouyer case GRPQUOTA:
657 1.26 bouyer gr = getgrgid(id);
658 1.26 bouyer
659 1.26 bouyer if (gr != NULL)
660 1.26 bouyer name = gr->gr_name;
661 1.26 bouyer break;
662 1.26 bouyer case USRQUOTA:
663 1.26 bouyer pw = getpwuid(id);
664 1.26 bouyer if (pw)
665 1.26 bouyer name = pw->pw_name;
666 1.26 bouyer break;
667 1.26 bouyer default:
668 1.26 bouyer errx(1, "unknown quota type %d\n", type);
669 1.26 bouyer }
670 1.26 bouyer }
671 1.26 bouyer
672 1.1 cgd if (name)
673 1.1 cgd len = strlen(name);
674 1.1 cgd else
675 1.1 cgd len = 10;
676 1.1 cgd if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
677 1.1 cgd fprintf(stderr, "out of memory for fileusage structures\n");
678 1.1 cgd exit(1);
679 1.1 cgd }
680 1.1 cgd fhp = &fuhead[type][id & (FUHASH - 1)];
681 1.1 cgd fup->fu_next = *fhp;
682 1.1 cgd *fhp = fup;
683 1.1 cgd fup->fu_id = id;
684 1.1 cgd if (id > highid[type])
685 1.1 cgd highid[type] = id;
686 1.1 cgd if (name) {
687 1.12 lukem memmove(fup->fu_name, name, len + 1);
688 1.1 cgd } else {
689 1.11 lukem sprintf(fup->fu_name, "%lu", (u_long)id);
690 1.1 cgd }
691 1.26 bouyer fup->fu_q2e = defaultq2e[type];
692 1.1 cgd return (fup);
693 1.1 cgd }
694