1 /* $NetBSD: vfs_syscalls_43.c,v 1.5 1997/06/06 19:36:31 christos 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/filedesc.h> 46 #include <sys/kernel.h> 47 #include <sys/proc.h> 48 #include <sys/file.h> 49 #include <sys/vnode.h> 50 #include <sys/namei.h> 51 #include <sys/dirent.h> 52 #include <sys/socket.h> 53 #include <sys/socketvar.h> 54 #include <sys/stat.h> 55 #include <sys/ioctl.h> 56 #include <sys/fcntl.h> 57 #include <sys/malloc.h> 58 #include <sys/syslog.h> 59 #include <sys/unistd.h> 60 #include <sys/resourcevar.h> 61 62 #include <sys/mount.h> 63 #include <sys/syscallargs.h> 64 65 static void cvtstat __P((struct stat *, struct ostat *)); 66 67 /* 68 * Convert from an old to a new stat structure. 69 */ 70 static void 71 cvtstat(st, ost) 72 struct stat *st; 73 struct ostat *ost; 74 { 75 76 ost->st_dev = st->st_dev; 77 ost->st_ino = st->st_ino; 78 ost->st_mode = st->st_mode; 79 ost->st_nlink = st->st_nlink; 80 ost->st_uid = st->st_uid; 81 ost->st_gid = st->st_gid; 82 ost->st_rdev = st->st_rdev; 83 if (st->st_size < (quad_t)1 << 32) 84 ost->st_size = st->st_size; 85 else 86 ost->st_size = -2; 87 ost->st_atime = st->st_atime; 88 ost->st_mtime = st->st_mtime; 89 ost->st_ctime = st->st_ctime; 90 ost->st_blksize = st->st_blksize; 91 ost->st_blocks = st->st_blocks; 92 ost->st_flags = st->st_flags; 93 ost->st_gen = st->st_gen; 94 } 95 96 /* 97 * Get file status; this version follows links. 98 */ 99 /* ARGSUSED */ 100 int 101 compat_43_sys_stat(p, v, retval) 102 struct proc *p; 103 void *v; 104 register_t *retval; 105 { 106 register struct compat_43_sys_stat_args /* { 107 syscallarg(char *) path; 108 syscallarg(struct ostat *) ub; 109 } */ *uap = v; 110 struct stat sb; 111 struct ostat osb; 112 int error; 113 struct nameidata nd; 114 115 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 116 SCARG(uap, path), p); 117 if ((error = namei(&nd)) != 0) 118 return (error); 119 error = vn_stat(nd.ni_vp, &sb, p); 120 vput(nd.ni_vp); 121 if (error) 122 return (error); 123 cvtstat(&sb, &osb); 124 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 125 return (error); 126 } 127 128 129 /* 130 * Get file status; this version does not follow links. 131 */ 132 /* ARGSUSED */ 133 int 134 compat_43_sys_lstat(p, v, retval) 135 struct proc *p; 136 void *v; 137 register_t *retval; 138 { 139 register struct compat_43_sys_lstat_args /* { 140 syscallarg(char *) path; 141 syscallarg(struct ostat *) ub; 142 } */ *uap = v; 143 struct stat sb; 144 struct ostat osb; 145 int error; 146 struct nameidata nd; 147 148 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 149 SCARG(uap, path), p); 150 if ((error = namei(&nd)) != 0) 151 return (error); 152 error = vn_stat(nd.ni_vp, &sb, p); 153 vput(nd.ni_vp); 154 if (error) 155 return (error); 156 cvtstat(&sb, &osb); 157 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 158 return (error); 159 } 160 161 162 /* 163 * Return status information about a file descriptor. 164 */ 165 /* ARGSUSED */ 166 int 167 compat_43_sys_fstat(p, v, retval) 168 struct proc *p; 169 void *v; 170 register_t *retval; 171 { 172 register struct compat_43_sys_fstat_args /* { 173 syscallarg(int) fd; 174 syscallarg(struct ostat *) sb; 175 } */ *uap = v; 176 int fd = SCARG(uap, fd); 177 register struct filedesc *fdp = p->p_fd; 178 register struct file *fp; 179 struct stat ub; 180 struct ostat oub; 181 int error; 182 183 if ((u_int)fd >= fdp->fd_nfiles || 184 (fp = fdp->fd_ofiles[fd]) == NULL) 185 return (EBADF); 186 switch (fp->f_type) { 187 188 case DTYPE_VNODE: 189 error = vn_stat((struct vnode *)fp->f_data, &ub, p); 190 break; 191 192 case DTYPE_SOCKET: 193 error = soo_stat((struct socket *)fp->f_data, &ub); 194 break; 195 196 default: 197 panic("ofstat"); 198 /*NOTREACHED*/ 199 } 200 cvtstat(&ub, &oub); 201 if (error == 0) 202 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb), 203 sizeof (oub)); 204 return (error); 205 } 206 207 208 /* 209 * Truncate a file given a file descriptor. 210 */ 211 /* ARGSUSED */ 212 int 213 compat_43_sys_ftruncate(p, v, retval) 214 struct proc *p; 215 void *v; 216 register_t *retval; 217 { 218 register struct compat_43_sys_ftruncate_args /* { 219 syscallarg(int) fd; 220 syscallarg(long) length; 221 } */ *uap = v; 222 struct sys_ftruncate_args /* { 223 syscallarg(int) fd; 224 syscallarg(int) pad; 225 syscallarg(off_t) length; 226 } */ nuap; 227 228 SCARG(&nuap, fd) = SCARG(uap, fd); 229 SCARG(&nuap, length) = SCARG(uap, length); 230 return (sys_ftruncate(p, &nuap, retval)); 231 } 232 233 /* 234 * Truncate a file given its path name. 235 */ 236 /* ARGSUSED */ 237 int 238 compat_43_sys_truncate(p, v, retval) 239 struct proc *p; 240 void *v; 241 register_t *retval; 242 { 243 register struct compat_43_sys_truncate_args /* { 244 syscallarg(char *) path; 245 syscallarg(long) length; 246 } */ *uap = v; 247 struct sys_truncate_args /* { 248 syscallarg(char *) path; 249 syscallarg(int) pad; 250 syscallarg(off_t) length; 251 } */ nuap; 252 253 SCARG(&nuap, path) = SCARG(uap, path); 254 SCARG(&nuap, length) = SCARG(uap, length); 255 return (sys_truncate(p, &nuap, retval)); 256 } 257 258 259 /* 260 * Reposition read/write file offset. 261 */ 262 int 263 compat_43_sys_lseek(p, v, retval) 264 struct proc *p; 265 void *v; 266 register_t *retval; 267 { 268 register struct compat_43_sys_lseek_args /* { 269 syscallarg(int) fd; 270 syscallarg(long) offset; 271 syscallarg(int) whence; 272 } */ *uap = v; 273 struct sys_lseek_args /* { 274 syscallarg(int) fd; 275 syscallarg(int) pad; 276 syscallarg(off_t) offset; 277 syscallarg(int) whence; 278 } */ nuap; 279 off_t qret; 280 int error; 281 282 SCARG(&nuap, fd) = SCARG(uap, fd); 283 SCARG(&nuap, offset) = SCARG(uap, offset); 284 SCARG(&nuap, whence) = SCARG(uap, whence); 285 error = sys_lseek(p, &nuap, (register_t *)&qret); 286 *(long *)retval = qret; 287 return (error); 288 } 289 290 291 /* 292 * Create a file. 293 */ 294 int 295 compat_43_sys_creat(p, v, retval) 296 struct proc *p; 297 void *v; 298 register_t *retval; 299 { 300 register struct compat_43_sys_creat_args /* { 301 syscallarg(char *) path; 302 syscallarg(int) mode; 303 } */ *uap = v; 304 struct sys_open_args /* { 305 syscallarg(char *) path; 306 syscallarg(int) flags; 307 syscallarg(int) mode; 308 } */ nuap; 309 310 SCARG(&nuap, path) = SCARG(uap, path); 311 SCARG(&nuap, mode) = SCARG(uap, mode); 312 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 313 return (sys_open(p, &nuap, retval)); 314 } 315 316 /*ARGSUSED*/ 317 int 318 compat_43_sys_quota(p, v, retval) 319 struct proc *p; 320 void *v; 321 register_t *retval; 322 { 323 324 return (ENOSYS); 325 } 326 327 328 /* 329 * Read a block of directory entries in a file system independent format. 330 */ 331 int 332 compat_43_sys_getdirentries(p, v, retval) 333 struct proc *p; 334 void *v; 335 register_t *retval; 336 { 337 register struct compat_43_sys_getdirentries_args /* { 338 syscallarg(int) fd; 339 syscallarg(char *) buf; 340 syscallarg(u_int) count; 341 syscallarg(long *) basep; 342 } */ *uap = v; 343 register struct vnode *vp; 344 struct file *fp; 345 struct uio auio, kuio; 346 struct iovec aiov, kiov; 347 struct dirent *dp, *edp; 348 caddr_t dirbuf; 349 int error, eofflag, readcnt; 350 long loff; 351 352 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 353 return (error); 354 if ((fp->f_flag & FREAD) == 0) 355 return (EBADF); 356 vp = (struct vnode *)fp->f_data; 357 unionread: 358 if (vp->v_type != VDIR) 359 return (EINVAL); 360 aiov.iov_base = SCARG(uap, buf); 361 aiov.iov_len = SCARG(uap, count); 362 auio.uio_iov = &aiov; 363 auio.uio_iovcnt = 1; 364 auio.uio_rw = UIO_READ; 365 auio.uio_segflg = UIO_USERSPACE; 366 auio.uio_procp = p; 367 auio.uio_resid = SCARG(uap, count); 368 VOP_LOCK(vp); 369 loff = auio.uio_offset = fp->f_offset; 370 # if (BYTE_ORDER != LITTLE_ENDIAN) 371 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 372 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 373 (u_long *)0, 0); 374 fp->f_offset = auio.uio_offset; 375 } else 376 # endif 377 { 378 kuio = auio; 379 kuio.uio_iov = &kiov; 380 kuio.uio_segflg = UIO_SYSSPACE; 381 kiov.iov_len = SCARG(uap, count); 382 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 383 kiov.iov_base = dirbuf; 384 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 385 (u_long *)0, 0); 386 fp->f_offset = kuio.uio_offset; 387 if (error == 0) { 388 readcnt = SCARG(uap, count) - kuio.uio_resid; 389 edp = (struct dirent *)&dirbuf[readcnt]; 390 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 391 # if (BYTE_ORDER == LITTLE_ENDIAN) 392 /* 393 * The expected low byte of 394 * dp->d_namlen is our dp->d_type. 395 * The high MBZ byte of dp->d_namlen 396 * is our dp->d_namlen. 397 */ 398 dp->d_type = dp->d_namlen; 399 dp->d_namlen = 0; 400 # else 401 /* 402 * The dp->d_type is the high byte 403 * of the expected dp->d_namlen, 404 * so must be zero'ed. 405 */ 406 dp->d_type = 0; 407 # endif 408 if (dp->d_reclen > 0) { 409 dp = (struct dirent *) 410 ((char *)dp + dp->d_reclen); 411 } else { 412 error = EIO; 413 break; 414 } 415 } 416 if (dp >= edp) 417 error = uiomove(dirbuf, readcnt, &auio); 418 } 419 FREE(dirbuf, M_TEMP); 420 } 421 VOP_UNLOCK(vp); 422 if (error) 423 return (error); 424 425 #ifdef UNION 426 { 427 extern int (**union_vnodeop_p) __P((void *)); 428 extern struct vnode *union_dircache __P((struct vnode *)); 429 430 if ((SCARG(uap, count) == auio.uio_resid) && 431 (vp->v_op == union_vnodeop_p)) { 432 struct vnode *lvp; 433 434 lvp = union_dircache(vp); 435 if (lvp != NULLVP) { 436 struct vattr va; 437 438 /* 439 * If the directory is opaque, 440 * then don't show lower entries 441 */ 442 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 443 if (va.va_flags & OPAQUE) { 444 vput(lvp); 445 lvp = NULL; 446 } 447 } 448 449 if (lvp != NULLVP) { 450 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 451 VOP_UNLOCK(lvp); 452 453 if (error) { 454 vrele(lvp); 455 return (error); 456 } 457 fp->f_data = (caddr_t) lvp; 458 fp->f_offset = 0; 459 error = vn_close(vp, FREAD, fp->f_cred, p); 460 if (error) 461 return (error); 462 vp = lvp; 463 goto unionread; 464 } 465 } 466 } 467 #endif /* UNION */ 468 469 if ((SCARG(uap, count) == auio.uio_resid) && 470 (vp->v_flag & VROOT) && 471 (vp->v_mount->mnt_flag & MNT_UNION)) { 472 struct vnode *tvp = vp; 473 vp = vp->v_mount->mnt_vnodecovered; 474 VREF(vp); 475 fp->f_data = (caddr_t) vp; 476 fp->f_offset = 0; 477 vrele(tvp); 478 goto unionread; 479 } 480 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 481 sizeof(long)); 482 *retval = SCARG(uap, count) - auio.uio_resid; 483 return (error); 484 } 485