xref: /original-bsd/sys/ufs/ufs/ufs_vfsops.c (revision efc5bb34)
1 /*
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ufs_vfsops.c	7.64 (Berkeley) 09/24/92
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 	if (argp->slen == 0) {
159 		if (mp->mnt_flag & MNT_DEFEXPORTED)
160 			return (EPERM);
161 		np = &ump->um_defexported;
162 		np->netc_exflags = argp->exflags;
163 		np->netc_anon = argp->anon;
164 		np->netc_anon.cr_ref = 1;
165 		mp->mnt_flag |= MNT_DEFEXPORTED;
166 		return (0);
167 	}
168 	i = sizeof(struct netcred) + argp->slen + argp->msklen;
169 	np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);
170 	bzero((caddr_t)np, i);
171 	saddr = (struct sockaddr *)(np + 1);
172 	if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen))
173 		goto out;
174 	if (saddr->sa_len > argp->slen)
175 		saddr->sa_len = argp->slen;
176 	if (argp->msklen) {
177 		smask = (struct sockaddr *)((caddr_t)saddr + argp->slen);
178 		if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen))
179 			goto out;
180 		if (smask->sa_len > argp->msklen)
181 			smask->sa_len = argp->msklen;
182 	}
183 	ump = VFSTOUFS(mp);
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_add)((caddr_t)saddr, (caddr_t)smask, rnh->rnh_treetop,
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 	free((caddr_t)rn, M_NETADDR);
223 }
224 
225 
226 /*
227  * Free the net address hash lists that are hanging off the mount points.
228  */
229 void
230 ufs_free_addrlist(ump)
231 	struct ufsmount *ump;
232 {
233 	register int i;
234 	register struct radix_node_head *rnh;
235 
236 	for (i = 0; i <= AF_MAX; i++)
237 		if (rnh = ump->um_rtable[i]) {
238 			(*rnh->rnh_walk)(rnh->rnh_treetop,
239 				ufs_free_netcred, (caddr_t)0);
240 			free((caddr_t)rnh, M_RTABLE);
241 			ump->um_rtable[i] = 0;
242 		}
243 }
244 
245 /*
246  * This is the generic part of fhtovp called after the underlying
247  * filesystem has validated the file handle.
248  *
249  * Verify that a host should have access to a filesystem, and if so
250  * return a vnode for the presented file handle.
251  */
252 int
253 ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
254 	register struct mount *mp;
255 	struct ufid *ufhp;
256 	struct mbuf *nam;
257 	struct vnode **vpp;
258 	int *exflagsp;
259 	struct ucred **credanonp;
260 {
261 	register struct inode *ip;
262 	register struct netcred *np;
263 	register struct ufsmount *ump = VFSTOUFS(mp);
264 	register struct radix_node_head *rnh;
265 	struct vnode *nvp;
266 	struct sockaddr *saddr;
267 	int error;
268 
269 	/*
270 	 * Get the export permission structure for this <mp, client> tuple.
271 	 */
272 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
273 		return (EACCES);
274 	if (nam == NULL) {
275 		np = NULL;
276 	} else {
277 		saddr = mtod(nam, struct sockaddr *);
278 		rnh = ump->um_rtable[saddr->sa_family];
279 		if (rnh == NULL) {
280 			np = NULL;
281 		} else {
282 			np = (struct netcred *)
283 			    (*rnh->rnh_match)((caddr_t)saddr, rnh->rnh_treetop);
284 			if (np->netc_rnodes->rn_flags & RNF_ROOT)
285 				np = NULL;
286 		}
287 	}
288 	if (np == NULL) {
289 		/*
290 		 * If no address match, use the default if it exists.
291 		 */
292 		if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
293 			return (EACCES);
294 		np = &ump->um_defexported;
295 	}
296 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
297 		*vpp = NULLVP;
298 		return (error);
299 	}
300 	ip = VTOI(nvp);
301 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
302 		ufs_iput(ip);
303 		*vpp = NULLVP;
304 		return (ESTALE);
305 	}
306 	*vpp = nvp;
307 	*exflagsp = np->netc_exflags;
308 	*credanonp = &np->netc_anon;
309 	return (0);
310 }
311