xref: /original-bsd/sys/ufs/ffs/ufs_vfsops.c (revision 48611f03)
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.67 (Berkeley) 04/08/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 	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_walktree)(rnh, ufs_free_netcred, (caddr_t)0);
239 			free((caddr_t)rnh, M_RTABLE);
240 			ump->um_rtable[i] = 0;
241 		}
242 }
243 
244 /*
245  * This is the generic part of fhtovp called after the underlying
246  * filesystem has validated the file handle.
247  *
248  * Verify that a host should have access to a filesystem, and if so
249  * return a vnode for the presented file handle.
250  */
251 int
252 ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
253 	register struct mount *mp;
254 	struct ufid *ufhp;
255 	struct mbuf *nam;
256 	struct vnode **vpp;
257 	int *exflagsp;
258 	struct ucred **credanonp;
259 {
260 	register struct inode *ip;
261 	register struct netcred *np;
262 	register struct ufsmount *ump = VFSTOUFS(mp);
263 	register struct radix_node_head *rnh;
264 	struct vnode *nvp;
265 	struct sockaddr *saddr;
266 	int error;
267 
268 	/*
269 	 * Get the export permission structure for this <mp, client> tuple.
270 	 */
271 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
272 		return (EACCES);
273 	np = NULL;
274 	if (nam != NULL) {
275 		saddr = mtod(nam, struct sockaddr *);
276 		rnh = ump->um_rtable[saddr->sa_family];
277 		if (rnh != NULL) {
278 			np = (struct netcred *)
279 			    (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
280 			if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
281 				np = NULL;
282 		}
283 	}
284 	if (np == NULL) {
285 		/*
286 		 * If no address match, use the default if it exists.
287 		 */
288 		if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
289 			return (EACCES);
290 		np = &ump->um_defexported;
291 	}
292 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
293 		*vpp = NULLVP;
294 		return (error);
295 	}
296 	ip = VTOI(nvp);
297 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
298 		vput(nvp);
299 		*vpp = NULLVP;
300 		return (ESTALE);
301 	}
302 	*vpp = nvp;
303 	*exflagsp = np->netc_exflags;
304 	*credanonp = &np->netc_anon;
305 	return (0);
306 }
307