diff options
Diffstat (limited to 'quotaops.c')
-rw-r--r-- | quotaops.c | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/quotaops.c b/quotaops.c new file mode 100644 index 0000000..82bfb43 --- /dev/null +++ b/quotaops.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: quotaops.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $" + +#include <rpc/rpc.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/wait.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <paths.h> +#include <unistd.h> + +#if defined(RPC) +#include "rquota.h" +#endif + +#include "mntopt.h" +#include "quotaops.h" +#include "pot.h" +#include "bylabel.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" + +/* + * Convert ASCII input times to seconds. + */ +static int cvtatos(time_t time, char *units, time_t * seconds) +{ + if (memcmp(units, "second", 6) == 0) + *seconds = time; + else if (memcmp(units, "minute", 6) == 0) + *seconds = time * 60; + else if (memcmp(units, "hour", 4) == 0) + *seconds = time * 60 * 60; + else if (memcmp(units, "day", 3) == 0) + *seconds = time * 24 * 60 * 60; + else { + fprintf(stderr, _("%s: bad units, specify:\n %s, %s, %s, or %s"), units, + "days", "hours", "minutes", "seconds"); + return -1; + } + return 0; +} + +/* + * Collect the requested quota information. + */ +struct dquot *getprivs(qid_t id, struct quota_handle **handles) +{ + struct dquot *q, *qtail = NULL, *qhead = NULL; + int i; + + for (i = 0; handles[i]; i++) { + if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) { + fprintf(stderr, _("Error while getting quota from %s for %u: %s\n"), + handles[i]->qh_quotadev, id, strerror(errno)); + continue; + } + if (qhead == NULL) + qhead = q; + else + qtail->dq_next = q; + qtail = q; + q->dq_next = NULL; /* This should be already set, but just for sure... */ + } + return qhead; +} + +/* + * Store the requested quota information. + */ +int putprivs(struct dquot *qlist) +{ + struct dquot *q; + + for (q = qlist; q; q = q->dq_next) { + if (q->dq_h->qh_ops->commit_dquot(q) == -1) { + fprintf(stderr, _("Can't write quota for %u on %s: %s\n"), q->dq_id, + q->dq_h->qh_quotadev, strerror(errno)); + continue; + } + } + return 0; +} + +/* + * Take a list of priviledges and get it edited. + */ +int editprivs(char *tmpfile) +{ + long omask; + int pid, stat; + + omask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGHUP)); + if ((pid = fork()) < 0) { + perror("fork"); + return -1; + } + if (pid == 0) { + char *ed; + + sigsetmask(omask); + setgid(getgid()); + setuid(getuid()); + if ((ed = getenv("VISUAL")) == (char *)0) + if ((ed = getenv("EDITOR")) == (char *)0) + ed = _PATH_VI; + execlp(ed, ed, tmpfile, 0); + die(1, _("Can't exec %s\n"), ed); + } + waitpid(pid, &stat, 0); + sigsetmask(omask); + + return 0; +} + +/* + * Convert a dquot list to an ASCII file. + */ +int writeprivs(struct dquot *qlist, int outfd, char *name, int quotatype) +{ + struct dquot *q; + FILE *fd; + + ftruncate(outfd, 0); + lseek(outfd, 0, SEEK_SET); + if (!(fd = fdopen(dup(outfd), "w"))) + die(1, _("Can't duplicate descriptor of file to write to: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + fprintf(fd, _("Disk quotas for %s %s (%cid %d):\n"), + type2name(quotatype), name, *type2name(quotatype), name2id(name, quotatype)); + + fprintf(fd, + _ + (" Filesystem blocks soft hard inodes soft hard\n")); + + for (q = qlist; q; q = q->dq_next) { + fprintf(fd, " %-24s %10Lu %10Lu %10Lu %10Lu %8Lu %8Lu\n", + q->dq_h->qh_quotadev, + (long long)toqb(q->dq_dqb.dqb_curspace), + (long long)q->dq_dqb.dqb_bsoftlimit, + (long long)q->dq_dqb.dqb_bhardlimit, + (long long)q->dq_dqb.dqb_curinodes, + (long long)q->dq_dqb.dqb_isoftlimit, (long long)q->dq_dqb.dqb_ihardlimit); + } +#else + fprintf(fd, _("Quotas for %s %s:\n"), type2name(quotatype), name); + for (q = qlist; q; q = q->dq_next) { + fprintf(fd, _("%s: %s %d, limits (soft = %d, hard = %d)\n"), + q->dq_h->qh_quotadev, _("blocks in use:"), + (int)toqb(q->dq_dqb.dqb_curspace), + q->dq_dqb.dqb_bsoftlimit, q->dq_dqb.dqb_bhardlimit); + fprintf(fd, _("%s %d, limits (soft = %d, hard = %d)\n"), + _("\tinodes in use:"), q->dq_dqb.dqb_curinodes, + q->dq_dqb.dqb_isoftlimit, q->dq_dqb.dqb_ihardlimit); + } +#endif + fclose(fd); + return 0; +} + +/* Merge changes on one dev to proper structure in the list */ +static void merge_to_list(struct dquot *qlist, char *dev, u_int64_t blocks, u_int64_t bsoft, + u_int64_t bhard, u_int64_t inodes, u_int64_t isoft, u_int64_t ihard) +{ + struct dquot *q; + + for (q = qlist; q; q = q->dq_next) { + if (strcmp(dev, q->dq_h->qh_quotadev)) + continue; + + /* + * Cause time limit to be reset when the quota is + * next used if previously had no soft limit or were + * under it, but now have a soft limit and are over + * it. + */ + if (bsoft && (toqb(q->dq_dqb.dqb_curspace) >= bsoft) && + (q->dq_dqb.dqb_bsoftlimit == 0 || + toqb(q->dq_dqb.dqb_curspace) < q->dq_dqb.dqb_bsoftlimit)) + q->dq_dqb.dqb_btime = 0; + + if (isoft && (q->dq_dqb.dqb_curinodes >= isoft) && + (q->dq_dqb.dqb_isoftlimit == 0 || + q->dq_dqb.dqb_curinodes < q->dq_dqb.dqb_isoftlimit)) q->dq_dqb.dqb_itime = 0; + + q->dq_dqb.dqb_bsoftlimit = bsoft; + q->dq_dqb.dqb_bhardlimit = bhard; + q->dq_dqb.dqb_isoftlimit = isoft; + q->dq_dqb.dqb_ihardlimit = ihard; + q->dq_flags |= DQ_FOUND; + + if (blocks != toqb(q->dq_dqb.dqb_curspace)) + fprintf(stderr, _("WARNING: %s: cannot change current block allocation\n"), + q->dq_h->qh_quotadev); + if (inodes != q->dq_dqb.dqb_curinodes) + fprintf(stderr, _("WARNING: %s: cannot change current inode allocation\n"), + q->dq_h->qh_quotadev); + } +} + +/* + * Merge changes to an ASCII file into a dquot list. + */ +int readprivs(struct dquot *qlist, int infd) +{ + FILE *fd; + int cnt; + long long blocks, bsoft, bhard, inodes, isoft, ihard; + struct dquot *q; + +#if defined(ALT_FORMAT) + char fsp[BUFSIZ], line[BUFSIZ]; +#else + char *fsp, line1[BUFSIZ], line2[BUFSIZ]; +#endif + + lseek(infd, 0, SEEK_SET); + if (!(fd = fdopen(dup(infd), "r"))) + die(1, _("Can't duplicate descriptor of temp file: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + /* + * Discard title lines, then read lines to process. + */ + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + + while (fgets(line, sizeof(line), fd)) { + cnt = sscanf(line, "%s %Lu %Lu %Lu %Lu %Lu %Lu", + fsp, &blocks, &bsoft, &bhard, &inodes, &isoft, &ihard); + + if (cnt != 7) { + fprintf(stderr, _("Bad format:\n%s\n"), line); + return -1; + } + + merge_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard); + } +#else + /* + * Discard title line, then read pairs of lines to process. + */ + fgets(line1, sizeof(line1), fd); + while (fgets(line1, sizeof(line1), fd) && fgets(line2, sizeof(line2), fd)) { + if (!(fsp = strtok(line1, " \t:"))) { + fprintf(stderr, _("%s: bad format\n"), line1); + return -1; + } + if (!(cp = strtok(NULL, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, &fsp[strlen(fsp) + 1]); + return -1; + } + + cnt = sscanf(cp, _(" blocks in use: %Lu, limits (soft = %Lu, hard = %Lu)"), + &blocks, &bsoft, &bhard); + if (cnt != 3) { + fprintf(stderr, _("%s:%s: bad format\n"), fsp, cp); + return -1; + } + + if (!(cp = strtok(line2, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, line2); + return -1; + } + + cnt = sscanf(cp, _("\tinodes in use: %Lu, limits (soft = %Lu, hard = %Lu)"), + &inodes, &isoft, &ihard); + if (cnt != 3) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, line2); + return -1; + } + + merge_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard); + } +#endif + fclose(fd); + + /* + * Disable quotas for any filesystems that have not been found. + */ + for (q = qlist; q; q = q->dq_next) { + if (q->dq_flags & DQ_FOUND) { + q->dq_flags &= ~DQ_FOUND; + continue; + } + q->dq_dqb.dqb_bsoftlimit = 0; + q->dq_dqb.dqb_bhardlimit = 0; + q->dq_dqb.dqb_isoftlimit = 0; + q->dq_dqb.dqb_ihardlimit = 0; + } + return 0; +} + +/* + * Convert a dquot list to an ASCII file of grace times. + */ +int writetimes(struct quota_handle **handles, int outfd) +{ + FILE *fd; + char itimebuf[MAXTIMELEN], btimebuf[MAXTIMELEN]; + int i; + + if (!handles[0]) + return 0; + + ftruncate(outfd, 0); + lseek(outfd, 0, SEEK_SET); + if ((fd = fdopen(dup(outfd), "w")) == NULL) + die(1, _("Can't duplicate descriptor of file to edit: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"), + type2name(handles[0]->qh_type)); + fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n")); + fprintf(fd, _(" Filesystem Block grace period Inode grace period\n")); + + for (i = 0; handles[i]; i++) { + time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0); + time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0); + fprintf(fd, " %-12s %22s %22s\n", handles[i]->qh_quotadev, btimebuf, itimebuf); + } +#else + fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n")); + fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"), + type2name(handles[0]->qh_type)); + for (i = 0; handles[i]; i++) { + time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0); + time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0); + fprintf(fd, _("%s: block grace period: %s, file grace period: %s\n"), + handles[i]->qh_quotadev, btimebuf, itimebuf); + } +#endif + + fclose(fd); + return 0; +} + +/* + * Merge changes of grace times in an ASCII file into a dquot list. + */ +int readtimes(struct quota_handle **handles, int infd) +{ + FILE *fd; + int itime, btime, i, cnt; + time_t iseconds, bseconds; + +#if defined(ALT_FORMAT) + char fsp[BUFSIZ], bunits[10], iunits[10], line[BUFSIZ]; +#else + char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; +#endif + + if (!handles[0]) + return 0; + lseek(infd, 0, SEEK_SET); + if (!(fd = fdopen(dup(infd), "r"))) { + fprintf(stderr, _("Can't reopen temp file: %s\n"), strerror(errno)); + return -1; + } + + /* Set all grace times to default values */ + for (i = 0; handles[i]; i++) { + handles[i]->qh_info.dqi_bgrace = MAX_DQ_TIME; + handles[i]->qh_info.dqi_igrace = MAX_IQ_TIME; + mark_quotafile_info_dirty(handles[i]); + } +#if defined(ALT_FORMAT) + /* + * Discard three title lines, then read lines to process. + */ + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + + while (fgets(line, sizeof(line), fd)) { + cnt = sscanf(line, "%s %d %s %d %s", fsp, &btime, bunits, &itime, iunits); + if (cnt != 5) { + fprintf(stderr, _("bad format:\n%s\n"), line); + return -1; + } +#else + /* + * Discard two title lines, then read lines to process. + */ + fgets(line1, sizeof(line1), fd); + fgets(line1, sizeof(line1), fd); + + while (fgets(line1, sizeof(line1), fd)) { + if (!(fsp = strtok(line1, " \t:"))) { + fprintf(stderr, _("%s: bad format\n"), line1); + return -1; + } + if (!(cp = strtok(NULL, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, &fsp[strlen(fsp) + 1]); + return -1; + } + cnt = sscanf(cp, _(" block grace period: %d %s file grace period: %d %s"), + &btime, bunits, &itime, iunits); + if (cnt != 4) { + fprintf(stderr, _("%s:%s: bad format\n"), fsp, cp); + return -1; + } +#endif + if (cvtatos(btime, bunits, &bseconds) < 0) + return -1; + if (cvtatos(itime, iunits, &iseconds) < 0) + return -1; + for (i = 0; handles[i]; i++) { + if (strcmp(fsp, handles[i]->qh_quotadev)) + continue; + handles[i]->qh_info.dqi_bgrace = bseconds; + handles[i]->qh_info.dqi_igrace = iseconds; + mark_quotafile_info_dirty(handles[i]); + break; + } + } + fclose(fd); + + return 0; +} + +/* + * Free a list of dquot structures. + */ +void freeprivs(struct dquot *qlist) +{ + struct dquot *q, *nextq; + + for (q = qlist; q; q = nextq) { + nextq = q->dq_next; + free(q); + } +} |