Esempio n. 1
1
/*
 * Convert a quota file from one format to another.
 */
int
quota_convert(struct quotafile *qf, int wordsize)
{
	struct quotafile *newqf;
	struct dqhdr64 dqh;
	struct dqblk dqblk;
	struct group *grp;
	int serrno, maxid, id, fd;

	/*
	 * Quotas must not be active and quotafile must be open
	 * for reading and writing.
	 */
	if ((qf->accmode & O_RDWR) != O_RDWR || qf->fd == -1) {
		errno = EBADF;
		return (-1);
	}
	if ((wordsize != 32 && wordsize != 64) ||
	     wordsize == qf->wordsize) {
		errno = EINVAL;
		return (-1);
	}
	maxid = quota_maxid(qf);
	if ((newqf = calloc(1, sizeof(*qf))) == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	*newqf = *qf;
	snprintf(newqf->qfname, MAXPATHLEN + 1, "%s_%d.orig", qf->qfname,
	    qf->wordsize);
	if (rename(qf->qfname, newqf->qfname) < 0) {
		free(newqf);
		return (-1);
	}
	if ((newqf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
		serrno = errno;
		goto error;
	}
	newqf->wordsize = wordsize;
	if (wordsize == 64) {
		memset(&dqh, 0, sizeof(dqh));
		memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
		dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
		dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
		dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
		if (write(newqf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
			serrno = errno;
			goto error;
		}
	}
	grp = getgrnam(QUOTAGROUP);
	fchown(newqf->fd, 0, grp ? grp->gr_gid : 0);
	fchmod(newqf->fd, 0640);
	for (id = 0; id <= maxid; id++) {
		if ((quota_read(qf, &dqblk, id)) < 0)
			break;
		switch (newqf->wordsize) {
		case 32:
			if ((quota_write32(newqf, &dqblk, id)) < 0)
				break;
			continue;
		case 64:
			if ((quota_write64(newqf, &dqblk, id)) < 0)
				break;
			continue;
		default:
			errno = EINVAL;
			break;
		}
	}
	if (id < maxid) {
		serrno = errno;
		goto error;
	}
	/*
	 * Update the passed in quotafile to reference the new file
	 * of the converted format size.
	 */
	fd = qf->fd;
	qf->fd = newqf->fd;
	newqf->fd = fd;
	qf->wordsize = newqf->wordsize;
	quota_close(newqf);
	return (0);
error:
	/* put back the original file */
	(void) rename(newqf->qfname, qf->qfname);
	quota_close(newqf);
	errno = serrno;
	return (-1);
}
Esempio n. 2
0
EXPORTED int quota_update_useds(const char *quotaroot,
                       const quota_t diff[QUOTA_NUMRESOURCES],
                       const char *mboxname)
{
    struct quota q;
    struct txn *tid = NULL;
    int r = 0;
    struct mboxevent *mboxevents = NULL;

    if (!quotaroot || !*quotaroot)
        return IMAP_QUOTAROOT_NONEXISTENT;

    quota_init(&q, quotaroot);

    r = quota_read(&q, &tid, 1);

    if (!r) {
        int res;
        int cmp = 1;
        if (q.scanmbox) {
            cmp = cyrusdb_compar(qdb, mboxname, strlen(mboxname),
                                 q.scanmbox, strlen(q.scanmbox));
        }
        for (res = 0; res < QUOTA_NUMRESOURCES; res++) {
            int was_over = quota_is_overquota(&q, res, NULL);
            quota_use(&q, res, diff[res]);
            if (cmp <= 0)
                q.scanuseds[res] += diff[res];

            if (was_over && !quota_is_overquota(&q, res, NULL)) {
                struct mboxevent *mboxevent =
                    mboxevent_enqueue(EVENT_QUOTA_WITHIN, &mboxevents);
                mboxevent_extract_quota(mboxevent, &q, res);
            }
        }
        r = quota_write(&q, &tid);
    }

    if (r) {
        quota_abort(&tid);
        goto out;
    }
    quota_commit(&tid);

    mboxevent_notify(mboxevents);

out:
    quota_free(&q);
    if (r) {
        syslog(LOG_ERR, "LOSTQUOTA: unable to record change of "
               QUOTA_T_FMT " bytes and " QUOTA_T_FMT " messages in quota %s: %s",
               diff[QUOTA_STORAGE], diff[QUOTA_MESSAGE],
               quotaroot, error_message(r));
    }

    mboxevent_freequeue(&mboxevents);

    return r;
}
Esempio n. 3
0
int
quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
{
	struct dqblk dqbuf;
	int qcmd;

	if (qf->fd == -1) {
		qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
		return (quotactl(qf->fsname, qcmd, id, dqb));
	}
	/*
	 * Have to do read-modify-write of quota in file.
	 */
	if ((qf->accmode & O_RDWR) != O_RDWR) {
		errno = EBADF;
		return (-1);
	}
	if (quota_read(qf, &dqbuf, id) != 0)
		return (-1);
	/*
	 * Reset time limit if have a soft limit and were
	 * previously under it, but are now over it
	 * or if there previously was no soft limit, but
	 * now have one and are over it.
	 */
	if (dqbuf.dqb_bsoftlimit && id != 0 &&
	    dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
	    dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
		dqb->dqb_btime = 0;
	if (dqbuf.dqb_bsoftlimit == 0 && id != 0 &&
	    dqb->dqb_bsoftlimit > 0 &&
	    dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
		dqb->dqb_btime = 0;
	if (dqbuf.dqb_isoftlimit && id != 0 &&
	    dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
	    dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
		dqb->dqb_itime = 0;
	if (dqbuf.dqb_isoftlimit == 0 && id !=0 &&
	    dqb->dqb_isoftlimit > 0 &&
	    dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
		dqb->dqb_itime = 0;
	dqb->dqb_curinodes = dqbuf.dqb_curinodes;
	dqb->dqb_curblocks = dqbuf.dqb_curblocks;
	/*
	 * Write it back.
	 */
	switch (qf->wordsize) {
	case 32:
		return (quota_write32(qf, dqb, id));
	case 64:
		return (quota_write64(qf, dqb, id));
	default:
		errno = EINVAL;
		return (-1);
	}
	/* not reached */
}
Esempio n. 4
0
/*
 * Check to see if a particular quota is available.
 */
static int
getufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype)
{
	struct quotafile *qf;

	if ((qf = quota_open(fs, quotatype, O_RDONLY)) == NULL)
		return (0);
	if (quota_read(qf, &qup->dqblk, id) != 0)
		return (0);
	quota_close(qf);
	return (1);
}
Esempio n. 5
0
/*
 * Collect the requested quota information.
 */
struct quotause *
getprivs(long id, int quotatype, char *fspath)
{
	struct quotafile *qf;
	struct fstab *fs;
	struct quotause *qup, *quptail;
	struct quotause *quphead;

	setfsent();
	quphead = quptail = NULL;
	while ((fs = getfsent())) {
		if (fspath && *fspath && strcmp(fspath, fs->fs_spec) &&
		    strcmp(fspath, fs->fs_file))
			continue;
		if (strcmp(fs->fs_vfstype, "ufs"))
			continue;
		if ((qf = quota_open(fs, quotatype, O_CREAT|O_RDWR)) == NULL) {
			if (errno != EOPNOTSUPP)
				warn("cannot open quotas on %s", fs->fs_file);
			continue;
		}
		if ((qup = (struct quotause *)calloc(1, sizeof(*qup))) == NULL)
			errx(2, "out of memory");
		qup->qf = qf;
		strncpy(qup->fsname, fs->fs_file, sizeof(qup->fsname));
		if (quota_read(qf, &qup->dqblk, id) == -1) {
			warn("cannot read quotas on %s", fs->fs_file);
			freeprivs(qup);
			continue;
		}
		if (quphead == NULL)
			quphead = qup;
		else
			quptail->next = qup;
		quptail = qup;
		qup->next = 0;
	}
	if (quphead == NULL) {
		warnx("No quotas on %s", fspath ? fspath : "any filesystems");
	}
	endfsent();
	return (quphead);
}
Esempio n. 6
0
EXPORTED int quota_check_useds(const char *quotaroot,
                      const quota_t diff[QUOTA_NUMRESOURCES])
{
    int r = 0;
    struct quota q;
    int res;

    /*
     * We are always allowed to *reduce* usage even if it doesn't get us
     * below the quota.  As a side effect this allows our caller to pass
     * delta = -1 meaning "don't care about quota checks".
     */
    for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++) {
        if (diff[res] >= 0)
            break;
    }
    if (res == QUOTA_NUMRESOURCES)
        return 0;           /* all negative */

    quota_init(&q, quotaroot);
    r = quota_read(&q, NULL, /*wrlock*/0);

    if (r == IMAP_QUOTAROOT_NONEXISTENT) {
        r = 0;
        goto done;
    }
    if (r) goto done;

    for (res = 0 ; res < QUOTA_NUMRESOURCES ; res++) {
        r = quota_check(&q, res, diff[res]);
        if (r) goto done;
    }

done:
    quota_free(&q);
    return r;
}
Esempio n. 7
0
/*
 * Update a specified quota file.
 */
int
update(const char *fsname, struct quotafile *qf, int type)
{
	struct fileusage *fup;
	u_long id, lastid, highid = 0;
	struct dqblk dqbuf;
	struct stat sb;
	static struct dqblk zerodqbuf;
	static struct fileusage zerofileusage;

	/*
	 * Scan the on-disk quota file and record any usage changes.
	 */
	lastid = quota_maxid(qf);
	for (id = 0; id <= lastid; id++) {
		if (quota_read(qf, &dqbuf, id) < 0)
			dqbuf = zerodqbuf;
		if ((fup = lookup(id, type)) == NULL)
			fup = &zerofileusage;
		if (fup->fu_curinodes || fup->fu_curblocks ||
		    dqbuf.dqb_bsoftlimit || dqbuf.dqb_bhardlimit ||
		    dqbuf.dqb_isoftlimit || dqbuf.dqb_ihardlimit)
			highid = id;
		if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
		    dqbuf.dqb_curblocks == fup->fu_curblocks) {
			fup->fu_curinodes = 0;
			fup->fu_curblocks = 0;
			continue;
		}
		printchanges(fsname, type, &dqbuf, fup, id);
		dqbuf.dqb_curinodes = fup->fu_curinodes;
		dqbuf.dqb_curblocks = fup->fu_curblocks;
		(void) quota_write_usage(qf, &dqbuf, id);
		fup->fu_curinodes = 0;
		fup->fu_curblocks = 0;
	}

	/*
	 * Walk the hash table looking for ids with non-zero usage
	 * that are not currently recorded in the quota file. E.g.
	 * ids that are past the end of the current file.
	 */
	for (id = 0; id < FUHASH; id++) {
		for (fup = fuhead[type][id]; fup != NULL; fup = fup->fu_next) {
			if (fup->fu_id <= lastid)
				continue;
			if (fup->fu_curinodes == 0 && fup->fu_curblocks == 0)
				continue;
			bzero(&dqbuf, sizeof(struct dqblk));
			if (fup->fu_id > highid)
				highid = fup->fu_id;
			printchanges(fsname, type, &dqbuf, fup, fup->fu_id);
			dqbuf.dqb_curinodes = fup->fu_curinodes;
			dqbuf.dqb_curblocks = fup->fu_curblocks;
			(void) quota_write_usage(qf, &dqbuf, fup->fu_id);
			fup->fu_curinodes = 0;
			fup->fu_curblocks = 0;
		}
	}
	/*
	 * If this is old format file, then size may be smaller,
	 * so ensure that we only truncate when it will make things
	 * smaller, and not if it will grow an old format file.
	 */
	if (highid < lastid &&
	    stat(quota_qfname(qf), &sb) == 0 &&
	    sb.st_size > (((off_t)highid + 2) * sizeof(struct dqblk)))
		truncate(quota_qfname(qf),
		    (((off_t)highid + 2) * sizeof(struct dqblk)));
	return (0);
}
Esempio n. 8
0
int
repquota(struct fstab *fs, int type)
{
	struct fileusage *fup;
	struct quotafile *qf;
	u_long id, maxid;
	struct dqblk dqbuf;
	static int multiple = 0;

	if ((qf = quota_open(fs, type, O_RDONLY)) == NULL) {
		if (vflag && !aflag) {
			if (multiple++)
				printf("\n");
			fprintf(stdout, "*** No %s quotas on %s (%s)\n",
			    qfextension[type], fs->fs_file, fs->fs_spec);
			return(1);
		}
		return(0);
	}
	if (multiple++)
		printf("\n");
	if (vflag)
		fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
		    qfextension[type], fs->fs_file, fs->fs_spec);
	printf("%*s           Block  limits                    File  limits\n",
		max(MAXLOGNAME - 1, 10), " ");
	printf("User%*s  used   soft   hard  grace     used    soft    hard  grace\n",
		max(MAXLOGNAME - 1, 10), " ");
	maxid = quota_maxid(qf);
	for (id = 0; id <= maxid; id++) {
		if (quota_read(qf, &dqbuf, id) != 0)
			break;
		if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
			continue;
		if ((fup = lookup(id, type)) == 0)
			fup = addid(id, type, (char *)0);
		printf("%-*s ", max(MAXLOGNAME - 1, 10), fup->fu_name);
		printf("%c%c", 
		    dqbuf.dqb_bsoftlimit &&
		    dqbuf.dqb_curblocks >=
		    dqbuf.dqb_bsoftlimit ? '+' : '-',
		    dqbuf.dqb_isoftlimit &&
		    dqbuf.dqb_curinodes >=
		    dqbuf.dqb_isoftlimit ? '+' : '-');
		prthumanval(dqbuf.dqb_curblocks);
		prthumanval(dqbuf.dqb_bsoftlimit);
		prthumanval(dqbuf.dqb_bhardlimit);
		printf(" %6s",
		    dqbuf.dqb_bsoftlimit &&
		    dqbuf.dqb_curblocks >=
		    dqbuf.dqb_bsoftlimit ?
		    timeprt(dqbuf.dqb_btime) : "-");
		printf("  %7ju %7ju %7ju %6s\n",
		    (uintmax_t)dqbuf.dqb_curinodes,
		    (uintmax_t)dqbuf.dqb_isoftlimit,
		    (uintmax_t)dqbuf.dqb_ihardlimit,
		    dqbuf.dqb_isoftlimit &&
		    dqbuf.dqb_curinodes >=
		    dqbuf.dqb_isoftlimit ?
		    timeprt(dqbuf.dqb_itime) : "-");
	}
	quota_close(qf);
	return (0);
}