2 * Copyright (c) 1980, 1990 Regents of the University of California. All
5 * This code is derived from software contributed to Berkeley by Robert Elz at
6 * The University of Melbourne.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution. 3. All advertising
15 * materials mentioning features or use of this software must display the
16 * following acknowledgement: This product includes software developed by the
17 * University of California, Berkeley and its contributors. 4. Neither the
18 * name of the University nor the names of its contributors may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/types.h>
66 * Set grace time if needed
68 void update_grace_times(struct dquot *q)
73 if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > q->dq_dqb.dqb_bsoftlimit) {
74 if (!q->dq_dqb.dqb_btime)
75 q->dq_dqb.dqb_btime = now + q->dq_h->qh_info.dqi_bgrace;
78 q->dq_dqb.dqb_btime = 0;
79 if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > q->dq_dqb.dqb_isoftlimit) {
80 if (!q->dq_dqb.dqb_itime)
81 q->dq_dqb.dqb_itime = now + q->dq_h->qh_info.dqi_igrace;
84 q->dq_dqb.dqb_itime = 0;
88 * Collect the requested quota information.
90 struct dquot *getprivs(qid_t id, struct quota_handle **handles, int quiet)
92 struct dquot *q, *qtail = NULL, *qhead = NULL;
94 #if defined(BSD_BEHAVIOUR)
97 gid_t gidset[NGROUPS], *gidsetp;
98 char name[MAXNAMELEN];
101 for (i = 0; handles[i]; i++) {
102 #if defined(BSD_BEHAVIOUR)
103 switch (handles[i]->qh_type) {
106 if (euid != id && euid != 0) {
108 errstr(_("%s (uid %d): Permission denied\n"), name, id);
109 return (struct dquot *)NULL;
115 ngroups = sysconf(_SC_NGROUPS_MAX);
116 if (ngroups > NGROUPS) {
117 gidsetp = malloc(ngroups * sizeof(gid_t));
120 errstr(_("%s (gid %d): gid set allocation (%d): %s\n"), name, id, ngroups, strerror(errno));
121 return (struct dquot *)NULL;
125 gidsetp = &gidset[0];
126 ngroups = getgroups(ngroups, gidsetp);
128 if (gidsetp != gidset)
131 errstr(_("%s (gid %d): error while trying getgroups(): %s\n"), name, id, strerror(errno));
132 return (struct dquot *)NULL;
135 for (j = 0; j < ngroups; j++)
136 if (id == gidsetp[j])
138 if (gidsetp != gidset)
142 errstr(_("%s (gid %d): Permission denied\n"),
144 return (struct dquot *)NULL;
152 if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) {
153 /* If rpc.rquotad is not running filesystem might be just without quotas... */
154 if (errno != ENOENT && (errno != ECONNREFUSED || !quiet)) {
155 int olderrno = errno;
157 id2name(id, handles[i]->qh_type, name);
158 errstr(_("error while getting quota from %s for %s (id %u): %s\n"),
159 handles[i]->qh_quotadev, name, id, strerror(olderrno));
168 q->dq_next = NULL; /* This should be already set, but just for sure... */
174 * Store the requested quota information.
176 int putprivs(struct dquot *qlist, int flags)
181 for (q = qlist; q; q = q->dq_next) {
182 if (q->dq_h->qh_ops->commit_dquot(q, flags) == -1) {
183 errstr(_("Cannot write quota for %u on %s: %s\n"),
184 q->dq_id, q->dq_h->qh_quotadev, strerror(errno));
193 * Take a list of priviledges and get it edited.
195 #define MAX_ED_PARS 128
196 int editprivs(char *tmpfile)
198 sigset_t omask, nmask;
203 sigaddset(&nmask, SIGINT);
204 sigaddset(&nmask, SIGQUIT);
205 sigaddset(&nmask, SIGHUP);
206 sigprocmask(SIG_SETMASK, &nmask, &omask);
207 if ((pid = fork()) < 0) {
208 errstr("Cannot fork(): %s\n", strerror(errno));
212 char *ed, *actp, *nextp;
213 char *edpars[MAX_ED_PARS];
216 sigprocmask(SIG_SETMASK, &omask, NULL);
219 if (!(ed = getenv("VISUAL")))
220 if (!(ed = getenv("EDITOR")))
223 ed = actp = sstrdup(ed);
225 nextp = strchr(actp, ' ');
231 if (i == MAX_ED_PARS-2) {
232 errstr(_("Too many parameters to editor.\n"));
237 edpars[i++] = tmpfile;
239 execvp(edpars[0], edpars);
240 die(1, _("Cannot exec %s\n"), ed);
242 waitpid(pid, &stat, 0);
243 sigprocmask(SIG_SETMASK, &omask, NULL);
249 * Convert a dquot list to an ASCII file.
251 int writeprivs(struct dquot *qlist, int outfd, char *name, int quotatype)
257 lseek(outfd, 0, SEEK_SET);
258 if (!(fd = fdopen(dup(outfd), "w")))
259 die(1, _("Cannot duplicate descriptor of file to write to: %s\n"), strerror(errno));
261 #if defined(ALT_FORMAT)
262 fprintf(fd, _("Disk quotas for %s %s (%cid %d):\n"),
263 type2name(quotatype), name, *type2name(quotatype), qlist->dq_id);
266 _(" Filesystem blocks soft hard inodes soft hard\n"));
268 for (q = qlist; q; q = q->dq_next) {
269 fprintf(fd, " %-24s %10llu %10llu %10llu %10llu %8llu %8llu\n",
270 q->dq_h->qh_quotadev,
271 (long long)toqb(q->dq_dqb.dqb_curspace),
272 (long long)q->dq_dqb.dqb_bsoftlimit,
273 (long long)q->dq_dqb.dqb_bhardlimit,
274 (long long)q->dq_dqb.dqb_curinodes,
275 (long long)q->dq_dqb.dqb_isoftlimit, (long long)q->dq_dqb.dqb_ihardlimit);
278 fprintf(fd, _("Quotas for %s %s:\n"), type2name(quotatype), name);
279 for (q = qlist; q; q = q->dq_next) {
280 fprintf(fd, _("%s %d, limits (soft = %d, hard = %d)\n"),
281 q->dq_h->qh_quotadev, _("blocks in use:"),
282 (int)toqb(q->dq_dqb.dqb_curspace),
283 q->dq_dqb.dqb_bsoftlimit, q->dq_dqb.dqb_bhardlimit);
284 fprintf(fd, _("%s %d, limits (soft = %d, hard = %d)\n"),
285 _("\tinodes in use:"), q->dq_dqb.dqb_curinodes,
286 q->dq_dqb.dqb_isoftlimit, q->dq_dqb.dqb_ihardlimit);
293 /* Merge changes on one dev to proper structure in the list */
294 static void merge_limits_to_list(struct dquot *qlist, char *dev, u_int64_t blocks, u_int64_t bsoft,
295 u_int64_t bhard, u_int64_t inodes, u_int64_t isoft, u_int64_t ihard)
299 for (q = qlist; q; q = q->dq_next) {
300 if (!devcmp_handle(dev, q->dq_h))
303 q->dq_dqb.dqb_bsoftlimit = bsoft;
304 q->dq_dqb.dqb_bhardlimit = bhard;
305 q->dq_dqb.dqb_isoftlimit = isoft;
306 q->dq_dqb.dqb_ihardlimit = ihard;
307 q->dq_flags |= DQ_FOUND;
308 update_grace_times(q);
310 if (blocks != toqb(q->dq_dqb.dqb_curspace))
311 errstr(_("WARNING - %s: cannot change current block allocation\n"),
312 q->dq_h->qh_quotadev);
313 if (inodes != q->dq_dqb.dqb_curinodes)
314 errstr(_("WARNING - %s: cannot change current inode allocation\n"),
315 q->dq_h->qh_quotadev);
320 * Merge changes to an ASCII file into a dquot list.
322 int readprivs(struct dquot *qlist, int infd)
326 long long blocks, bsoft, bhard, inodes, isoft, ihard;
329 #if defined(ALT_FORMAT)
330 char fsp[BUFSIZ], line[BUFSIZ];
332 char *fsp, line1[BUFSIZ], line2[BUFSIZ];
335 lseek(infd, 0, SEEK_SET);
336 if (!(fd = fdopen(dup(infd), "r")))
337 die(1, _("Cannot duplicate descriptor of temp file: %s\n"), strerror(errno));
339 #if defined(ALT_FORMAT)
341 * Discard title lines, then read lines to process.
343 fgets(line, sizeof(line), fd);
344 fgets(line, sizeof(line), fd);
346 while (fgets(line, sizeof(line), fd)) {
347 cnt = sscanf(line, "%s %llu %llu %llu %llu %llu %llu",
348 fsp, &blocks, &bsoft, &bhard, &inodes, &isoft, &ihard);
351 errstr(_("Bad format:\n%s\n"), line);
355 merge_limits_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard);
359 * Discard title line, then read pairs of lines to process.
361 fgets(line1, sizeof(line1), fd);
362 while (fgets(line1, sizeof(line1), fd) && fgets(line2, sizeof(line2), fd)) {
363 if (!(fsp = strtok(line1, " \t:"))) {
364 errstr(_("%s - bad format\n"), line1);
367 if (!(cp = strtok(NULL, "\n"))) {
368 errstr(_("%s - %s -- bad format\n"),
369 fsp, &fsp[strlen(fsp) + 1]);
373 cnt = sscanf(cp, _(" blocks in use: %llu, limits (soft = %llu, hard = %llu)"),
374 &blocks, &bsoft, &bhard);
376 errstr(_("%s - %s -- bad format\n"),
381 if (!(cp = strtok(line2, "\n"))) {
382 errstr(_("%s - %s -- bad format\n"),
387 cnt = sscanf(cp, _("\tinodes in use: %llu, limits (soft = %llu, hard = %llu)"),
388 &inodes, &isoft, &ihard);
390 errstr(_("%s - %s -- bad format\n"),
395 merge_limits_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard);
401 * Disable quotas for any filesystems that have not been found.
403 for (q = qlist; q; q = q->dq_next) {
404 if (q->dq_flags & DQ_FOUND) {
405 q->dq_flags &= ~DQ_FOUND;
408 q->dq_dqb.dqb_bsoftlimit = 0;
409 q->dq_dqb.dqb_bhardlimit = 0;
410 q->dq_dqb.dqb_isoftlimit = 0;
411 q->dq_dqb.dqb_ihardlimit = 0;
416 /* Merge changes on one dev to proper structure in the list */
417 static void merge_times_to_list(struct dquot *qlist, char *dev, time_t btime, time_t itime)
421 for (q = qlist; q; q = q->dq_next) {
422 if (!devcmp_handle(dev, q->dq_h))
425 q->dq_dqb.dqb_btime = btime;
426 q->dq_dqb.dqb_itime = itime;
427 q->dq_flags |= DQ_FOUND;
432 * Write grace times of user to file
434 int writeindividualtimes(struct dquot *qlist, int outfd, char *name, int quotatype)
439 char btimestr[MAXTIMELEN], itimestr[MAXTIMELEN];
442 lseek(outfd, 0, SEEK_SET);
443 if (!(fd = fdopen(dup(outfd), "w")))
444 die(1, _("Cannot duplicate descriptor of file to write to: %s\n"), strerror(errno));
446 fprintf(fd, _("Times to enforce softlimit for %s %s (%cid %d):\n"),
447 type2name(quotatype), name, *type2name(quotatype), qlist->dq_id);
448 fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n"));
450 _(" Filesystem block grace inode grace\n"));
453 for (q = qlist; q; q = q->dq_next) {
454 if (!q->dq_dqb.dqb_btime)
455 strcpy(btimestr, _("unset"));
456 else if (q->dq_dqb.dqb_btime <= now)
457 strcpy(btimestr, _("0seconds"));
459 sprintf(btimestr, "%useconds", (unsigned)(q->dq_dqb.dqb_btime - now));
460 if (!q->dq_dqb.dqb_itime)
461 strcpy(itimestr, _("unset"));
462 else if (q->dq_dqb.dqb_itime <= now)
463 strcpy(itimestr, _("0seconds"));
465 sprintf(itimestr, _("%useconds"), (unsigned)(q->dq_dqb.dqb_itime - now));
467 fprintf(fd, " %-24s %22s %22s\n", q->dq_h->qh_quotadev, btimestr, itimestr);
474 * Read list of grace times for a user and convert it
476 int readindividualtimes(struct dquot *qlist, int infd)
479 int cnt, btime, itime;
480 char line[BUFSIZ], fsp[BUFSIZ], btimestr[BUFSIZ], itimestr[BUFSIZ];
481 char iunits[BUFSIZ], bunits[BUFSIZ];
482 time_t now, bseconds, iseconds;
484 lseek(infd, 0, SEEK_SET);
485 if (!(fd = fdopen(dup(infd), "r")))
486 die(1, _("Cannot duplicate descriptor of temp file: %s\n"), strerror(errno));
489 * Discard title lines, then read lines to process.
491 fgets(line, sizeof(line), fd);
492 fgets(line, sizeof(line), fd);
493 fgets(line, sizeof(line), fd);
496 while (fgets(line, sizeof(line), fd)) {
497 cnt = sscanf(line, "%s %s %s", fsp, btimestr, itimestr);
500 errstr(_("bad format:\n%s\n"), line);
503 if (!strcmp(btimestr, _("unset")))
506 if (sscanf(btimestr, "%d%s", &btime, bunits) != 2)
508 if (str2timeunits(btime, bunits, &bseconds) < 0) {
510 errstr(_("Bad time units. Units are 'second', 'minute', 'hour', and 'day'.\n"));
515 if (!strcmp(itimestr, _("unset")))
518 if (sscanf(itimestr, "%d%s", &itime, iunits) != 2)
520 if (str2timeunits(itime, iunits, &iseconds) < 0)
524 merge_times_to_list(qlist, fsp, bseconds, iseconds);
532 * Convert a dquot list to an ASCII file of grace times.
534 int writetimes(struct quota_handle **handles, int outfd)
537 char itimebuf[MAXTIMELEN], btimebuf[MAXTIMELEN];
544 lseek(outfd, 0, SEEK_SET);
545 if ((fd = fdopen(dup(outfd), "w")) == NULL)
546 die(1, _("Cannot duplicate descriptor of file to edit: %s\n"), strerror(errno));
548 #if defined(ALT_FORMAT)
549 fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"),
550 type2name(handles[0]->qh_type));
551 fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n"));
552 fprintf(fd, _(" Filesystem Block grace period Inode grace period\n"));
554 for (i = 0; handles[i]; i++) {
555 time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0);
556 time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0);
557 fprintf(fd, " %-12s %22s %22s\n", handles[i]->qh_quotadev, btimebuf, itimebuf);
560 fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n"));
561 fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"),
562 type2name(handles[0]->qh_type));
563 for (i = 0; handles[i]; i++) {
564 time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0);
565 time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0);
566 fprintf(fd, _("block grace period: %s, file grace period: %s\n"),
567 handles[i]->qh_quotadev, btimebuf, itimebuf);
576 * Merge changes of grace times in an ASCII file into a dquot list.
578 int readtimes(struct quota_handle **handles, int infd)
581 int itime, btime, i, cnt;
582 time_t iseconds, bseconds;
584 #if defined(ALT_FORMAT)
585 char fsp[BUFSIZ], bunits[10], iunits[10], line[BUFSIZ];
587 char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
592 lseek(infd, 0, SEEK_SET);
593 if (!(fd = fdopen(dup(infd), "r"))) {
594 errstr(_("Cannot reopen temp file: %s\n"),
599 /* Set all grace times to default values */
600 for (i = 0; handles[i]; i++) {
601 handles[i]->qh_info.dqi_bgrace = MAX_DQ_TIME;
602 handles[i]->qh_info.dqi_igrace = MAX_IQ_TIME;
603 mark_quotafile_info_dirty(handles[i]);
605 #if defined(ALT_FORMAT)
607 * Discard three title lines, then read lines to process.
609 fgets(line, sizeof(line), fd);
610 fgets(line, sizeof(line), fd);
611 fgets(line, sizeof(line), fd);
613 while (fgets(line, sizeof(line), fd)) {
614 cnt = sscanf(line, "%s %d %s %d %s", fsp, &btime, bunits, &itime, iunits);
616 errstr(_("bad format:\n%s\n"), line);
621 * Discard two title lines, then read lines to process.
623 fgets(line1, sizeof(line1), fd);
624 fgets(line1, sizeof(line1), fd);
626 while (fgets(line1, sizeof(line1), fd)) {
627 if (!(fsp = strtok(line1, " \t:"))) {
628 errstr(_("%s - bad format\n"), line1);
631 if (!(cp = strtok(NULL, "\n"))) {
632 errstr(_("%s - %s -- bad format\n"),
633 fsp, &fsp[strlen(fsp) + 1]);
636 cnt = sscanf(cp, _(" block grace period: %d %s file grace period: %d %s"),
637 &btime, bunits, &itime, iunits);
639 errstr(_("%s - %s -- bad format\n"),
644 if (str2timeunits(btime, bunits, &bseconds) < 0 ||
645 str2timeunits(itime, iunits, &iseconds) < 0) {
646 errstr(_("Bad time units. Units are 'second', 'minute', 'hour', and 'day'.\n"));
649 for (i = 0; handles[i]; i++) {
650 if (!devcmp_handle(fsp, handles[i]))
652 handles[i]->qh_info.dqi_bgrace = bseconds;
653 handles[i]->qh_info.dqi_igrace = iseconds;
654 mark_quotafile_info_dirty(handles[i]);
664 * Free a list of dquot structures.
666 void freeprivs(struct dquot *qlist)
668 struct dquot *q, *nextq;
670 for (q = qlist; q; q = nextq) {