vfs_syscalls_43.c revision 1.54.20.1 1 /* $NetBSD: vfs_syscalls_43.c,v 1.54.20.1 2016/08/27 14:51:50 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.20.1 2016/08/27 14:51:50 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/syslog.h>
62 #include <sys/unistd.h>
63 #include <sys/resourcevar.h>
64 #include <sys/sysctl.h>
65
66 #include <sys/mount.h>
67 #include <sys/syscallargs.h>
68 #include <sys/vfs_syscalls.h>
69
70 #include <compat/sys/stat.h>
71 #include <compat/sys/mount.h>
72
73 #include <compat/common/compat_util.h>
74
75 static void cvttimespec(struct timespec *, struct timespec50 *);
76 static void cvtstat(struct stat *, struct stat43 *);
77
78 /*
79 * Convert from an old to a new timespec structure.
80 */
81 static void
82 cvttimespec(struct timespec *ts, struct timespec50 *ots)
83 {
84
85 if (ts->tv_sec > INT_MAX) {
86 #if defined(DEBUG) || 1
87 static bool first = true;
88
89 if (first) {
90 first = false;
91 printf("%s[%s:%d]: time_t does not fit\n",
92 __func__, curlwp->l_proc->p_comm,
93 curlwp->l_lid);
94 }
95 #endif
96 ots->tv_sec = INT_MAX;
97 } else
98 ots->tv_sec = ts->tv_sec;
99 ots->tv_nsec = ts->tv_nsec;
100 }
101
102 /*
103 * Convert from an old to a new stat structure.
104 */
105 static void
106 cvtstat(struct stat *st, struct stat43 *ost)
107 {
108
109 /* Handle any padding. */
110 memset(ost, 0, sizeof *ost);
111 ost->st_dev = st->st_dev;
112 ost->st_ino = st->st_ino;
113 ost->st_mode = st->st_mode & 0xffff;
114 ost->st_nlink = st->st_nlink;
115 ost->st_uid = st->st_uid;
116 ost->st_gid = st->st_gid;
117 ost->st_rdev = st->st_rdev;
118 if (st->st_size < (quad_t)1 << 32)
119 ost->st_size = st->st_size;
120 else
121 ost->st_size = -2;
122 cvttimespec(&st->st_atimespec, &ost->st_atimespec);
123 cvttimespec(&st->st_mtimespec, &ost->st_mtimespec);
124 cvttimespec(&st->st_ctimespec, &ost->st_ctimespec);
125 ost->st_blksize = st->st_blksize;
126 ost->st_blocks = st->st_blocks;
127 ost->st_flags = st->st_flags;
128 ost->st_gen = st->st_gen;
129 }
130
131 /*
132 * Get file status; this version follows links.
133 */
134 /* ARGSUSED */
135 int
136 compat_43_sys_stat(struct lwp *l, const struct compat_43_sys_stat_args *uap, register_t *retval)
137 {
138 /* {
139 syscallarg(char *) path;
140 syscallarg(struct stat43 *) ub;
141 } */
142 struct stat sb;
143 struct stat43 osb;
144 int error;
145
146 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
147 if (error)
148 return (error);
149 cvtstat(&sb, &osb);
150 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
151 return (error);
152 }
153
154 /*
155 * Get file status; this version does not follow links.
156 */
157 /* ARGSUSED */
158 int
159 compat_43_sys_lstat(struct lwp *l, const struct compat_43_sys_lstat_args *uap, register_t *retval)
160 {
161 /* {
162 syscallarg(char *) path;
163 syscallarg(struct ostat *) ub;
164 } */
165 struct vnode *vp, *dvp;
166 struct stat sb, sb1;
167 struct stat43 osb;
168 int error;
169 struct pathbuf *pb;
170 struct nameidata nd;
171 int ndflags;
172
173 error = pathbuf_copyin(SCARG(uap, path), &pb);
174 if (error) {
175 return error;
176 }
177
178 ndflags = NOFOLLOW | LOCKLEAF | LOCKPARENT | TRYEMULROOT;
179 again:
180 NDINIT(&nd, LOOKUP, ndflags, pb);
181 if ((error = namei(&nd))) {
182 if (error == EISDIR && (ndflags & LOCKPARENT) != 0) {
183 /*
184 * Should only happen on '/'. Retry without LOCKPARENT;
185 * this is safe since the vnode won't be a VLNK.
186 */
187 ndflags &= ~LOCKPARENT;
188 goto again;
189 }
190 pathbuf_destroy(pb);
191 return (error);
192 }
193 /*
194 * For symbolic links, always return the attributes of its
195 * containing directory, except for mode, size, and links.
196 */
197 vp = nd.ni_vp;
198 dvp = nd.ni_dvp;
199 pathbuf_destroy(pb);
200 if (vp->v_type != VLNK) {
201 if ((ndflags & LOCKPARENT) != 0) {
202 if (dvp == vp)
203 vrele(dvp);
204 else
205 vput(dvp);
206 }
207 error = vn_stat(vp, &sb);
208 vput(vp);
209 if (error)
210 return (error);
211 } else {
212 error = vn_stat(dvp, &sb);
213 vput(dvp);
214 if (error) {
215 vput(vp);
216 return (error);
217 }
218 error = vn_stat(vp, &sb1);
219 vput(vp);
220 if (error)
221 return (error);
222 sb.st_mode &= ~S_IFDIR;
223 sb.st_mode |= S_IFLNK;
224 sb.st_nlink = sb1.st_nlink;
225 sb.st_size = sb1.st_size;
226 sb.st_blocks = sb1.st_blocks;
227 }
228 cvtstat(&sb, &osb);
229 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
230 return (error);
231 }
232
233 /*
234 * Return status information about a file descriptor.
235 */
236 /* ARGSUSED */
237 int
238 compat_43_sys_fstat(struct lwp *l, const struct compat_43_sys_fstat_args *uap, register_t *retval)
239 {
240 /* {
241 syscallarg(int) fd;
242 syscallarg(struct stat43 *) sb;
243 } */
244 struct stat ub;
245 struct stat43 oub;
246 int error;
247
248 error = do_sys_fstat(SCARG(uap, fd), &ub);
249 if (error == 0) {
250 cvtstat(&ub, &oub);
251 error = copyout((void *)&oub, (void *)SCARG(uap, sb),
252 sizeof (oub));
253 }
254
255 return (error);
256 }
257
258
259 /*
260 * Truncate a file given a file descriptor.
261 */
262 /* ARGSUSED */
263 int
264 compat_43_sys_ftruncate(struct lwp *l, const struct compat_43_sys_ftruncate_args *uap, register_t *retval)
265 {
266 /* {
267 syscallarg(int) fd;
268 syscallarg(long) length;
269 } */
270 struct sys_ftruncate_args /* {
271 syscallarg(int) fd;
272 syscallarg(int) pad;
273 syscallarg(off_t) length;
274 } */ nuap;
275
276 SCARG(&nuap, fd) = SCARG(uap, fd);
277 SCARG(&nuap, length) = SCARG(uap, length);
278 return (sys_ftruncate(l, &nuap, retval));
279 }
280
281 /*
282 * Truncate a file given its path name.
283 */
284 /* ARGSUSED */
285 int
286 compat_43_sys_truncate(struct lwp *l, const struct compat_43_sys_truncate_args *uap, register_t *retval)
287 {
288 /* {
289 syscallarg(char *) path;
290 syscallarg(long) length;
291 } */
292 struct sys_truncate_args /* {
293 syscallarg(char *) path;
294 syscallarg(int) pad;
295 syscallarg(off_t) length;
296 } */ nuap;
297
298 SCARG(&nuap, path) = SCARG(uap, path);
299 SCARG(&nuap, length) = SCARG(uap, length);
300 return (sys_truncate(l, &nuap, retval));
301 }
302
303
304 /*
305 * Reposition read/write file offset.
306 */
307 int
308 compat_43_sys_lseek(struct lwp *l, const struct compat_43_sys_lseek_args *uap, register_t *retval)
309 {
310 /* {
311 syscallarg(int) fd;
312 syscallarg(long) offset;
313 syscallarg(int) whence;
314 } */
315 struct sys_lseek_args /* {
316 syscallarg(int) fd;
317 syscallarg(int) pad;
318 syscallarg(off_t) offset;
319 syscallarg(int) whence;
320 } */ nuap;
321 off_t qret;
322 int error;
323
324 SCARG(&nuap, fd) = SCARG(uap, fd);
325 SCARG(&nuap, offset) = SCARG(uap, offset);
326 SCARG(&nuap, whence) = SCARG(uap, whence);
327 error = sys_lseek(l, &nuap, (void *)&qret);
328 *(long *)retval = qret;
329 return (error);
330 }
331
332
333 /*
334 * Create a file.
335 */
336 int
337 compat_43_sys_creat(struct lwp *l, const struct compat_43_sys_creat_args *uap, register_t *retval)
338 {
339 /* {
340 syscallarg(char *) path;
341 syscallarg(int) mode;
342 } */
343 struct sys_open_args /* {
344 syscallarg(char *) path;
345 syscallarg(int) flags;
346 syscallarg(int) mode;
347 } */ nuap;
348
349 SCARG(&nuap, path) = SCARG(uap, path);
350 SCARG(&nuap, mode) = SCARG(uap, mode);
351 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
352 return (sys_open(l, &nuap, retval));
353 }
354
355 /*ARGSUSED*/
356 int
357 compat_43_sys_quota(struct lwp *l, const void *v, register_t *retval)
358 {
359
360 return (ENOSYS);
361 }
362
363
364 /*
365 * Read a block of directory entries in a file system independent format.
366 */
367 int
368 compat_43_sys_getdirentries(struct lwp *l, const struct compat_43_sys_getdirentries_args *uap, register_t *retval)
369 {
370 /* {
371 syscallarg(int) fd;
372 syscallarg(char *) buf;
373 syscallarg(u_int) count;
374 syscallarg(long *) basep;
375 } */
376 struct vnode *vp;
377 struct file *fp;
378 struct uio auio, kuio;
379 struct iovec aiov, kiov;
380 struct dirent *dp, *edp;
381 char *dirbuf;
382 size_t count = min(MAXBSIZE, (size_t)SCARG(uap, count));
383
384 int error, eofflag, readcnt;
385 long loff;
386
387 /* fd_getvnode() will use the descriptor for us */
388 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
389 return (error);
390 if ((fp->f_flag & FREAD) == 0) {
391 error = EBADF;
392 goto out;
393 }
394 vp = (struct vnode *)fp->f_data;
395 unionread:
396 if (vp->v_type != VDIR) {
397 error = EINVAL;
398 goto out;
399 }
400 aiov.iov_base = SCARG(uap, buf);
401 aiov.iov_len = count;
402 auio.uio_iov = &aiov;
403 auio.uio_iovcnt = 1;
404 auio.uio_rw = UIO_READ;
405 auio.uio_resid = count;
406 KASSERT(l == curlwp);
407 auio.uio_vmspace = curproc->p_vmspace;
408 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
409 loff = auio.uio_offset = fp->f_offset;
410 # if (BYTE_ORDER != LITTLE_ENDIAN)
411 if ((vp->v_mount->mnt_iflag & IMNT_DTYPE) == 0) {
412 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
413 (off_t **)0, (int *)0);
414 fp->f_offset = auio.uio_offset;
415 } else
416 # endif
417 {
418 kuio = auio;
419 kuio.uio_iov = &kiov;
420 kiov.iov_len = count;
421 dirbuf = malloc(count, M_TEMP, M_WAITOK);
422 kiov.iov_base = dirbuf;
423 UIO_SETUP_SYSSPACE(&kuio);
424 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
425 (off_t **)0, (int *)0);
426 fp->f_offset = kuio.uio_offset;
427 if (error == 0) {
428 readcnt = count - kuio.uio_resid;
429 edp = (struct dirent *)&dirbuf[readcnt];
430 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
431 # if (BYTE_ORDER == LITTLE_ENDIAN)
432 /*
433 * The expected low byte of
434 * dp->d_namlen is our dp->d_type.
435 * The high MBZ byte of dp->d_namlen
436 * is our dp->d_namlen.
437 */
438 dp->d_type = dp->d_namlen;
439 dp->d_namlen = 0;
440 # else
441 /*
442 * The dp->d_type is the high byte
443 * of the expected dp->d_namlen,
444 * so must be zero'ed.
445 */
446 dp->d_type = 0;
447 # endif
448 if (dp->d_reclen > 0) {
449 dp = (struct dirent *)
450 ((char *)dp + dp->d_reclen);
451 } else {
452 error = EIO;
453 break;
454 }
455 }
456 if (dp >= edp)
457 error = uiomove(dirbuf, readcnt, &auio);
458 }
459 free(dirbuf, M_TEMP);
460 }
461 VOP_UNLOCK(vp);
462 if (error)
463 goto out;
464
465 if ((count == auio.uio_resid) &&
466 (vp->v_vflag & VV_ROOT) &&
467 (vp->v_mount->mnt_flag & MNT_UNION)) {
468 struct vnode *tvp = vp;
469 vp = vp->v_mount->mnt_vnodecovered;
470 vref(vp);
471 fp->f_data = (void *) vp;
472 fp->f_offset = 0;
473 vrele(tvp);
474 goto unionread;
475 }
476 error = copyout((void *)&loff, (void *)SCARG(uap, basep),
477 sizeof(long));
478 *retval = count - auio.uio_resid;
479 out:
480 fd_putfile(SCARG(uap, fd));
481 return (error);
482 }
483
484 /*
485 * sysctl helper routine for vfs.generic.conf lookups.
486 */
487 #if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44)
488 static struct sysctllog *compat_clog;
489
490 static int
491 sysctl_vfs_generic_conf(SYSCTLFN_ARGS)
492 {
493 struct vfsconf vfc;
494 extern const char * const mountcompatnames[];
495 extern int nmountcompatnames;
496 struct sysctlnode node;
497 struct vfsops *vfsp;
498 u_int vfsnum;
499
500 if (namelen != 1)
501 return (ENOTDIR);
502 vfsnum = name[0];
503 if (vfsnum >= nmountcompatnames ||
504 mountcompatnames[vfsnum] == NULL)
505 return (EOPNOTSUPP);
506 vfsp = vfs_getopsbyname(mountcompatnames[vfsnum]);
507 if (vfsp == NULL)
508 return (EOPNOTSUPP);
509
510 vfc.vfc_vfsops = vfsp;
511 strncpy(vfc.vfc_name, vfsp->vfs_name, sizeof(vfc.vfc_name));
512 vfc.vfc_typenum = vfsnum;
513 vfc.vfc_refcount = vfsp->vfs_refcount;
514 vfc.vfc_flags = 0;
515 vfc.vfc_mountroot = vfsp->vfs_mountroot;
516 vfc.vfc_next = NULL;
517 vfs_delref(vfsp);
518
519 node = *rnode;
520 node.sysctl_data = &vfc;
521 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
522 }
523
524 /*
525 * Top level filesystem related information gathering.
526 */
527 void
528 compat_sysctl_init(void)
529 {
530 extern int nmountcompatnames;
531
532 sysctl_createv(&compat_clog, 0, NULL, NULL,
533 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
534 CTLTYPE_INT, "maxtypenum",
535 SYSCTL_DESCR("Highest valid filesystem type number"),
536 NULL, nmountcompatnames, NULL, 0,
537 CTL_VFS, VFS_GENERIC, VFS_MAXTYPENUM, CTL_EOL);
538 sysctl_createv(&compat_clog, 0, NULL, NULL,
539 CTLFLAG_PERMANENT,
540 CTLTYPE_STRUCT, "conf",
541 SYSCTL_DESCR("Filesystem configuration information"),
542 sysctl_vfs_generic_conf, 0, NULL,
543 sizeof(struct vfsconf),
544 CTL_VFS, VFS_GENERIC, VFS_CONF, CTL_EOL);
545 }
546
547 void
548 compat_sysctl_fini(void)
549 {
550
551 sysctl_teardown(&compat_clog);
552 }
553 #endif
554