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