vfs_syscalls_43.c revision 1.62.2.1 1 /* $NetBSD: vfs_syscalls_43.c,v 1.62.2.1 2018/03/31 11:45:33 pgoyette 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.62.2.1 2018/03/31 11:45:33 pgoyette 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
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 #include <compat/sys/dirent.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, (register_t *)&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 dirent *bdp;
379 struct vnode *vp;
380 void *tbuf; /* Current-format */
381 char *inp; /* Current-format */
382 int len, reclen; /* Current-format */
383 char *outp; /* Dirent12-format */
384 int resid, old_reclen = 0; /* Dirent12-format */
385 struct file *fp;
386 struct uio auio;
387 struct iovec aiov;
388 struct dirent43 idb;
389 off_t off; /* true file offset */
390 int buflen, error, eofflag, nbytes;
391 struct vattr va;
392 off_t *cookiebuf = NULL, *cookie;
393 int ncookies;
394 long loff;
395
396 /* fd_getvnode() will use the descriptor for us */
397 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
398 return (error);
399
400 if ((fp->f_flag & FREAD) == 0) {
401 error = EBADF;
402 goto out1;
403 }
404
405 vp = fp->f_vnode;
406 if (vp->v_type != VDIR) {
407 error = ENOTDIR;
408 goto out1;
409 }
410
411 vn_lock(vp, LK_SHARED | LK_RETRY);
412 error = VOP_GETATTR(vp, &va, l->l_cred);
413 VOP_UNLOCK(vp);
414 if (error)
415 goto out1;
416
417 loff = fp->f_offset;
418 nbytes = SCARG(uap, count);
419 buflen = min(MAXBSIZE, nbytes);
420 if (buflen < va.va_blocksize)
421 buflen = va.va_blocksize;
422 tbuf = malloc(buflen, M_TEMP, M_WAITOK);
423
424 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
425 off = fp->f_offset;
426 again:
427 aiov.iov_base = tbuf;
428 aiov.iov_len = buflen;
429 auio.uio_iov = &aiov;
430 auio.uio_iovcnt = 1;
431 auio.uio_rw = UIO_READ;
432 auio.uio_resid = buflen;
433 auio.uio_offset = off;
434 UIO_SETUP_SYSSPACE(&auio);
435 /*
436 * First we read into the malloc'ed buffer, then
437 * we massage it into user space, one record at a time.
438 */
439 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
440 &ncookies);
441 if (error)
442 goto out;
443
444 inp = (char *)tbuf;
445 outp = SCARG(uap, buf);
446 resid = nbytes;
447 if ((len = buflen - auio.uio_resid) == 0)
448 goto eof;
449
450 for (cookie = cookiebuf; len > 0; len -= reclen) {
451 bdp = (struct dirent *)inp;
452 reclen = bdp->d_reclen;
453 if (reclen & 3) {
454 error = EIO;
455 goto out;
456 }
457 if (bdp->d_fileno == 0) {
458 inp += reclen; /* it is a hole; squish it out */
459 if (cookie)
460 off = *cookie++;
461 else
462 off += reclen;
463 continue;
464 }
465 if (bdp->d_namlen >= sizeof(idb.d_name))
466 idb.d_namlen = sizeof(idb.d_name) - 1;
467 else
468 idb.d_namlen = bdp->d_namlen;
469 old_reclen = _DIRENT_RECLEN(&idb, bdp->d_namlen);
470 if (reclen > len || resid < old_reclen) {
471 /* entry too big for buffer, so just stop */
472 outp++;
473 break;
474 }
475 /*
476 * Massage in place to make a Dirent12-shaped dirent (otherwise
477 * we have to worry about touching user memory outside of
478 * the copyout() call).
479 */
480 idb.d_fileno = (uint32_t)bdp->d_fileno;
481 idb.d_reclen = (uint16_t)old_reclen;
482 idb.d_fileno = (uint32_t)bdp->d_fileno;
483 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen);
484 memset(idb.d_name + idb.d_namlen, 0,
485 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen);
486 if ((error = copyout(&idb, outp, old_reclen)))
487 goto out;
488 /* advance past this real entry */
489 inp += reclen;
490 if (cookie)
491 off = *cookie++; /* each entry points to itself */
492 else
493 off += reclen;
494 /* advance output past Dirent12-shaped entry */
495 outp += old_reclen;
496 resid -= old_reclen;
497 }
498
499 /* if we squished out the whole block, try again */
500 if (outp == SCARG(uap, buf)) {
501 if (cookiebuf)
502 free(cookiebuf, M_TEMP);
503 cookiebuf = NULL;
504 goto again;
505 }
506 fp->f_offset = off; /* update the vnode offset */
507
508 eof:
509 *retval = nbytes - resid;
510 out:
511 VOP_UNLOCK(vp);
512 if (cookiebuf)
513 free(cookiebuf, M_TEMP);
514 free(tbuf, M_TEMP);
515 out1:
516 fd_putfile(SCARG(uap, fd));
517 if (error)
518 return error;
519 return copyout(&loff, SCARG(uap, basep), sizeof(long));
520 }
521
522 /*
523 * sysctl helper routine for vfs.generic.conf lookups.
524 */
525 #if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44)
526
527 static int
528 sysctl_vfs_generic_conf(SYSCTLFN_ARGS)
529 {
530 struct vfsconf vfc;
531 struct sysctlnode node;
532 struct vfsops *vfsp;
533 u_int vfsnum;
534
535 if (namelen != 1)
536 return (ENOTDIR);
537 vfsnum = name[0];
538 if (vfsnum >= nmountcompatnames ||
539 mountcompatnames[vfsnum] == NULL)
540 return (EOPNOTSUPP);
541 vfsp = vfs_getopsbyname(mountcompatnames[vfsnum]);
542 if (vfsp == NULL)
543 return (EOPNOTSUPP);
544
545 vfc.vfc_vfsops = vfsp;
546 strncpy(vfc.vfc_name, vfsp->vfs_name, sizeof(vfc.vfc_name));
547 vfc.vfc_typenum = vfsnum;
548 vfc.vfc_refcount = vfsp->vfs_refcount;
549 vfc.vfc_flags = 0;
550 vfc.vfc_mountroot = vfsp->vfs_mountroot;
551 vfc.vfc_next = NULL;
552 vfs_delref(vfsp);
553
554 node = *rnode;
555 node.sysctl_data = &vfc;
556 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
557 }
558
559 /*
560 * Top level filesystem related information gathering.
561 */
562 void
563 compat_sysctl_vfs(struct sysctllog **clog)
564 {
565
566 sysctl_createv(clog, 0, NULL, NULL,
567 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
568 CTLTYPE_INT, "maxtypenum",
569 SYSCTL_DESCR("Highest valid filesystem type number"),
570 NULL, nmountcompatnames, NULL, 0,
571 CTL_VFS, VFS_GENERIC, VFS_MAXTYPENUM, CTL_EOL);
572 sysctl_createv(clog, 0, NULL, NULL,
573 CTLFLAG_PERMANENT,
574 CTLTYPE_STRUCT, "conf",
575 SYSCTL_DESCR("Filesystem configuration information"),
576 sysctl_vfs_generic_conf, 0, NULL,
577 sizeof(struct vfsconf),
578 CTL_VFS, VFS_GENERIC, VFS_CONF, CTL_EOL);
579 }
580 #endif
581