#include "opt_quota.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/caps.h>
#include <sys/malloc.h>
#include <sys/vnode.h>
#include "quota.h"
#include "inode.h"
#include "ufsmount.h"
#include "ufs_extern.h"
MALLOC_DEFINE(M_UFSMNT, "UFS mount", "UFS mount structure");
int
ufs_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *nvp;
int error;
error = VFS_VGET(mp, NULL, (ino_t)UFS_ROOTINO, &nvp);
if (error)
return (error);
*vpp = nvp;
return (0);
}
int
ufs_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);
}
}
switch (cmd) {
case Q_QUOTAON:
error = caps_priv_check(cred, SYSCAP_NOQUOTA_WR);
break;
case Q_QUOTAOFF:
error = caps_priv_check(cred, SYSCAP_NOQUOTA_WR);
break;
case Q_SETQUOTA:
error = caps_priv_check(cred, SYSCAP_NOQUOTA_WR);
break;
case Q_SETUSE:
error = caps_priv_check(cred, SYSCAP_NOQUOTA_WR);
break;
case Q_GETQUOTA:
if (uid == cred->cr_ruid)
error = 0;
else
error = caps_priv_check(cred, SYSCAP_RESTRICTEDROOT);
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 = ufs_quotaon(cred, mp, type, arg);
break;
case Q_QUOTAOFF:
error = ufs_quotaoff(mp, type);
break;
case Q_SETQUOTA:
error = ufs_setquota(mp, uid, type, arg);
break;
case Q_SETUSE:
error = ufs_setuse(mp, uid, type, arg);
break;
case Q_GETQUOTA:
error = ufs_getquota(mp, uid, type, arg);
break;
case Q_SYNC:
error = ufs_qsync(mp);
break;
default:
error = EINVAL;
break;
}
vfs_unbusy(mp);
return (error);
#endif
}
int
ufs_init(struct vfsconf *vfsp)
{
static int done;
if (done)
return (0);
done = 1;
#ifdef QUOTA
ufs_dqinit();
#endif
return (0);
}
int
ufs_fhtovp(struct mount *mp, struct vnode *rootvp,
struct ufid *ufhp, struct vnode **vpp)
{
struct inode *ip;
struct vnode *nvp;
int error;
error = VFS_VGET(mp, NULL, ufhp->ufid_ino, &nvp);
if (error) {
*vpp = NULLVP;
return (error);
}
ip = VTOI(nvp);
if (ip->i_mode == 0 ||
ip->i_gen != ufhp->ufid_gen ||
(VFSTOUFS(mp)->um_i_effnlink_valid ? ip->i_effnlink :
ip->i_nlink) <= 0) {
vput(nvp);
*vpp = NULLVP;
return (ESTALE);
}
*vpp = nvp;
return (0);
}
int
ufs_check_export(struct mount *mp, struct sockaddr *nam, int *exflagsp,
struct ucred **credanonp)
{
struct netcred *np;
struct ufsmount *ump;
ump = VFSTOUFS(mp);
np = vfs_export_lookup(mp, &ump->um_export, nam);
if (np == NULL)
return (EACCES);
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
return (0);
}