| @@ -1,1072 +1,1072 @@ | | | @@ -1,1072 +1,1072 @@ |
1 | /* $NetBSD: vfs_syscalls.c,v 1.516 2017/06/01 02:45:13 chs Exp $ */ | | 1 | /* $NetBSD: vfs_syscalls.c,v 1.516.2.1 2020/04/22 18:18:26 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 1989, 1993 | | 33 | * Copyright (c) 1989, 1993 |
34 | * The Regents of the University of California. All rights reserved. | | 34 | * The Regents of the University of California. All rights reserved. |
35 | * (c) UNIX System Laboratories, Inc. | | 35 | * (c) UNIX System Laboratories, Inc. |
36 | * All or some portions of this file are derived from material licensed | | 36 | * All or some portions of this file are derived from material licensed |
37 | * to the University of California by American Telephone and Telegraph | | 37 | * to the University of California by American Telephone and Telegraph |
38 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | | 38 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
39 | * the permission of UNIX System Laboratories, Inc. | | 39 | * the permission of UNIX System Laboratories, Inc. |
40 | * | | 40 | * |
41 | * Redistribution and use in source and binary forms, with or without | | 41 | * Redistribution and use in source and binary forms, with or without |
42 | * modification, are permitted provided that the following conditions | | 42 | * modification, are permitted provided that the following conditions |
43 | * are met: | | 43 | * are met: |
44 | * 1. Redistributions of source code must retain the above copyright | | 44 | * 1. Redistributions of source code must retain the above copyright |
45 | * notice, this list of conditions and the following disclaimer. | | 45 | * notice, this list of conditions and the following disclaimer. |
46 | * 2. Redistributions in binary form must reproduce the above copyright | | 46 | * 2. Redistributions in binary form must reproduce the above copyright |
47 | * notice, this list of conditions and the following disclaimer in the | | 47 | * notice, this list of conditions and the following disclaimer in the |
48 | * documentation and/or other materials provided with the distribution. | | 48 | * documentation and/or other materials provided with the distribution. |
49 | * 3. Neither the name of the University nor the names of its contributors | | 49 | * 3. Neither the name of the University nor the names of its contributors |
50 | * may be used to endorse or promote products derived from this software | | 50 | * may be used to endorse or promote products derived from this software |
51 | * without specific prior written permission. | | 51 | * without specific prior written permission. |
52 | * | | 52 | * |
53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
63 | * SUCH DAMAGE. | | 63 | * SUCH DAMAGE. |
64 | * | | 64 | * |
65 | * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95 | | 65 | * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95 |
66 | */ | | 66 | */ |
67 | | | 67 | |
68 | /* | | 68 | /* |
69 | * Virtual File System System Calls | | 69 | * Virtual File System System Calls |
70 | */ | | 70 | */ |
71 | | | 71 | |
72 | #include <sys/cdefs.h> | | 72 | #include <sys/cdefs.h> |
73 | __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.516 2017/06/01 02:45:13 chs Exp $"); | | 73 | __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.516.2.1 2020/04/22 18:18:26 martin Exp $"); |
74 | | | 74 | |
75 | #ifdef _KERNEL_OPT | | 75 | #ifdef _KERNEL_OPT |
76 | #include "opt_fileassoc.h" | | 76 | #include "opt_fileassoc.h" |
77 | #include "veriexec.h" | | 77 | #include "veriexec.h" |
78 | #endif | | 78 | #endif |
79 | | | 79 | |
80 | #include <sys/param.h> | | 80 | #include <sys/param.h> |
81 | #include <sys/systm.h> | | 81 | #include <sys/systm.h> |
82 | #include <sys/namei.h> | | 82 | #include <sys/namei.h> |
83 | #include <sys/filedesc.h> | | 83 | #include <sys/filedesc.h> |
84 | #include <sys/kernel.h> | | 84 | #include <sys/kernel.h> |
85 | #include <sys/file.h> | | 85 | #include <sys/file.h> |
86 | #include <sys/fcntl.h> | | 86 | #include <sys/fcntl.h> |
87 | #include <sys/stat.h> | | 87 | #include <sys/stat.h> |
88 | #include <sys/vnode.h> | | 88 | #include <sys/vnode.h> |
89 | #include <sys/mount.h> | | 89 | #include <sys/mount.h> |
90 | #include <sys/fstrans.h> | | 90 | #include <sys/fstrans.h> |
91 | #include <sys/proc.h> | | 91 | #include <sys/proc.h> |
92 | #include <sys/uio.h> | | 92 | #include <sys/uio.h> |
93 | #include <sys/kmem.h> | | 93 | #include <sys/kmem.h> |
94 | #include <sys/dirent.h> | | 94 | #include <sys/dirent.h> |
95 | #include <sys/sysctl.h> | | 95 | #include <sys/sysctl.h> |
96 | #include <sys/syscallargs.h> | | 96 | #include <sys/syscallargs.h> |
97 | #include <sys/vfs_syscalls.h> | | 97 | #include <sys/vfs_syscalls.h> |
98 | #include <sys/quota.h> | | 98 | #include <sys/quota.h> |
99 | #include <sys/quotactl.h> | | 99 | #include <sys/quotactl.h> |
100 | #include <sys/ktrace.h> | | 100 | #include <sys/ktrace.h> |
101 | #ifdef FILEASSOC | | 101 | #ifdef FILEASSOC |
102 | #include <sys/fileassoc.h> | | 102 | #include <sys/fileassoc.h> |
103 | #endif /* FILEASSOC */ | | 103 | #endif /* FILEASSOC */ |
104 | #include <sys/extattr.h> | | 104 | #include <sys/extattr.h> |
105 | #include <sys/verified_exec.h> | | 105 | #include <sys/verified_exec.h> |
106 | #include <sys/kauth.h> | | 106 | #include <sys/kauth.h> |
107 | #include <sys/atomic.h> | | 107 | #include <sys/atomic.h> |
108 | #include <sys/module.h> | | 108 | #include <sys/module.h> |
109 | #include <sys/buf.h> | | 109 | #include <sys/buf.h> |
110 | | | 110 | |
111 | #include <miscfs/genfs/genfs.h> | | 111 | #include <miscfs/genfs/genfs.h> |
112 | #include <miscfs/specfs/specdev.h> | | 112 | #include <miscfs/specfs/specdev.h> |
113 | | | 113 | |
114 | #include <nfs/rpcv2.h> | | 114 | #include <nfs/rpcv2.h> |
115 | #include <nfs/nfsproto.h> | | 115 | #include <nfs/nfsproto.h> |
116 | #include <nfs/nfs.h> | | 116 | #include <nfs/nfs.h> |
117 | #include <nfs/nfs_var.h> | | 117 | #include <nfs/nfs_var.h> |
118 | | | 118 | |
119 | /* XXX this shouldn't be here */ | | 119 | /* XXX this shouldn't be here */ |
120 | #ifndef OFF_T_MAX | | 120 | #ifndef OFF_T_MAX |
121 | #define OFF_T_MAX __type_max(off_t) | | 121 | #define OFF_T_MAX __type_max(off_t) |
122 | #endif | | 122 | #endif |
123 | | | 123 | |
124 | static int change_flags(struct vnode *, u_long, struct lwp *); | | 124 | static int change_flags(struct vnode *, u_long, struct lwp *); |
125 | static int change_mode(struct vnode *, int, struct lwp *); | | 125 | static int change_mode(struct vnode *, int, struct lwp *); |
126 | static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); | | 126 | static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); |
127 | static int do_sys_openat(lwp_t *, int, const char *, int, int, int *); | | 127 | static int do_sys_openat(lwp_t *, int, const char *, int, int, int *); |
128 | static int do_sys_mkdirat(struct lwp *l, int, const char *, mode_t, | | 128 | static int do_sys_mkdirat(struct lwp *l, int, const char *, mode_t, |
129 | enum uio_seg); | | 129 | enum uio_seg); |
130 | static int do_sys_mkfifoat(struct lwp *, int, const char *, mode_t); | | 130 | static int do_sys_mkfifoat(struct lwp *, int, const char *, mode_t); |
131 | static int do_sys_symlinkat(struct lwp *, const char *, int, const char *, | | 131 | static int do_sys_symlinkat(struct lwp *, const char *, int, const char *, |
132 | enum uio_seg); | | 132 | enum uio_seg); |
133 | static int do_sys_renameat(struct lwp *l, int, const char *, int, const char *, | | 133 | static int do_sys_renameat(struct lwp *l, int, const char *, int, const char *, |
134 | enum uio_seg, int); | | 134 | enum uio_seg, int); |
135 | static int do_sys_readlinkat(struct lwp *, int, const char *, char *, | | 135 | static int do_sys_readlinkat(struct lwp *, int, const char *, char *, |
136 | size_t, register_t *); | | 136 | size_t, register_t *); |
137 | static int do_sys_unlinkat(struct lwp *, int, const char *, int, enum uio_seg); | | 137 | static int do_sys_unlinkat(struct lwp *, int, const char *, int, enum uio_seg); |
138 | | | 138 | |
139 | static int fd_nameiat(struct lwp *, int, struct nameidata *); | | 139 | static int fd_nameiat(struct lwp *, int, struct nameidata *); |
140 | static int fd_nameiat_simple_user(struct lwp *, int, const char *, | | 140 | static int fd_nameiat_simple_user(struct lwp *, int, const char *, |
141 | namei_simple_flags_t, struct vnode **); | | 141 | namei_simple_flags_t, struct vnode **); |
142 | | | 142 | |
143 | | | 143 | |
144 | /* | | 144 | /* |
145 | * This table is used to maintain compatibility with 4.3BSD | | 145 | * This table is used to maintain compatibility with 4.3BSD |
146 | * and NetBSD 0.9 mount syscalls - and possibly other systems. | | 146 | * and NetBSD 0.9 mount syscalls - and possibly other systems. |
147 | * Note, the order is important! | | 147 | * Note, the order is important! |
148 | * | | 148 | * |
149 | * Do not modify this table. It should only contain filesystems | | 149 | * Do not modify this table. It should only contain filesystems |
150 | * supported by NetBSD 0.9 and 4.3BSD. | | 150 | * supported by NetBSD 0.9 and 4.3BSD. |
151 | */ | | 151 | */ |
152 | const char * const mountcompatnames[] = { | | 152 | const char * const mountcompatnames[] = { |
153 | NULL, /* 0 = MOUNT_NONE */ | | 153 | NULL, /* 0 = MOUNT_NONE */ |
154 | MOUNT_FFS, /* 1 = MOUNT_UFS */ | | 154 | MOUNT_FFS, /* 1 = MOUNT_UFS */ |
155 | MOUNT_NFS, /* 2 */ | | 155 | MOUNT_NFS, /* 2 */ |
156 | MOUNT_MFS, /* 3 */ | | 156 | MOUNT_MFS, /* 3 */ |
157 | MOUNT_MSDOS, /* 4 */ | | 157 | MOUNT_MSDOS, /* 4 */ |
158 | MOUNT_CD9660, /* 5 = MOUNT_ISOFS */ | | 158 | MOUNT_CD9660, /* 5 = MOUNT_ISOFS */ |
159 | MOUNT_FDESC, /* 6 */ | | 159 | MOUNT_FDESC, /* 6 */ |
160 | MOUNT_KERNFS, /* 7 */ | | 160 | MOUNT_KERNFS, /* 7 */ |
161 | NULL, /* 8 = MOUNT_DEVFS */ | | 161 | NULL, /* 8 = MOUNT_DEVFS */ |
162 | MOUNT_AFS, /* 9 */ | | 162 | MOUNT_AFS, /* 9 */ |
163 | }; | | 163 | }; |
164 | | | 164 | |
165 | const int nmountcompatnames = __arraycount(mountcompatnames); | | 165 | const int nmountcompatnames = __arraycount(mountcompatnames); |
166 | | | 166 | |
167 | static int | | 167 | static int |
168 | fd_nameiat(struct lwp *l, int fdat, struct nameidata *ndp) | | 168 | fd_nameiat(struct lwp *l, int fdat, struct nameidata *ndp) |
169 | { | | 169 | { |
170 | file_t *dfp; | | 170 | file_t *dfp; |
171 | int error; | | 171 | int error; |
172 | | | 172 | |
173 | if (fdat != AT_FDCWD) { | | 173 | if (fdat != AT_FDCWD) { |
174 | if ((error = fd_getvnode(fdat, &dfp)) != 0) | | 174 | if ((error = fd_getvnode(fdat, &dfp)) != 0) |
175 | goto out; | | 175 | goto out; |
176 | | | 176 | |
177 | NDAT(ndp, dfp->f_vnode); | | 177 | NDAT(ndp, dfp->f_vnode); |
178 | } | | 178 | } |
179 | | | 179 | |
180 | error = namei(ndp); | | 180 | error = namei(ndp); |
181 | | | 181 | |
182 | if (fdat != AT_FDCWD) | | 182 | if (fdat != AT_FDCWD) |
183 | fd_putfile(fdat); | | 183 | fd_putfile(fdat); |
184 | out: | | 184 | out: |
185 | return error; | | 185 | return error; |
186 | } | | 186 | } |
187 | | | 187 | |
188 | static int | | 188 | static int |
189 | fd_nameiat_simple_user(struct lwp *l, int fdat, const char *path, | | 189 | fd_nameiat_simple_user(struct lwp *l, int fdat, const char *path, |
190 | namei_simple_flags_t sflags, struct vnode **vp_ret) | | 190 | namei_simple_flags_t sflags, struct vnode **vp_ret) |
191 | { | | 191 | { |
192 | file_t *dfp; | | 192 | file_t *dfp; |
193 | struct vnode *dvp; | | 193 | struct vnode *dvp; |
194 | int error; | | 194 | int error; |
195 | | | 195 | |
196 | if (fdat != AT_FDCWD) { | | 196 | if (fdat != AT_FDCWD) { |
197 | if ((error = fd_getvnode(fdat, &dfp)) != 0) | | 197 | if ((error = fd_getvnode(fdat, &dfp)) != 0) |
198 | goto out; | | 198 | goto out; |
199 | | | 199 | |
200 | dvp = dfp->f_vnode; | | 200 | dvp = dfp->f_vnode; |
201 | } else { | | 201 | } else { |
202 | dvp = NULL; | | 202 | dvp = NULL; |
203 | } | | 203 | } |
204 | | | 204 | |
205 | error = nameiat_simple_user(dvp, path, sflags, vp_ret); | | 205 | error = nameiat_simple_user(dvp, path, sflags, vp_ret); |
206 | | | 206 | |
207 | if (fdat != AT_FDCWD) | | 207 | if (fdat != AT_FDCWD) |
208 | fd_putfile(fdat); | | 208 | fd_putfile(fdat); |
209 | out: | | 209 | out: |
210 | return error; | | 210 | return error; |
211 | } | | 211 | } |
212 | | | 212 | |
213 | static int | | 213 | static int |
214 | open_setfp(struct lwp *l, file_t *fp, struct vnode *vp, int indx, int flags) | | 214 | open_setfp(struct lwp *l, file_t *fp, struct vnode *vp, int indx, int flags) |
215 | { | | 215 | { |
216 | int error; | | 216 | int error; |
217 | | | 217 | |
218 | fp->f_flag = flags & FMASK; | | 218 | fp->f_flag = flags & FMASK; |
219 | fp->f_type = DTYPE_VNODE; | | 219 | fp->f_type = DTYPE_VNODE; |
220 | fp->f_ops = &vnops; | | 220 | fp->f_ops = &vnops; |
221 | fp->f_vnode = vp; | | 221 | fp->f_vnode = vp; |
222 | | | 222 | |
223 | if (flags & (O_EXLOCK | O_SHLOCK)) { | | 223 | if (flags & (O_EXLOCK | O_SHLOCK)) { |
224 | struct flock lf; | | 224 | struct flock lf; |
225 | int type; | | 225 | int type; |
226 | | | 226 | |
227 | lf.l_whence = SEEK_SET; | | 227 | lf.l_whence = SEEK_SET; |
228 | lf.l_start = 0; | | 228 | lf.l_start = 0; |
229 | lf.l_len = 0; | | 229 | lf.l_len = 0; |
230 | if (flags & O_EXLOCK) | | 230 | if (flags & O_EXLOCK) |
231 | lf.l_type = F_WRLCK; | | 231 | lf.l_type = F_WRLCK; |
232 | else | | 232 | else |
233 | lf.l_type = F_RDLCK; | | 233 | lf.l_type = F_RDLCK; |
234 | type = F_FLOCK; | | 234 | type = F_FLOCK; |
235 | if ((flags & FNONBLOCK) == 0) | | 235 | if ((flags & FNONBLOCK) == 0) |
236 | type |= F_WAIT; | | 236 | type |= F_WAIT; |
237 | VOP_UNLOCK(vp); | | 237 | VOP_UNLOCK(vp); |
238 | error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); | | 238 | error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); |
239 | if (error) { | | 239 | if (error) { |
240 | (void) vn_close(vp, fp->f_flag, fp->f_cred); | | 240 | (void) vn_close(vp, fp->f_flag, fp->f_cred); |
241 | fd_abort(l->l_proc, fp, indx); | | 241 | fd_abort(l->l_proc, fp, indx); |
242 | return error; | | 242 | return error; |
243 | } | | 243 | } |
244 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 244 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
245 | atomic_or_uint(&fp->f_flag, FHASLOCK); | | 245 | atomic_or_uint(&fp->f_flag, FHASLOCK); |
246 | } | | 246 | } |
247 | if (flags & O_CLOEXEC) | | 247 | if (flags & O_CLOEXEC) |
248 | fd_set_exclose(l, indx, true); | | 248 | fd_set_exclose(l, indx, true); |
249 | return 0; | | 249 | return 0; |
250 | } | | 250 | } |
251 | | | 251 | |
252 | static int | | 252 | static int |
253 | mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags, | | 253 | mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags, |
254 | void *data, size_t *data_len) | | 254 | void *data, size_t *data_len) |
255 | { | | 255 | { |
256 | struct mount *mp; | | 256 | struct mount *mp; |
257 | int error = 0, saved_flags; | | 257 | int error = 0, saved_flags; |
258 | | | 258 | |
259 | mp = vp->v_mount; | | 259 | mp = vp->v_mount; |
260 | saved_flags = mp->mnt_flag; | | 260 | saved_flags = mp->mnt_flag; |
261 | | | 261 | |
262 | /* We can operate only on VV_ROOT nodes. */ | | 262 | /* We can operate only on VV_ROOT nodes. */ |
263 | if ((vp->v_vflag & VV_ROOT) == 0) { | | 263 | if ((vp->v_vflag & VV_ROOT) == 0) { |
264 | error = EINVAL; | | 264 | error = EINVAL; |
265 | goto out; | | 265 | goto out; |
266 | } | | 266 | } |
267 | | | 267 | |
268 | /* | | 268 | /* |
269 | * We only allow the filesystem to be reloaded if it | | 269 | * We only allow the filesystem to be reloaded if it |
270 | * is currently mounted read-only. Additionally, we | | 270 | * is currently mounted read-only. Additionally, we |
271 | * prevent read-write to read-only downgrades. | | 271 | * prevent read-write to read-only downgrades. |
272 | */ | | 272 | */ |
273 | if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 && | | 273 | if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 && |
274 | (mp->mnt_flag & MNT_RDONLY) == 0 && | | 274 | (mp->mnt_flag & MNT_RDONLY) == 0 && |
275 | (mp->mnt_iflag & IMNT_CAN_RWTORO) == 0) { | | 275 | (mp->mnt_iflag & IMNT_CAN_RWTORO) == 0) { |
276 | error = EOPNOTSUPP; /* Needs translation */ | | 276 | error = EOPNOTSUPP; /* Needs translation */ |
277 | goto out; | | 277 | goto out; |
278 | } | | 278 | } |
279 | | | 279 | |
280 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, | | 280 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
281 | KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data); | | 281 | KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data); |
282 | if (error) | | 282 | if (error) |
283 | goto out; | | 283 | goto out; |
284 | | | 284 | |
285 | error = vfs_suspend(mp, 0); | | 285 | error = vfs_suspend(mp, 0); |
286 | if (error) | | 286 | if (error) |
287 | goto out; | | 287 | goto out; |
288 | | | 288 | |
289 | mutex_enter(&mp->mnt_updating); | | 289 | mutex_enter(&mp->mnt_updating); |
290 | | | 290 | |
291 | mp->mnt_flag &= ~MNT_OP_FLAGS; | | 291 | mp->mnt_flag &= ~MNT_OP_FLAGS; |
292 | mp->mnt_flag |= flags & MNT_OP_FLAGS; | | 292 | mp->mnt_flag |= flags & MNT_OP_FLAGS; |
293 | | | 293 | |
294 | /* | | 294 | /* |
295 | * Set the mount level flags. | | 295 | * Set the mount level flags. |
296 | */ | | 296 | */ |
297 | if ((flags & MNT_RDONLY) != (mp->mnt_flag & MNT_RDONLY)) { | | 297 | if ((flags & MNT_RDONLY) != (mp->mnt_flag & MNT_RDONLY)) { |
298 | if ((flags & MNT_RDONLY)) | | 298 | if ((flags & MNT_RDONLY)) |
299 | mp->mnt_iflag |= IMNT_WANTRDONLY; | | 299 | mp->mnt_iflag |= IMNT_WANTRDONLY; |
300 | else | | 300 | else |
301 | mp->mnt_iflag |= IMNT_WANTRDWR; | | 301 | mp->mnt_iflag |= IMNT_WANTRDWR; |
302 | } | | 302 | } |
303 | mp->mnt_flag &= ~MNT_BASIC_FLAGS; | | 303 | mp->mnt_flag &= ~MNT_BASIC_FLAGS; |
304 | mp->mnt_flag |= flags & MNT_BASIC_FLAGS; | | 304 | mp->mnt_flag |= flags & MNT_BASIC_FLAGS; |
305 | if ((mp->mnt_iflag & IMNT_WANTRDONLY)) | | 305 | if ((mp->mnt_iflag & IMNT_WANTRDONLY)) |
306 | mp->mnt_flag &= ~MNT_RDONLY; | | 306 | mp->mnt_flag &= ~MNT_RDONLY; |
307 | | | 307 | |
308 | error = VFS_MOUNT(mp, path, data, data_len); | | 308 | error = VFS_MOUNT(mp, path, data, data_len); |
309 | | | 309 | |
310 | if (error && data != NULL) { | | 310 | if (error && data != NULL) { |
311 | int error2; | | 311 | int error2; |
312 | | | 312 | |
313 | /* | | 313 | /* |
314 | * Update failed; let's try and see if it was an | | 314 | * Update failed; let's try and see if it was an |
315 | * export request. For compat with 3.0 and earlier. | | 315 | * export request. For compat with 3.0 and earlier. |
316 | */ | | 316 | */ |
317 | error2 = vfs_hooks_reexport(mp, path, data); | | 317 | error2 = vfs_hooks_reexport(mp, path, data); |
318 | | | 318 | |
319 | /* | | 319 | /* |
320 | * Only update error code if the export request was | | 320 | * Only update error code if the export request was |
321 | * understood but some problem occurred while | | 321 | * understood but some problem occurred while |
322 | * processing it. | | 322 | * processing it. |
323 | */ | | 323 | */ |
324 | if (error2 != EJUSTRETURN) | | 324 | if (error2 != EJUSTRETURN) |
325 | error = error2; | | 325 | error = error2; |
326 | } | | 326 | } |
327 | | | 327 | |
328 | if (error == 0 && (mp->mnt_iflag & IMNT_WANTRDONLY)) | | 328 | if (error == 0 && (mp->mnt_iflag & IMNT_WANTRDONLY)) |
329 | mp->mnt_flag |= MNT_RDONLY; | | 329 | mp->mnt_flag |= MNT_RDONLY; |
330 | if (error) | | 330 | if (error) |
331 | mp->mnt_flag = saved_flags; | | 331 | mp->mnt_flag = saved_flags; |
332 | mp->mnt_flag &= ~MNT_OP_FLAGS; | | 332 | mp->mnt_flag &= ~MNT_OP_FLAGS; |
333 | mp->mnt_iflag &= ~(IMNT_WANTRDONLY | IMNT_WANTRDWR); | | 333 | mp->mnt_iflag &= ~(IMNT_WANTRDONLY | IMNT_WANTRDWR); |
334 | if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) { | | 334 | if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) { |
335 | if ((mp->mnt_iflag & IMNT_ONWORKLIST) == 0) | | 335 | if ((mp->mnt_iflag & IMNT_ONWORKLIST) == 0) |
336 | vfs_syncer_add_to_worklist(mp); | | 336 | vfs_syncer_add_to_worklist(mp); |
337 | } else { | | 337 | } else { |
338 | if ((mp->mnt_iflag & IMNT_ONWORKLIST) != 0) | | 338 | if ((mp->mnt_iflag & IMNT_ONWORKLIST) != 0) |
339 | vfs_syncer_remove_from_worklist(mp); | | 339 | vfs_syncer_remove_from_worklist(mp); |
340 | } | | 340 | } |
341 | mutex_exit(&mp->mnt_updating); | | 341 | mutex_exit(&mp->mnt_updating); |
342 | vfs_resume(mp); | | 342 | vfs_resume(mp); |
343 | | | 343 | |
344 | if ((error == 0) && !(saved_flags & MNT_EXTATTR) && | | 344 | if ((error == 0) && !(saved_flags & MNT_EXTATTR) && |
345 | (flags & MNT_EXTATTR)) { | | 345 | (flags & MNT_EXTATTR)) { |
346 | if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_START, | | 346 | if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_START, |
347 | NULL, 0, NULL) != 0) { | | 347 | NULL, 0, NULL) != 0) { |
348 | printf("%s: failed to start extattr, error = %d", | | 348 | printf("%s: failed to start extattr, error = %d", |
349 | mp->mnt_stat.f_mntonname, error); | | 349 | mp->mnt_stat.f_mntonname, error); |
350 | mp->mnt_flag &= ~MNT_EXTATTR; | | 350 | mp->mnt_flag &= ~MNT_EXTATTR; |
351 | } | | 351 | } |
352 | } | | 352 | } |
353 | | | 353 | |
354 | if ((error == 0) && (saved_flags & MNT_EXTATTR) && | | 354 | if ((error == 0) && (saved_flags & MNT_EXTATTR) && |
355 | !(flags & MNT_EXTATTR)) { | | 355 | !(flags & MNT_EXTATTR)) { |
356 | if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_STOP, | | 356 | if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_STOP, |
357 | NULL, 0, NULL) != 0) { | | 357 | NULL, 0, NULL) != 0) { |
358 | printf("%s: failed to stop extattr, error = %d", | | 358 | printf("%s: failed to stop extattr, error = %d", |
359 | mp->mnt_stat.f_mntonname, error); | | 359 | mp->mnt_stat.f_mntonname, error); |
360 | mp->mnt_flag |= MNT_RDONLY; | | 360 | mp->mnt_flag |= MNT_RDONLY; |
361 | } | | 361 | } |
362 | } | | 362 | } |
363 | out: | | 363 | out: |
364 | return (error); | | 364 | return (error); |
365 | } | | 365 | } |
366 | | | 366 | |
367 | static int | | 367 | static int |
368 | mount_get_vfsops(const char *fstype, enum uio_seg type_seg, | | 368 | mount_get_vfsops(const char *fstype, enum uio_seg type_seg, |
369 | struct vfsops **vfsops) | | 369 | struct vfsops **vfsops) |
370 | { | | 370 | { |
371 | char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)]; | | 371 | char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)]; |
372 | int error; | | 372 | int error; |
373 | | | 373 | |
374 | if (type_seg == UIO_USERSPACE) { | | 374 | if (type_seg == UIO_USERSPACE) { |
375 | /* Copy file-system type from userspace. */ | | 375 | /* Copy file-system type from userspace. */ |
376 | error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL); | | 376 | error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL); |
377 | } else { | | 377 | } else { |
378 | error = copystr(fstype, fstypename, sizeof(fstypename), NULL); | | 378 | error = copystr(fstype, fstypename, sizeof(fstypename), NULL); |
379 | KASSERT(error == 0); | | 379 | KASSERT(error == 0); |
380 | } | | 380 | } |
381 | | | 381 | |
382 | if (error) { | | 382 | if (error) { |
383 | /* | | 383 | /* |
384 | * Historically, filesystem types were identified by numbers. | | 384 | * Historically, filesystem types were identified by numbers. |
385 | * If we get an integer for the filesystem type instead of a | | 385 | * If we get an integer for the filesystem type instead of a |
386 | * string, we check to see if it matches one of the historic | | 386 | * string, we check to see if it matches one of the historic |
387 | * filesystem types. | | 387 | * filesystem types. |
388 | */ | | 388 | */ |
389 | u_long fsindex = (u_long)fstype; | | 389 | u_long fsindex = (u_long)fstype; |
390 | if (fsindex >= nmountcompatnames || | | 390 | if (fsindex >= nmountcompatnames || |
391 | mountcompatnames[fsindex] == NULL) | | 391 | mountcompatnames[fsindex] == NULL) |
392 | return ENODEV; | | 392 | return ENODEV; |
393 | strlcpy(fstypename, mountcompatnames[fsindex], | | 393 | strlcpy(fstypename, mountcompatnames[fsindex], |
394 | sizeof(fstypename)); | | 394 | sizeof(fstypename)); |
395 | } | | 395 | } |
396 | | | 396 | |
397 | /* Accept `ufs' as an alias for `ffs', for compatibility. */ | | 397 | /* Accept `ufs' as an alias for `ffs', for compatibility. */ |
398 | if (strcmp(fstypename, "ufs") == 0) | | 398 | if (strcmp(fstypename, "ufs") == 0) |
399 | fstypename[0] = 'f'; | | 399 | fstypename[0] = 'f'; |
400 | | | 400 | |
401 | if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) | | 401 | if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) |
402 | return 0; | | 402 | return 0; |
403 | | | 403 | |
404 | /* If we can autoload a vfs module, try again */ | | 404 | /* If we can autoload a vfs module, try again */ |
405 | (void)module_autoload(fstypename, MODULE_CLASS_VFS); | | 405 | (void)module_autoload(fstypename, MODULE_CLASS_VFS); |
406 | | | 406 | |
407 | if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) | | 407 | if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) |
408 | return 0; | | 408 | return 0; |
409 | | | 409 | |
410 | return ENODEV; | | 410 | return ENODEV; |
411 | } | | 411 | } |
412 | | | 412 | |
413 | static int | | 413 | static int |
414 | mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags, | | 414 | mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags, |
415 | void *data, size_t *data_len) | | 415 | void *data, size_t *data_len) |
416 | { | | 416 | { |
417 | struct mount *mp; | | 417 | struct mount *mp; |
418 | int error; | | 418 | int error; |
419 | | | 419 | |
420 | /* If MNT_GETARGS is specified, it should be the only flag. */ | | 420 | /* If MNT_GETARGS is specified, it should be the only flag. */ |
421 | if (flags & ~MNT_GETARGS) | | 421 | if (flags & ~MNT_GETARGS) |
422 | return EINVAL; | | 422 | return EINVAL; |
423 | | | 423 | |
424 | mp = vp->v_mount; | | 424 | mp = vp->v_mount; |
425 | | | 425 | |
426 | /* XXX: probably some notion of "can see" here if we want isolation. */ | | 426 | /* XXX: probably some notion of "can see" here if we want isolation. */ |
427 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, | | 427 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
428 | KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL); | | 428 | KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL); |
429 | if (error) | | 429 | if (error) |
430 | return error; | | 430 | return error; |
431 | | | 431 | |
432 | if ((vp->v_vflag & VV_ROOT) == 0) | | 432 | if ((vp->v_vflag & VV_ROOT) == 0) |
433 | return EINVAL; | | 433 | return EINVAL; |
434 | | | 434 | |
435 | if (vfs_busy(mp)) | | 435 | if (vfs_busy(mp)) |
436 | return EPERM; | | 436 | return EPERM; |
437 | | | 437 | |
438 | mutex_enter(&mp->mnt_updating); | | 438 | mutex_enter(&mp->mnt_updating); |
439 | mp->mnt_flag &= ~MNT_OP_FLAGS; | | 439 | mp->mnt_flag &= ~MNT_OP_FLAGS; |
440 | mp->mnt_flag |= MNT_GETARGS; | | 440 | mp->mnt_flag |= MNT_GETARGS; |
441 | error = VFS_MOUNT(mp, path, data, data_len); | | 441 | error = VFS_MOUNT(mp, path, data, data_len); |
442 | mp->mnt_flag &= ~MNT_OP_FLAGS; | | 442 | mp->mnt_flag &= ~MNT_OP_FLAGS; |
443 | mutex_exit(&mp->mnt_updating); | | 443 | mutex_exit(&mp->mnt_updating); |
444 | | | 444 | |
445 | vfs_unbusy(mp); | | 445 | vfs_unbusy(mp); |
446 | return (error); | | 446 | return (error); |
447 | } | | 447 | } |
448 | | | 448 | |
449 | int | | 449 | int |
450 | sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval) | | 450 | sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval) |
451 | { | | 451 | { |
452 | /* { | | 452 | /* { |
453 | syscallarg(const char *) type; | | 453 | syscallarg(const char *) type; |
454 | syscallarg(const char *) path; | | 454 | syscallarg(const char *) path; |
455 | syscallarg(int) flags; | | 455 | syscallarg(int) flags; |
456 | syscallarg(void *) data; | | 456 | syscallarg(void *) data; |
457 | syscallarg(size_t) data_len; | | 457 | syscallarg(size_t) data_len; |
458 | } */ | | 458 | } */ |
459 | | | 459 | |
460 | return do_sys_mount(l, SCARG(uap, type), UIO_USERSPACE, SCARG(uap, path), | | 460 | return do_sys_mount(l, SCARG(uap, type), UIO_USERSPACE, SCARG(uap, path), |
461 | SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, | | 461 | SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, |
462 | SCARG(uap, data_len), retval); | | 462 | SCARG(uap, data_len), retval); |
463 | } | | 463 | } |
464 | | | 464 | |
465 | int | | 465 | int |
466 | do_sys_mount(struct lwp *l, const char *type, enum uio_seg type_seg, | | 466 | do_sys_mount(struct lwp *l, const char *type, enum uio_seg type_seg, |
467 | const char *path, int flags, void *data, enum uio_seg data_seg, | | 467 | const char *path, int flags, void *data, enum uio_seg data_seg, |
468 | size_t data_len, register_t *retval) | | 468 | size_t data_len, register_t *retval) |
469 | { | | 469 | { |
470 | struct vfsops *vfsops = NULL; /* XXX gcc4.8 */ | | 470 | struct vfsops *vfsops = NULL; /* XXX gcc4.8 */ |
471 | struct vnode *vp; | | 471 | struct vnode *vp; |
472 | void *data_buf = data; | | 472 | void *data_buf = data; |
473 | bool vfsopsrele = false; | | 473 | bool vfsopsrele = false; |
474 | size_t alloc_sz = 0; | | 474 | size_t alloc_sz = 0; |
475 | int error; | | 475 | int error; |
476 | | | 476 | |
477 | /* | | 477 | /* |
478 | * Get vnode to be covered | | 478 | * Get vnode to be covered |
479 | */ | | 479 | */ |
480 | error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp); | | 480 | error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp); |
481 | if (error != 0) { | | 481 | if (error != 0) { |
482 | vp = NULL; | | 482 | vp = NULL; |
483 | goto done; | | 483 | goto done; |
484 | } | | 484 | } |
485 | | | 485 | |
486 | if (flags & (MNT_GETARGS | MNT_UPDATE)) { | | 486 | if (flags & (MNT_GETARGS | MNT_UPDATE)) { |
487 | vfsops = vp->v_mount->mnt_op; | | 487 | vfsops = vp->v_mount->mnt_op; |
488 | } else { | | 488 | } else { |
489 | /* 'type' is userspace */ | | 489 | /* 'type' is userspace */ |
490 | error = mount_get_vfsops(type, type_seg, &vfsops); | | 490 | error = mount_get_vfsops(type, type_seg, &vfsops); |
491 | if (error != 0) | | 491 | if (error != 0) |
492 | goto done; | | 492 | goto done; |
493 | vfsopsrele = true; | | 493 | vfsopsrele = true; |
494 | } | | 494 | } |
495 | | | 495 | |
496 | /* | | 496 | /* |
497 | * We allow data to be NULL, even for userspace. Some fs's don't need | | 497 | * We allow data to be NULL, even for userspace. Some fs's don't need |
498 | * it. The others will handle NULL. | | 498 | * it. The others will handle NULL. |
499 | */ | | 499 | */ |
500 | if (data != NULL && data_seg == UIO_USERSPACE) { | | 500 | if (data != NULL && data_seg == UIO_USERSPACE) { |
501 | if (data_len == 0) { | | 501 | if (data_len == 0) { |
502 | /* No length supplied, use default for filesystem */ | | 502 | /* No length supplied, use default for filesystem */ |
503 | data_len = vfsops->vfs_min_mount_data; | | 503 | data_len = vfsops->vfs_min_mount_data; |
504 | | | 504 | |
505 | /* | | 505 | /* |
506 | * Hopefully a longer buffer won't make copyin() fail. | | 506 | * Hopefully a longer buffer won't make copyin() fail. |
507 | * For compatibility with 3.0 and earlier. | | 507 | * For compatibility with 3.0 and earlier. |
508 | */ | | 508 | */ |
509 | if (flags & MNT_UPDATE | | 509 | if (flags & MNT_UPDATE |
510 | && data_len < sizeof (struct mnt_export_args30)) | | 510 | && data_len < sizeof (struct mnt_export_args30)) |
511 | data_len = sizeof (struct mnt_export_args30); | | 511 | data_len = sizeof (struct mnt_export_args30); |
512 | } | | 512 | } |
513 | if ((data_len == 0) || (data_len > VFS_MAX_MOUNT_DATA)) { | | 513 | if ((data_len == 0) || (data_len > VFS_MAX_MOUNT_DATA)) { |
514 | error = EINVAL; | | 514 | error = EINVAL; |
515 | goto done; | | 515 | goto done; |
516 | } | | 516 | } |
517 | alloc_sz = data_len; | | 517 | alloc_sz = data_len; |
518 | data_buf = kmem_alloc(alloc_sz, KM_SLEEP); | | 518 | data_buf = kmem_alloc(alloc_sz, KM_SLEEP); |
519 | | | 519 | |
520 | /* NFS needs the buffer even for mnt_getargs .... */ | | 520 | /* NFS needs the buffer even for mnt_getargs .... */ |
521 | error = copyin(data, data_buf, data_len); | | 521 | error = copyin(data, data_buf, data_len); |
522 | if (error != 0) | | 522 | if (error != 0) |
523 | goto done; | | 523 | goto done; |
524 | } | | 524 | } |
525 | | | 525 | |
526 | if (flags & MNT_GETARGS) { | | 526 | if (flags & MNT_GETARGS) { |
527 | if (data_len == 0) { | | 527 | if (data_len == 0) { |
528 | error = EINVAL; | | 528 | error = EINVAL; |
529 | goto done; | | 529 | goto done; |
530 | } | | 530 | } |
531 | error = mount_getargs(l, vp, path, flags, data_buf, &data_len); | | 531 | error = mount_getargs(l, vp, path, flags, data_buf, &data_len); |
532 | if (error != 0) | | 532 | if (error != 0) |
533 | goto done; | | 533 | goto done; |
534 | if (data_seg == UIO_USERSPACE) | | 534 | if (data_seg == UIO_USERSPACE) |
535 | error = copyout(data_buf, data, data_len); | | 535 | error = copyout(data_buf, data, data_len); |
536 | *retval = data_len; | | 536 | *retval = data_len; |
537 | } else if (flags & MNT_UPDATE) { | | 537 | } else if (flags & MNT_UPDATE) { |
538 | error = mount_update(l, vp, path, flags, data_buf, &data_len); | | 538 | error = mount_update(l, vp, path, flags, data_buf, &data_len); |
539 | } else { | | 539 | } else { |
540 | /* Locking is handled internally in mount_domount(). */ | | 540 | /* Locking is handled internally in mount_domount(). */ |
541 | KASSERT(vfsopsrele == true); | | 541 | KASSERT(vfsopsrele == true); |
542 | error = mount_domount(l, &vp, vfsops, path, flags, data_buf, | | 542 | error = mount_domount(l, &vp, vfsops, path, flags, data_buf, |
543 | &data_len); | | 543 | &data_len); |
544 | vfsopsrele = false; | | 544 | vfsopsrele = false; |
545 | } | | 545 | } |
546 | | | 546 | |
547 | done: | | 547 | done: |
548 | if (vfsopsrele) | | 548 | if (vfsopsrele) |
549 | vfs_delref(vfsops); | | 549 | vfs_delref(vfsops); |
550 | if (vp != NULL) { | | 550 | if (vp != NULL) { |
551 | vrele(vp); | | 551 | vrele(vp); |
552 | } | | 552 | } |
553 | if (data_buf != data) | | 553 | if (data_buf != data) |
554 | kmem_free(data_buf, alloc_sz); | | 554 | kmem_free(data_buf, alloc_sz); |
555 | return (error); | | 555 | return (error); |
556 | } | | 556 | } |
557 | | | 557 | |
558 | /* | | 558 | /* |
559 | * Unmount a file system. | | 559 | * Unmount a file system. |
560 | * | | 560 | * |
561 | * Note: unmount takes a path to the vnode mounted on as argument, | | 561 | * Note: unmount takes a path to the vnode mounted on as argument, |
562 | * not special file (as before). | | 562 | * not special file (as before). |
563 | */ | | 563 | */ |
564 | /* ARGSUSED */ | | 564 | /* ARGSUSED */ |
565 | int | | 565 | int |
566 | sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval) | | 566 | sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval) |
567 | { | | 567 | { |
568 | /* { | | 568 | /* { |
569 | syscallarg(const char *) path; | | 569 | syscallarg(const char *) path; |
570 | syscallarg(int) flags; | | 570 | syscallarg(int) flags; |
571 | } */ | | 571 | } */ |
572 | struct vnode *vp; | | 572 | struct vnode *vp; |
573 | struct mount *mp; | | 573 | struct mount *mp; |
574 | int error; | | 574 | int error; |
575 | struct pathbuf *pb; | | 575 | struct pathbuf *pb; |
576 | struct nameidata nd; | | 576 | struct nameidata nd; |
577 | | | 577 | |
578 | error = pathbuf_copyin(SCARG(uap, path), &pb); | | 578 | error = pathbuf_copyin(SCARG(uap, path), &pb); |
579 | if (error) { | | 579 | if (error) { |
580 | return error; | | 580 | return error; |
581 | } | | 581 | } |
582 | | | 582 | |
583 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb); | | 583 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb); |
584 | if ((error = namei(&nd)) != 0) { | | 584 | if ((error = namei(&nd)) != 0) { |
585 | pathbuf_destroy(pb); | | 585 | pathbuf_destroy(pb); |
586 | return error; | | 586 | return error; |
587 | } | | 587 | } |
588 | vp = nd.ni_vp; | | 588 | vp = nd.ni_vp; |
589 | pathbuf_destroy(pb); | | 589 | pathbuf_destroy(pb); |
590 | | | 590 | |
591 | mp = vp->v_mount; | | 591 | mp = vp->v_mount; |
592 | vfs_ref(mp); | | 592 | vfs_ref(mp); |
593 | VOP_UNLOCK(vp); | | 593 | VOP_UNLOCK(vp); |
594 | | | 594 | |
595 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, | | 595 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
596 | KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); | | 596 | KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); |
597 | if (error) { | | 597 | if (error) { |
598 | vrele(vp); | | 598 | vrele(vp); |
599 | vfs_rele(mp); | | 599 | vfs_rele(mp); |
600 | return (error); | | 600 | return (error); |
601 | } | | 601 | } |
602 | | | 602 | |
603 | /* | | 603 | /* |
604 | * Don't allow unmounting the root file system. | | 604 | * Don't allow unmounting the root file system. |
605 | */ | | 605 | */ |
606 | if (mp->mnt_flag & MNT_ROOTFS) { | | 606 | if (mp->mnt_flag & MNT_ROOTFS) { |
607 | vrele(vp); | | 607 | vrele(vp); |
608 | vfs_rele(mp); | | 608 | vfs_rele(mp); |
609 | return (EINVAL); | | 609 | return (EINVAL); |
610 | } | | 610 | } |
611 | | | 611 | |
612 | /* | | 612 | /* |
613 | * Must be the root of the filesystem | | 613 | * Must be the root of the filesystem |
614 | */ | | 614 | */ |
615 | if ((vp->v_vflag & VV_ROOT) == 0) { | | 615 | if ((vp->v_vflag & VV_ROOT) == 0) { |
616 | vrele(vp); | | 616 | vrele(vp); |
617 | vfs_rele(mp); | | 617 | vfs_rele(mp); |
618 | return (EINVAL); | | 618 | return (EINVAL); |
619 | } | | 619 | } |
620 | | | 620 | |
621 | vrele(vp); | | 621 | vrele(vp); |
622 | error = dounmount(mp, SCARG(uap, flags), l); | | 622 | error = dounmount(mp, SCARG(uap, flags), l); |
623 | vfs_rele(mp); | | 623 | vfs_rele(mp); |
624 | return error; | | 624 | return error; |
625 | } | | 625 | } |
626 | | | 626 | |
627 | /* | | 627 | /* |
628 | * Sync each mounted filesystem. | | 628 | * Sync each mounted filesystem. |
629 | */ | | 629 | */ |
630 | #ifdef DEBUG | | 630 | #ifdef DEBUG |
631 | int syncprt = 0; | | 631 | int syncprt = 0; |
632 | struct ctldebug debug0 = { "syncprt", &syncprt }; | | 632 | struct ctldebug debug0 = { "syncprt", &syncprt }; |
633 | #endif | | 633 | #endif |
634 | | | 634 | |
635 | void | | 635 | void |
636 | do_sys_sync(struct lwp *l) | | 636 | do_sys_sync(struct lwp *l) |
637 | { | | 637 | { |
638 | mount_iterator_t *iter; | | 638 | mount_iterator_t *iter; |
639 | struct mount *mp; | | 639 | struct mount *mp; |
640 | int asyncflag; | | 640 | int asyncflag; |
641 | | | 641 | |
642 | mountlist_iterator_init(&iter); | | 642 | mountlist_iterator_init(&iter); |
643 | while ((mp = mountlist_iterator_next(iter)) != NULL) { | | 643 | while ((mp = mountlist_iterator_next(iter)) != NULL) { |
644 | mutex_enter(&mp->mnt_updating); | | 644 | mutex_enter(&mp->mnt_updating); |
645 | if ((mp->mnt_flag & MNT_RDONLY) == 0) { | | 645 | if ((mp->mnt_flag & MNT_RDONLY) == 0) { |
646 | asyncflag = mp->mnt_flag & MNT_ASYNC; | | 646 | asyncflag = mp->mnt_flag & MNT_ASYNC; |
647 | mp->mnt_flag &= ~MNT_ASYNC; | | 647 | mp->mnt_flag &= ~MNT_ASYNC; |
648 | VFS_SYNC(mp, MNT_NOWAIT, l->l_cred); | | 648 | VFS_SYNC(mp, MNT_NOWAIT, l->l_cred); |
649 | if (asyncflag) | | 649 | if (asyncflag) |
650 | mp->mnt_flag |= MNT_ASYNC; | | 650 | mp->mnt_flag |= MNT_ASYNC; |
651 | } | | 651 | } |
652 | mutex_exit(&mp->mnt_updating); | | 652 | mutex_exit(&mp->mnt_updating); |
653 | } | | 653 | } |
654 | mountlist_iterator_destroy(iter); | | 654 | mountlist_iterator_destroy(iter); |
655 | #ifdef DEBUG | | 655 | #ifdef DEBUG |
656 | if (syncprt) | | 656 | if (syncprt) |
657 | vfs_bufstats(); | | 657 | vfs_bufstats(); |
658 | #endif /* DEBUG */ | | 658 | #endif /* DEBUG */ |
659 | } | | 659 | } |
660 | | | 660 | |
661 | /* ARGSUSED */ | | 661 | /* ARGSUSED */ |
662 | int | | 662 | int |
663 | sys_sync(struct lwp *l, const void *v, register_t *retval) | | 663 | sys_sync(struct lwp *l, const void *v, register_t *retval) |
664 | { | | 664 | { |
665 | do_sys_sync(l); | | 665 | do_sys_sync(l); |
666 | return (0); | | 666 | return (0); |
667 | } | | 667 | } |
668 | | | 668 | |
669 | | | 669 | |
670 | /* | | 670 | /* |
671 | * Access or change filesystem quotas. | | 671 | * Access or change filesystem quotas. |
672 | * | | 672 | * |
673 | * (this is really 14 different calls bundled into one) | | 673 | * (this is really 14 different calls bundled into one) |
674 | */ | | 674 | */ |
675 | | | 675 | |
676 | static int | | 676 | static int |
677 | do_sys_quotactl_stat(struct mount *mp, struct quotastat *info_u) | | 677 | do_sys_quotactl_stat(struct mount *mp, struct quotastat *info_u) |
678 | { | | 678 | { |
679 | struct quotastat info_k; | | 679 | struct quotastat info_k; |
680 | int error; | | 680 | int error; |
681 | | | 681 | |
682 | /* ensure any padding bytes are cleared */ | | 682 | /* ensure any padding bytes are cleared */ |
683 | memset(&info_k, 0, sizeof(info_k)); | | 683 | memset(&info_k, 0, sizeof(info_k)); |
684 | | | 684 | |
685 | error = vfs_quotactl_stat(mp, &info_k); | | 685 | error = vfs_quotactl_stat(mp, &info_k); |
686 | if (error) { | | 686 | if (error) { |
687 | return error; | | 687 | return error; |
688 | } | | 688 | } |
689 | | | 689 | |
690 | return copyout(&info_k, info_u, sizeof(info_k)); | | 690 | return copyout(&info_k, info_u, sizeof(info_k)); |
691 | } | | 691 | } |
692 | | | 692 | |
693 | static int | | 693 | static int |
694 | do_sys_quotactl_idtypestat(struct mount *mp, int idtype, | | 694 | do_sys_quotactl_idtypestat(struct mount *mp, int idtype, |
695 | struct quotaidtypestat *info_u) | | 695 | struct quotaidtypestat *info_u) |
696 | { | | 696 | { |
697 | struct quotaidtypestat info_k; | | 697 | struct quotaidtypestat info_k; |
698 | int error; | | 698 | int error; |
699 | | | 699 | |
700 | /* ensure any padding bytes are cleared */ | | 700 | /* ensure any padding bytes are cleared */ |
701 | memset(&info_k, 0, sizeof(info_k)); | | 701 | memset(&info_k, 0, sizeof(info_k)); |
702 | | | 702 | |
703 | error = vfs_quotactl_idtypestat(mp, idtype, &info_k); | | 703 | error = vfs_quotactl_idtypestat(mp, idtype, &info_k); |
704 | if (error) { | | 704 | if (error) { |
705 | return error; | | 705 | return error; |
706 | } | | 706 | } |
707 | | | 707 | |
708 | return copyout(&info_k, info_u, sizeof(info_k)); | | 708 | return copyout(&info_k, info_u, sizeof(info_k)); |
709 | } | | 709 | } |
710 | | | 710 | |
711 | static int | | 711 | static int |
712 | do_sys_quotactl_objtypestat(struct mount *mp, int objtype, | | 712 | do_sys_quotactl_objtypestat(struct mount *mp, int objtype, |
713 | struct quotaobjtypestat *info_u) | | 713 | struct quotaobjtypestat *info_u) |
714 | { | | 714 | { |
715 | struct quotaobjtypestat info_k; | | 715 | struct quotaobjtypestat info_k; |
716 | int error; | | 716 | int error; |
717 | | | 717 | |
718 | /* ensure any padding bytes are cleared */ | | 718 | /* ensure any padding bytes are cleared */ |
719 | memset(&info_k, 0, sizeof(info_k)); | | 719 | memset(&info_k, 0, sizeof(info_k)); |
720 | | | 720 | |
721 | error = vfs_quotactl_objtypestat(mp, objtype, &info_k); | | 721 | error = vfs_quotactl_objtypestat(mp, objtype, &info_k); |
722 | if (error) { | | 722 | if (error) { |
723 | return error; | | 723 | return error; |
724 | } | | 724 | } |
725 | | | 725 | |
726 | return copyout(&info_k, info_u, sizeof(info_k)); | | 726 | return copyout(&info_k, info_u, sizeof(info_k)); |
727 | } | | 727 | } |
728 | | | 728 | |
729 | static int | | 729 | static int |
730 | do_sys_quotactl_get(struct mount *mp, const struct quotakey *key_u, | | 730 | do_sys_quotactl_get(struct mount *mp, const struct quotakey *key_u, |
731 | struct quotaval *val_u) | | 731 | struct quotaval *val_u) |
732 | { | | 732 | { |
733 | struct quotakey key_k; | | 733 | struct quotakey key_k; |
734 | struct quotaval val_k; | | 734 | struct quotaval val_k; |
735 | int error; | | 735 | int error; |
736 | | | 736 | |
737 | /* ensure any padding bytes are cleared */ | | 737 | /* ensure any padding bytes are cleared */ |
738 | memset(&val_k, 0, sizeof(val_k)); | | 738 | memset(&val_k, 0, sizeof(val_k)); |
739 | | | 739 | |
740 | error = copyin(key_u, &key_k, sizeof(key_k)); | | 740 | error = copyin(key_u, &key_k, sizeof(key_k)); |
741 | if (error) { | | 741 | if (error) { |
742 | return error; | | 742 | return error; |
743 | } | | 743 | } |
744 | | | 744 | |
745 | error = vfs_quotactl_get(mp, &key_k, &val_k); | | 745 | error = vfs_quotactl_get(mp, &key_k, &val_k); |
746 | if (error) { | | 746 | if (error) { |
747 | return error; | | 747 | return error; |
748 | } | | 748 | } |
749 | | | 749 | |
750 | return copyout(&val_k, val_u, sizeof(val_k)); | | 750 | return copyout(&val_k, val_u, sizeof(val_k)); |
751 | } | | 751 | } |
752 | | | 752 | |
753 | static int | | 753 | static int |
754 | do_sys_quotactl_put(struct mount *mp, const struct quotakey *key_u, | | 754 | do_sys_quotactl_put(struct mount *mp, const struct quotakey *key_u, |
755 | const struct quotaval *val_u) | | 755 | const struct quotaval *val_u) |
756 | { | | 756 | { |
757 | struct quotakey key_k; | | 757 | struct quotakey key_k; |
758 | struct quotaval val_k; | | 758 | struct quotaval val_k; |
759 | int error; | | 759 | int error; |
760 | | | 760 | |
761 | error = copyin(key_u, &key_k, sizeof(key_k)); | | 761 | error = copyin(key_u, &key_k, sizeof(key_k)); |
762 | if (error) { | | 762 | if (error) { |
763 | return error; | | 763 | return error; |
764 | } | | 764 | } |
765 | | | 765 | |
766 | error = copyin(val_u, &val_k, sizeof(val_k)); | | 766 | error = copyin(val_u, &val_k, sizeof(val_k)); |
767 | if (error) { | | 767 | if (error) { |
768 | return error; | | 768 | return error; |
769 | } | | 769 | } |
770 | | | 770 | |
771 | return vfs_quotactl_put(mp, &key_k, &val_k); | | 771 | return vfs_quotactl_put(mp, &key_k, &val_k); |
772 | } | | 772 | } |
773 | | | 773 | |
774 | static int | | 774 | static int |
775 | do_sys_quotactl_del(struct mount *mp, const struct quotakey *key_u) | | 775 | do_sys_quotactl_del(struct mount *mp, const struct quotakey *key_u) |
776 | { | | 776 | { |
777 | struct quotakey key_k; | | 777 | struct quotakey key_k; |
778 | int error; | | 778 | int error; |
779 | | | 779 | |
780 | error = copyin(key_u, &key_k, sizeof(key_k)); | | 780 | error = copyin(key_u, &key_k, sizeof(key_k)); |
781 | if (error) { | | 781 | if (error) { |
782 | return error; | | 782 | return error; |
783 | } | | 783 | } |
784 | | | 784 | |
785 | return vfs_quotactl_del(mp, &key_k); | | 785 | return vfs_quotactl_del(mp, &key_k); |
786 | } | | 786 | } |
787 | | | 787 | |
788 | static int | | 788 | static int |
789 | do_sys_quotactl_cursoropen(struct mount *mp, struct quotakcursor *cursor_u) | | 789 | do_sys_quotactl_cursoropen(struct mount *mp, struct quotakcursor *cursor_u) |
790 | { | | 790 | { |
791 | struct quotakcursor cursor_k; | | 791 | struct quotakcursor cursor_k; |
792 | int error; | | 792 | int error; |
793 | | | 793 | |
794 | /* ensure any padding bytes are cleared */ | | 794 | /* ensure any padding bytes are cleared */ |
795 | memset(&cursor_k, 0, sizeof(cursor_k)); | | 795 | memset(&cursor_k, 0, sizeof(cursor_k)); |
796 | | | 796 | |
797 | error = vfs_quotactl_cursoropen(mp, &cursor_k); | | 797 | error = vfs_quotactl_cursoropen(mp, &cursor_k); |
798 | if (error) { | | 798 | if (error) { |
799 | return error; | | 799 | return error; |
800 | } | | 800 | } |
801 | | | 801 | |
802 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); | | 802 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); |
803 | } | | 803 | } |
804 | | | 804 | |
805 | static int | | 805 | static int |
806 | do_sys_quotactl_cursorclose(struct mount *mp, struct quotakcursor *cursor_u) | | 806 | do_sys_quotactl_cursorclose(struct mount *mp, struct quotakcursor *cursor_u) |
807 | { | | 807 | { |
808 | struct quotakcursor cursor_k; | | 808 | struct quotakcursor cursor_k; |
809 | int error; | | 809 | int error; |
810 | | | 810 | |
811 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); | | 811 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); |
812 | if (error) { | | 812 | if (error) { |
813 | return error; | | 813 | return error; |
814 | } | | 814 | } |
815 | | | 815 | |
816 | return vfs_quotactl_cursorclose(mp, &cursor_k); | | 816 | return vfs_quotactl_cursorclose(mp, &cursor_k); |
817 | } | | 817 | } |
818 | | | 818 | |
819 | static int | | 819 | static int |
820 | do_sys_quotactl_cursorskipidtype(struct mount *mp, | | 820 | do_sys_quotactl_cursorskipidtype(struct mount *mp, |
821 | struct quotakcursor *cursor_u, int idtype) | | 821 | struct quotakcursor *cursor_u, int idtype) |
822 | { | | 822 | { |
823 | struct quotakcursor cursor_k; | | 823 | struct quotakcursor cursor_k; |
824 | int error; | | 824 | int error; |
825 | | | 825 | |
826 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); | | 826 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); |
827 | if (error) { | | 827 | if (error) { |
828 | return error; | | 828 | return error; |
829 | } | | 829 | } |
830 | | | 830 | |
831 | error = vfs_quotactl_cursorskipidtype(mp, &cursor_k, idtype); | | 831 | error = vfs_quotactl_cursorskipidtype(mp, &cursor_k, idtype); |
832 | if (error) { | | 832 | if (error) { |
833 | return error; | | 833 | return error; |
834 | } | | 834 | } |
835 | | | 835 | |
836 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); | | 836 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); |
837 | } | | 837 | } |
838 | | | 838 | |
839 | static int | | 839 | static int |
840 | do_sys_quotactl_cursorget(struct mount *mp, struct quotakcursor *cursor_u, | | 840 | do_sys_quotactl_cursorget(struct mount *mp, struct quotakcursor *cursor_u, |
841 | struct quotakey *keys_u, struct quotaval *vals_u, unsigned maxnum, | | 841 | struct quotakey *keys_u, struct quotaval *vals_u, unsigned maxnum, |
842 | unsigned *ret_u) | | 842 | unsigned *ret_u) |
843 | { | | 843 | { |
844 | #define CGET_STACK_MAX 8 | | 844 | #define CGET_STACK_MAX 8 |
845 | struct quotakcursor cursor_k; | | 845 | struct quotakcursor cursor_k; |
846 | struct quotakey stackkeys[CGET_STACK_MAX]; | | 846 | struct quotakey stackkeys[CGET_STACK_MAX]; |
847 | struct quotaval stackvals[CGET_STACK_MAX]; | | 847 | struct quotaval stackvals[CGET_STACK_MAX]; |
848 | struct quotakey *keys_k; | | 848 | struct quotakey *keys_k; |
849 | struct quotaval *vals_k; | | 849 | struct quotaval *vals_k; |
850 | unsigned ret_k; | | 850 | unsigned ret_k; |
851 | int error; | | 851 | int error; |
852 | | | 852 | |
853 | if (maxnum > 128) { | | 853 | if (maxnum > 128) { |
854 | maxnum = 128; | | 854 | maxnum = 128; |
855 | } | | 855 | } |
856 | | | 856 | |
857 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); | | 857 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); |
858 | if (error) { | | 858 | if (error) { |
859 | return error; | | 859 | return error; |
860 | } | | 860 | } |
861 | | | 861 | |
862 | if (maxnum <= CGET_STACK_MAX) { | | 862 | if (maxnum <= CGET_STACK_MAX) { |
863 | keys_k = stackkeys; | | 863 | keys_k = stackkeys; |
864 | vals_k = stackvals; | | 864 | vals_k = stackvals; |
865 | /* ensure any padding bytes are cleared */ | | 865 | /* ensure any padding bytes are cleared */ |
866 | memset(keys_k, 0, maxnum * sizeof(keys_k[0])); | | 866 | memset(keys_k, 0, maxnum * sizeof(keys_k[0])); |
867 | memset(vals_k, 0, maxnum * sizeof(vals_k[0])); | | 867 | memset(vals_k, 0, maxnum * sizeof(vals_k[0])); |
868 | } else { | | 868 | } else { |
869 | keys_k = kmem_zalloc(maxnum * sizeof(keys_k[0]), KM_SLEEP); | | 869 | keys_k = kmem_zalloc(maxnum * sizeof(keys_k[0]), KM_SLEEP); |
870 | vals_k = kmem_zalloc(maxnum * sizeof(vals_k[0]), KM_SLEEP); | | 870 | vals_k = kmem_zalloc(maxnum * sizeof(vals_k[0]), KM_SLEEP); |
871 | } | | 871 | } |
872 | | | 872 | |
873 | error = vfs_quotactl_cursorget(mp, &cursor_k, keys_k, vals_k, maxnum, | | 873 | error = vfs_quotactl_cursorget(mp, &cursor_k, keys_k, vals_k, maxnum, |
874 | &ret_k); | | 874 | &ret_k); |
875 | if (error) { | | 875 | if (error) { |
876 | goto fail; | | 876 | goto fail; |
877 | } | | 877 | } |
878 | | | 878 | |
879 | error = copyout(keys_k, keys_u, ret_k * sizeof(keys_k[0])); | | 879 | error = copyout(keys_k, keys_u, ret_k * sizeof(keys_k[0])); |
880 | if (error) { | | 880 | if (error) { |
881 | goto fail; | | 881 | goto fail; |
882 | } | | 882 | } |
883 | | | 883 | |
884 | error = copyout(vals_k, vals_u, ret_k * sizeof(vals_k[0])); | | 884 | error = copyout(vals_k, vals_u, ret_k * sizeof(vals_k[0])); |
885 | if (error) { | | 885 | if (error) { |
886 | goto fail; | | 886 | goto fail; |
887 | } | | 887 | } |
888 | | | 888 | |
889 | error = copyout(&ret_k, ret_u, sizeof(ret_k)); | | 889 | error = copyout(&ret_k, ret_u, sizeof(ret_k)); |
890 | if (error) { | | 890 | if (error) { |
891 | goto fail; | | 891 | goto fail; |
892 | } | | 892 | } |
893 | | | 893 | |
894 | /* do last to maximize the chance of being able to recover a failure */ | | 894 | /* do last to maximize the chance of being able to recover a failure */ |
895 | error = copyout(&cursor_k, cursor_u, sizeof(cursor_k)); | | 895 | error = copyout(&cursor_k, cursor_u, sizeof(cursor_k)); |
896 | | | 896 | |
897 | fail: | | 897 | fail: |
898 | if (keys_k != stackkeys) { | | 898 | if (keys_k != stackkeys) { |
899 | kmem_free(keys_k, maxnum * sizeof(keys_k[0])); | | 899 | kmem_free(keys_k, maxnum * sizeof(keys_k[0])); |
900 | } | | 900 | } |
901 | if (vals_k != stackvals) { | | 901 | if (vals_k != stackvals) { |
902 | kmem_free(vals_k, maxnum * sizeof(vals_k[0])); | | 902 | kmem_free(vals_k, maxnum * sizeof(vals_k[0])); |
903 | } | | 903 | } |
904 | return error; | | 904 | return error; |
905 | } | | 905 | } |
906 | | | 906 | |
907 | static int | | 907 | static int |
908 | do_sys_quotactl_cursoratend(struct mount *mp, struct quotakcursor *cursor_u, | | 908 | do_sys_quotactl_cursoratend(struct mount *mp, struct quotakcursor *cursor_u, |
909 | int *ret_u) | | 909 | int *ret_u) |
910 | { | | 910 | { |
911 | struct quotakcursor cursor_k; | | 911 | struct quotakcursor cursor_k; |
912 | int ret_k; | | 912 | int ret_k; |
913 | int error; | | 913 | int error; |
914 | | | 914 | |
915 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); | | 915 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); |
916 | if (error) { | | 916 | if (error) { |
917 | return error; | | 917 | return error; |
918 | } | | 918 | } |
919 | | | 919 | |
920 | error = vfs_quotactl_cursoratend(mp, &cursor_k, &ret_k); | | 920 | error = vfs_quotactl_cursoratend(mp, &cursor_k, &ret_k); |
921 | if (error) { | | 921 | if (error) { |
922 | return error; | | 922 | return error; |
923 | } | | 923 | } |
924 | | | 924 | |
925 | error = copyout(&ret_k, ret_u, sizeof(ret_k)); | | 925 | error = copyout(&ret_k, ret_u, sizeof(ret_k)); |
926 | if (error) { | | 926 | if (error) { |
927 | return error; | | 927 | return error; |
928 | } | | 928 | } |
929 | | | 929 | |
930 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); | | 930 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); |
931 | } | | 931 | } |
932 | | | 932 | |
933 | static int | | 933 | static int |
934 | do_sys_quotactl_cursorrewind(struct mount *mp, struct quotakcursor *cursor_u) | | 934 | do_sys_quotactl_cursorrewind(struct mount *mp, struct quotakcursor *cursor_u) |
935 | { | | 935 | { |
936 | struct quotakcursor cursor_k; | | 936 | struct quotakcursor cursor_k; |
937 | int error; | | 937 | int error; |
938 | | | 938 | |
939 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); | | 939 | error = copyin(cursor_u, &cursor_k, sizeof(cursor_k)); |
940 | if (error) { | | 940 | if (error) { |
941 | return error; | | 941 | return error; |
942 | } | | 942 | } |
943 | | | 943 | |
944 | error = vfs_quotactl_cursorrewind(mp, &cursor_k); | | 944 | error = vfs_quotactl_cursorrewind(mp, &cursor_k); |
945 | if (error) { | | 945 | if (error) { |
946 | return error; | | 946 | return error; |
947 | } | | 947 | } |
948 | | | 948 | |
949 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); | | 949 | return copyout(&cursor_k, cursor_u, sizeof(cursor_k)); |
950 | } | | 950 | } |
951 | | | 951 | |
952 | static int | | 952 | static int |
953 | do_sys_quotactl_quotaon(struct mount *mp, int idtype, const char *path_u) | | 953 | do_sys_quotactl_quotaon(struct mount *mp, int idtype, const char *path_u) |
954 | { | | 954 | { |
955 | char *path_k; | | 955 | char *path_k; |
956 | int error; | | 956 | int error; |
957 | | | 957 | |
958 | /* XXX this should probably be a struct pathbuf */ | | 958 | /* XXX this should probably be a struct pathbuf */ |
959 | path_k = PNBUF_GET(); | | 959 | path_k = PNBUF_GET(); |
960 | error = copyin(path_u, path_k, PATH_MAX); | | 960 | error = copyin(path_u, path_k, PATH_MAX); |
961 | if (error) { | | 961 | if (error) { |
962 | PNBUF_PUT(path_k); | | 962 | PNBUF_PUT(path_k); |
963 | return error; | | 963 | return error; |
964 | } | | 964 | } |
965 | | | 965 | |
966 | error = vfs_quotactl_quotaon(mp, idtype, path_k); | | 966 | error = vfs_quotactl_quotaon(mp, idtype, path_k); |
967 | | | 967 | |
968 | PNBUF_PUT(path_k); | | 968 | PNBUF_PUT(path_k); |
969 | return error; | | 969 | return error; |
970 | } | | 970 | } |
971 | | | 971 | |
972 | static int | | 972 | static int |
973 | do_sys_quotactl_quotaoff(struct mount *mp, int idtype) | | 973 | do_sys_quotactl_quotaoff(struct mount *mp, int idtype) |
974 | { | | 974 | { |
975 | return vfs_quotactl_quotaoff(mp, idtype); | | 975 | return vfs_quotactl_quotaoff(mp, idtype); |
976 | } | | 976 | } |
977 | | | 977 | |
978 | int | | 978 | int |
979 | do_sys_quotactl(const char *path_u, const struct quotactl_args *args) | | 979 | do_sys_quotactl(const char *path_u, const struct quotactl_args *args) |
980 | { | | 980 | { |
981 | struct mount *mp; | | 981 | struct mount *mp; |
982 | struct vnode *vp; | | 982 | struct vnode *vp; |
983 | int error; | | 983 | int error; |
984 | | | 984 | |
985 | error = namei_simple_user(path_u, NSM_FOLLOW_TRYEMULROOT, &vp); | | 985 | error = namei_simple_user(path_u, NSM_FOLLOW_TRYEMULROOT, &vp); |
986 | if (error != 0) | | 986 | if (error != 0) |
987 | return (error); | | 987 | return (error); |
988 | mp = vp->v_mount; | | 988 | mp = vp->v_mount; |
989 | | | 989 | |
990 | switch (args->qc_op) { | | 990 | switch (args->qc_op) { |
991 | case QUOTACTL_STAT: | | 991 | case QUOTACTL_STAT: |
992 | error = do_sys_quotactl_stat(mp, args->u.stat.qc_info); | | 992 | error = do_sys_quotactl_stat(mp, args->u.stat.qc_info); |
993 | break; | | 993 | break; |
994 | case QUOTACTL_IDTYPESTAT: | | 994 | case QUOTACTL_IDTYPESTAT: |
995 | error = do_sys_quotactl_idtypestat(mp, | | 995 | error = do_sys_quotactl_idtypestat(mp, |
996 | args->u.idtypestat.qc_idtype, | | 996 | args->u.idtypestat.qc_idtype, |
997 | args->u.idtypestat.qc_info); | | 997 | args->u.idtypestat.qc_info); |
998 | break; | | 998 | break; |
999 | case QUOTACTL_OBJTYPESTAT: | | 999 | case QUOTACTL_OBJTYPESTAT: |
1000 | error = do_sys_quotactl_objtypestat(mp, | | 1000 | error = do_sys_quotactl_objtypestat(mp, |
1001 | args->u.objtypestat.qc_objtype, | | 1001 | args->u.objtypestat.qc_objtype, |
1002 | args->u.objtypestat.qc_info); | | 1002 | args->u.objtypestat.qc_info); |
1003 | break; | | 1003 | break; |
1004 | case QUOTACTL_GET: | | 1004 | case QUOTACTL_GET: |
1005 | error = do_sys_quotactl_get(mp, | | 1005 | error = do_sys_quotactl_get(mp, |
1006 | args->u.get.qc_key, | | 1006 | args->u.get.qc_key, |
1007 | args->u.get.qc_val); | | 1007 | args->u.get.qc_val); |
1008 | break; | | 1008 | break; |
1009 | case QUOTACTL_PUT: | | 1009 | case QUOTACTL_PUT: |
1010 | error = do_sys_quotactl_put(mp, | | 1010 | error = do_sys_quotactl_put(mp, |
1011 | args->u.put.qc_key, | | 1011 | args->u.put.qc_key, |
1012 | args->u.put.qc_val); | | 1012 | args->u.put.qc_val); |
1013 | break; | | 1013 | break; |
1014 | case QUOTACTL_DEL: | | 1014 | case QUOTACTL_DEL: |
1015 | error = do_sys_quotactl_del(mp, args->u.del.qc_key); | | 1015 | error = do_sys_quotactl_del(mp, args->u.del.qc_key); |
1016 | break; | | 1016 | break; |
1017 | case QUOTACTL_CURSOROPEN: | | 1017 | case QUOTACTL_CURSOROPEN: |
1018 | error = do_sys_quotactl_cursoropen(mp, | | 1018 | error = do_sys_quotactl_cursoropen(mp, |
1019 | args->u.cursoropen.qc_cursor); | | 1019 | args->u.cursoropen.qc_cursor); |
1020 | break; | | 1020 | break; |
1021 | case QUOTACTL_CURSORCLOSE: | | 1021 | case QUOTACTL_CURSORCLOSE: |
1022 | error = do_sys_quotactl_cursorclose(mp, | | 1022 | error = do_sys_quotactl_cursorclose(mp, |
1023 | args->u.cursorclose.qc_cursor); | | 1023 | args->u.cursorclose.qc_cursor); |
1024 | break; | | 1024 | break; |
1025 | case QUOTACTL_CURSORSKIPIDTYPE: | | 1025 | case QUOTACTL_CURSORSKIPIDTYPE: |
1026 | error = do_sys_quotactl_cursorskipidtype(mp, | | 1026 | error = do_sys_quotactl_cursorskipidtype(mp, |
1027 | args->u.cursorskipidtype.qc_cursor, | | 1027 | args->u.cursorskipidtype.qc_cursor, |
1028 | args->u.cursorskipidtype.qc_idtype); | | 1028 | args->u.cursorskipidtype.qc_idtype); |
1029 | break; | | 1029 | break; |
1030 | case QUOTACTL_CURSORGET: | | 1030 | case QUOTACTL_CURSORGET: |
1031 | error = do_sys_quotactl_cursorget(mp, | | 1031 | error = do_sys_quotactl_cursorget(mp, |
1032 | args->u.cursorget.qc_cursor, | | 1032 | args->u.cursorget.qc_cursor, |
1033 | args->u.cursorget.qc_keys, | | 1033 | args->u.cursorget.qc_keys, |
1034 | args->u.cursorget.qc_vals, | | 1034 | args->u.cursorget.qc_vals, |
1035 | args->u.cursorget.qc_maxnum, | | 1035 | args->u.cursorget.qc_maxnum, |
1036 | args->u.cursorget.qc_ret); | | 1036 | args->u.cursorget.qc_ret); |
1037 | break; | | 1037 | break; |
1038 | case QUOTACTL_CURSORATEND: | | 1038 | case QUOTACTL_CURSORATEND: |
1039 | error = do_sys_quotactl_cursoratend(mp, | | 1039 | error = do_sys_quotactl_cursoratend(mp, |
1040 | args->u.cursoratend.qc_cursor, | | 1040 | args->u.cursoratend.qc_cursor, |
1041 | args->u.cursoratend.qc_ret); | | 1041 | args->u.cursoratend.qc_ret); |
1042 | break; | | 1042 | break; |
1043 | case QUOTACTL_CURSORREWIND: | | 1043 | case QUOTACTL_CURSORREWIND: |
1044 | error = do_sys_quotactl_cursorrewind(mp, | | 1044 | error = do_sys_quotactl_cursorrewind(mp, |
1045 | args->u.cursorrewind.qc_cursor); | | 1045 | args->u.cursorrewind.qc_cursor); |
1046 | break; | | 1046 | break; |
1047 | case QUOTACTL_QUOTAON: | | 1047 | case QUOTACTL_QUOTAON: |
1048 | error = do_sys_quotactl_quotaon(mp, | | 1048 | error = do_sys_quotactl_quotaon(mp, |
1049 | args->u.quotaon.qc_idtype, | | 1049 | args->u.quotaon.qc_idtype, |
1050 | args->u.quotaon.qc_quotafile); | | 1050 | args->u.quotaon.qc_quotafile); |
1051 | break; | | 1051 | break; |
1052 | case QUOTACTL_QUOTAOFF: | | 1052 | case QUOTACTL_QUOTAOFF: |
1053 | error = do_sys_quotactl_quotaoff(mp, | | 1053 | error = do_sys_quotactl_quotaoff(mp, |
1054 | args->u.quotaoff.qc_idtype); | | 1054 | args->u.quotaoff.qc_idtype); |
1055 | break; | | 1055 | break; |
1056 | default: | | 1056 | default: |
1057 | error = EINVAL; | | 1057 | error = EINVAL; |
1058 | break; | | 1058 | break; |
1059 | } | | 1059 | } |
1060 | | | 1060 | |
1061 | vrele(vp); | | 1061 | vrele(vp); |
1062 | return error; | | 1062 | return error; |
1063 | } | | 1063 | } |
1064 | | | 1064 | |
1065 | /* ARGSUSED */ | | 1065 | /* ARGSUSED */ |
1066 | int | | 1066 | int |
1067 | sys___quotactl(struct lwp *l, const struct sys___quotactl_args *uap, | | 1067 | sys___quotactl(struct lwp *l, const struct sys___quotactl_args *uap, |
1068 | register_t *retval) | | 1068 | register_t *retval) |
1069 | { | | 1069 | { |
1070 | /* { | | 1070 | /* { |
1071 | syscallarg(const char *) path; | | 1071 | syscallarg(const char *) path; |
1072 | syscallarg(struct quotactl_args *) args; | | 1072 | syscallarg(struct quotactl_args *) args; |
| @@ -3008,1789 +3008,1784 @@ sys_faccessat(struct lwp *l, const struc | | | @@ -3008,1789 +3008,1784 @@ sys_faccessat(struct lwp *l, const struc |
3008 | SCARG(uap, amode), SCARG(uap, flag)); | | 3008 | SCARG(uap, amode), SCARG(uap, flag)); |
3009 | } | | 3009 | } |
3010 | | | 3010 | |
3011 | /* | | 3011 | /* |
3012 | * Common code for all sys_stat functions, including compat versions. | | 3012 | * Common code for all sys_stat functions, including compat versions. |
3013 | */ | | 3013 | */ |
3014 | int | | 3014 | int |
3015 | do_sys_stat(const char *userpath, unsigned int nd_flag, | | 3015 | do_sys_stat(const char *userpath, unsigned int nd_flag, |
3016 | struct stat *sb) | | 3016 | struct stat *sb) |
3017 | { | | 3017 | { |
3018 | return do_sys_statat(NULL, AT_FDCWD, userpath, nd_flag, sb); | | 3018 | return do_sys_statat(NULL, AT_FDCWD, userpath, nd_flag, sb); |
3019 | } | | 3019 | } |
3020 | | | 3020 | |
3021 | int | | 3021 | int |
3022 | do_sys_statat(struct lwp *l, int fdat, const char *userpath, | | 3022 | do_sys_statat(struct lwp *l, int fdat, const char *userpath, |
3023 | unsigned int nd_flag, struct stat *sb) | | 3023 | unsigned int nd_flag, struct stat *sb) |
3024 | { | | 3024 | { |
3025 | int error; | | 3025 | int error; |
3026 | struct pathbuf *pb; | | 3026 | struct pathbuf *pb; |
3027 | struct nameidata nd; | | 3027 | struct nameidata nd; |
3028 | | | 3028 | |
3029 | KASSERT(l != NULL || fdat == AT_FDCWD); | | 3029 | KASSERT(l != NULL || fdat == AT_FDCWD); |
3030 | | | 3030 | |
3031 | error = pathbuf_copyin(userpath, &pb); | | 3031 | error = pathbuf_copyin(userpath, &pb); |
3032 | if (error) { | | 3032 | if (error) { |
3033 | return error; | | 3033 | return error; |
3034 | } | | 3034 | } |
3035 | | | 3035 | |
3036 | NDINIT(&nd, LOOKUP, nd_flag | LOCKLEAF | TRYEMULROOT, pb); | | 3036 | NDINIT(&nd, LOOKUP, nd_flag | LOCKLEAF | TRYEMULROOT, pb); |
3037 | | | 3037 | |
3038 | error = fd_nameiat(l, fdat, &nd); | | 3038 | error = fd_nameiat(l, fdat, &nd); |
3039 | if (error != 0) { | | 3039 | if (error != 0) { |
3040 | pathbuf_destroy(pb); | | 3040 | pathbuf_destroy(pb); |
3041 | return error; | | 3041 | return error; |
3042 | } | | 3042 | } |
3043 | error = vn_stat(nd.ni_vp, sb); | | 3043 | error = vn_stat(nd.ni_vp, sb); |
3044 | vput(nd.ni_vp); | | 3044 | vput(nd.ni_vp); |
3045 | pathbuf_destroy(pb); | | 3045 | pathbuf_destroy(pb); |
3046 | return error; | | 3046 | return error; |
3047 | } | | 3047 | } |
3048 | | | 3048 | |
3049 | /* | | 3049 | /* |
3050 | * Get file status; this version follows links. | | 3050 | * Get file status; this version follows links. |
3051 | */ | | 3051 | */ |
3052 | /* ARGSUSED */ | | 3052 | /* ARGSUSED */ |
3053 | int | | 3053 | int |
3054 | sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval) | | 3054 | sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval) |
3055 | { | | 3055 | { |
3056 | /* { | | 3056 | /* { |
3057 | syscallarg(const char *) path; | | 3057 | syscallarg(const char *) path; |
3058 | syscallarg(struct stat *) ub; | | 3058 | syscallarg(struct stat *) ub; |
3059 | } */ | | 3059 | } */ |
3060 | struct stat sb; | | 3060 | struct stat sb; |
3061 | int error; | | 3061 | int error; |
3062 | | | 3062 | |
3063 | error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), FOLLOW, &sb); | | 3063 | error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), FOLLOW, &sb); |
3064 | if (error) | | 3064 | if (error) |
3065 | return error; | | 3065 | return error; |
3066 | return copyout(&sb, SCARG(uap, ub), sizeof(sb)); | | 3066 | return copyout(&sb, SCARG(uap, ub), sizeof(sb)); |
3067 | } | | 3067 | } |
3068 | | | 3068 | |
3069 | /* | | 3069 | /* |
3070 | * Get file status; this version does not follow links. | | 3070 | * Get file status; this version does not follow links. |
3071 | */ | | 3071 | */ |
3072 | /* ARGSUSED */ | | 3072 | /* ARGSUSED */ |
3073 | int | | 3073 | int |
3074 | sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval) | | 3074 | sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval) |
3075 | { | | 3075 | { |
3076 | /* { | | 3076 | /* { |
3077 | syscallarg(const char *) path; | | 3077 | syscallarg(const char *) path; |
3078 | syscallarg(struct stat *) ub; | | 3078 | syscallarg(struct stat *) ub; |
3079 | } */ | | 3079 | } */ |
3080 | struct stat sb; | | 3080 | struct stat sb; |
3081 | int error; | | 3081 | int error; |
3082 | | | 3082 | |
3083 | error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), NOFOLLOW, &sb); | | 3083 | error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), NOFOLLOW, &sb); |
3084 | if (error) | | 3084 | if (error) |
3085 | return error; | | 3085 | return error; |
3086 | return copyout(&sb, SCARG(uap, ub), sizeof(sb)); | | 3086 | return copyout(&sb, SCARG(uap, ub), sizeof(sb)); |
3087 | } | | 3087 | } |
3088 | | | 3088 | |
3089 | int | | 3089 | int |
3090 | sys_fstatat(struct lwp *l, const struct sys_fstatat_args *uap, | | 3090 | sys_fstatat(struct lwp *l, const struct sys_fstatat_args *uap, |
3091 | register_t *retval) | | 3091 | register_t *retval) |
3092 | { | | 3092 | { |
3093 | /* { | | 3093 | /* { |
3094 | syscallarg(int) fd; | | 3094 | syscallarg(int) fd; |
3095 | syscallarg(const char *) path; | | 3095 | syscallarg(const char *) path; |
3096 | syscallarg(struct stat *) buf; | | 3096 | syscallarg(struct stat *) buf; |
3097 | syscallarg(int) flag; | | 3097 | syscallarg(int) flag; |
3098 | } */ | | 3098 | } */ |
3099 | unsigned int nd_flag; | | 3099 | unsigned int nd_flag; |
3100 | struct stat sb; | | 3100 | struct stat sb; |
3101 | int error; | | 3101 | int error; |
3102 | | | 3102 | |
3103 | if (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) | | 3103 | if (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) |
3104 | nd_flag = NOFOLLOW; | | 3104 | nd_flag = NOFOLLOW; |
3105 | else | | 3105 | else |
3106 | nd_flag = FOLLOW; | | 3106 | nd_flag = FOLLOW; |
3107 | | | 3107 | |
3108 | error = do_sys_statat(l, SCARG(uap, fd), SCARG(uap, path), nd_flag, | | 3108 | error = do_sys_statat(l, SCARG(uap, fd), SCARG(uap, path), nd_flag, |
3109 | &sb); | | 3109 | &sb); |
3110 | if (error) | | 3110 | if (error) |
3111 | return error; | | 3111 | return error; |
3112 | return copyout(&sb, SCARG(uap, buf), sizeof(sb)); | | 3112 | return copyout(&sb, SCARG(uap, buf), sizeof(sb)); |
3113 | } | | 3113 | } |
3114 | | | 3114 | |
3115 | /* | | 3115 | /* |
3116 | * Get configurable pathname variables. | | 3116 | * Get configurable pathname variables. |
3117 | */ | | 3117 | */ |
3118 | /* ARGSUSED */ | | 3118 | /* ARGSUSED */ |
3119 | int | | 3119 | int |
3120 | sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval) | | 3120 | sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval) |
3121 | { | | 3121 | { |
3122 | /* { | | 3122 | /* { |
3123 | syscallarg(const char *) path; | | 3123 | syscallarg(const char *) path; |
3124 | syscallarg(int) name; | | 3124 | syscallarg(int) name; |
3125 | } */ | | 3125 | } */ |
3126 | int error; | | 3126 | int error; |
3127 | struct pathbuf *pb; | | 3127 | struct pathbuf *pb; |
3128 | struct nameidata nd; | | 3128 | struct nameidata nd; |
3129 | | | 3129 | |
3130 | error = pathbuf_copyin(SCARG(uap, path), &pb); | | 3130 | error = pathbuf_copyin(SCARG(uap, path), &pb); |
3131 | if (error) { | | 3131 | if (error) { |
3132 | return error; | | 3132 | return error; |
3133 | } | | 3133 | } |
3134 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); | | 3134 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); |
3135 | if ((error = namei(&nd)) != 0) { | | 3135 | if ((error = namei(&nd)) != 0) { |
3136 | pathbuf_destroy(pb); | | 3136 | pathbuf_destroy(pb); |
3137 | return (error); | | 3137 | return (error); |
3138 | } | | 3138 | } |
3139 | error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); | | 3139 | error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); |
3140 | vput(nd.ni_vp); | | 3140 | vput(nd.ni_vp); |
3141 | pathbuf_destroy(pb); | | 3141 | pathbuf_destroy(pb); |
3142 | return (error); | | 3142 | return (error); |
3143 | } | | 3143 | } |
3144 | | | 3144 | |
3145 | /* | | 3145 | /* |
3146 | * Return target name of a symbolic link. | | 3146 | * Return target name of a symbolic link. |
3147 | */ | | 3147 | */ |
3148 | /* ARGSUSED */ | | 3148 | /* ARGSUSED */ |
3149 | int | | 3149 | int |
3150 | sys_readlink(struct lwp *l, const struct sys_readlink_args *uap, | | 3150 | sys_readlink(struct lwp *l, const struct sys_readlink_args *uap, |
3151 | register_t *retval) | | 3151 | register_t *retval) |
3152 | { | | 3152 | { |
3153 | /* { | | 3153 | /* { |
3154 | syscallarg(const char *) path; | | 3154 | syscallarg(const char *) path; |
3155 | syscallarg(char *) buf; | | 3155 | syscallarg(char *) buf; |
3156 | syscallarg(size_t) count; | | 3156 | syscallarg(size_t) count; |
3157 | } */ | | 3157 | } */ |
3158 | return do_sys_readlinkat(l, AT_FDCWD, SCARG(uap, path), | | 3158 | return do_sys_readlinkat(l, AT_FDCWD, SCARG(uap, path), |
3159 | SCARG(uap, buf), SCARG(uap, count), retval); | | 3159 | SCARG(uap, buf), SCARG(uap, count), retval); |
3160 | } | | 3160 | } |
3161 | | | 3161 | |
3162 | static int | | 3162 | static int |
3163 | do_sys_readlinkat(struct lwp *l, int fdat, const char *path, char *buf, | | 3163 | do_sys_readlinkat(struct lwp *l, int fdat, const char *path, char *buf, |
3164 | size_t count, register_t *retval) | | 3164 | size_t count, register_t *retval) |
3165 | { | | 3165 | { |
3166 | struct vnode *vp; | | 3166 | struct vnode *vp; |
3167 | struct iovec aiov; | | 3167 | struct iovec aiov; |
3168 | struct uio auio; | | 3168 | struct uio auio; |
3169 | int error; | | 3169 | int error; |
3170 | struct pathbuf *pb; | | 3170 | struct pathbuf *pb; |
3171 | struct nameidata nd; | | 3171 | struct nameidata nd; |
3172 | | | 3172 | |
3173 | error = pathbuf_copyin(path, &pb); | | 3173 | error = pathbuf_copyin(path, &pb); |
3174 | if (error) { | | 3174 | if (error) { |
3175 | return error; | | 3175 | return error; |
3176 | } | | 3176 | } |
3177 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb); | | 3177 | NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb); |
3178 | if ((error = fd_nameiat(l, fdat, &nd)) != 0) { | | 3178 | if ((error = fd_nameiat(l, fdat, &nd)) != 0) { |
3179 | pathbuf_destroy(pb); | | 3179 | pathbuf_destroy(pb); |
3180 | return error; | | 3180 | return error; |
3181 | } | | 3181 | } |
3182 | vp = nd.ni_vp; | | 3182 | vp = nd.ni_vp; |
3183 | pathbuf_destroy(pb); | | 3183 | pathbuf_destroy(pb); |
3184 | if (vp->v_type != VLNK) | | 3184 | if (vp->v_type != VLNK) |
3185 | error = EINVAL; | | 3185 | error = EINVAL; |
3186 | else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) || | | 3186 | else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) || |
3187 | (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) { | | 3187 | (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) { |
3188 | aiov.iov_base = buf; | | 3188 | aiov.iov_base = buf; |
3189 | aiov.iov_len = count; | | 3189 | aiov.iov_len = count; |
3190 | auio.uio_iov = &aiov; | | 3190 | auio.uio_iov = &aiov; |
3191 | auio.uio_iovcnt = 1; | | 3191 | auio.uio_iovcnt = 1; |
3192 | auio.uio_offset = 0; | | 3192 | auio.uio_offset = 0; |
3193 | auio.uio_rw = UIO_READ; | | 3193 | auio.uio_rw = UIO_READ; |
3194 | KASSERT(l == curlwp); | | 3194 | KASSERT(l == curlwp); |
3195 | auio.uio_vmspace = l->l_proc->p_vmspace; | | 3195 | auio.uio_vmspace = l->l_proc->p_vmspace; |
3196 | auio.uio_resid = count; | | 3196 | auio.uio_resid = count; |
3197 | if ((error = VOP_READLINK(vp, &auio, l->l_cred)) == 0) | | 3197 | if ((error = VOP_READLINK(vp, &auio, l->l_cred)) == 0) |
3198 | *retval = count - auio.uio_resid; | | 3198 | *retval = count - auio.uio_resid; |
3199 | } | | 3199 | } |
3200 | vput(vp); | | 3200 | vput(vp); |
3201 | return (error); | | 3201 | return (error); |
3202 | } | | 3202 | } |
3203 | | | 3203 | |
3204 | int | | 3204 | int |
3205 | sys_readlinkat(struct lwp *l, const struct sys_readlinkat_args *uap, | | 3205 | sys_readlinkat(struct lwp *l, const struct sys_readlinkat_args *uap, |
3206 | register_t *retval) | | 3206 | register_t *retval) |
3207 | { | | 3207 | { |
3208 | /* { | | 3208 | /* { |
3209 | syscallarg(int) fd; | | 3209 | syscallarg(int) fd; |
3210 | syscallarg(const char *) path; | | 3210 | syscallarg(const char *) path; |
3211 | syscallarg(char *) buf; | | 3211 | syscallarg(char *) buf; |
3212 | syscallarg(size_t) bufsize; | | 3212 | syscallarg(size_t) bufsize; |
3213 | } */ | | 3213 | } */ |
3214 | | | 3214 | |
3215 | return do_sys_readlinkat(l, SCARG(uap, fd), SCARG(uap, path), | | 3215 | return do_sys_readlinkat(l, SCARG(uap, fd), SCARG(uap, path), |
3216 | SCARG(uap, buf), SCARG(uap, bufsize), retval); | | 3216 | SCARG(uap, buf), SCARG(uap, bufsize), retval); |
3217 | } | | 3217 | } |
3218 | | | 3218 | |
3219 | /* | | 3219 | /* |
3220 | * Change flags of a file given a path name. | | 3220 | * Change flags of a file given a path name. |
3221 | */ | | 3221 | */ |
3222 | /* ARGSUSED */ | | 3222 | /* ARGSUSED */ |
3223 | int | | 3223 | int |
3224 | sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval) | | 3224 | sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval) |
3225 | { | | 3225 | { |
3226 | /* { | | 3226 | /* { |
3227 | syscallarg(const char *) path; | | 3227 | syscallarg(const char *) path; |
3228 | syscallarg(u_long) flags; | | 3228 | syscallarg(u_long) flags; |
3229 | } */ | | 3229 | } */ |
3230 | struct vnode *vp; | | 3230 | struct vnode *vp; |
3231 | int error; | | 3231 | int error; |
3232 | | | 3232 | |
3233 | error = namei_simple_user(SCARG(uap, path), | | 3233 | error = namei_simple_user(SCARG(uap, path), |
3234 | NSM_FOLLOW_TRYEMULROOT, &vp); | | 3234 | NSM_FOLLOW_TRYEMULROOT, &vp); |
3235 | if (error != 0) | | 3235 | if (error != 0) |
3236 | return (error); | | 3236 | return (error); |
3237 | error = change_flags(vp, SCARG(uap, flags), l); | | 3237 | error = change_flags(vp, SCARG(uap, flags), l); |
3238 | vput(vp); | | 3238 | vput(vp); |
3239 | return (error); | | 3239 | return (error); |
3240 | } | | 3240 | } |
3241 | | | 3241 | |
3242 | /* | | 3242 | /* |
3243 | * Change flags of a file given a file descriptor. | | 3243 | * Change flags of a file given a file descriptor. |
3244 | */ | | 3244 | */ |
3245 | /* ARGSUSED */ | | 3245 | /* ARGSUSED */ |
3246 | int | | 3246 | int |
3247 | sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval) | | 3247 | sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval) |
3248 | { | | 3248 | { |
3249 | /* { | | 3249 | /* { |
3250 | syscallarg(int) fd; | | 3250 | syscallarg(int) fd; |
3251 | syscallarg(u_long) flags; | | 3251 | syscallarg(u_long) flags; |
3252 | } */ | | 3252 | } */ |
3253 | struct vnode *vp; | | 3253 | struct vnode *vp; |
3254 | file_t *fp; | | 3254 | file_t *fp; |
3255 | int error; | | 3255 | int error; |
3256 | | | 3256 | |
3257 | /* fd_getvnode() will use the descriptor for us */ | | 3257 | /* fd_getvnode() will use the descriptor for us */ |
3258 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3258 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3259 | return (error); | | 3259 | return (error); |
3260 | vp = fp->f_vnode; | | 3260 | vp = fp->f_vnode; |
3261 | error = change_flags(vp, SCARG(uap, flags), l); | | 3261 | error = change_flags(vp, SCARG(uap, flags), l); |
3262 | VOP_UNLOCK(vp); | | 3262 | VOP_UNLOCK(vp); |
3263 | fd_putfile(SCARG(uap, fd)); | | 3263 | fd_putfile(SCARG(uap, fd)); |
3264 | return (error); | | 3264 | return (error); |
3265 | } | | 3265 | } |
3266 | | | 3266 | |
3267 | /* | | 3267 | /* |
3268 | * Change flags of a file given a path name; this version does | | 3268 | * Change flags of a file given a path name; this version does |
3269 | * not follow links. | | 3269 | * not follow links. |
3270 | */ | | 3270 | */ |
3271 | int | | 3271 | int |
3272 | sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval) | | 3272 | sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval) |
3273 | { | | 3273 | { |
3274 | /* { | | 3274 | /* { |
3275 | syscallarg(const char *) path; | | 3275 | syscallarg(const char *) path; |
3276 | syscallarg(u_long) flags; | | 3276 | syscallarg(u_long) flags; |
3277 | } */ | | 3277 | } */ |
3278 | struct vnode *vp; | | 3278 | struct vnode *vp; |
3279 | int error; | | 3279 | int error; |
3280 | | | 3280 | |
3281 | error = namei_simple_user(SCARG(uap, path), | | 3281 | error = namei_simple_user(SCARG(uap, path), |
3282 | NSM_NOFOLLOW_TRYEMULROOT, &vp); | | 3282 | NSM_NOFOLLOW_TRYEMULROOT, &vp); |
3283 | if (error != 0) | | 3283 | if (error != 0) |
3284 | return (error); | | 3284 | return (error); |
3285 | error = change_flags(vp, SCARG(uap, flags), l); | | 3285 | error = change_flags(vp, SCARG(uap, flags), l); |
3286 | vput(vp); | | 3286 | vput(vp); |
3287 | return (error); | | 3287 | return (error); |
3288 | } | | 3288 | } |
3289 | | | 3289 | |
3290 | /* | | 3290 | /* |
3291 | * Common routine to change flags of a file. | | 3291 | * Common routine to change flags of a file. |
3292 | */ | | 3292 | */ |
3293 | int | | 3293 | int |
3294 | change_flags(struct vnode *vp, u_long flags, struct lwp *l) | | 3294 | change_flags(struct vnode *vp, u_long flags, struct lwp *l) |
3295 | { | | 3295 | { |
3296 | struct vattr vattr; | | 3296 | struct vattr vattr; |
3297 | int error; | | 3297 | int error; |
3298 | | | 3298 | |
3299 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3299 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3300 | | | 3300 | |
3301 | vattr_null(&vattr); | | 3301 | vattr_null(&vattr); |
3302 | vattr.va_flags = flags; | | 3302 | vattr.va_flags = flags; |
3303 | error = VOP_SETATTR(vp, &vattr, l->l_cred); | | 3303 | error = VOP_SETATTR(vp, &vattr, l->l_cred); |
3304 | | | 3304 | |
3305 | return (error); | | 3305 | return (error); |
3306 | } | | 3306 | } |
3307 | | | 3307 | |
3308 | /* | | 3308 | /* |
3309 | * Change mode of a file given path name; this version follows links. | | 3309 | * Change mode of a file given path name; this version follows links. |
3310 | */ | | 3310 | */ |
3311 | /* ARGSUSED */ | | 3311 | /* ARGSUSED */ |
3312 | int | | 3312 | int |
3313 | sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval) | | 3313 | sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval) |
3314 | { | | 3314 | { |
3315 | /* { | | 3315 | /* { |
3316 | syscallarg(const char *) path; | | 3316 | syscallarg(const char *) path; |
3317 | syscallarg(int) mode; | | 3317 | syscallarg(int) mode; |
3318 | } */ | | 3318 | } */ |
3319 | return do_sys_chmodat(l, AT_FDCWD, SCARG(uap, path), | | 3319 | return do_sys_chmodat(l, AT_FDCWD, SCARG(uap, path), |
3320 | SCARG(uap, mode), 0); | | 3320 | SCARG(uap, mode), 0); |
3321 | } | | 3321 | } |
3322 | | | 3322 | |
3323 | int | | 3323 | int |
3324 | do_sys_chmodat(struct lwp *l, int fdat, const char *path, int mode, int flags) | | 3324 | do_sys_chmodat(struct lwp *l, int fdat, const char *path, int mode, int flags) |
3325 | { | | 3325 | { |
3326 | int error; | | 3326 | int error; |
3327 | struct vnode *vp; | | 3327 | struct vnode *vp; |
3328 | namei_simple_flags_t ns_flag; | | 3328 | namei_simple_flags_t ns_flag; |
3329 | | | 3329 | |
3330 | if (flags & AT_SYMLINK_NOFOLLOW) | | 3330 | if (flags & AT_SYMLINK_NOFOLLOW) |
3331 | ns_flag = NSM_NOFOLLOW_TRYEMULROOT; | | 3331 | ns_flag = NSM_NOFOLLOW_TRYEMULROOT; |
3332 | else | | 3332 | else |
3333 | ns_flag = NSM_FOLLOW_TRYEMULROOT; | | 3333 | ns_flag = NSM_FOLLOW_TRYEMULROOT; |
3334 | | | 3334 | |
3335 | error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp); | | 3335 | error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp); |
3336 | if (error != 0) | | 3336 | if (error != 0) |
3337 | return error; | | 3337 | return error; |
3338 | | | 3338 | |
3339 | error = change_mode(vp, mode, l); | | 3339 | error = change_mode(vp, mode, l); |
3340 | | | 3340 | |
3341 | vrele(vp); | | 3341 | vrele(vp); |
3342 | | | 3342 | |
3343 | return (error); | | 3343 | return (error); |
3344 | } | | 3344 | } |
3345 | | | 3345 | |
3346 | /* | | 3346 | /* |
3347 | * Change mode of a file given a file descriptor. | | 3347 | * Change mode of a file given a file descriptor. |
3348 | */ | | 3348 | */ |
3349 | /* ARGSUSED */ | | 3349 | /* ARGSUSED */ |
3350 | int | | 3350 | int |
3351 | sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval) | | 3351 | sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval) |
3352 | { | | 3352 | { |
3353 | /* { | | 3353 | /* { |
3354 | syscallarg(int) fd; | | 3354 | syscallarg(int) fd; |
3355 | syscallarg(int) mode; | | 3355 | syscallarg(int) mode; |
3356 | } */ | | 3356 | } */ |
3357 | file_t *fp; | | 3357 | file_t *fp; |
3358 | int error; | | 3358 | int error; |
3359 | | | 3359 | |
3360 | /* fd_getvnode() will use the descriptor for us */ | | 3360 | /* fd_getvnode() will use the descriptor for us */ |
3361 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3361 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3362 | return (error); | | 3362 | return (error); |
3363 | error = change_mode(fp->f_vnode, SCARG(uap, mode), l); | | 3363 | error = change_mode(fp->f_vnode, SCARG(uap, mode), l); |
3364 | fd_putfile(SCARG(uap, fd)); | | 3364 | fd_putfile(SCARG(uap, fd)); |
3365 | return (error); | | 3365 | return (error); |
3366 | } | | 3366 | } |
3367 | | | 3367 | |
3368 | int | | 3368 | int |
3369 | sys_fchmodat(struct lwp *l, const struct sys_fchmodat_args *uap, | | 3369 | sys_fchmodat(struct lwp *l, const struct sys_fchmodat_args *uap, |
3370 | register_t *retval) | | 3370 | register_t *retval) |
3371 | { | | 3371 | { |
3372 | /* { | | 3372 | /* { |
3373 | syscallarg(int) fd; | | 3373 | syscallarg(int) fd; |
3374 | syscallarg(const char *) path; | | 3374 | syscallarg(const char *) path; |
3375 | syscallarg(int) mode; | | 3375 | syscallarg(int) mode; |
3376 | syscallarg(int) flag; | | 3376 | syscallarg(int) flag; |
3377 | } */ | | 3377 | } */ |
3378 | | | 3378 | |
3379 | return do_sys_chmodat(l, SCARG(uap, fd), SCARG(uap, path), | | 3379 | return do_sys_chmodat(l, SCARG(uap, fd), SCARG(uap, path), |
3380 | SCARG(uap, mode), SCARG(uap, flag)); | | 3380 | SCARG(uap, mode), SCARG(uap, flag)); |
3381 | } | | 3381 | } |
3382 | | | 3382 | |
3383 | /* | | 3383 | /* |
3384 | * Change mode of a file given path name; this version does not follow links. | | 3384 | * Change mode of a file given path name; this version does not follow links. |
3385 | */ | | 3385 | */ |
3386 | /* ARGSUSED */ | | 3386 | /* ARGSUSED */ |
3387 | int | | 3387 | int |
3388 | sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval) | | 3388 | sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval) |
3389 | { | | 3389 | { |
3390 | /* { | | 3390 | /* { |
3391 | syscallarg(const char *) path; | | 3391 | syscallarg(const char *) path; |
3392 | syscallarg(int) mode; | | 3392 | syscallarg(int) mode; |
3393 | } */ | | 3393 | } */ |
3394 | int error; | | 3394 | int error; |
3395 | struct vnode *vp; | | 3395 | struct vnode *vp; |
3396 | | | 3396 | |
3397 | error = namei_simple_user(SCARG(uap, path), | | 3397 | error = namei_simple_user(SCARG(uap, path), |
3398 | NSM_NOFOLLOW_TRYEMULROOT, &vp); | | 3398 | NSM_NOFOLLOW_TRYEMULROOT, &vp); |
3399 | if (error != 0) | | 3399 | if (error != 0) |
3400 | return (error); | | 3400 | return (error); |
3401 | | | 3401 | |
3402 | error = change_mode(vp, SCARG(uap, mode), l); | | 3402 | error = change_mode(vp, SCARG(uap, mode), l); |
3403 | | | 3403 | |
3404 | vrele(vp); | | 3404 | vrele(vp); |
3405 | return (error); | | 3405 | return (error); |
3406 | } | | 3406 | } |
3407 | | | 3407 | |
3408 | /* | | 3408 | /* |
3409 | * Common routine to set mode given a vnode. | | 3409 | * Common routine to set mode given a vnode. |
3410 | */ | | 3410 | */ |
3411 | static int | | 3411 | static int |
3412 | change_mode(struct vnode *vp, int mode, struct lwp *l) | | 3412 | change_mode(struct vnode *vp, int mode, struct lwp *l) |
3413 | { | | 3413 | { |
3414 | struct vattr vattr; | | 3414 | struct vattr vattr; |
3415 | int error; | | 3415 | int error; |
3416 | | | 3416 | |
3417 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3417 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3418 | vattr_null(&vattr); | | 3418 | vattr_null(&vattr); |
3419 | vattr.va_mode = mode & ALLPERMS; | | 3419 | vattr.va_mode = mode & ALLPERMS; |
3420 | error = VOP_SETATTR(vp, &vattr, l->l_cred); | | 3420 | error = VOP_SETATTR(vp, &vattr, l->l_cred); |
3421 | VOP_UNLOCK(vp); | | 3421 | VOP_UNLOCK(vp); |
3422 | return (error); | | 3422 | return (error); |
3423 | } | | 3423 | } |
3424 | | | 3424 | |
3425 | /* | | 3425 | /* |
3426 | * Set ownership given a path name; this version follows links. | | 3426 | * Set ownership given a path name; this version follows links. |
3427 | */ | | 3427 | */ |
3428 | /* ARGSUSED */ | | 3428 | /* ARGSUSED */ |
3429 | int | | 3429 | int |
3430 | sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval) | | 3430 | sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval) |
3431 | { | | 3431 | { |
3432 | /* { | | 3432 | /* { |
3433 | syscallarg(const char *) path; | | 3433 | syscallarg(const char *) path; |
3434 | syscallarg(uid_t) uid; | | 3434 | syscallarg(uid_t) uid; |
3435 | syscallarg(gid_t) gid; | | 3435 | syscallarg(gid_t) gid; |
3436 | } */ | | 3436 | } */ |
3437 | return do_sys_chownat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap,uid), | | 3437 | return do_sys_chownat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap,uid), |
3438 | SCARG(uap, gid), 0); | | 3438 | SCARG(uap, gid), 0); |
3439 | } | | 3439 | } |
3440 | | | 3440 | |
3441 | int | | 3441 | int |
3442 | do_sys_chownat(struct lwp *l, int fdat, const char *path, uid_t uid, | | 3442 | do_sys_chownat(struct lwp *l, int fdat, const char *path, uid_t uid, |
3443 | gid_t gid, int flags) | | 3443 | gid_t gid, int flags) |
3444 | { | | 3444 | { |
3445 | int error; | | 3445 | int error; |
3446 | struct vnode *vp; | | 3446 | struct vnode *vp; |
3447 | namei_simple_flags_t ns_flag; | | 3447 | namei_simple_flags_t ns_flag; |
3448 | | | 3448 | |
3449 | if (flags & AT_SYMLINK_NOFOLLOW) | | 3449 | if (flags & AT_SYMLINK_NOFOLLOW) |
3450 | ns_flag = NSM_NOFOLLOW_TRYEMULROOT; | | 3450 | ns_flag = NSM_NOFOLLOW_TRYEMULROOT; |
3451 | else | | 3451 | else |
3452 | ns_flag = NSM_FOLLOW_TRYEMULROOT; | | 3452 | ns_flag = NSM_FOLLOW_TRYEMULROOT; |
3453 | | | 3453 | |
3454 | error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp); | | 3454 | error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp); |
3455 | if (error != 0) | | 3455 | if (error != 0) |
3456 | return error; | | 3456 | return error; |
3457 | | | 3457 | |
3458 | error = change_owner(vp, uid, gid, l, 0); | | 3458 | error = change_owner(vp, uid, gid, l, 0); |
3459 | | | 3459 | |
3460 | vrele(vp); | | 3460 | vrele(vp); |
3461 | | | 3461 | |
3462 | return (error); | | 3462 | return (error); |
3463 | } | | 3463 | } |
3464 | | | 3464 | |
3465 | /* | | 3465 | /* |
3466 | * Set ownership given a path name; this version follows links. | | 3466 | * Set ownership given a path name; this version follows links. |
3467 | * Provides POSIX semantics. | | 3467 | * Provides POSIX semantics. |
3468 | */ | | 3468 | */ |
3469 | /* ARGSUSED */ | | 3469 | /* ARGSUSED */ |
3470 | int | | 3470 | int |
3471 | sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval) | | 3471 | sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval) |
3472 | { | | 3472 | { |
3473 | /* { | | 3473 | /* { |
3474 | syscallarg(const char *) path; | | 3474 | syscallarg(const char *) path; |
3475 | syscallarg(uid_t) uid; | | 3475 | syscallarg(uid_t) uid; |
3476 | syscallarg(gid_t) gid; | | 3476 | syscallarg(gid_t) gid; |
3477 | } */ | | 3477 | } */ |
3478 | int error; | | 3478 | int error; |
3479 | struct vnode *vp; | | 3479 | struct vnode *vp; |
3480 | | | 3480 | |
3481 | error = namei_simple_user(SCARG(uap, path), | | 3481 | error = namei_simple_user(SCARG(uap, path), |
3482 | NSM_FOLLOW_TRYEMULROOT, &vp); | | 3482 | NSM_FOLLOW_TRYEMULROOT, &vp); |
3483 | if (error != 0) | | 3483 | if (error != 0) |
3484 | return (error); | | 3484 | return (error); |
3485 | | | 3485 | |
3486 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); | | 3486 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
3487 | | | 3487 | |
3488 | vrele(vp); | | 3488 | vrele(vp); |
3489 | return (error); | | 3489 | return (error); |
3490 | } | | 3490 | } |
3491 | | | 3491 | |
3492 | /* | | 3492 | /* |
3493 | * Set ownership given a file descriptor. | | 3493 | * Set ownership given a file descriptor. |
3494 | */ | | 3494 | */ |
3495 | /* ARGSUSED */ | | 3495 | /* ARGSUSED */ |
3496 | int | | 3496 | int |
3497 | sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval) | | 3497 | sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval) |
3498 | { | | 3498 | { |
3499 | /* { | | 3499 | /* { |
3500 | syscallarg(int) fd; | | 3500 | syscallarg(int) fd; |
3501 | syscallarg(uid_t) uid; | | 3501 | syscallarg(uid_t) uid; |
3502 | syscallarg(gid_t) gid; | | 3502 | syscallarg(gid_t) gid; |
3503 | } */ | | 3503 | } */ |
3504 | int error; | | 3504 | int error; |
3505 | file_t *fp; | | 3505 | file_t *fp; |
3506 | | | 3506 | |
3507 | /* fd_getvnode() will use the descriptor for us */ | | 3507 | /* fd_getvnode() will use the descriptor for us */ |
3508 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3508 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3509 | return (error); | | 3509 | return (error); |
3510 | error = change_owner(fp->f_vnode, SCARG(uap, uid), SCARG(uap, gid), | | 3510 | error = change_owner(fp->f_vnode, SCARG(uap, uid), SCARG(uap, gid), |
3511 | l, 0); | | 3511 | l, 0); |
3512 | fd_putfile(SCARG(uap, fd)); | | 3512 | fd_putfile(SCARG(uap, fd)); |
3513 | return (error); | | 3513 | return (error); |
3514 | } | | 3514 | } |
3515 | | | 3515 | |
3516 | int | | 3516 | int |
3517 | sys_fchownat(struct lwp *l, const struct sys_fchownat_args *uap, | | 3517 | sys_fchownat(struct lwp *l, const struct sys_fchownat_args *uap, |
3518 | register_t *retval) | | 3518 | register_t *retval) |
3519 | { | | 3519 | { |
3520 | /* { | | 3520 | /* { |
3521 | syscallarg(int) fd; | | 3521 | syscallarg(int) fd; |
3522 | syscallarg(const char *) path; | | 3522 | syscallarg(const char *) path; |
3523 | syscallarg(uid_t) owner; | | 3523 | syscallarg(uid_t) owner; |
3524 | syscallarg(gid_t) group; | | 3524 | syscallarg(gid_t) group; |
3525 | syscallarg(int) flag; | | 3525 | syscallarg(int) flag; |
3526 | } */ | | 3526 | } */ |
3527 | | | 3527 | |
3528 | return do_sys_chownat(l, SCARG(uap, fd), SCARG(uap, path), | | 3528 | return do_sys_chownat(l, SCARG(uap, fd), SCARG(uap, path), |
3529 | SCARG(uap, owner), SCARG(uap, group), | | 3529 | SCARG(uap, owner), SCARG(uap, group), |
3530 | SCARG(uap, flag)); | | 3530 | SCARG(uap, flag)); |
3531 | } | | 3531 | } |
3532 | | | 3532 | |
3533 | /* | | 3533 | /* |
3534 | * Set ownership given a file descriptor, providing POSIX/XPG semantics. | | 3534 | * Set ownership given a file descriptor, providing POSIX/XPG semantics. |
3535 | */ | | 3535 | */ |
3536 | /* ARGSUSED */ | | 3536 | /* ARGSUSED */ |
3537 | int | | 3537 | int |
3538 | sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval) | | 3538 | sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval) |
3539 | { | | 3539 | { |
3540 | /* { | | 3540 | /* { |
3541 | syscallarg(int) fd; | | 3541 | syscallarg(int) fd; |
3542 | syscallarg(uid_t) uid; | | 3542 | syscallarg(uid_t) uid; |
3543 | syscallarg(gid_t) gid; | | 3543 | syscallarg(gid_t) gid; |
3544 | } */ | | 3544 | } */ |
3545 | int error; | | 3545 | int error; |
3546 | file_t *fp; | | 3546 | file_t *fp; |
3547 | | | 3547 | |
3548 | /* fd_getvnode() will use the descriptor for us */ | | 3548 | /* fd_getvnode() will use the descriptor for us */ |
3549 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3549 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3550 | return (error); | | 3550 | return (error); |
3551 | error = change_owner(fp->f_vnode, SCARG(uap, uid), SCARG(uap, gid), | | 3551 | error = change_owner(fp->f_vnode, SCARG(uap, uid), SCARG(uap, gid), |
3552 | l, 1); | | 3552 | l, 1); |
3553 | fd_putfile(SCARG(uap, fd)); | | 3553 | fd_putfile(SCARG(uap, fd)); |
3554 | return (error); | | 3554 | return (error); |
3555 | } | | 3555 | } |
3556 | | | 3556 | |
3557 | /* | | 3557 | /* |
3558 | * Set ownership given a path name; this version does not follow links. | | 3558 | * Set ownership given a path name; this version does not follow links. |
3559 | */ | | 3559 | */ |
3560 | /* ARGSUSED */ | | 3560 | /* ARGSUSED */ |
3561 | int | | 3561 | int |
3562 | sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval) | | 3562 | sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval) |
3563 | { | | 3563 | { |
3564 | /* { | | 3564 | /* { |
3565 | syscallarg(const char *) path; | | 3565 | syscallarg(const char *) path; |
3566 | syscallarg(uid_t) uid; | | 3566 | syscallarg(uid_t) uid; |
3567 | syscallarg(gid_t) gid; | | 3567 | syscallarg(gid_t) gid; |
3568 | } */ | | 3568 | } */ |
3569 | int error; | | 3569 | int error; |
3570 | struct vnode *vp; | | 3570 | struct vnode *vp; |
3571 | | | 3571 | |
3572 | error = namei_simple_user(SCARG(uap, path), | | 3572 | error = namei_simple_user(SCARG(uap, path), |
3573 | NSM_NOFOLLOW_TRYEMULROOT, &vp); | | 3573 | NSM_NOFOLLOW_TRYEMULROOT, &vp); |
3574 | if (error != 0) | | 3574 | if (error != 0) |
3575 | return (error); | | 3575 | return (error); |
3576 | | | 3576 | |
3577 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); | | 3577 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); |
3578 | | | 3578 | |
3579 | vrele(vp); | | 3579 | vrele(vp); |
3580 | return (error); | | 3580 | return (error); |
3581 | } | | 3581 | } |
3582 | | | 3582 | |
3583 | /* | | 3583 | /* |
3584 | * Set ownership given a path name; this version does not follow links. | | 3584 | * Set ownership given a path name; this version does not follow links. |
3585 | * Provides POSIX/XPG semantics. | | 3585 | * Provides POSIX/XPG semantics. |
3586 | */ | | 3586 | */ |
3587 | /* ARGSUSED */ | | 3587 | /* ARGSUSED */ |
3588 | int | | 3588 | int |
3589 | sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval) | | 3589 | sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval) |
3590 | { | | 3590 | { |
3591 | /* { | | 3591 | /* { |
3592 | syscallarg(const char *) path; | | 3592 | syscallarg(const char *) path; |
3593 | syscallarg(uid_t) uid; | | 3593 | syscallarg(uid_t) uid; |
3594 | syscallarg(gid_t) gid; | | 3594 | syscallarg(gid_t) gid; |
3595 | } */ | | 3595 | } */ |
3596 | int error; | | 3596 | int error; |
3597 | struct vnode *vp; | | 3597 | struct vnode *vp; |
3598 | | | 3598 | |
3599 | error = namei_simple_user(SCARG(uap, path), | | 3599 | error = namei_simple_user(SCARG(uap, path), |
3600 | NSM_NOFOLLOW_TRYEMULROOT, &vp); | | 3600 | NSM_NOFOLLOW_TRYEMULROOT, &vp); |
3601 | if (error != 0) | | 3601 | if (error != 0) |
3602 | return (error); | | 3602 | return (error); |
3603 | | | 3603 | |
3604 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); | | 3604 | error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
3605 | | | 3605 | |
3606 | vrele(vp); | | 3606 | vrele(vp); |
3607 | return (error); | | 3607 | return (error); |
3608 | } | | 3608 | } |
3609 | | | 3609 | |
3610 | /* | | 3610 | /* |
3611 | * Common routine to set ownership given a vnode. | | 3611 | * Common routine to set ownership given a vnode. |
3612 | */ | | 3612 | */ |
3613 | static int | | 3613 | static int |
3614 | change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l, | | 3614 | change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l, |
3615 | int posix_semantics) | | 3615 | int posix_semantics) |
3616 | { | | 3616 | { |
3617 | struct vattr vattr; | | 3617 | struct vattr vattr; |
3618 | mode_t newmode; | | 3618 | mode_t newmode; |
3619 | int error; | | 3619 | int error; |
3620 | | | 3620 | |
3621 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3621 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3622 | if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0) | | 3622 | if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0) |
3623 | goto out; | | 3623 | goto out; |
3624 | | | 3624 | |
3625 | #define CHANGED(x) ((int)(x) != -1) | | 3625 | #define CHANGED(x) ((int)(x) != -1) |
3626 | newmode = vattr.va_mode; | | 3626 | newmode = vattr.va_mode; |
3627 | if (posix_semantics) { | | 3627 | if (posix_semantics) { |
3628 | /* | | 3628 | /* |
3629 | * POSIX/XPG semantics: if the caller is not the super-user, | | 3629 | * POSIX/XPG semantics: if the caller is not the super-user, |
3630 | * clear set-user-id and set-group-id bits. Both POSIX and | | 3630 | * clear set-user-id and set-group-id bits. Both POSIX and |
3631 | * the XPG consider the behaviour for calls by the super-user | | 3631 | * the XPG consider the behaviour for calls by the super-user |
3632 | * implementation-defined; we leave the set-user-id and set- | | 3632 | * implementation-defined; we leave the set-user-id and set- |
3633 | * group-id settings intact in that case. | | 3633 | * group-id settings intact in that case. |
3634 | */ | | 3634 | */ |
3635 | if (vattr.va_mode & S_ISUID) { | | 3635 | if (vattr.va_mode & S_ISUID) { |
3636 | if (kauth_authorize_vnode(l->l_cred, | | 3636 | if (kauth_authorize_vnode(l->l_cred, |
3637 | KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) | | 3637 | KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) |
3638 | newmode &= ~S_ISUID; | | 3638 | newmode &= ~S_ISUID; |
3639 | } | | 3639 | } |
3640 | if (vattr.va_mode & S_ISGID) { | | 3640 | if (vattr.va_mode & S_ISGID) { |
3641 | if (kauth_authorize_vnode(l->l_cred, | | 3641 | if (kauth_authorize_vnode(l->l_cred, |
3642 | KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) | | 3642 | KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) |
3643 | newmode &= ~S_ISGID; | | 3643 | newmode &= ~S_ISGID; |
3644 | } | | 3644 | } |
3645 | } else { | | 3645 | } else { |
3646 | /* | | 3646 | /* |
3647 | * NetBSD semantics: when changing owner and/or group, | | 3647 | * NetBSD semantics: when changing owner and/or group, |
3648 | * clear the respective bit(s). | | 3648 | * clear the respective bit(s). |
3649 | */ | | 3649 | */ |
3650 | if (CHANGED(uid)) | | 3650 | if (CHANGED(uid)) |
3651 | newmode &= ~S_ISUID; | | 3651 | newmode &= ~S_ISUID; |
3652 | if (CHANGED(gid)) | | 3652 | if (CHANGED(gid)) |
3653 | newmode &= ~S_ISGID; | | 3653 | newmode &= ~S_ISGID; |
3654 | } | | 3654 | } |
3655 | /* Update va_mode iff altered. */ | | 3655 | /* Update va_mode iff altered. */ |
3656 | if (vattr.va_mode == newmode) | | 3656 | if (vattr.va_mode == newmode) |
3657 | newmode = VNOVAL; | | 3657 | newmode = VNOVAL; |
3658 | | | 3658 | |
3659 | vattr_null(&vattr); | | 3659 | vattr_null(&vattr); |
3660 | vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL; | | 3660 | vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL; |
3661 | vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL; | | 3661 | vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL; |
3662 | vattr.va_mode = newmode; | | 3662 | vattr.va_mode = newmode; |
3663 | error = VOP_SETATTR(vp, &vattr, l->l_cred); | | 3663 | error = VOP_SETATTR(vp, &vattr, l->l_cred); |
3664 | #undef CHANGED | | 3664 | #undef CHANGED |
3665 | | | 3665 | |
3666 | out: | | 3666 | out: |
3667 | VOP_UNLOCK(vp); | | 3667 | VOP_UNLOCK(vp); |
3668 | return (error); | | 3668 | return (error); |
3669 | } | | 3669 | } |
3670 | | | 3670 | |
3671 | /* | | 3671 | /* |
3672 | * Set the access and modification times given a path name; this | | 3672 | * Set the access and modification times given a path name; this |
3673 | * version follows links. | | 3673 | * version follows links. |
3674 | */ | | 3674 | */ |
3675 | /* ARGSUSED */ | | 3675 | /* ARGSUSED */ |
3676 | int | | 3676 | int |
3677 | sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap, | | 3677 | sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap, |
3678 | register_t *retval) | | 3678 | register_t *retval) |
3679 | { | | 3679 | { |
3680 | /* { | | 3680 | /* { |
3681 | syscallarg(const char *) path; | | 3681 | syscallarg(const char *) path; |
3682 | syscallarg(const struct timeval *) tptr; | | 3682 | syscallarg(const struct timeval *) tptr; |
3683 | } */ | | 3683 | } */ |
3684 | | | 3684 | |
3685 | return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, | | 3685 | return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, |
3686 | SCARG(uap, tptr), UIO_USERSPACE); | | 3686 | SCARG(uap, tptr), UIO_USERSPACE); |
3687 | } | | 3687 | } |
3688 | | | 3688 | |
3689 | /* | | 3689 | /* |
3690 | * Set the access and modification times given a file descriptor. | | 3690 | * Set the access and modification times given a file descriptor. |
3691 | */ | | 3691 | */ |
3692 | /* ARGSUSED */ | | 3692 | /* ARGSUSED */ |
3693 | int | | 3693 | int |
3694 | sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap, | | 3694 | sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap, |
3695 | register_t *retval) | | 3695 | register_t *retval) |
3696 | { | | 3696 | { |
3697 | /* { | | 3697 | /* { |
3698 | syscallarg(int) fd; | | 3698 | syscallarg(int) fd; |
3699 | syscallarg(const struct timeval *) tptr; | | 3699 | syscallarg(const struct timeval *) tptr; |
3700 | } */ | | 3700 | } */ |
3701 | int error; | | 3701 | int error; |
3702 | file_t *fp; | | 3702 | file_t *fp; |
3703 | | | 3703 | |
3704 | /* fd_getvnode() will use the descriptor for us */ | | 3704 | /* fd_getvnode() will use the descriptor for us */ |
3705 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3705 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3706 | return (error); | | 3706 | return (error); |
3707 | error = do_sys_utimes(l, fp->f_vnode, NULL, 0, SCARG(uap, tptr), | | 3707 | error = do_sys_utimes(l, fp->f_vnode, NULL, 0, SCARG(uap, tptr), |
3708 | UIO_USERSPACE); | | 3708 | UIO_USERSPACE); |
3709 | fd_putfile(SCARG(uap, fd)); | | 3709 | fd_putfile(SCARG(uap, fd)); |
3710 | return (error); | | 3710 | return (error); |
3711 | } | | 3711 | } |
3712 | | | 3712 | |
3713 | int | | 3713 | int |
3714 | sys_futimens(struct lwp *l, const struct sys_futimens_args *uap, | | 3714 | sys_futimens(struct lwp *l, const struct sys_futimens_args *uap, |
3715 | register_t *retval) | | 3715 | register_t *retval) |
3716 | { | | 3716 | { |
3717 | /* { | | 3717 | /* { |
3718 | syscallarg(int) fd; | | 3718 | syscallarg(int) fd; |
3719 | syscallarg(const struct timespec *) tptr; | | 3719 | syscallarg(const struct timespec *) tptr; |
3720 | } */ | | 3720 | } */ |
3721 | int error; | | 3721 | int error; |
3722 | file_t *fp; | | 3722 | file_t *fp; |
3723 | | | 3723 | |
3724 | /* fd_getvnode() will use the descriptor for us */ | | 3724 | /* fd_getvnode() will use the descriptor for us */ |
3725 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3725 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3726 | return (error); | | 3726 | return (error); |
3727 | error = do_sys_utimensat(l, AT_FDCWD, fp->f_vnode, NULL, 0, | | 3727 | error = do_sys_utimensat(l, AT_FDCWD, fp->f_vnode, NULL, 0, |
3728 | SCARG(uap, tptr), UIO_USERSPACE); | | 3728 | SCARG(uap, tptr), UIO_USERSPACE); |
3729 | fd_putfile(SCARG(uap, fd)); | | 3729 | fd_putfile(SCARG(uap, fd)); |
3730 | return (error); | | 3730 | return (error); |
3731 | } | | 3731 | } |
3732 | | | 3732 | |
3733 | /* | | 3733 | /* |
3734 | * Set the access and modification times given a path name; this | | 3734 | * Set the access and modification times given a path name; this |
3735 | * version does not follow links. | | 3735 | * version does not follow links. |
3736 | */ | | 3736 | */ |
3737 | int | | 3737 | int |
3738 | sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap, | | 3738 | sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap, |
3739 | register_t *retval) | | 3739 | register_t *retval) |
3740 | { | | 3740 | { |
3741 | /* { | | 3741 | /* { |
3742 | syscallarg(const char *) path; | | 3742 | syscallarg(const char *) path; |
3743 | syscallarg(const struct timeval *) tptr; | | 3743 | syscallarg(const struct timeval *) tptr; |
3744 | } */ | | 3744 | } */ |
3745 | | | 3745 | |
3746 | return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW, | | 3746 | return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW, |
3747 | SCARG(uap, tptr), UIO_USERSPACE); | | 3747 | SCARG(uap, tptr), UIO_USERSPACE); |
3748 | } | | 3748 | } |
3749 | | | 3749 | |
3750 | int | | 3750 | int |
3751 | sys_utimensat(struct lwp *l, const struct sys_utimensat_args *uap, | | 3751 | sys_utimensat(struct lwp *l, const struct sys_utimensat_args *uap, |
3752 | register_t *retval) | | 3752 | register_t *retval) |
3753 | { | | 3753 | { |
3754 | /* { | | 3754 | /* { |
3755 | syscallarg(int) fd; | | 3755 | syscallarg(int) fd; |
3756 | syscallarg(const char *) path; | | 3756 | syscallarg(const char *) path; |
3757 | syscallarg(const struct timespec *) tptr; | | 3757 | syscallarg(const struct timespec *) tptr; |
3758 | syscallarg(int) flag; | | 3758 | syscallarg(int) flag; |
3759 | } */ | | 3759 | } */ |
3760 | int follow; | | 3760 | int follow; |
3761 | const struct timespec *tptr; | | 3761 | const struct timespec *tptr; |
3762 | int error; | | 3762 | int error; |
3763 | | | 3763 | |
3764 | tptr = SCARG(uap, tptr); | | 3764 | tptr = SCARG(uap, tptr); |
3765 | follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; | | 3765 | follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; |
3766 | | | 3766 | |
3767 | error = do_sys_utimensat(l, SCARG(uap, fd), NULL, | | 3767 | error = do_sys_utimensat(l, SCARG(uap, fd), NULL, |
3768 | SCARG(uap, path), follow, tptr, UIO_USERSPACE); | | 3768 | SCARG(uap, path), follow, tptr, UIO_USERSPACE); |
3769 | | | 3769 | |
3770 | return error; | | 3770 | return error; |
3771 | } | | 3771 | } |
3772 | | | 3772 | |
3773 | /* | | 3773 | /* |
3774 | * Common routine to set access and modification times given a vnode. | | 3774 | * Common routine to set access and modification times given a vnode. |
3775 | */ | | 3775 | */ |
3776 | int | | 3776 | int |
3777 | do_sys_utimens(struct lwp *l, struct vnode *vp, const char *path, int flag, | | 3777 | do_sys_utimens(struct lwp *l, struct vnode *vp, const char *path, int flag, |
3778 | const struct timespec *tptr, enum uio_seg seg) | | 3778 | const struct timespec *tptr, enum uio_seg seg) |
3779 | { | | 3779 | { |
3780 | return do_sys_utimensat(l, AT_FDCWD, vp, path, flag, tptr, seg); | | 3780 | return do_sys_utimensat(l, AT_FDCWD, vp, path, flag, tptr, seg); |
3781 | } | | 3781 | } |
3782 | | | 3782 | |
3783 | int | | 3783 | int |
3784 | do_sys_utimensat(struct lwp *l, int fdat, struct vnode *vp, | | 3784 | do_sys_utimensat(struct lwp *l, int fdat, struct vnode *vp, |
3785 | const char *path, int flag, const struct timespec *tptr, enum uio_seg seg) | | 3785 | const char *path, int flag, const struct timespec *tptr, enum uio_seg seg) |
3786 | { | | 3786 | { |
3787 | struct vattr vattr; | | 3787 | struct vattr vattr; |
3788 | int error, dorele = 0; | | 3788 | int error, dorele = 0; |
3789 | namei_simple_flags_t sflags; | | 3789 | namei_simple_flags_t sflags; |
3790 | bool vanull, setbirthtime; | | 3790 | bool vanull, setbirthtime; |
3791 | struct timespec ts[2]; | | 3791 | struct timespec ts[2]; |
3792 | | | 3792 | |
3793 | KASSERT(l != NULL || fdat == AT_FDCWD); | | 3793 | KASSERT(l != NULL || fdat == AT_FDCWD); |
3794 | | | 3794 | |
3795 | /* | | 3795 | /* |
3796 | * I have checked all callers and they pass either FOLLOW, | | 3796 | * I have checked all callers and they pass either FOLLOW, |
3797 | * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW | | 3797 | * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW |
3798 | * is 0. More to the point, they don't pass anything else. | | 3798 | * is 0. More to the point, they don't pass anything else. |
3799 | * Let's keep it that way at least until the namei interfaces | | 3799 | * Let's keep it that way at least until the namei interfaces |
3800 | * are fully sanitized. | | 3800 | * are fully sanitized. |
3801 | */ | | 3801 | */ |
3802 | KASSERT(flag == NOFOLLOW || flag == FOLLOW); | | 3802 | KASSERT(flag == NOFOLLOW || flag == FOLLOW); |
3803 | sflags = (flag == FOLLOW) ? | | 3803 | sflags = (flag == FOLLOW) ? |
3804 | NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT; | | 3804 | NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT; |
3805 | | | 3805 | |
3806 | if (tptr == NULL) { | | 3806 | if (tptr == NULL) { |
3807 | vanull = true; | | 3807 | vanull = true; |
3808 | nanotime(&ts[0]); | | 3808 | nanotime(&ts[0]); |
3809 | ts[1] = ts[0]; | | 3809 | ts[1] = ts[0]; |
3810 | } else { | | 3810 | } else { |
3811 | vanull = false; | | 3811 | vanull = false; |
3812 | if (seg != UIO_SYSSPACE) { | | 3812 | if (seg != UIO_SYSSPACE) { |
3813 | error = copyin(tptr, ts, sizeof (ts)); | | 3813 | error = copyin(tptr, ts, sizeof (ts)); |
3814 | if (error != 0) | | 3814 | if (error != 0) |
3815 | return error; | | 3815 | return error; |
3816 | } else { | | 3816 | } else { |
3817 | ts[0] = tptr[0]; | | 3817 | ts[0] = tptr[0]; |
3818 | ts[1] = tptr[1]; | | 3818 | ts[1] = tptr[1]; |
3819 | } | | 3819 | } |
3820 | } | | 3820 | } |
3821 | | | 3821 | |
3822 | if (ts[0].tv_nsec == UTIME_NOW) { | | 3822 | if (ts[0].tv_nsec == UTIME_NOW) { |
3823 | nanotime(&ts[0]); | | 3823 | nanotime(&ts[0]); |
3824 | if (ts[1].tv_nsec == UTIME_NOW) { | | 3824 | if (ts[1].tv_nsec == UTIME_NOW) { |
3825 | vanull = true; | | 3825 | vanull = true; |
3826 | ts[1] = ts[0]; | | 3826 | ts[1] = ts[0]; |
3827 | } | | 3827 | } |
3828 | } else if (ts[1].tv_nsec == UTIME_NOW) | | 3828 | } else if (ts[1].tv_nsec == UTIME_NOW) |
3829 | nanotime(&ts[1]); | | 3829 | nanotime(&ts[1]); |
3830 | | | 3830 | |
3831 | if (vp == NULL) { | | 3831 | if (vp == NULL) { |
3832 | /* note: SEG describes TPTR, not PATH; PATH is always user */ | | 3832 | /* note: SEG describes TPTR, not PATH; PATH is always user */ |
3833 | error = fd_nameiat_simple_user(l, fdat, path, sflags, &vp); | | 3833 | error = fd_nameiat_simple_user(l, fdat, path, sflags, &vp); |
3834 | if (error != 0) | | 3834 | if (error != 0) |
3835 | return error; | | 3835 | return error; |
3836 | dorele = 1; | | 3836 | dorele = 1; |
3837 | } | | 3837 | } |
3838 | | | 3838 | |
3839 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3839 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3840 | setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 && | | 3840 | setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 && |
3841 | timespeccmp(&ts[1], &vattr.va_birthtime, <)); | | 3841 | timespeccmp(&ts[1], &vattr.va_birthtime, <)); |
3842 | vattr_null(&vattr); | | 3842 | vattr_null(&vattr); |
3843 | | | 3843 | |
3844 | if (ts[0].tv_nsec != UTIME_OMIT) | | 3844 | if (ts[0].tv_nsec != UTIME_OMIT) |
3845 | vattr.va_atime = ts[0]; | | 3845 | vattr.va_atime = ts[0]; |
3846 | | | 3846 | |
3847 | if (ts[1].tv_nsec != UTIME_OMIT) { | | 3847 | if (ts[1].tv_nsec != UTIME_OMIT) { |
3848 | vattr.va_mtime = ts[1]; | | 3848 | vattr.va_mtime = ts[1]; |
3849 | if (setbirthtime) | | 3849 | if (setbirthtime) |
3850 | vattr.va_birthtime = ts[1]; | | 3850 | vattr.va_birthtime = ts[1]; |
3851 | } | | 3851 | } |
3852 | | | 3852 | |
3853 | if (vanull) | | 3853 | if (vanull) |
3854 | vattr.va_vaflags |= VA_UTIMES_NULL; | | 3854 | vattr.va_vaflags |= VA_UTIMES_NULL; |
3855 | error = VOP_SETATTR(vp, &vattr, l->l_cred); | | 3855 | error = VOP_SETATTR(vp, &vattr, l->l_cred); |
3856 | VOP_UNLOCK(vp); | | 3856 | VOP_UNLOCK(vp); |
3857 | | | 3857 | |
3858 | if (dorele != 0) | | 3858 | if (dorele != 0) |
3859 | vrele(vp); | | 3859 | vrele(vp); |
3860 | | | 3860 | |
3861 | return error; | | 3861 | return error; |
3862 | } | | 3862 | } |
3863 | | | 3863 | |
3864 | int | | 3864 | int |
3865 | do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag, | | 3865 | do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag, |
3866 | const struct timeval *tptr, enum uio_seg seg) | | 3866 | const struct timeval *tptr, enum uio_seg seg) |
3867 | { | | 3867 | { |
3868 | struct timespec ts[2]; | | 3868 | struct timespec ts[2]; |
3869 | struct timespec *tsptr = NULL; | | 3869 | struct timespec *tsptr = NULL; |
3870 | int error; | | 3870 | int error; |
3871 | | | 3871 | |
3872 | if (tptr != NULL) { | | 3872 | if (tptr != NULL) { |
3873 | struct timeval tv[2]; | | 3873 | struct timeval tv[2]; |
3874 | | | 3874 | |
3875 | if (seg != UIO_SYSSPACE) { | | 3875 | if (seg != UIO_SYSSPACE) { |
3876 | error = copyin(tptr, tv, sizeof (tv)); | | 3876 | error = copyin(tptr, tv, sizeof (tv)); |
3877 | if (error != 0) | | 3877 | if (error != 0) |
3878 | return error; | | 3878 | return error; |
3879 | tptr = tv; | | 3879 | tptr = tv; |
3880 | } | | 3880 | } |
3881 | | | 3881 | |
3882 | if ((tv[0].tv_usec == UTIME_NOW) || | | 3882 | if ((tv[0].tv_usec == UTIME_NOW) || |
3883 | (tv[0].tv_usec == UTIME_OMIT)) | | 3883 | (tv[0].tv_usec == UTIME_OMIT)) |
3884 | ts[0].tv_nsec = tv[0].tv_usec; | | 3884 | ts[0].tv_nsec = tv[0].tv_usec; |
3885 | else | | 3885 | else |
3886 | TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]); | | 3886 | TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]); |
3887 | | | 3887 | |
3888 | if ((tv[1].tv_usec == UTIME_NOW) || | | 3888 | if ((tv[1].tv_usec == UTIME_NOW) || |
3889 | (tv[1].tv_usec == UTIME_OMIT)) | | 3889 | (tv[1].tv_usec == UTIME_OMIT)) |
3890 | ts[1].tv_nsec = tv[1].tv_usec; | | 3890 | ts[1].tv_nsec = tv[1].tv_usec; |
3891 | else | | 3891 | else |
3892 | TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]); | | 3892 | TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]); |
3893 | | | 3893 | |
3894 | tsptr = &ts[0]; | | 3894 | tsptr = &ts[0]; |
3895 | } | | 3895 | } |
3896 | | | 3896 | |
3897 | return do_sys_utimens(l, vp, path, flag, tsptr, UIO_SYSSPACE); | | 3897 | return do_sys_utimens(l, vp, path, flag, tsptr, UIO_SYSSPACE); |
3898 | } | | 3898 | } |
3899 | | | 3899 | |
3900 | /* | | 3900 | /* |
3901 | * Truncate a file given its path name. | | 3901 | * Truncate a file given its path name. |
3902 | */ | | 3902 | */ |
3903 | /* ARGSUSED */ | | 3903 | /* ARGSUSED */ |
3904 | int | | 3904 | int |
3905 | sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval) | | 3905 | sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval) |
3906 | { | | 3906 | { |
3907 | /* { | | 3907 | /* { |
3908 | syscallarg(const char *) path; | | 3908 | syscallarg(const char *) path; |
3909 | syscallarg(int) pad; | | 3909 | syscallarg(int) pad; |
3910 | syscallarg(off_t) length; | | 3910 | syscallarg(off_t) length; |
3911 | } */ | | 3911 | } */ |
3912 | struct vnode *vp; | | 3912 | struct vnode *vp; |
3913 | struct vattr vattr; | | 3913 | struct vattr vattr; |
3914 | int error; | | 3914 | int error; |
3915 | | | 3915 | |
3916 | if (SCARG(uap, length) < 0) | | 3916 | if (SCARG(uap, length) < 0) |
3917 | return EINVAL; | | 3917 | return EINVAL; |
3918 | | | 3918 | |
3919 | error = namei_simple_user(SCARG(uap, path), | | 3919 | error = namei_simple_user(SCARG(uap, path), |
3920 | NSM_FOLLOW_TRYEMULROOT, &vp); | | 3920 | NSM_FOLLOW_TRYEMULROOT, &vp); |
3921 | if (error != 0) | | 3921 | if (error != 0) |
3922 | return (error); | | 3922 | return (error); |
3923 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3923 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3924 | if (vp->v_type == VDIR) | | 3924 | if (vp->v_type == VDIR) |
3925 | error = EISDIR; | | 3925 | error = EISDIR; |
3926 | else if ((error = vn_writechk(vp)) == 0 && | | 3926 | else if ((error = vn_writechk(vp)) == 0 && |
3927 | (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) { | | 3927 | (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) { |
3928 | vattr_null(&vattr); | | 3928 | vattr_null(&vattr); |
3929 | vattr.va_size = SCARG(uap, length); | | 3929 | vattr.va_size = SCARG(uap, length); |
3930 | error = VOP_SETATTR(vp, &vattr, l->l_cred); | | 3930 | error = VOP_SETATTR(vp, &vattr, l->l_cred); |
3931 | } | | 3931 | } |
3932 | vput(vp); | | 3932 | vput(vp); |
3933 | return (error); | | 3933 | return (error); |
3934 | } | | 3934 | } |
3935 | | | 3935 | |
3936 | /* | | 3936 | /* |
3937 | * Truncate a file given a file descriptor. | | 3937 | * Truncate a file given a file descriptor. |
3938 | */ | | 3938 | */ |
3939 | /* ARGSUSED */ | | 3939 | /* ARGSUSED */ |
3940 | int | | 3940 | int |
3941 | sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval) | | 3941 | sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval) |
3942 | { | | 3942 | { |
3943 | /* { | | 3943 | /* { |
3944 | syscallarg(int) fd; | | 3944 | syscallarg(int) fd; |
3945 | syscallarg(int) pad; | | 3945 | syscallarg(int) pad; |
3946 | syscallarg(off_t) length; | | 3946 | syscallarg(off_t) length; |
3947 | } */ | | 3947 | } */ |
3948 | struct vattr vattr; | | 3948 | struct vattr vattr; |
3949 | struct vnode *vp; | | 3949 | struct vnode *vp; |
3950 | file_t *fp; | | 3950 | file_t *fp; |
3951 | int error; | | 3951 | int error; |
3952 | | | 3952 | |
3953 | if (SCARG(uap, length) < 0) | | 3953 | if (SCARG(uap, length) < 0) |
3954 | return EINVAL; | | 3954 | return EINVAL; |
3955 | | | 3955 | |
3956 | /* fd_getvnode() will use the descriptor for us */ | | 3956 | /* fd_getvnode() will use the descriptor for us */ |
3957 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3957 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3958 | return (error); | | 3958 | return (error); |
3959 | if ((fp->f_flag & FWRITE) == 0) { | | 3959 | if ((fp->f_flag & FWRITE) == 0) { |
3960 | error = EINVAL; | | 3960 | error = EINVAL; |
3961 | goto out; | | 3961 | goto out; |
3962 | } | | 3962 | } |
3963 | vp = fp->f_vnode; | | 3963 | vp = fp->f_vnode; |
3964 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3964 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3965 | if (vp->v_type == VDIR) | | 3965 | if (vp->v_type == VDIR) |
3966 | error = EISDIR; | | 3966 | error = EISDIR; |
3967 | else if ((error = vn_writechk(vp)) == 0) { | | 3967 | else if ((error = vn_writechk(vp)) == 0) { |
3968 | vattr_null(&vattr); | | 3968 | vattr_null(&vattr); |
3969 | vattr.va_size = SCARG(uap, length); | | 3969 | vattr.va_size = SCARG(uap, length); |
3970 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); | | 3970 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); |
3971 | } | | 3971 | } |
3972 | VOP_UNLOCK(vp); | | 3972 | VOP_UNLOCK(vp); |
3973 | out: | | 3973 | out: |
3974 | fd_putfile(SCARG(uap, fd)); | | 3974 | fd_putfile(SCARG(uap, fd)); |
3975 | return (error); | | 3975 | return (error); |
3976 | } | | 3976 | } |
3977 | | | 3977 | |
3978 | /* | | 3978 | /* |
3979 | * Sync an open file. | | 3979 | * Sync an open file. |
3980 | */ | | 3980 | */ |
3981 | /* ARGSUSED */ | | 3981 | /* ARGSUSED */ |
3982 | int | | 3982 | int |
3983 | sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval) | | 3983 | sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval) |
3984 | { | | 3984 | { |
3985 | /* { | | 3985 | /* { |
3986 | syscallarg(int) fd; | | 3986 | syscallarg(int) fd; |
3987 | } */ | | 3987 | } */ |
3988 | struct vnode *vp; | | 3988 | struct vnode *vp; |
3989 | file_t *fp; | | 3989 | file_t *fp; |
3990 | int error; | | 3990 | int error; |
3991 | | | 3991 | |
3992 | /* fd_getvnode() will use the descriptor for us */ | | 3992 | /* fd_getvnode() will use the descriptor for us */ |
3993 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 3993 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
3994 | return (error); | | 3994 | return (error); |
3995 | vp = fp->f_vnode; | | 3995 | vp = fp->f_vnode; |
3996 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 3996 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
3997 | error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0); | | 3997 | error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0); |
3998 | VOP_UNLOCK(vp); | | 3998 | VOP_UNLOCK(vp); |
3999 | fd_putfile(SCARG(uap, fd)); | | 3999 | fd_putfile(SCARG(uap, fd)); |
4000 | return (error); | | 4000 | return (error); |
4001 | } | | 4001 | } |
4002 | | | 4002 | |
4003 | /* | | 4003 | /* |
4004 | * Sync a range of file data. API modeled after that found in AIX. | | 4004 | * Sync a range of file data. API modeled after that found in AIX. |
4005 | * | | 4005 | * |
4006 | * FDATASYNC indicates that we need only save enough metadata to be able | | 4006 | * FDATASYNC indicates that we need only save enough metadata to be able |
4007 | * to re-read the written data. Note we duplicate AIX's requirement that | | 4007 | * to re-read the written data. |
4008 | * the file be open for writing. | | | |
4009 | */ | | 4008 | */ |
4010 | /* ARGSUSED */ | | 4009 | /* ARGSUSED */ |
4011 | int | | 4010 | int |
4012 | sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval) | | 4011 | sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval) |
4013 | { | | 4012 | { |
4014 | /* { | | 4013 | /* { |
4015 | syscallarg(int) fd; | | 4014 | syscallarg(int) fd; |
4016 | syscallarg(int) flags; | | 4015 | syscallarg(int) flags; |
4017 | syscallarg(off_t) start; | | 4016 | syscallarg(off_t) start; |
4018 | syscallarg(off_t) length; | | 4017 | syscallarg(off_t) length; |
4019 | } */ | | 4018 | } */ |
4020 | struct vnode *vp; | | 4019 | struct vnode *vp; |
4021 | file_t *fp; | | 4020 | file_t *fp; |
4022 | int flags, nflags; | | 4021 | int flags, nflags; |
4023 | off_t s, e, len; | | 4022 | off_t s, e, len; |
4024 | int error; | | 4023 | int error; |
4025 | | | 4024 | |
4026 | /* fd_getvnode() will use the descriptor for us */ | | 4025 | /* fd_getvnode() will use the descriptor for us */ |
4027 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 4026 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
4028 | return (error); | | 4027 | return (error); |
4029 | | | 4028 | |
4030 | if ((fp->f_flag & FWRITE) == 0) { | | 4029 | if ((fp->f_flag & FWRITE) == 0) { |
4031 | error = EBADF; | | 4030 | error = EBADF; |
4032 | goto out; | | 4031 | goto out; |
4033 | } | | 4032 | } |
4034 | | | 4033 | |
4035 | flags = SCARG(uap, flags); | | 4034 | flags = SCARG(uap, flags); |
4036 | if (((flags & (FDATASYNC | FFILESYNC)) == 0) || | | 4035 | if (((flags & (FDATASYNC | FFILESYNC)) == 0) || |
4037 | ((~flags & (FDATASYNC | FFILESYNC)) == 0)) { | | 4036 | ((~flags & (FDATASYNC | FFILESYNC)) == 0)) { |
4038 | error = EINVAL; | | 4037 | error = EINVAL; |
4039 | goto out; | | 4038 | goto out; |
4040 | } | | 4039 | } |
4041 | /* Now set up the flags for value(s) to pass to VOP_FSYNC() */ | | 4040 | /* Now set up the flags for value(s) to pass to VOP_FSYNC() */ |
4042 | if (flags & FDATASYNC) | | 4041 | if (flags & FDATASYNC) |
4043 | nflags = FSYNC_DATAONLY | FSYNC_WAIT; | | 4042 | nflags = FSYNC_DATAONLY | FSYNC_WAIT; |
4044 | else | | 4043 | else |
4045 | nflags = FSYNC_WAIT; | | 4044 | nflags = FSYNC_WAIT; |
4046 | if (flags & FDISKSYNC) | | 4045 | if (flags & FDISKSYNC) |
4047 | nflags |= FSYNC_CACHE; | | 4046 | nflags |= FSYNC_CACHE; |
4048 | | | 4047 | |
4049 | len = SCARG(uap, length); | | 4048 | len = SCARG(uap, length); |
4050 | /* If length == 0, we do the whole file, and s = e = 0 will do that */ | | 4049 | /* If length == 0, we do the whole file, and s = e = 0 will do that */ |
4051 | if (len) { | | 4050 | if (len) { |
4052 | s = SCARG(uap, start); | | 4051 | s = SCARG(uap, start); |
4053 | e = s + len; | | 4052 | e = s + len; |
4054 | if (e < s) { | | 4053 | if (e < s) { |
4055 | error = EINVAL; | | 4054 | error = EINVAL; |
4056 | goto out; | | 4055 | goto out; |
4057 | } | | 4056 | } |
4058 | } else { | | 4057 | } else { |
4059 | e = 0; | | 4058 | e = 0; |
4060 | s = 0; | | 4059 | s = 0; |
4061 | } | | 4060 | } |
4062 | | | 4061 | |
4063 | vp = fp->f_vnode; | | 4062 | vp = fp->f_vnode; |
4064 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 4063 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
4065 | error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e); | | 4064 | error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e); |
4066 | VOP_UNLOCK(vp); | | 4065 | VOP_UNLOCK(vp); |
4067 | out: | | 4066 | out: |
4068 | fd_putfile(SCARG(uap, fd)); | | 4067 | fd_putfile(SCARG(uap, fd)); |
4069 | return (error); | | 4068 | return (error); |
4070 | } | | 4069 | } |
4071 | | | 4070 | |
4072 | /* | | 4071 | /* |
4073 | * Sync the data of an open file. | | 4072 | * Sync the data of an open file. |
4074 | */ | | 4073 | */ |
4075 | /* ARGSUSED */ | | 4074 | /* ARGSUSED */ |
4076 | int | | 4075 | int |
4077 | sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval) | | 4076 | sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval) |
4078 | { | | 4077 | { |
4079 | /* { | | 4078 | /* { |
4080 | syscallarg(int) fd; | | 4079 | syscallarg(int) fd; |
4081 | } */ | | 4080 | } */ |
4082 | struct vnode *vp; | | 4081 | struct vnode *vp; |
4083 | file_t *fp; | | 4082 | file_t *fp; |
4084 | int error; | | 4083 | int error; |
4085 | | | 4084 | |
4086 | /* fd_getvnode() will use the descriptor for us */ | | 4085 | /* fd_getvnode() will use the descriptor for us */ |
4087 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 4086 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
4088 | return (error); | | 4087 | return (error); |
4089 | if ((fp->f_flag & FWRITE) == 0) { | | | |
4090 | fd_putfile(SCARG(uap, fd)); | | | |
4091 | return (EBADF); | | | |
4092 | } | | | |
4093 | vp = fp->f_vnode; | | 4088 | vp = fp->f_vnode; |
4094 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 4089 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
4095 | error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0); | | 4090 | error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0); |
4096 | VOP_UNLOCK(vp); | | 4091 | VOP_UNLOCK(vp); |
4097 | fd_putfile(SCARG(uap, fd)); | | 4092 | fd_putfile(SCARG(uap, fd)); |
4098 | return (error); | | 4093 | return (error); |
4099 | } | | 4094 | } |
4100 | | | 4095 | |
4101 | /* | | 4096 | /* |
4102 | * Rename files, (standard) BSD semantics frontend. | | 4097 | * Rename files, (standard) BSD semantics frontend. |
4103 | */ | | 4098 | */ |
4104 | /* ARGSUSED */ | | 4099 | /* ARGSUSED */ |
4105 | int | | 4100 | int |
4106 | sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval) | | 4101 | sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval) |
4107 | { | | 4102 | { |
4108 | /* { | | 4103 | /* { |
4109 | syscallarg(const char *) from; | | 4104 | syscallarg(const char *) from; |
4110 | syscallarg(const char *) to; | | 4105 | syscallarg(const char *) to; |
4111 | } */ | | 4106 | } */ |
4112 | | | 4107 | |
4113 | return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD, | | 4108 | return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD, |
4114 | SCARG(uap, to), UIO_USERSPACE, 0)); | | 4109 | SCARG(uap, to), UIO_USERSPACE, 0)); |
4115 | } | | 4110 | } |
4116 | | | 4111 | |
4117 | int | | 4112 | int |
4118 | sys_renameat(struct lwp *l, const struct sys_renameat_args *uap, | | 4113 | sys_renameat(struct lwp *l, const struct sys_renameat_args *uap, |
4119 | register_t *retval) | | 4114 | register_t *retval) |
4120 | { | | 4115 | { |
4121 | /* { | | 4116 | /* { |
4122 | syscallarg(int) fromfd; | | 4117 | syscallarg(int) fromfd; |
4123 | syscallarg(const char *) from; | | 4118 | syscallarg(const char *) from; |
4124 | syscallarg(int) tofd; | | 4119 | syscallarg(int) tofd; |
4125 | syscallarg(const char *) to; | | 4120 | syscallarg(const char *) to; |
4126 | } */ | | 4121 | } */ |
4127 | | | 4122 | |
4128 | return (do_sys_renameat(l, SCARG(uap, fromfd), SCARG(uap, from), | | 4123 | return (do_sys_renameat(l, SCARG(uap, fromfd), SCARG(uap, from), |
4129 | SCARG(uap, tofd), SCARG(uap, to), UIO_USERSPACE, 0)); | | 4124 | SCARG(uap, tofd), SCARG(uap, to), UIO_USERSPACE, 0)); |
4130 | } | | 4125 | } |
4131 | | | 4126 | |
4132 | /* | | 4127 | /* |
4133 | * Rename files, POSIX semantics frontend. | | 4128 | * Rename files, POSIX semantics frontend. |
4134 | */ | | 4129 | */ |
4135 | /* ARGSUSED */ | | 4130 | /* ARGSUSED */ |
4136 | int | | 4131 | int |
4137 | sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval) | | 4132 | sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval) |
4138 | { | | 4133 | { |
4139 | /* { | | 4134 | /* { |
4140 | syscallarg(const char *) from; | | 4135 | syscallarg(const char *) from; |
4141 | syscallarg(const char *) to; | | 4136 | syscallarg(const char *) to; |
4142 | } */ | | 4137 | } */ |
4143 | | | 4138 | |
4144 | return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD, | | 4139 | return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD, |
4145 | SCARG(uap, to), UIO_USERSPACE, 1)); | | 4140 | SCARG(uap, to), UIO_USERSPACE, 1)); |
4146 | } | | 4141 | } |
4147 | | | 4142 | |
4148 | /* | | 4143 | /* |
4149 | * Rename files. Source and destination must either both be directories, | | 4144 | * Rename files. Source and destination must either both be directories, |
4150 | * or both not be directories. If target is a directory, it must be empty. | | 4145 | * or both not be directories. If target is a directory, it must be empty. |
4151 | * If `from' and `to' refer to the same object, the value of the `retain' | | 4146 | * If `from' and `to' refer to the same object, the value of the `retain' |
4152 | * argument is used to determine whether `from' will be | | 4147 | * argument is used to determine whether `from' will be |
4153 | * | | 4148 | * |
4154 | * (retain == 0) deleted unless `from' and `to' refer to the same | | 4149 | * (retain == 0) deleted unless `from' and `to' refer to the same |
4155 | * object in the file system's name space (BSD). | | 4150 | * object in the file system's name space (BSD). |
4156 | * (retain == 1) always retained (POSIX). | | 4151 | * (retain == 1) always retained (POSIX). |
4157 | * | | 4152 | * |
4158 | * XXX Synchronize with nfsrv_rename in nfs_serv.c. | | 4153 | * XXX Synchronize with nfsrv_rename in nfs_serv.c. |
4159 | */ | | 4154 | */ |
4160 | int | | 4155 | int |
4161 | do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain) | | 4156 | do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain) |
4162 | { | | 4157 | { |
4163 | return do_sys_renameat(NULL, AT_FDCWD, from, AT_FDCWD, to, seg, retain); | | 4158 | return do_sys_renameat(NULL, AT_FDCWD, from, AT_FDCWD, to, seg, retain); |
4164 | } | | 4159 | } |
4165 | | | 4160 | |
4166 | static int | | 4161 | static int |
4167 | do_sys_renameat(struct lwp *l, int fromfd, const char *from, int tofd, | | 4162 | do_sys_renameat(struct lwp *l, int fromfd, const char *from, int tofd, |
4168 | const char *to, enum uio_seg seg, int retain) | | 4163 | const char *to, enum uio_seg seg, int retain) |
4169 | { | | 4164 | { |
4170 | struct pathbuf *fpb, *tpb; | | 4165 | struct pathbuf *fpb, *tpb; |
4171 | struct nameidata fnd, tnd; | | 4166 | struct nameidata fnd, tnd; |
4172 | struct vnode *fdvp, *fvp; | | 4167 | struct vnode *fdvp, *fvp; |
4173 | struct vnode *tdvp, *tvp; | | 4168 | struct vnode *tdvp, *tvp; |
4174 | struct mount *mp, *tmp; | | 4169 | struct mount *mp, *tmp; |
4175 | int error; | | 4170 | int error; |
4176 | | | 4171 | |
4177 | KASSERT(l != NULL || (fromfd == AT_FDCWD && tofd == AT_FDCWD)); | | 4172 | KASSERT(l != NULL || (fromfd == AT_FDCWD && tofd == AT_FDCWD)); |
4178 | | | 4173 | |
4179 | error = pathbuf_maybe_copyin(from, seg, &fpb); | | 4174 | error = pathbuf_maybe_copyin(from, seg, &fpb); |
4180 | if (error) | | 4175 | if (error) |
4181 | goto out0; | | 4176 | goto out0; |
4182 | KASSERT(fpb != NULL); | | 4177 | KASSERT(fpb != NULL); |
4183 | | | 4178 | |
4184 | error = pathbuf_maybe_copyin(to, seg, &tpb); | | 4179 | error = pathbuf_maybe_copyin(to, seg, &tpb); |
4185 | if (error) | | 4180 | if (error) |
4186 | goto out1; | | 4181 | goto out1; |
4187 | KASSERT(tpb != NULL); | | 4182 | KASSERT(tpb != NULL); |
4188 | | | 4183 | |
4189 | /* | | 4184 | /* |
4190 | * Lookup from. | | 4185 | * Lookup from. |
4191 | * | | 4186 | * |
4192 | * XXX LOCKPARENT is wrong because we don't actually want it | | 4187 | * XXX LOCKPARENT is wrong because we don't actually want it |
4193 | * locked yet, but (a) namei is insane, and (b) VOP_RENAME is | | 4188 | * locked yet, but (a) namei is insane, and (b) VOP_RENAME is |
4194 | * insane, so for the time being we need to leave it like this. | | 4189 | * insane, so for the time being we need to leave it like this. |
4195 | */ | | 4190 | */ |
4196 | NDINIT(&fnd, DELETE, (LOCKPARENT | TRYEMULROOT), fpb); | | 4191 | NDINIT(&fnd, DELETE, (LOCKPARENT | TRYEMULROOT), fpb); |
4197 | if ((error = fd_nameiat(l, fromfd, &fnd)) != 0) | | 4192 | if ((error = fd_nameiat(l, fromfd, &fnd)) != 0) |
4198 | goto out2; | | 4193 | goto out2; |
4199 | | | 4194 | |
4200 | /* | | 4195 | /* |
4201 | * Pull out the important results of the lookup, fdvp and fvp. | | 4196 | * Pull out the important results of the lookup, fdvp and fvp. |
4202 | * Of course, fvp is bogus because we're about to unlock fdvp. | | 4197 | * Of course, fvp is bogus because we're about to unlock fdvp. |
4203 | */ | | 4198 | */ |
4204 | fdvp = fnd.ni_dvp; | | 4199 | fdvp = fnd.ni_dvp; |
4205 | fvp = fnd.ni_vp; | | 4200 | fvp = fnd.ni_vp; |
4206 | KASSERT(fdvp != NULL); | | 4201 | KASSERT(fdvp != NULL); |
4207 | KASSERT(fvp != NULL); | | 4202 | KASSERT(fvp != NULL); |
4208 | KASSERT((fdvp == fvp) || (VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE)); | | 4203 | KASSERT((fdvp == fvp) || (VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE)); |
4209 | | | 4204 | |
4210 | /* | | 4205 | /* |
4211 | * Make sure neither fdvp nor fvp is locked. | | 4206 | * Make sure neither fdvp nor fvp is locked. |
4212 | */ | | 4207 | */ |
4213 | if (fdvp != fvp) | | 4208 | if (fdvp != fvp) |
4214 | VOP_UNLOCK(fdvp); | | 4209 | VOP_UNLOCK(fdvp); |
4215 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ | | 4210 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ |
4216 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ | | 4211 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ |
4217 | | | 4212 | |
4218 | /* | | 4213 | /* |
4219 | * Reject renaming `.' and `..'. Can't do this until after | | 4214 | * Reject renaming `.' and `..'. Can't do this until after |
4220 | * namei because we need namei's parsing to find the final | | 4215 | * namei because we need namei's parsing to find the final |
4221 | * component name. (namei should just leave us with the final | | 4216 | * component name. (namei should just leave us with the final |
4222 | * component name and not look it up itself, but anyway...) | | 4217 | * component name and not look it up itself, but anyway...) |
4223 | * | | 4218 | * |
4224 | * This was here before because we used to relookup from | | 4219 | * This was here before because we used to relookup from |
4225 | * instead of to and relookup requires the caller to check | | 4220 | * instead of to and relookup requires the caller to check |
4226 | * this, but now file systems may depend on this check, so we | | 4221 | * this, but now file systems may depend on this check, so we |
4227 | * must retain it until the file systems are all rototilled. | | 4222 | * must retain it until the file systems are all rototilled. |
4228 | */ | | 4223 | */ |
4229 | if (((fnd.ni_cnd.cn_namelen == 1) && | | 4224 | if (((fnd.ni_cnd.cn_namelen == 1) && |
4230 | (fnd.ni_cnd.cn_nameptr[0] == '.')) || | | 4225 | (fnd.ni_cnd.cn_nameptr[0] == '.')) || |
4231 | ((fnd.ni_cnd.cn_namelen == 2) && | | 4226 | ((fnd.ni_cnd.cn_namelen == 2) && |
4232 | (fnd.ni_cnd.cn_nameptr[0] == '.') && | | 4227 | (fnd.ni_cnd.cn_nameptr[0] == '.') && |
4233 | (fnd.ni_cnd.cn_nameptr[1] == '.'))) { | | 4228 | (fnd.ni_cnd.cn_nameptr[1] == '.'))) { |
4234 | error = EINVAL; /* XXX EISDIR? */ | | 4229 | error = EINVAL; /* XXX EISDIR? */ |
4235 | goto abort0; | | 4230 | goto abort0; |
4236 | } | | 4231 | } |
4237 | | | 4232 | |
4238 | /* | | 4233 | /* |
4239 | * Lookup to. | | 4234 | * Lookup to. |
4240 | * | | 4235 | * |
4241 | * XXX LOCKPARENT is wrong, but...insanity, &c. Also, using | | 4236 | * XXX LOCKPARENT is wrong, but...insanity, &c. Also, using |
4242 | * fvp here to decide whether to add CREATEDIR is a load of | | 4237 | * fvp here to decide whether to add CREATEDIR is a load of |
4243 | * bollocks because fvp might be the wrong node by now, since | | 4238 | * bollocks because fvp might be the wrong node by now, since |
4244 | * fdvp is unlocked. | | 4239 | * fdvp is unlocked. |
4245 | * | | 4240 | * |
4246 | * XXX Why not pass CREATEDIR always? | | 4241 | * XXX Why not pass CREATEDIR always? |
4247 | */ | | 4242 | */ |
4248 | NDINIT(&tnd, RENAME, | | 4243 | NDINIT(&tnd, RENAME, |
4249 | (LOCKPARENT | NOCACHE | TRYEMULROOT | | | 4244 | (LOCKPARENT | NOCACHE | TRYEMULROOT | |
4250 | ((fvp->v_type == VDIR)? CREATEDIR : 0)), | | 4245 | ((fvp->v_type == VDIR)? CREATEDIR : 0)), |
4251 | tpb); | | 4246 | tpb); |
4252 | if ((error = fd_nameiat(l, tofd, &tnd)) != 0) | | 4247 | if ((error = fd_nameiat(l, tofd, &tnd)) != 0) |
4253 | goto abort0; | | 4248 | goto abort0; |
4254 | | | 4249 | |
4255 | /* | | 4250 | /* |
4256 | * Pull out the important results of the lookup, tdvp and tvp. | | 4251 | * Pull out the important results of the lookup, tdvp and tvp. |
4257 | * Of course, tvp is bogus because we're about to unlock tdvp. | | 4252 | * Of course, tvp is bogus because we're about to unlock tdvp. |
4258 | */ | | 4253 | */ |
4259 | tdvp = tnd.ni_dvp; | | 4254 | tdvp = tnd.ni_dvp; |
4260 | tvp = tnd.ni_vp; | | 4255 | tvp = tnd.ni_vp; |
4261 | KASSERT(tdvp != NULL); | | 4256 | KASSERT(tdvp != NULL); |
4262 | KASSERT((tdvp == tvp) || (VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE)); | | 4257 | KASSERT((tdvp == tvp) || (VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE)); |
4263 | | | 4258 | |
4264 | /* | | 4259 | /* |
4265 | * Make sure neither tdvp nor tvp is locked. | | 4260 | * Make sure neither tdvp nor tvp is locked. |
4266 | */ | | 4261 | */ |
4267 | if (tdvp != tvp) | | 4262 | if (tdvp != tvp) |
4268 | VOP_UNLOCK(tdvp); | | 4263 | VOP_UNLOCK(tdvp); |
4269 | /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */ | | 4264 | /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */ |
4270 | /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */ | | 4265 | /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */ |
4271 | | | 4266 | |
4272 | /* | | 4267 | /* |
4273 | * Reject renaming onto `.' or `..'. relookup is unhappy with | | 4268 | * Reject renaming onto `.' or `..'. relookup is unhappy with |
4274 | * these, which is why we must do this here. Once upon a time | | 4269 | * these, which is why we must do this here. Once upon a time |
4275 | * we relooked up from instead of to, and consequently didn't | | 4270 | * we relooked up from instead of to, and consequently didn't |
4276 | * need this check, but now that we relookup to instead of | | 4271 | * need this check, but now that we relookup to instead of |
4277 | * from, we need this; and we shall need it forever forward | | 4272 | * from, we need this; and we shall need it forever forward |
4278 | * until the VOP_RENAME protocol changes, because file systems | | 4273 | * until the VOP_RENAME protocol changes, because file systems |
4279 | * will no doubt begin to depend on this check. | | 4274 | * will no doubt begin to depend on this check. |
4280 | */ | | 4275 | */ |
4281 | if ((tnd.ni_cnd.cn_namelen == 1) && (tnd.ni_cnd.cn_nameptr[0] == '.')) { | | 4276 | if ((tnd.ni_cnd.cn_namelen == 1) && (tnd.ni_cnd.cn_nameptr[0] == '.')) { |
4282 | error = EISDIR; | | 4277 | error = EISDIR; |
4283 | goto abort1; | | 4278 | goto abort1; |
4284 | } | | 4279 | } |
4285 | if ((tnd.ni_cnd.cn_namelen == 2) && | | 4280 | if ((tnd.ni_cnd.cn_namelen == 2) && |
4286 | (tnd.ni_cnd.cn_nameptr[0] == '.') && | | 4281 | (tnd.ni_cnd.cn_nameptr[0] == '.') && |
4287 | (tnd.ni_cnd.cn_nameptr[1] == '.')) { | | 4282 | (tnd.ni_cnd.cn_nameptr[1] == '.')) { |
4288 | error = EINVAL; | | 4283 | error = EINVAL; |
4289 | goto abort1; | | 4284 | goto abort1; |
4290 | } | | 4285 | } |
4291 | | | 4286 | |
4292 | /* | | 4287 | /* |
4293 | * Get the mount point. If the file system has been unmounted, | | 4288 | * Get the mount point. If the file system has been unmounted, |
4294 | * which it may be because we're not holding any vnode locks, | | 4289 | * which it may be because we're not holding any vnode locks, |
4295 | * then v_mount will be NULL. We're not really supposed to | | 4290 | * then v_mount will be NULL. We're not really supposed to |
4296 | * read v_mount without holding the vnode lock, but since we | | 4291 | * read v_mount without holding the vnode lock, but since we |
4297 | * have fdvp referenced, if fdvp->v_mount changes then at worst | | 4292 | * have fdvp referenced, if fdvp->v_mount changes then at worst |
4298 | * it will be set to NULL, not changed to another mount point. | | 4293 | * it will be set to NULL, not changed to another mount point. |
4299 | * And, of course, since it is up to the file system to | | 4294 | * And, of course, since it is up to the file system to |
4300 | * determine the real lock order, we can't lock both fdvp and | | 4295 | * determine the real lock order, we can't lock both fdvp and |
4301 | * tdvp at the same time. | | 4296 | * tdvp at the same time. |
4302 | */ | | 4297 | */ |
4303 | mp = fdvp->v_mount; | | 4298 | mp = fdvp->v_mount; |
4304 | if (mp == NULL) { | | 4299 | if (mp == NULL) { |
4305 | error = ENOENT; | | 4300 | error = ENOENT; |
4306 | goto abort1; | | 4301 | goto abort1; |
4307 | } | | 4302 | } |
4308 | | | 4303 | |
4309 | /* | | 4304 | /* |
4310 | * Make sure the mount points match. Again, although we don't | | 4305 | * Make sure the mount points match. Again, although we don't |
4311 | * hold any vnode locks, the v_mount fields may change -- but | | 4306 | * hold any vnode locks, the v_mount fields may change -- but |
4312 | * at worst they will change to NULL, so this will never become | | 4307 | * at worst they will change to NULL, so this will never become |
4313 | * a cross-device rename, because we hold vnode references. | | 4308 | * a cross-device rename, because we hold vnode references. |
4314 | * | | 4309 | * |
4315 | * XXX Because nothing is locked and the compiler may reorder | | 4310 | * XXX Because nothing is locked and the compiler may reorder |
4316 | * things here, unmounting the file system at an inopportune | | 4311 | * things here, unmounting the file system at an inopportune |
4317 | * moment may cause rename to fail with EXDEV when it really | | 4312 | * moment may cause rename to fail with EXDEV when it really |
4318 | * should fail with ENOENT. | | 4313 | * should fail with ENOENT. |
4319 | */ | | 4314 | */ |
4320 | tmp = tdvp->v_mount; | | 4315 | tmp = tdvp->v_mount; |
4321 | if (tmp == NULL) { | | 4316 | if (tmp == NULL) { |
4322 | error = ENOENT; | | 4317 | error = ENOENT; |
4323 | goto abort1; | | 4318 | goto abort1; |
4324 | } | | 4319 | } |
4325 | | | 4320 | |
4326 | if (mp != tmp) { | | 4321 | if (mp != tmp) { |
4327 | error = EXDEV; | | 4322 | error = EXDEV; |
4328 | goto abort1; | | 4323 | goto abort1; |
4329 | } | | 4324 | } |
4330 | | | 4325 | |
4331 | /* | | 4326 | /* |
4332 | * Take the vfs rename lock to avoid cross-directory screw cases. | | 4327 | * Take the vfs rename lock to avoid cross-directory screw cases. |
4333 | * Nothing is locked currently, so taking this lock is safe. | | 4328 | * Nothing is locked currently, so taking this lock is safe. |
4334 | */ | | 4329 | */ |
4335 | error = VFS_RENAMELOCK_ENTER(mp); | | 4330 | error = VFS_RENAMELOCK_ENTER(mp); |
4336 | if (error) | | 4331 | if (error) |
4337 | goto abort1; | | 4332 | goto abort1; |
4338 | | | 4333 | |
4339 | /* | | 4334 | /* |
4340 | * Now fdvp, fvp, tdvp, and (if nonnull) tvp are referenced, | | 4335 | * Now fdvp, fvp, tdvp, and (if nonnull) tvp are referenced, |
4341 | * and nothing is locked except for the vfs rename lock. | | 4336 | * and nothing is locked except for the vfs rename lock. |
4342 | * | | 4337 | * |
4343 | * The next step is a little rain dance to conform to the | | 4338 | * The next step is a little rain dance to conform to the |
4344 | * insane lock protocol, even though it does nothing to ward | | 4339 | * insane lock protocol, even though it does nothing to ward |
4345 | * off race conditions. | | 4340 | * off race conditions. |
4346 | * | | 4341 | * |
4347 | * We need tdvp and tvp to be locked. However, because we have | | 4342 | * We need tdvp and tvp to be locked. However, because we have |
4348 | * unlocked tdvp in order to hold no locks while we take the | | 4343 | * unlocked tdvp in order to hold no locks while we take the |
4349 | * vfs rename lock, tvp may be wrong here, and we can't safely | | 4344 | * vfs rename lock, tvp may be wrong here, and we can't safely |
4350 | * lock it even if the sensible file systems will just unlock | | 4345 | * lock it even if the sensible file systems will just unlock |
4351 | * it straight away. Consequently, we must lock tdvp and then | | 4346 | * it straight away. Consequently, we must lock tdvp and then |
4352 | * relookup tvp to get it locked. | | 4347 | * relookup tvp to get it locked. |
4353 | * | | 4348 | * |
4354 | * Finally, because the VOP_RENAME protocol is brain-damaged | | 4349 | * Finally, because the VOP_RENAME protocol is brain-damaged |
4355 | * and various file systems insanely depend on the semantics of | | 4350 | * and various file systems insanely depend on the semantics of |
4356 | * this brain damage, the lookup of to must be the last lookup | | 4351 | * this brain damage, the lookup of to must be the last lookup |
4357 | * before VOP_RENAME. | | 4352 | * before VOP_RENAME. |
4358 | */ | | 4353 | */ |
4359 | vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); | | 4354 | vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); |
4360 | error = relookup(tdvp, &tnd.ni_vp, &tnd.ni_cnd, 0); | | 4355 | error = relookup(tdvp, &tnd.ni_vp, &tnd.ni_cnd, 0); |
4361 | if (error) | | 4356 | if (error) |
4362 | goto abort2; | | 4357 | goto abort2; |
4363 | | | 4358 | |
4364 | /* | | 4359 | /* |
4365 | * Drop the old tvp and pick up the new one -- which might be | | 4360 | * Drop the old tvp and pick up the new one -- which might be |
4366 | * the same, but that doesn't matter to us. After this, tdvp | | 4361 | * the same, but that doesn't matter to us. After this, tdvp |
4367 | * and tvp should both be locked. | | 4362 | * and tvp should both be locked. |
4368 | */ | | 4363 | */ |
4369 | if (tvp != NULL) | | 4364 | if (tvp != NULL) |
4370 | vrele(tvp); | | 4365 | vrele(tvp); |
4371 | tvp = tnd.ni_vp; | | 4366 | tvp = tnd.ni_vp; |
4372 | KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); | | 4367 | KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); |
4373 | KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); | | 4368 | KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); |
4374 | | | 4369 | |
4375 | /* | | 4370 | /* |
4376 | * The old do_sys_rename had various consistency checks here | | 4371 | * The old do_sys_rename had various consistency checks here |
4377 | * involving fvp and tvp. fvp is bogus already here, and tvp | | 4372 | * involving fvp and tvp. fvp is bogus already here, and tvp |
4378 | * will become bogus soon in any sensible file system, so the | | 4373 | * will become bogus soon in any sensible file system, so the |
4379 | * only purpose in putting these checks here is to give lip | | 4374 | * only purpose in putting these checks here is to give lip |
4380 | * service to these screw cases and to acknowledge that they | | 4375 | * service to these screw cases and to acknowledge that they |
4381 | * exist, not actually to handle them, but here you go | | 4376 | * exist, not actually to handle them, but here you go |
4382 | * anyway... | | 4377 | * anyway... |
4383 | */ | | 4378 | */ |
4384 | | | 4379 | |
4385 | /* | | 4380 | /* |
4386 | * Acknowledge that directories and non-directories aren't | | 4381 | * Acknowledge that directories and non-directories aren't |
4387 | * suposed to mix. | | 4382 | * suposed to mix. |
4388 | */ | | 4383 | */ |
4389 | if (tvp != NULL) { | | 4384 | if (tvp != NULL) { |
4390 | if ((fvp->v_type == VDIR) && (tvp->v_type != VDIR)) { | | 4385 | if ((fvp->v_type == VDIR) && (tvp->v_type != VDIR)) { |
4391 | error = ENOTDIR; | | 4386 | error = ENOTDIR; |
4392 | goto abort3; | | 4387 | goto abort3; |
4393 | } else if ((fvp->v_type != VDIR) && (tvp->v_type == VDIR)) { | | 4388 | } else if ((fvp->v_type != VDIR) && (tvp->v_type == VDIR)) { |
4394 | error = EISDIR; | | 4389 | error = EISDIR; |
4395 | goto abort3; | | 4390 | goto abort3; |
4396 | } | | 4391 | } |
4397 | } | | 4392 | } |
4398 | | | 4393 | |
4399 | /* | | 4394 | /* |
4400 | * Acknowledge some random screw case, among the dozens that | | 4395 | * Acknowledge some random screw case, among the dozens that |
4401 | * might arise. | | 4396 | * might arise. |
4402 | */ | | 4397 | */ |
4403 | if (fvp == tdvp) { | | 4398 | if (fvp == tdvp) { |
4404 | error = EINVAL; | | 4399 | error = EINVAL; |
4405 | goto abort3; | | 4400 | goto abort3; |
4406 | } | | 4401 | } |
4407 | | | 4402 | |
4408 | /* | | 4403 | /* |
4409 | * Acknowledge that POSIX has a wacky screw case. | | 4404 | * Acknowledge that POSIX has a wacky screw case. |
4410 | * | | 4405 | * |
4411 | * XXX Eventually the retain flag needs to be passed on to | | 4406 | * XXX Eventually the retain flag needs to be passed on to |
4412 | * VOP_RENAME. | | 4407 | * VOP_RENAME. |
4413 | */ | | 4408 | */ |
4414 | if (fvp == tvp) { | | 4409 | if (fvp == tvp) { |
4415 | if (retain) { | | 4410 | if (retain) { |
4416 | error = 0; | | 4411 | error = 0; |
4417 | goto abort3; | | 4412 | goto abort3; |
4418 | } else if ((fdvp == tdvp) && | | 4413 | } else if ((fdvp == tdvp) && |
4419 | (fnd.ni_cnd.cn_namelen == tnd.ni_cnd.cn_namelen) && | | 4414 | (fnd.ni_cnd.cn_namelen == tnd.ni_cnd.cn_namelen) && |
4420 | (0 == memcmp(fnd.ni_cnd.cn_nameptr, tnd.ni_cnd.cn_nameptr, | | 4415 | (0 == memcmp(fnd.ni_cnd.cn_nameptr, tnd.ni_cnd.cn_nameptr, |
4421 | fnd.ni_cnd.cn_namelen))) { | | 4416 | fnd.ni_cnd.cn_namelen))) { |
4422 | error = 0; | | 4417 | error = 0; |
4423 | goto abort3; | | 4418 | goto abort3; |
4424 | } | | 4419 | } |
4425 | } | | 4420 | } |
4426 | | | 4421 | |
4427 | /* | | 4422 | /* |
4428 | * Make sure veriexec can screw us up. (But a race can screw | | 4423 | * Make sure veriexec can screw us up. (But a race can screw |
4429 | * up veriexec, of course -- remember, fvp and (soon) tvp are | | 4424 | * up veriexec, of course -- remember, fvp and (soon) tvp are |
4430 | * bogus.) | | 4425 | * bogus.) |
4431 | */ | | 4426 | */ |
4432 | #if NVERIEXEC > 0 | | 4427 | #if NVERIEXEC > 0 |
4433 | { | | 4428 | { |
4434 | char *f1, *f2; | | 4429 | char *f1, *f2; |
4435 | size_t f1_len; | | 4430 | size_t f1_len; |
4436 | size_t f2_len; | | 4431 | size_t f2_len; |
4437 | | | 4432 | |
4438 | f1_len = fnd.ni_cnd.cn_namelen + 1; | | 4433 | f1_len = fnd.ni_cnd.cn_namelen + 1; |
4439 | f1 = kmem_alloc(f1_len, KM_SLEEP); | | 4434 | f1 = kmem_alloc(f1_len, KM_SLEEP); |
4440 | strlcpy(f1, fnd.ni_cnd.cn_nameptr, f1_len); | | 4435 | strlcpy(f1, fnd.ni_cnd.cn_nameptr, f1_len); |
4441 | | | 4436 | |
4442 | f2_len = tnd.ni_cnd.cn_namelen + 1; | | 4437 | f2_len = tnd.ni_cnd.cn_namelen + 1; |
4443 | f2 = kmem_alloc(f2_len, KM_SLEEP); | | 4438 | f2 = kmem_alloc(f2_len, KM_SLEEP); |
4444 | strlcpy(f2, tnd.ni_cnd.cn_nameptr, f2_len); | | 4439 | strlcpy(f2, tnd.ni_cnd.cn_nameptr, f2_len); |
4445 | | | 4440 | |
4446 | error = veriexec_renamechk(curlwp, fvp, f1, tvp, f2); | | 4441 | error = veriexec_renamechk(curlwp, fvp, f1, tvp, f2); |
4447 | | | 4442 | |
4448 | kmem_free(f1, f1_len); | | 4443 | kmem_free(f1, f1_len); |
4449 | kmem_free(f2, f2_len); | | 4444 | kmem_free(f2, f2_len); |
4450 | | | 4445 | |
4451 | if (error) | | 4446 | if (error) |
4452 | goto abort3; | | 4447 | goto abort3; |
4453 | } | | 4448 | } |
4454 | #endif /* NVERIEXEC > 0 */ | | 4449 | #endif /* NVERIEXEC > 0 */ |
4455 | | | 4450 | |
4456 | /* | | 4451 | /* |
4457 | * All ready. Incant the rename vop. | | 4452 | * All ready. Incant the rename vop. |
4458 | */ | | 4453 | */ |
4459 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ | | 4454 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ |
4460 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ | | 4455 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ |
4461 | KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); | | 4456 | KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); |
4462 | KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); | | 4457 | KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); |
4463 | error = VOP_RENAME(fdvp, fvp, &fnd.ni_cnd, tdvp, tvp, &tnd.ni_cnd); | | 4458 | error = VOP_RENAME(fdvp, fvp, &fnd.ni_cnd, tdvp, tvp, &tnd.ni_cnd); |
4464 | | | 4459 | |
4465 | /* | | 4460 | /* |
4466 | * VOP_RENAME releases fdvp, fvp, tdvp, and tvp, and unlocks | | 4461 | * VOP_RENAME releases fdvp, fvp, tdvp, and tvp, and unlocks |
4467 | * tdvp and tvp. But we can't assert any of that. | | 4462 | * tdvp and tvp. But we can't assert any of that. |
4468 | */ | | 4463 | */ |
4469 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ | | 4464 | /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */ |
4470 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ | | 4465 | /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */ |
4471 | /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */ | | 4466 | /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */ |
4472 | /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */ | | 4467 | /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */ |
4473 | | | 4468 | |
4474 | /* | | 4469 | /* |
4475 | * So all we have left to do is to drop the rename lock and | | 4470 | * So all we have left to do is to drop the rename lock and |
4476 | * destroy the pathbufs. | | 4471 | * destroy the pathbufs. |
4477 | */ | | 4472 | */ |
4478 | VFS_RENAMELOCK_EXIT(mp); | | 4473 | VFS_RENAMELOCK_EXIT(mp); |
4479 | goto out2; | | 4474 | goto out2; |
4480 | | | 4475 | |
4481 | abort3: if ((tvp != NULL) && (tvp != tdvp)) | | 4476 | abort3: if ((tvp != NULL) && (tvp != tdvp)) |
4482 | VOP_UNLOCK(tvp); | | 4477 | VOP_UNLOCK(tvp); |
4483 | abort2: VOP_UNLOCK(tdvp); | | 4478 | abort2: VOP_UNLOCK(tdvp); |
4484 | VFS_RENAMELOCK_EXIT(mp); | | 4479 | VFS_RENAMELOCK_EXIT(mp); |
4485 | abort1: VOP_ABORTOP(tdvp, &tnd.ni_cnd); | | 4480 | abort1: VOP_ABORTOP(tdvp, &tnd.ni_cnd); |
4486 | vrele(tdvp); | | 4481 | vrele(tdvp); |
4487 | if (tvp != NULL) | | 4482 | if (tvp != NULL) |
4488 | vrele(tvp); | | 4483 | vrele(tvp); |
4489 | abort0: VOP_ABORTOP(fdvp, &fnd.ni_cnd); | | 4484 | abort0: VOP_ABORTOP(fdvp, &fnd.ni_cnd); |
4490 | vrele(fdvp); | | 4485 | vrele(fdvp); |
4491 | vrele(fvp); | | 4486 | vrele(fvp); |
4492 | out2: pathbuf_destroy(tpb); | | 4487 | out2: pathbuf_destroy(tpb); |
4493 | out1: pathbuf_destroy(fpb); | | 4488 | out1: pathbuf_destroy(fpb); |
4494 | out0: return error; | | 4489 | out0: return error; |
4495 | } | | 4490 | } |
4496 | | | 4491 | |
4497 | /* | | 4492 | /* |
4498 | * Make a directory file. | | 4493 | * Make a directory file. |
4499 | */ | | 4494 | */ |
4500 | /* ARGSUSED */ | | 4495 | /* ARGSUSED */ |
4501 | int | | 4496 | int |
4502 | sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval) | | 4497 | sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval) |
4503 | { | | 4498 | { |
4504 | /* { | | 4499 | /* { |
4505 | syscallarg(const char *) path; | | 4500 | syscallarg(const char *) path; |
4506 | syscallarg(int) mode; | | 4501 | syscallarg(int) mode; |
4507 | } */ | | 4502 | } */ |
4508 | | | 4503 | |
4509 | return do_sys_mkdirat(l, AT_FDCWD, SCARG(uap, path), | | 4504 | return do_sys_mkdirat(l, AT_FDCWD, SCARG(uap, path), |
4510 | SCARG(uap, mode), UIO_USERSPACE); | | 4505 | SCARG(uap, mode), UIO_USERSPACE); |
4511 | } | | 4506 | } |
4512 | | | 4507 | |
4513 | int | | 4508 | int |
4514 | sys_mkdirat(struct lwp *l, const struct sys_mkdirat_args *uap, | | 4509 | sys_mkdirat(struct lwp *l, const struct sys_mkdirat_args *uap, |
4515 | register_t *retval) | | 4510 | register_t *retval) |
4516 | { | | 4511 | { |
4517 | /* { | | 4512 | /* { |
4518 | syscallarg(int) fd; | | 4513 | syscallarg(int) fd; |
4519 | syscallarg(const char *) path; | | 4514 | syscallarg(const char *) path; |
4520 | syscallarg(int) mode; | | 4515 | syscallarg(int) mode; |
4521 | } */ | | 4516 | } */ |
4522 | | | 4517 | |
4523 | return do_sys_mkdirat(l, SCARG(uap, fd), SCARG(uap, path), | | 4518 | return do_sys_mkdirat(l, SCARG(uap, fd), SCARG(uap, path), |
4524 | SCARG(uap, mode), UIO_USERSPACE); | | 4519 | SCARG(uap, mode), UIO_USERSPACE); |
4525 | } | | 4520 | } |
4526 | | | 4521 | |
4527 | | | 4522 | |
4528 | int | | 4523 | int |
4529 | do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg) | | 4524 | do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg) |
4530 | { | | 4525 | { |
4531 | return do_sys_mkdirat(NULL, AT_FDCWD, path, mode, UIO_USERSPACE); | | 4526 | return do_sys_mkdirat(NULL, AT_FDCWD, path, mode, UIO_USERSPACE); |
4532 | } | | 4527 | } |
4533 | | | 4528 | |
4534 | static int | | 4529 | static int |
4535 | do_sys_mkdirat(struct lwp *l, int fdat, const char *path, mode_t mode, | | 4530 | do_sys_mkdirat(struct lwp *l, int fdat, const char *path, mode_t mode, |
4536 | enum uio_seg seg) | | 4531 | enum uio_seg seg) |
4537 | { | | 4532 | { |
4538 | struct proc *p = curlwp->l_proc; | | 4533 | struct proc *p = curlwp->l_proc; |
4539 | struct vnode *vp; | | 4534 | struct vnode *vp; |
4540 | struct vattr vattr; | | 4535 | struct vattr vattr; |
4541 | int error; | | 4536 | int error; |
4542 | struct pathbuf *pb; | | 4537 | struct pathbuf *pb; |
4543 | struct nameidata nd; | | 4538 | struct nameidata nd; |
4544 | | | 4539 | |
4545 | KASSERT(l != NULL || fdat == AT_FDCWD); | | 4540 | KASSERT(l != NULL || fdat == AT_FDCWD); |
4546 | | | 4541 | |
4547 | /* XXX bollocks, should pass in a pathbuf */ | | 4542 | /* XXX bollocks, should pass in a pathbuf */ |
4548 | error = pathbuf_maybe_copyin(path, seg, &pb); | | 4543 | error = pathbuf_maybe_copyin(path, seg, &pb); |
4549 | if (error) { | | 4544 | if (error) { |
4550 | return error; | | 4545 | return error; |
4551 | } | | 4546 | } |
4552 | | | 4547 | |
4553 | NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, pb); | | 4548 | NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, pb); |
4554 | | | 4549 | |
4555 | if ((error = fd_nameiat(l, fdat, &nd)) != 0) { | | 4550 | if ((error = fd_nameiat(l, fdat, &nd)) != 0) { |
4556 | pathbuf_destroy(pb); | | 4551 | pathbuf_destroy(pb); |
4557 | return (error); | | 4552 | return (error); |
4558 | } | | 4553 | } |
4559 | vp = nd.ni_vp; | | 4554 | vp = nd.ni_vp; |
4560 | if (vp != NULL) { | | 4555 | if (vp != NULL) { |
4561 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); | | 4556 | VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); |
4562 | if (nd.ni_dvp == vp) | | 4557 | if (nd.ni_dvp == vp) |
4563 | vrele(nd.ni_dvp); | | 4558 | vrele(nd.ni_dvp); |
4564 | else | | 4559 | else |
4565 | vput(nd.ni_dvp); | | 4560 | vput(nd.ni_dvp); |
4566 | vrele(vp); | | 4561 | vrele(vp); |
4567 | pathbuf_destroy(pb); | | 4562 | pathbuf_destroy(pb); |
4568 | return (EEXIST); | | 4563 | return (EEXIST); |
4569 | } | | 4564 | } |
4570 | vattr_null(&vattr); | | 4565 | vattr_null(&vattr); |
4571 | vattr.va_type = VDIR; | | 4566 | vattr.va_type = VDIR; |
4572 | /* We will read cwdi->cwdi_cmask unlocked. */ | | 4567 | /* We will read cwdi->cwdi_cmask unlocked. */ |
4573 | vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask; | | 4568 | vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask; |
4574 | error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); | | 4569 | error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); |
4575 | if (!error) | | 4570 | if (!error) |
4576 | vrele(nd.ni_vp); | | 4571 | vrele(nd.ni_vp); |
4577 | vput(nd.ni_dvp); | | 4572 | vput(nd.ni_dvp); |
4578 | pathbuf_destroy(pb); | | 4573 | pathbuf_destroy(pb); |
4579 | return (error); | | 4574 | return (error); |
4580 | } | | 4575 | } |
4581 | | | 4576 | |
4582 | /* | | 4577 | /* |
4583 | * Remove a directory file. | | 4578 | * Remove a directory file. |
4584 | */ | | 4579 | */ |
4585 | /* ARGSUSED */ | | 4580 | /* ARGSUSED */ |
4586 | int | | 4581 | int |
4587 | sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval) | | 4582 | sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval) |
4588 | { | | 4583 | { |
4589 | return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path), | | 4584 | return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path), |
4590 | AT_REMOVEDIR, UIO_USERSPACE); | | 4585 | AT_REMOVEDIR, UIO_USERSPACE); |
4591 | } | | 4586 | } |
4592 | | | 4587 | |
4593 | /* | | 4588 | /* |
4594 | * Read a block of directory entries in a file system independent format. | | 4589 | * Read a block of directory entries in a file system independent format. |
4595 | */ | | 4590 | */ |
4596 | int | | 4591 | int |
4597 | sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval) | | 4592 | sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval) |
4598 | { | | 4593 | { |
4599 | /* { | | 4594 | /* { |
4600 | syscallarg(int) fd; | | 4595 | syscallarg(int) fd; |
4601 | syscallarg(char *) buf; | | 4596 | syscallarg(char *) buf; |
4602 | syscallarg(size_t) count; | | 4597 | syscallarg(size_t) count; |
4603 | } */ | | 4598 | } */ |
4604 | file_t *fp; | | 4599 | file_t *fp; |
4605 | int error, done; | | 4600 | int error, done; |
4606 | | | 4601 | |
4607 | /* fd_getvnode() will use the descriptor for us */ | | 4602 | /* fd_getvnode() will use the descriptor for us */ |
4608 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 4603 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
4609 | return (error); | | 4604 | return (error); |
4610 | if ((fp->f_flag & FREAD) == 0) { | | 4605 | if ((fp->f_flag & FREAD) == 0) { |
4611 | error = EBADF; | | 4606 | error = EBADF; |
4612 | goto out; | | 4607 | goto out; |
4613 | } | | 4608 | } |
4614 | error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE, | | 4609 | error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE, |
4615 | SCARG(uap, count), &done, l, 0, 0); | | 4610 | SCARG(uap, count), &done, l, 0, 0); |
4616 | ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error); | | 4611 | ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error); |
4617 | *retval = done; | | 4612 | *retval = done; |
4618 | out: | | 4613 | out: |
4619 | fd_putfile(SCARG(uap, fd)); | | 4614 | fd_putfile(SCARG(uap, fd)); |
4620 | return (error); | | 4615 | return (error); |
4621 | } | | 4616 | } |
4622 | | | 4617 | |
4623 | /* | | 4618 | /* |
4624 | * Set the mode mask for creation of filesystem nodes. | | 4619 | * Set the mode mask for creation of filesystem nodes. |
4625 | */ | | 4620 | */ |
4626 | int | | 4621 | int |
4627 | sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval) | | 4622 | sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval) |
4628 | { | | 4623 | { |
4629 | /* { | | 4624 | /* { |
4630 | syscallarg(mode_t) newmask; | | 4625 | syscallarg(mode_t) newmask; |
4631 | } */ | | 4626 | } */ |
4632 | struct proc *p = l->l_proc; | | 4627 | struct proc *p = l->l_proc; |
4633 | struct cwdinfo *cwdi; | | 4628 | struct cwdinfo *cwdi; |
4634 | | | 4629 | |
4635 | /* | | 4630 | /* |
4636 | * cwdi->cwdi_cmask will be read unlocked elsewhere. What's | | 4631 | * cwdi->cwdi_cmask will be read unlocked elsewhere. What's |
4637 | * important is that we serialize changes to the mask. The | | 4632 | * important is that we serialize changes to the mask. The |
4638 | * rw_exit() will issue a write memory barrier on our behalf, | | 4633 | * rw_exit() will issue a write memory barrier on our behalf, |
4639 | * and force the changes out to other CPUs (as it must use an | | 4634 | * and force the changes out to other CPUs (as it must use an |
4640 | * atomic operation, draining the local CPU's store buffers). | | 4635 | * atomic operation, draining the local CPU's store buffers). |
4641 | */ | | 4636 | */ |
4642 | cwdi = p->p_cwdi; | | 4637 | cwdi = p->p_cwdi; |
4643 | rw_enter(&cwdi->cwdi_lock, RW_WRITER); | | 4638 | rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
4644 | *retval = cwdi->cwdi_cmask; | | 4639 | *retval = cwdi->cwdi_cmask; |
4645 | cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS; | | 4640 | cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS; |
4646 | rw_exit(&cwdi->cwdi_lock); | | 4641 | rw_exit(&cwdi->cwdi_lock); |
4647 | | | 4642 | |
4648 | return (0); | | 4643 | return (0); |
4649 | } | | 4644 | } |
4650 | | | 4645 | |
4651 | int | | 4646 | int |
4652 | dorevoke(struct vnode *vp, kauth_cred_t cred) | | 4647 | dorevoke(struct vnode *vp, kauth_cred_t cred) |
4653 | { | | 4648 | { |
4654 | struct vattr vattr; | | 4649 | struct vattr vattr; |
4655 | int error, fs_decision; | | 4650 | int error, fs_decision; |
4656 | | | 4651 | |
4657 | vn_lock(vp, LK_SHARED | LK_RETRY); | | 4652 | vn_lock(vp, LK_SHARED | LK_RETRY); |
4658 | error = VOP_GETATTR(vp, &vattr, cred); | | 4653 | error = VOP_GETATTR(vp, &vattr, cred); |
4659 | VOP_UNLOCK(vp); | | 4654 | VOP_UNLOCK(vp); |
4660 | if (error != 0) | | 4655 | if (error != 0) |
4661 | return error; | | 4656 | return error; |
4662 | fs_decision = (kauth_cred_geteuid(cred) == vattr.va_uid) ? 0 : EPERM; | | 4657 | fs_decision = (kauth_cred_geteuid(cred) == vattr.va_uid) ? 0 : EPERM; |
4663 | error = kauth_authorize_vnode(cred, KAUTH_VNODE_REVOKE, vp, NULL, | | 4658 | error = kauth_authorize_vnode(cred, KAUTH_VNODE_REVOKE, vp, NULL, |
4664 | fs_decision); | | 4659 | fs_decision); |
4665 | if (!error) | | 4660 | if (!error) |
4666 | VOP_REVOKE(vp, REVOKEALL); | | 4661 | VOP_REVOKE(vp, REVOKEALL); |
4667 | return (error); | | 4662 | return (error); |
4668 | } | | 4663 | } |
4669 | | | 4664 | |
4670 | /* | | 4665 | /* |
4671 | * Void all references to file by ripping underlying filesystem | | 4666 | * Void all references to file by ripping underlying filesystem |
4672 | * away from vnode. | | 4667 | * away from vnode. |
4673 | */ | | 4668 | */ |
4674 | /* ARGSUSED */ | | 4669 | /* ARGSUSED */ |
4675 | int | | 4670 | int |
4676 | sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval) | | 4671 | sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval) |
4677 | { | | 4672 | { |
4678 | /* { | | 4673 | /* { |
4679 | syscallarg(const char *) path; | | 4674 | syscallarg(const char *) path; |
4680 | } */ | | 4675 | } */ |
4681 | struct vnode *vp; | | 4676 | struct vnode *vp; |
4682 | int error; | | 4677 | int error; |
4683 | | | 4678 | |
4684 | error = namei_simple_user(SCARG(uap, path), | | 4679 | error = namei_simple_user(SCARG(uap, path), |
4685 | NSM_FOLLOW_TRYEMULROOT, &vp); | | 4680 | NSM_FOLLOW_TRYEMULROOT, &vp); |
4686 | if (error != 0) | | 4681 | if (error != 0) |
4687 | return (error); | | 4682 | return (error); |
4688 | error = dorevoke(vp, l->l_cred); | | 4683 | error = dorevoke(vp, l->l_cred); |
4689 | vrele(vp); | | 4684 | vrele(vp); |
4690 | return (error); | | 4685 | return (error); |
4691 | } | | 4686 | } |
4692 | | | 4687 | |
4693 | /* | | 4688 | /* |
4694 | * Allocate backing store for a file, filling a hole without having to | | 4689 | * Allocate backing store for a file, filling a hole without having to |
4695 | * explicitly write anything out. | | 4690 | * explicitly write anything out. |
4696 | */ | | 4691 | */ |
4697 | /* ARGSUSED */ | | 4692 | /* ARGSUSED */ |
4698 | int | | 4693 | int |
4699 | sys_posix_fallocate(struct lwp *l, const struct sys_posix_fallocate_args *uap, | | 4694 | sys_posix_fallocate(struct lwp *l, const struct sys_posix_fallocate_args *uap, |
4700 | register_t *retval) | | 4695 | register_t *retval) |
4701 | { | | 4696 | { |
4702 | /* { | | 4697 | /* { |
4703 | syscallarg(int) fd; | | 4698 | syscallarg(int) fd; |
4704 | syscallarg(off_t) pos; | | 4699 | syscallarg(off_t) pos; |
4705 | syscallarg(off_t) len; | | 4700 | syscallarg(off_t) len; |
4706 | } */ | | 4701 | } */ |
4707 | int fd; | | 4702 | int fd; |
4708 | off_t pos, len; | | 4703 | off_t pos, len; |
4709 | struct file *fp; | | 4704 | struct file *fp; |
4710 | struct vnode *vp; | | 4705 | struct vnode *vp; |
4711 | int error; | | 4706 | int error; |
4712 | | | 4707 | |
4713 | fd = SCARG(uap, fd); | | 4708 | fd = SCARG(uap, fd); |
4714 | pos = SCARG(uap, pos); | | 4709 | pos = SCARG(uap, pos); |
4715 | len = SCARG(uap, len); | | 4710 | len = SCARG(uap, len); |
4716 | | | 4711 | |
4717 | if (pos < 0 || len < 0 || len > OFF_T_MAX - pos) { | | 4712 | if (pos < 0 || len < 0 || len > OFF_T_MAX - pos) { |
4718 | *retval = EINVAL; | | 4713 | *retval = EINVAL; |
4719 | return 0; | | 4714 | return 0; |
4720 | } | | 4715 | } |
4721 | | | 4716 | |
4722 | error = fd_getvnode(fd, &fp); | | 4717 | error = fd_getvnode(fd, &fp); |
4723 | if (error) { | | 4718 | if (error) { |
4724 | *retval = error; | | 4719 | *retval = error; |
4725 | return 0; | | 4720 | return 0; |
4726 | } | | 4721 | } |
4727 | if ((fp->f_flag & FWRITE) == 0) { | | 4722 | if ((fp->f_flag & FWRITE) == 0) { |
4728 | error = EBADF; | | 4723 | error = EBADF; |
4729 | goto fail; | | 4724 | goto fail; |
4730 | } | | 4725 | } |
4731 | vp = fp->f_vnode; | | 4726 | vp = fp->f_vnode; |
4732 | | | 4727 | |
4733 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 4728 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
4734 | if (vp->v_type == VDIR) { | | 4729 | if (vp->v_type == VDIR) { |
4735 | error = EISDIR; | | 4730 | error = EISDIR; |
4736 | } else { | | 4731 | } else { |
4737 | error = VOP_FALLOCATE(vp, pos, len); | | 4732 | error = VOP_FALLOCATE(vp, pos, len); |
4738 | } | | 4733 | } |
4739 | VOP_UNLOCK(vp); | | 4734 | VOP_UNLOCK(vp); |
4740 | | | 4735 | |
4741 | fail: | | 4736 | fail: |
4742 | fd_putfile(fd); | | 4737 | fd_putfile(fd); |
4743 | *retval = error; | | 4738 | *retval = error; |
4744 | return 0; | | 4739 | return 0; |
4745 | } | | 4740 | } |
4746 | | | 4741 | |
4747 | /* | | 4742 | /* |
4748 | * Deallocate backing store for a file, creating a hole. Also used for | | 4743 | * Deallocate backing store for a file, creating a hole. Also used for |
4749 | * invoking TRIM on disks. | | 4744 | * invoking TRIM on disks. |
4750 | */ | | 4745 | */ |
4751 | /* ARGSUSED */ | | 4746 | /* ARGSUSED */ |
4752 | int | | 4747 | int |
4753 | sys_fdiscard(struct lwp *l, const struct sys_fdiscard_args *uap, | | 4748 | sys_fdiscard(struct lwp *l, const struct sys_fdiscard_args *uap, |
4754 | register_t *retval) | | 4749 | register_t *retval) |
4755 | { | | 4750 | { |
4756 | /* { | | 4751 | /* { |
4757 | syscallarg(int) fd; | | 4752 | syscallarg(int) fd; |
4758 | syscallarg(off_t) pos; | | 4753 | syscallarg(off_t) pos; |
4759 | syscallarg(off_t) len; | | 4754 | syscallarg(off_t) len; |
4760 | } */ | | 4755 | } */ |
4761 | int fd; | | 4756 | int fd; |
4762 | off_t pos, len; | | 4757 | off_t pos, len; |
4763 | struct file *fp; | | 4758 | struct file *fp; |
4764 | struct vnode *vp; | | 4759 | struct vnode *vp; |
4765 | int error; | | 4760 | int error; |
4766 | | | 4761 | |
4767 | fd = SCARG(uap, fd); | | 4762 | fd = SCARG(uap, fd); |
4768 | pos = SCARG(uap, pos); | | 4763 | pos = SCARG(uap, pos); |
4769 | len = SCARG(uap, len); | | 4764 | len = SCARG(uap, len); |
4770 | | | 4765 | |
4771 | if (pos < 0 || len < 0 || len > OFF_T_MAX - pos) { | | 4766 | if (pos < 0 || len < 0 || len > OFF_T_MAX - pos) { |
4772 | return EINVAL; | | 4767 | return EINVAL; |
4773 | } | | 4768 | } |
4774 | | | 4769 | |
4775 | error = fd_getvnode(fd, &fp); | | 4770 | error = fd_getvnode(fd, &fp); |
4776 | if (error) { | | 4771 | if (error) { |
4777 | return error; | | 4772 | return error; |
4778 | } | | 4773 | } |
4779 | if ((fp->f_flag & FWRITE) == 0) { | | 4774 | if ((fp->f_flag & FWRITE) == 0) { |
4780 | error = EBADF; | | 4775 | error = EBADF; |
4781 | goto fail; | | 4776 | goto fail; |
4782 | } | | 4777 | } |
4783 | vp = fp->f_vnode; | | 4778 | vp = fp->f_vnode; |
4784 | | | 4779 | |
4785 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | | 4780 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
4786 | if (vp->v_type == VDIR) { | | 4781 | if (vp->v_type == VDIR) { |
4787 | error = EISDIR; | | 4782 | error = EISDIR; |
4788 | } else { | | 4783 | } else { |
4789 | error = VOP_FDISCARD(vp, pos, len); | | 4784 | error = VOP_FDISCARD(vp, pos, len); |
4790 | } | | 4785 | } |
4791 | VOP_UNLOCK(vp); | | 4786 | VOP_UNLOCK(vp); |
4792 | | | 4787 | |
4793 | fail: | | 4788 | fail: |
4794 | fd_putfile(fd); | | 4789 | fd_putfile(fd); |
4795 | return error; | | 4790 | return error; |
4796 | } | | 4791 | } |