vfs_syscalls_43.c revision 1.54.14.1.2.1 1 /* $NetBSD: vfs_syscalls_43.c,v 1.54.14.1.2.1 2016/08/27 14:52:25 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_43.c,v 1.54.14.1.2.1 2016/08/27 14:52:25 bouyer Exp $");
41
42 #if defined(_KERNEL_OPT)
43 #include "opt_compat_netbsd.h"
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/filedesc.h>
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51 #include <sys/file.h>
52 #include <sys/vnode.h>
53 #include <sys/namei.h>
54 #include <sys/dirent.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/stat.h>
58 #include <sys/malloc.h>
59 #include <sys/ioctl.h>
60 #include <sys/fcntl.h>
61 #include <sys/sysctl.h>
62 #include <sys/syslog.h>
63 #include <sys/unistd.h>
64 #include <sys/resourcevar.h>
65 #include <sys/sysctl.h>
66
67 #include <sys/mount.h>
68 #include <sys/syscallargs.h>
69 #include <sys/vfs_syscalls.h>
70
71 #include <compat/sys/stat.h>
72 #include <compat/sys/mount.h>
73
74 #include <compat/common/compat_util.h>
75 #include <compat/common/compat_mod.h>
76
77 static void cvttimespec(struct timespec *, struct timespec50 *);
78 static void cvtstat(struct stat *, struct stat43 *);
79
80 /*
81 * Convert from an old to a new timespec structure.
82 */
83 static void
84 cvttimespec(struct timespec *ts, struct timespec50 *ots)
85 {
86
87 if (ts->tv_sec > INT_MAX) {
88 #if defined(DEBUG) || 1
89 static bool first = true;
90
91 if (first) {
92 first = false;
93 printf("%s[%s:%d]: time_t does not fit\n",
94 __func__, curlwp->l_proc->p_comm,
95 curlwp->l_lid);
96 }
97 #endif
98 ots->tv_sec = INT_MAX;
99 } else
100 ots->tv_sec = ts->tv_sec;
101 ots->tv_nsec = ts->tv_nsec;
102 }
103
104 /*
105 * Convert from an old to a new stat structure.
106 */
107 static void
108 cvtstat(struct stat *st, struct stat43 *ost)
109 {
110
111 /* Handle any padding. */
112 memset(ost, 0, sizeof *ost);
113 ost->st_dev = st->st_dev;
114 ost->st_ino = st->st_ino;
115 ost->st_mode = st->st_mode & 0xffff;
116 ost->st_nlink = st->st_nlink;
117 ost->st_uid = st->st_uid;
118 ost->st_gid = st->st_gid;
119 ost->st_rdev = st->st_rdev;
120 if (st->st_size < (quad_t)1 << 32)
121 ost->st_size = st->st_size;
122 else
123 ost->st_size = -2;
124 cvttimespec(&st->st_atimespec, &ost->st_atimespec);
125 cvttimespec(&st->st_mtimespec, &ost->st_mtimespec);
126 cvttimespec(&st->st_ctimespec, &ost->st_ctimespec);
127 ost->st_blksize = st->st_blksize;
128 ost->st_blocks = st->st_blocks;
129 ost->st_flags = st->st_flags;
130 ost->st_gen = st->st_gen;
131 }
132
133 /*
134 * Get file status; this version follows links.
135 */
136 /* ARGSUSED */
137 int
138 compat_43_sys_stat(struct lwp *l, const struct compat_43_sys_stat_args *uap, register_t *retval)
139 {
140 /* {
141 syscallarg(char *) path;
142 syscallarg(struct stat43 *) ub;
143 } */
144 struct stat sb;
145 struct stat43 osb;
146 int error;
147
148 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
149 if (error)
150 return (error);
151 cvtstat(&sb, &osb);
152 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
153 return (error);
154 }
155
156 /*
157 * Get file status; this version does not follow links.
158 */
159 /* ARGSUSED */
160 int
161 compat_43_sys_lstat(struct lwp *l, const struct compat_43_sys_lstat_args *uap, register_t *retval)
162 {
163 /* {
164 syscallarg(char *) path;
165 syscallarg(struct ostat *) ub;
166 } */
167 struct vnode *vp, *dvp;
168 struct stat sb, sb1;
169 struct stat43 osb;
170 int error;
171 struct pathbuf *pb;
172 struct nameidata nd;
173 int ndflags;
174
175 error = pathbuf_copyin(SCARG(uap, path), &pb);
176 if (error) {
177 return error;
178 }
179
180 ndflags = NOFOLLOW | LOCKLEAF | LOCKPARENT | TRYEMULROOT;
181 again:
182 NDINIT(&nd, LOOKUP, ndflags, pb);
183 if ((error = namei(&nd))) {
184 if (error == EISDIR && (ndflags & LOCKPARENT) != 0) {
185 /*
186 * Should only happen on '/'. Retry without LOCKPARENT;
187 * this is safe since the vnode won't be a VLNK.
188 */
189 ndflags &= ~LOCKPARENT;
190 goto again;
191 }
192 pathbuf_destroy(pb);
193 return (error);
194 }
195 /*
196 * For symbolic links, always return the attributes of its
197 * containing directory, except for mode, size, and links.
198 */
199 vp = nd.ni_vp;
200 dvp = nd.ni_dvp;
201 pathbuf_destroy(pb);
202 if (vp->v_type != VLNK) {
203 if ((ndflags & LOCKPARENT) != 0) {
204 if (dvp == vp)
205 vrele(dvp);
206 else
207 vput(dvp);
208 }
209 error = vn_stat(vp, &sb);
210 vput(vp);
211 if (error)
212 return (error);
213 } else {
214 error = vn_stat(dvp, &sb);
215 vput(dvp);
216 if (error) {
217 vput(vp);
218 return (error);
219 }
220 error = vn_stat(vp, &sb1);
221 vput(vp);
222 if (error)
223 return (error);
224 sb.st_mode &= ~S_IFDIR;
225 sb.st_mode |= S_IFLNK;
226 sb.st_nlink = sb1.st_nlink;
227 sb.st_size = sb1.st_size;
228 sb.st_blocks = sb1.st_blocks;
229 }
230 cvtstat(&sb, &osb);
231 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
232 return (error);
233 }
234
235 /*
236 * Return status information about a file descriptor.
237 */
238 /* ARGSUSED */
239 int
240 compat_43_sys_fstat(struct lwp *l, const struct compat_43_sys_fstat_args *uap, register_t *retval)
241 {
242 /* {
243 syscallarg(int) fd;
244 syscallarg(struct stat43 *) sb;
245 } */
246 struct stat ub;
247 struct stat43 oub;
248 int error;
249
250 error = do_sys_fstat(SCARG(uap, fd), &ub);
251 if (error == 0) {
252 cvtstat(&ub, &oub);
253 error = copyout((void *)&oub, (void *)SCARG(uap, sb),
254 sizeof (oub));
255 }
256
257 return (error);
258 }
259
260
261 /*
262 * Truncate a file given a file descriptor.
263 */
264 /* ARGSUSED */
265 int
266 compat_43_sys_ftruncate(struct lwp *l, const struct compat_43_sys_ftruncate_args *uap, register_t *retval)
267 {
268 /* {
269 syscallarg(int) fd;
270 syscallarg(long) length;
271 } */
272 struct sys_ftruncate_args /* {
273 syscallarg(int) fd;
274 syscallarg(int) pad;
275 syscallarg(off_t) length;
276 } */ nuap;
277
278 SCARG(&nuap, fd) = SCARG(uap, fd);
279 SCARG(&nuap, length) = SCARG(uap, length);
280 return (sys_ftruncate(l, &nuap, retval));
281 }
282
283 /*
284 * Truncate a file given its path name.
285 */
286 /* ARGSUSED */
287 int
288 compat_43_sys_truncate(struct lwp *l, const struct compat_43_sys_truncate_args *uap, register_t *retval)
289 {
290 /* {
291 syscallarg(char *) path;
292 syscallarg(long) length;
293 } */
294 struct sys_truncate_args /* {
295 syscallarg(char *) path;
296 syscallarg(int) pad;
297 syscallarg(off_t) length;
298 } */ nuap;
299
300 SCARG(&nuap, path) = SCARG(uap, path);
301 SCARG(&nuap, length) = SCARG(uap, length);
302 return (sys_truncate(l, &nuap, retval));
303 }
304
305
306 /*
307 * Reposition read/write file offset.
308 */
309 int
310 compat_43_sys_lseek(struct lwp *l, const struct compat_43_sys_lseek_args *uap, register_t *retval)
311 {
312 /* {
313 syscallarg(int) fd;
314 syscallarg(long) offset;
315 syscallarg(int) whence;
316 } */
317 struct sys_lseek_args /* {
318 syscallarg(int) fd;
319 syscallarg(int) pad;
320 syscallarg(off_t) offset;
321 syscallarg(int) whence;
322 } */ nuap;
323 off_t qret;
324 int error;
325
326 SCARG(&nuap, fd) = SCARG(uap, fd);
327 SCARG(&nuap, offset) = SCARG(uap, offset);
328 SCARG(&nuap, whence) = SCARG(uap, whence);
329 error = sys_lseek(l, &nuap, (void *)&qret);
330 *(long *)retval = qret;
331 return (error);
332 }
333
334
335 /*
336 * Create a file.
337 */
338 int
339 compat_43_sys_creat(struct lwp *l, const struct compat_43_sys_creat_args *uap, register_t *retval)
340 {
341 /* {
342 syscallarg(char *) path;
343 syscallarg(int) mode;
344 } */
345 struct sys_open_args /* {
346 syscallarg(char *) path;
347 syscallarg(int) flags;
348 syscallarg(int) mode;
349 } */ nuap;
350
351 SCARG(&nuap, path) = SCARG(uap, path);
352 SCARG(&nuap, mode) = SCARG(uap, mode);
353 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
354 return (sys_open(l, &nuap, retval));
355 }
356
357 /*ARGSUSED*/
358 int
359 compat_43_sys_quota(struct lwp *l, const void *v, register_t *retval)
360 {
361
362 return (ENOSYS);
363 }
364
365
366 /*
367 * Read a block of directory entries in a file system independent format.
368 */
369 int
370 compat_43_sys_getdirentries(struct lwp *l, const struct compat_43_sys_getdirentries_args *uap, register_t *retval)
371 {
372 /* {
373 syscallarg(int) fd;
374 syscallarg(char *) buf;
375 syscallarg(u_int) count;
376 syscallarg(long *) basep;
377 } */
378 struct vnode *vp;
379 struct file *fp;
380 struct uio auio, kuio;
381 struct iovec aiov, kiov;
382 struct dirent *dp, *edp;
383 char *dirbuf;
384 size_t count = min(MAXBSIZE, (size_t)SCARG(uap, count));
385
386 int error, eofflag, readcnt;
387 long loff;
388
389 /* fd_getvnode() will use the descriptor for us */
390 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
391 return (error);
392 if ((fp->f_flag & FREAD) == 0) {
393 error = EBADF;
394 goto out;
395 }
396 vp = (struct vnode *)fp->f_data;
397 unionread:
398 if (vp->v_type != VDIR) {
399 error = EINVAL;
400 goto out;
401 }
402 aiov.iov_base = SCARG(uap, buf);
403 aiov.iov_len = count;
404 auio.uio_iov = &aiov;
405 auio.uio_iovcnt = 1;
406 auio.uio_rw = UIO_READ;
407 auio.uio_resid = count;
408 KASSERT(l == curlwp);
409 auio.uio_vmspace = curproc->p_vmspace;
410 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
411 loff = auio.uio_offset = fp->f_offset;
412 # if (BYTE_ORDER != LITTLE_ENDIAN)
413 if ((vp->v_mount->mnt_iflag & IMNT_DTYPE) == 0) {
414 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
415 (off_t **)0, (int *)0);
416 fp->f_offset = auio.uio_offset;
417 } else
418 # endif
419 {
420 kuio = auio;
421 kuio.uio_iov = &kiov;
422 kiov.iov_len = count;
423 dirbuf = malloc(count, M_TEMP, M_WAITOK);
424 kiov.iov_base = dirbuf;
425 UIO_SETUP_SYSSPACE(&kuio);
426 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
427 (off_t **)0, (int *)0);
428 fp->f_offset = kuio.uio_offset;
429 if (error == 0) {
430 readcnt = count - kuio.uio_resid;
431 edp = (struct dirent *)&dirbuf[readcnt];
432 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
433 # if (BYTE_ORDER == LITTLE_ENDIAN)
434 /*
435 * The expected low byte of
436 * dp->d_namlen is our dp->d_type.
437 * The high MBZ byte of dp->d_namlen
438 * is our dp->d_namlen.
439 */
440 dp->d_type = dp->d_namlen;
441 dp->d_namlen = 0;
442 # else
443 /*
444 * The dp->d_type is the high byte
445 * of the expected dp->d_namlen,
446 * so must be zero'ed.
447 */
448 dp->d_type = 0;
449 # endif
450 if (dp->d_reclen > 0) {
451 dp = (struct dirent *)
452 ((char *)dp + dp->d_reclen);
453 } else {
454 error = EIO;
455 break;
456 }
457 }
458 if (dp >= edp)
459 error = uiomove(dirbuf, readcnt, &auio);
460 }
461 free(dirbuf, M_TEMP);
462 }
463 VOP_UNLOCK(vp);
464 if (error)
465 goto out;
466
467 if ((count == auio.uio_resid) &&
468 (vp->v_vflag & VV_ROOT) &&
469 (vp->v_mount->mnt_flag & MNT_UNION)) {
470 struct vnode *tvp = vp;
471 vp = vp->v_mount->mnt_vnodecovered;
472 vref(vp);
473 fp->f_data = (void *) vp;
474 fp->f_offset = 0;
475 vrele(tvp);
476 goto unionread;
477 }
478 error = copyout((void *)&loff, (void *)SCARG(uap, basep),
479 sizeof(long));
480 *retval = count - auio.uio_resid;
481 out:
482 fd_putfile(SCARG(uap, fd));
483 return (error);
484 }
485
486 /*
487 * sysctl helper routine for vfs.generic.conf lookups.
488 */
489 #if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44)
490
491 static int
492 sysctl_vfs_generic_conf(SYSCTLFN_ARGS)
493 {
494 struct vfsconf vfc;
495 extern const char * const mountcompatnames[];
496 extern int nmountcompatnames;
497 struct sysctlnode node;
498 struct vfsops *vfsp;
499 u_int vfsnum;
500
501 if (namelen != 1)
502 return (ENOTDIR);
503 vfsnum = name[0];
504 if (vfsnum >= nmountcompatnames ||
505 mountcompatnames[vfsnum] == NULL)
506 return (EOPNOTSUPP);
507 vfsp = vfs_getopsbyname(mountcompatnames[vfsnum]);
508 if (vfsp == NULL)
509 return (EOPNOTSUPP);
510
511 vfc.vfc_vfsops = vfsp;
512 strncpy(vfc.vfc_name, vfsp->vfs_name, sizeof(vfc.vfc_name));
513 vfc.vfc_typenum = vfsnum;
514 vfc.vfc_refcount = vfsp->vfs_refcount;
515 vfc.vfc_flags = 0;
516 vfc.vfc_mountroot = vfsp->vfs_mountroot;
517 vfc.vfc_next = NULL;
518 vfs_delref(vfsp);
519
520 node = *rnode;
521 node.sysctl_data = &vfc;
522 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
523 }
524
525 /*
526 * Top level filesystem related information gathering.
527 */
528 void
529 compat_sysctl_vfs(struct sysctllog **clog)
530 {
531 extern int nmountcompatnames;
532
533 sysctl_createv(clog, 0, NULL, NULL,
534 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
535 CTLTYPE_INT, "maxtypenum",
536 SYSCTL_DESCR("Highest valid filesystem type number"),
537 NULL, nmountcompatnames, NULL, 0,
538 CTL_VFS, VFS_GENERIC, VFS_MAXTYPENUM, CTL_EOL);
539 sysctl_createv(clog, 0, NULL, NULL,
540 CTLFLAG_PERMANENT,
541 CTLTYPE_STRUCT, "conf",
542 SYSCTL_DESCR("Filesystem configuration information"),
543 sysctl_vfs_generic_conf, 0, NULL,
544 sizeof(struct vfsconf),
545 CTL_VFS, VFS_GENERIC, VFS_CONF, CTL_EOL);
546 }
547 #endif
548