xref: /original-bsd/sys/ufs/ffs/ufs_vfsops.c (revision 3705696b)
1 /*
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ufs_vfsops.c	8.1 (Berkeley) 06/11/93
8  */
9 
10 #include <sys/param.h>
11 #include <net/radix.h>
12 #include <sys/domain.h>
13 #include <sys/socket.h>
14 #include <sys/mbuf.h>
15 #include <sys/mount.h>
16 #include <sys/proc.h>
17 #include <sys/buf.h>
18 #include <sys/vnode.h>
19 #include <sys/malloc.h>
20 
21 #include <miscfs/specfs/specdev.h>
22 
23 #include <ufs/ufs/quota.h>
24 #include <ufs/ufs/inode.h>
25 #include <ufs/ufs/ufsmount.h>
26 #include <ufs/ufs/ufs_extern.h>
27 
28 /*
29  * Flag to permit forcible unmounting.
30  */
31 int doforce = 1;
32 
33 /*
34  * Make a filesystem operational.
35  * Nothing to do at the moment.
36  */
37 /* ARGSUSED */
38 int
39 ufs_start(mp, flags, p)
40 	struct mount *mp;
41 	int flags;
42 	struct proc *p;
43 {
44 
45 	return (0);
46 }
47 
48 /*
49  * Check to see if a filesystem is mounted on a block device.
50  */
51 int
52 ufs_mountedon(vp)
53 	register struct vnode *vp;
54 {
55 	register struct vnode *vq;
56 
57 	if (vp->v_specflags & SI_MOUNTEDON)
58 		return (EBUSY);
59 	if (vp->v_flag & VALIASED) {
60 		for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
61 			if (vq->v_rdev != vp->v_rdev ||
62 			    vq->v_type != vp->v_type)
63 				continue;
64 			if (vq->v_specflags & SI_MOUNTEDON)
65 				return (EBUSY);
66 		}
67 	}
68 	return (0);
69 }
70 
71 /*
72  * Do operations associated with quotas
73  */
74 int
75 ufs_quotactl(mp, cmds, uid, arg, p)
76 	struct mount *mp;
77 	int cmds;
78 	uid_t uid;
79 	caddr_t arg;
80 	struct proc *p;
81 {
82 	int cmd, type, error;
83 
84 #ifndef QUOTA
85 	return (EOPNOTSUPP);
86 #else
87 	if (uid == -1)
88 		uid = p->p_cred->p_ruid;
89 	cmd = cmds >> SUBCMDSHIFT;
90 
91 	switch (cmd) {
92 	case Q_GETQUOTA:
93 	case Q_SYNC:
94 		if (uid == p->p_cred->p_ruid)
95 			break;
96 		/* fall through */
97 	default:
98 		if (error = suser(p->p_ucred, &p->p_acflag))
99 			return (error);
100 	}
101 
102 	type = cmd & SUBCMDMASK;
103 	if ((u_int)type >= MAXQUOTAS)
104 		return (EINVAL);
105 
106 	switch (cmd) {
107 
108 	case Q_QUOTAON:
109 		return (quotaon(p, mp, type, arg));
110 
111 	case Q_QUOTAOFF:
112 		if (vfs_busy(mp))
113 			return (0);
114 		error = quotaoff(p, mp, type);
115 		vfs_unbusy(mp);
116 		return (error);
117 
118 	case Q_SETQUOTA:
119 		return (setquota(mp, uid, type, arg));
120 
121 	case Q_SETUSE:
122 		return (setuse(mp, uid, type, arg));
123 
124 	case Q_GETQUOTA:
125 		return (getquota(mp, uid, type, arg));
126 
127 	case Q_SYNC:
128 		if (vfs_busy(mp))
129 			return (0);
130 		error = qsync(mp);
131 		vfs_unbusy(mp);
132 		return (error);
133 
134 	default:
135 		return (EINVAL);
136 	}
137 	/* NOTREACHED */
138 #endif
139 }
140 
141 /*
142  * Build hash lists of net addresses and hang them off the mount point.
143  * Called by ufs_mount() to set up the lists of export addresses.
144  */
145 ufs_hang_addrlist(mp, argp)
146 	struct mount *mp;
147 	struct ufs_args *argp;
148 {
149 	register struct netcred *np;
150 	register struct radix_node_head *rnh;
151 	register int i;
152 	struct radix_node *rn;
153 	struct ufsmount *ump;
154 	struct sockaddr *saddr, *smask = 0;
155 	struct domain *dom;
156 	int error;
157 
158 	ump = VFSTOUFS(mp);
159 	if (argp->slen == 0) {
160 		if (mp->mnt_flag & MNT_DEFEXPORTED)
161 			return (EPERM);
162 		np = &ump->um_defexported;
163 		np->netc_exflags = argp->exflags;
164 		np->netc_anon = argp->anon;
165 		np->netc_anon.cr_ref = 1;
166 		mp->mnt_flag |= MNT_DEFEXPORTED;
167 		return (0);
168 	}
169 	i = sizeof(struct netcred) + argp->slen + argp->msklen;
170 	np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);
171 	bzero((caddr_t)np, i);
172 	saddr = (struct sockaddr *)(np + 1);
173 	if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen))
174 		goto out;
175 	if (saddr->sa_len > argp->slen)
176 		saddr->sa_len = argp->slen;
177 	if (argp->msklen) {
178 		smask = (struct sockaddr *)((caddr_t)saddr + argp->slen);
179 		if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen))
180 			goto out;
181 		if (smask->sa_len > argp->msklen)
182 			smask->sa_len = argp->msklen;
183 	}
184 	i = saddr->sa_family;
185 	if ((rnh = ump->um_rtable[i]) == 0) {
186 		/*
187 		 * Seems silly to initialize every AF when most are not
188 		 * used, do so on demand here
189 		 */
190 		for (dom = domains; dom; dom = dom->dom_next)
191 			if (dom->dom_family == i && dom->dom_rtattach) {
192 				dom->dom_rtattach((void **)&ump->um_rtable[i],
193 					dom->dom_rtoffset);
194 				break;
195 			}
196 		if ((rnh = ump->um_rtable[i]) == 0) {
197 			error = ENOBUFS;
198 			goto out;
199 		}
200 	}
201 	rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh,
202 		np->netc_rnodes);
203 	if (rn == 0 || np != (struct netcred *)rn) { /* already exists */
204 		error = EPERM;
205 		goto out;
206 	}
207 	np->netc_exflags = argp->exflags;
208 	np->netc_anon = argp->anon;
209 	np->netc_anon.cr_ref = 1;
210 	return (0);
211 out:
212 	free(np, M_NETADDR);
213 	return (error);
214 }
215 
216 /* ARGSUSED */
217 static int
218 ufs_free_netcred(rn, w)
219 	struct radix_node *rn;
220 	caddr_t w;
221 {
222 	register struct radix_node_head *rnh = (struct radix_node_head *)w;
223 
224 	(*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
225 	free((caddr_t)rn, M_NETADDR);
226 	return (0);
227 }
228 
229 
230 /*
231  * Free the net address hash lists that are hanging off the mount points.
232  */
233 void
234 ufs_free_addrlist(ump)
235 	struct ufsmount *ump;
236 {
237 	register int i;
238 	register struct radix_node_head *rnh;
239 
240 	for (i = 0; i <= AF_MAX; i++)
241 		if (rnh = ump->um_rtable[i]) {
242 			(*rnh->rnh_walktree)(rnh, ufs_free_netcred,
243 			    (caddr_t)rnh);
244 			free((caddr_t)rnh, M_RTABLE);
245 			ump->um_rtable[i] = 0;
246 		}
247 }
248 
249 /*
250  * This is the generic part of fhtovp called after the underlying
251  * filesystem has validated the file handle.
252  *
253  * Verify that a host should have access to a filesystem, and if so
254  * return a vnode for the presented file handle.
255  */
256 int
257 ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
258 	register struct mount *mp;
259 	struct ufid *ufhp;
260 	struct mbuf *nam;
261 	struct vnode **vpp;
262 	int *exflagsp;
263 	struct ucred **credanonp;
264 {
265 	register struct inode *ip;
266 	register struct netcred *np;
267 	register struct ufsmount *ump = VFSTOUFS(mp);
268 	register struct radix_node_head *rnh;
269 	struct vnode *nvp;
270 	struct sockaddr *saddr;
271 	int error;
272 
273 	/*
274 	 * Get the export permission structure for this <mp, client> tuple.
275 	 */
276 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
277 		return (EACCES);
278 	np = NULL;
279 	if (nam != NULL) {
280 		saddr = mtod(nam, struct sockaddr *);
281 		rnh = ump->um_rtable[saddr->sa_family];
282 		if (rnh != NULL) {
283 			np = (struct netcred *)
284 			    (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
285 			if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
286 				np = NULL;
287 		}
288 	}
289 	if (np == NULL) {
290 		/*
291 		 * If no address match, use the default if it exists.
292 		 */
293 		if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
294 			return (EACCES);
295 		np = &ump->um_defexported;
296 	}
297 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
298 		*vpp = NULLVP;
299 		return (error);
300 	}
301 	ip = VTOI(nvp);
302 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
303 		vput(nvp);
304 		*vpp = NULLVP;
305 		return (ESTALE);
306 	}
307 	*vpp = nvp;
308 	*exflagsp = np->netc_exflags;
309 	*credanonp = &np->netc_anon;
310 	return (0);
311 }
312