Exemple #1
0
/*
 * Do operations associated with quotas
 */
int
ext2_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
	     struct ucred *cred)
{
#ifndef QUOTA
	return (EOPNOTSUPP);
#else
	int cmd, type, error;

	type = cmds & SUBCMDMASK;
	cmd = cmds >> SUBCMDSHIFT;

	if (uid == -1) {
		switch(type) {
			case USRQUOTA:
				uid = cred->cr_ruid;
				break;
			case GRPQUOTA:
				uid = cred->cr_rgid;
				break;
			default:
				return (EINVAL);
		}
	}

	/*
	 * Check permissions.
	 */
	switch (cmd) {

	case Q_QUOTAON:
		error = priv_check_cred(cred, PRIV_UFS_QUOTAON, 0);
		break;

	case Q_QUOTAOFF:
		error = priv_check_cred(cred, PRIV_UFS_QUOTAOFF, 0);
		break;

	case Q_SETQUOTA:
		error = priv_check_cred(cred, PRIV_VFS_SETQUOTA, 0);
		break;

	case Q_SETUSE:
		error = priv_check_cred(cred, PRIV_UFS_SETUSE, 0);
		break;

	case Q_GETQUOTA:
		if (uid == cred->cr_ruid)
			error = 0;
		else
			error = priv_check_cred(cred, PRIV_VFS_GETQUOTA, 0);
		break;

	case Q_SYNC:
		error = 0;
		break;

	default:
		error = EINVAL;
		break;
	}

	if (error)
		return (error);


	if ((uint)type >= MAXQUOTAS)
		return (EINVAL);
	if (vfs_busy(mp, LK_NOWAIT))
		return (0);

	switch (cmd) {

	case Q_QUOTAON:
		error = ext2_quotaon(cred, mp, type, arg);
		break;

	case Q_QUOTAOFF:
		error = ext2_quotaoff(mp, type);
		break;

	case Q_SETQUOTA:
		error = ext2_setquota(mp, uid, type, arg);
		break;

	case Q_SETUSE:
		error = ext2_setuse(mp, uid, type, arg);
		break;

	case Q_GETQUOTA:
		error = ext2_getquota(mp, uid, type, arg);
		break;

	case Q_SYNC:
		error = ext2_qsync(mp);
		break;

	default:
		error = EINVAL;
		break;
	}
	vfs_unbusy(mp);
	return (error);
#endif
}
Exemple #2
0
int
ext2_quotaon(struct ucred *cred, struct mount *mp, int type, caddr_t fname)
{
	struct ext2mount *ump = VFSTOEXT2(mp);
	struct vnode *vp, **vpp;
	struct ext2_dquot *dq;
	int error;
	struct nlookupdata nd;
	struct scaninfo scaninfo;

	vpp = &ump->um_quotas[type];
	error = nlookup_init(&nd, fname, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP);
	if (error == 0)
		error = vn_open(&nd, NULL, FREAD|FWRITE, 0);
	if (error == 0 && nd.nl_open_vp->v_type != VREG)
		error = EACCES;
	if (error) {
		nlookup_done(&nd);
		return (error);
	}
	vp = nd.nl_open_vp;
	nd.nl_open_vp = NULL;
	nlookup_done(&nd);

	vn_unlock(vp);
	if (*vpp != vp)
		ext2_quotaoff(mp, type);
	ump->um_qflags[type] |= QTF_OPENING;
	mp->mnt_flag |= MNT_QUOTA;
	vsetflags(vp, VSYSTEM);
	*vpp = vp;
	/* XXX release duplicate vp if *vpp == vp? */
	/*
	 * Save the credential of the process that turned on quotas.
	 * Set up the time limits for this quota.
	 */
	ump->um_cred[type] = crhold(cred);
	ump->um_btime[type] = MAX_DQ_TIME;
	ump->um_itime[type] = MAX_IQ_TIME;
	if (ext2_dqget(NULLVP, 0, ump, type, &dq) == 0) {
		if (dq->dq_btime > 0)
			ump->um_btime[type] = dq->dq_btime;
		if (dq->dq_itime > 0)
			ump->um_itime[type] = dq->dq_itime;
		ext2_dqrele(NULLVP, dq);
	}
	/*
	 * Search vnodes associated with this mount point,
	 * adding references to quota file being opened.
	 * NB: only need to add dquot's for inodes being modified.
	 */
	scaninfo.rescan = 1;
	while (scaninfo.rescan) {
		scaninfo.rescan = 0;
		error = vmntvnodescan(mp, VMSC_GETVP,
					NULL, ext2_quotaon_scan, &scaninfo);
		if (error)
			break;
	}
	ump->um_qflags[type] &= ~QTF_OPENING;
	if (error)
		ext2_quotaoff(mp, type);
	return (error);
}