1/* $NetBSD: svr4_32_misc.c,v 1.73 2010/11/30 10:43:02 dholland Exp $ */ 2 3/*- 4 * Copyright (c) 1994, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 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 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 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 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 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * SVR4 compatibility module. 34 * 35 * SVR4 system calls that are implemented differently in BSD are 36 * handled here. 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: svr4_32_misc.c,v 1.73 2010/11/30 10:43:02 dholland Exp $"); 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/namei.h> 45#include <sys/dirent.h> 46#include <sys/proc.h> 47#include <sys/file.h> 48#include <sys/stat.h> 49#include <sys/time.h> 50#include <sys/filedesc.h> 51#include <sys/ioctl.h> 52#include <sys/kernel.h> 53#include <sys/malloc.h> 54#include <sys/pool.h> 55#include <sys/mbuf.h> 56#include <sys/mman.h> 57#include <sys/mount.h> 58#include <sys/resource.h> 59#include <sys/resourcevar.h> 60#include <sys/socket.h> 61#include <sys/vnode.h> 62#include <sys/uio.h> 63#include <sys/wait.h> 64#include <sys/utsname.h> 65#include <sys/unistd.h> 66#include <sys/vfs_syscalls.h> 67#include <sys/times.h> 68#include <sys/sem.h> 69#include <sys/msg.h> 70#include <sys/ptrace.h> 71#include <sys/signalvar.h> 72 73#include <netinet/in.h> 74#include <sys/syscallargs.h> 75 76#include <miscfs/specfs/specdev.h> 77 78#include <compat/svr4_32/svr4_32_types.h> 79#include <compat/netbsd32/netbsd32_syscallargs.h> 80#include <compat/svr4_32/svr4_32_signal.h> 81#include <compat/svr4_32/svr4_32_lwp.h> 82#include <compat/svr4_32/svr4_32_ucontext.h> 83#include <compat/svr4_32/svr4_32_syscallargs.h> 84#include <compat/svr4_32/svr4_32_util.h> 85#include <compat/svr4_32/svr4_32_time.h> 86#include <compat/svr4_32/svr4_32_dirent.h> 87#include <compat/svr4/svr4_ulimit.h> 88#include <compat/svr4_32/svr4_32_hrt.h> 89#include <compat/svr4/svr4_wait.h> 90#include <compat/svr4_32/svr4_32_statvfs.h> 91#include <compat/svr4/svr4_sysconfig.h> 92#include <compat/svr4_32/svr4_32_acl.h> 93#include <compat/svr4/svr4_mman.h> 94 95#include <sys/cpu.h> 96 97#include <uvm/uvm_extern.h> 98 99static int svr4_to_bsd_mmap_flags(int); 100 101static inline clock_t timeval_to_clock_t(struct timeval *); 102static int svr4_32_setinfo(int, struct rusage *, int, svr4_32_siginfo_tp); 103 104static int svr4_32_mknod(struct lwp *, register_t *, const char *, 105 svr4_32_mode_t, svr4_32_dev_t); 106 107int 108svr4_32_sys_wait(struct lwp *l, const struct svr4_32_sys_wait_args *uap, 109 register_t *retval) 110{ 111 int error, st, sig, pid = WAIT_ANY; 112 113 error = do_sys_wait(&pid, &st, 0, NULL); 114 115 retval[0] = pid; 116 if (pid == 0) 117 return error; 118 119 if (WIFSIGNALED(st)) { 120 sig = WTERMSIG(st); 121 if (sig >= 0 && sig < NSIG) 122 st = (st & ~0177) | native_to_svr4_signo[sig]; 123 } else if (WIFSTOPPED(st)) { 124 sig = WSTOPSIG(st); 125 if (sig >= 0 && sig < NSIG) 126 st = (st & ~0xff00) | (native_to_svr4_signo[sig] << 8); 127 } 128 129 /* 130 * It looks like wait(2) on svr4/solaris/2.4 returns 131 * the status in retval[1], and the pid on retval[0]. 132 */ 133 retval[1] = st; 134 135 if (SCARG_P32(uap, status)) 136 error = copyout(&st, SCARG_P32(uap, status), sizeof(st)); 137 return error; 138} 139 140 141int 142svr4_32_sys_execv(struct lwp *l, const struct svr4_32_sys_execv_args *uap, register_t *retval) 143{ 144 /* { 145 syscallarg(char *) path; 146 syscallarg(char **) argv; 147 } */ 148 struct netbsd32_execve_args ap; 149 150 SCARG(&ap, path) = SCARG(uap, path); 151 SCARG(&ap, argp) = SCARG(uap, argp); 152 NETBSD32PTR32(SCARG(&ap, envp), 0); 153 154 return netbsd32_execve(l, &ap, retval); 155} 156 157#if 0 158int 159svr4_32_sys_execve(struct proc *p, void *v, register_t *retval) 160{ 161 struct svr4_32_sys_execve_args /* { 162 syscallarg(const char *) path; 163 syscallarg(char **) argv; 164 syscallarg(char **) envp; 165 } */ *uap = v; 166 struct sys_execve_args ap; 167 168 SCARG(&ap, path) = SCARG_P32(uap, path); 169 SCARG(&ap, argp) = SCARG_P32(uap, argp); 170 SCARG(&ap, envp) = SCARG_P32(uap, envp); 171 172 return netbsd32_execve(p, &ap, retval); 173} 174#endif 175 176int 177svr4_32_sys_time(struct lwp *l, const struct svr4_32_sys_time_args *uap, register_t *retval) 178{ 179 int error = 0; 180 struct timeval tv; 181 struct netbsd32_timeval ntv; 182 183 microtime(&tv); 184 ntv.tv_sec = tv.tv_sec; 185 ntv.tv_usec = tv.tv_usec; 186 if (SCARG_P32(uap, t)) 187 error = copyout(&ntv.tv_sec, SCARG_P32(uap, t), 188 sizeof(ntv.tv_sec)); 189 *retval = (int) ntv.tv_sec; 190 191 return error; 192} 193 194 195/* 196 * Read SVR4-style directory entries. We suck them into kernel space so 197 * that they can be massaged before being copied out to user code. Like 198 * SunOS, we squish out `empty' entries. 199 * 200 * This is quite ugly, but what do you expect from compatibility code? 201 */ 202int 203svr4_32_sys_getdents64(struct lwp *l, const struct svr4_32_sys_getdents64_args *uap, register_t *retval) 204{ 205 struct dirent *bdp; 206 struct vnode *vp; 207 char *inp, *sbuf; /* BSD-format */ 208 int len, reclen; /* BSD-format */ 209 char *outp; /* SVR4-format */ 210 int resid, svr4_32_reclen; /* SVR4-format */ 211 file_t *fp; 212 struct uio auio; 213 struct iovec aiov; 214 struct svr4_32_dirent64 idb; 215 off_t off; /* true file offset */ 216 int buflen, error, eofflag; 217 off_t *cookiebuf = NULL, *cookie; 218 int ncookies; 219 220 /* fd_getvnode() will use the descriptor for us */ 221 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 222 return (error); 223 224 if ((fp->f_flag & FREAD) == 0) { 225 error = EBADF; 226 goto out1; 227 } 228 229 vp = fp->f_data; 230 if (vp->v_type != VDIR) { 231 error = EINVAL; 232 goto out1; 233 } 234 235 buflen = min(MAXBSIZE, SCARG(uap, nbytes)); 236 sbuf = malloc(buflen, M_TEMP, M_WAITOK); 237 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 238 off = fp->f_offset; 239again: 240 aiov.iov_base = sbuf; 241 aiov.iov_len = buflen; 242 auio.uio_iov = &aiov; 243 auio.uio_iovcnt = 1; 244 auio.uio_rw = UIO_READ; 245 auio.uio_resid = buflen; 246 auio.uio_offset = off; 247 UIO_SETUP_SYSSPACE(&auio); 248 /* 249 * First we read into the malloc'ed buffer, then 250 * we massage it into user space, one record at a time. 251 */ 252 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 253 &ncookies); 254 if (error) 255 goto out; 256 257 inp = sbuf; 258 outp = SCARG_P32(uap, dp); 259 resid = SCARG(uap, nbytes); 260 if ((len = buflen - auio.uio_resid) == 0) 261 goto eof; 262 263 for (cookie = cookiebuf; len > 0; len -= reclen) { 264 bdp = (struct dirent *)inp; 265 reclen = bdp->d_reclen; 266 if (reclen & 3) 267 panic("svr4_32_getdents64: bad reclen"); 268 if (bdp->d_fileno == 0) { 269 inp += reclen; /* it is a hole; squish it out */ 270 if (cookie) 271 off = *cookie++; 272 else 273 off += reclen; 274 continue; 275 } 276 svr4_32_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); 277 if (reclen > len || resid < svr4_32_reclen) { 278 /* entry too big for buffer, so just stop */ 279 outp++; 280 break; 281 } 282 if (cookie) 283 off = *cookie++; /* each entry points to the next */ 284 else 285 off += reclen; 286 /* 287 * Massage in place to make a SVR4-shaped dirent (otherwise 288 * we have to worry about touching user memory outside of 289 * the copyout() call). 290 */ 291 idb.d_ino = (svr4_32_ino64_t)bdp->d_fileno; 292 idb.d_off = (svr4_32_off64_t)off; 293 idb.d_reclen = (u_short)svr4_32_reclen; 294 strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); 295 if ((error = copyout((void *)&idb, outp, svr4_32_reclen))) 296 goto out; 297 /* advance past this real entry */ 298 inp += reclen; 299 /* advance output past SVR4-shaped entry */ 300 outp += svr4_32_reclen; 301 resid -= svr4_32_reclen; 302 } 303 304 /* if we squished out the whole block, try again */ 305 if (outp == SCARG_P32(uap, dp)) { 306 if (cookiebuf) 307 free(cookiebuf, M_TEMP); 308 cookiebuf = NULL; 309 goto again; 310 } 311 fp->f_offset = off; /* update the vnode offset */ 312 313eof: 314 *retval = SCARG(uap, nbytes) - resid; 315out: 316 VOP_UNLOCK(vp); 317 if (cookiebuf) 318 free(cookiebuf, M_TEMP); 319 free(sbuf, M_TEMP); 320 out1: 321 fd_putfile(SCARG(uap, fd)); 322 return error; 323} 324 325 326int 327svr4_32_sys_getdents(struct lwp *l, const struct svr4_32_sys_getdents_args *uap, register_t *retval) 328{ 329 struct dirent *bdp; 330 struct vnode *vp; 331 char *inp, *sbuf; /* BSD-format */ 332 int len, reclen; /* BSD-format */ 333 char *outp; /* SVR4-format */ 334 int resid, svr4_reclen; /* SVR4-format */ 335 file_t *fp; 336 struct uio auio; 337 struct iovec aiov; 338 struct svr4_32_dirent idb; 339 off_t off; /* true file offset */ 340 int buflen, error, eofflag; 341 off_t *cookiebuf = NULL, *cookie; 342 int ncookies; 343 344 /* fd_getvnode() will use the descriptor for us */ 345 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 346 return (error); 347 348 if ((fp->f_flag & FREAD) == 0) { 349 error = EBADF; 350 goto out1; 351 } 352 353 vp = fp->f_data; 354 if (vp->v_type != VDIR) { 355 error = EINVAL; 356 goto out1; 357 } 358 359 buflen = min(MAXBSIZE, SCARG(uap, nbytes)); 360 sbuf = malloc(buflen, M_TEMP, M_WAITOK); 361 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 362 off = fp->f_offset; 363again: 364 aiov.iov_base = sbuf; 365 aiov.iov_len = buflen; 366 auio.uio_iov = &aiov; 367 auio.uio_iovcnt = 1; 368 auio.uio_rw = UIO_READ; 369 auio.uio_resid = buflen; 370 auio.uio_offset = off; 371 UIO_SETUP_SYSSPACE(&auio); 372 /* 373 * First we read into the malloc'ed buffer, then 374 * we massage it into user space, one record at a time. 375 */ 376 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 377 &ncookies); 378 if (error) 379 goto out; 380 381 inp = sbuf; 382 outp = SCARG_P32(uap, buf); 383 resid = SCARG(uap, nbytes); 384 if ((len = buflen - auio.uio_resid) == 0) 385 goto eof; 386 387 for (cookie = cookiebuf; len > 0; len -= reclen) { 388 bdp = (struct dirent *)inp; 389 reclen = bdp->d_reclen; 390 if (reclen & 3) 391 panic("svr4_32_getdents: bad reclen"); 392 if (cookie) 393 off = *cookie++; /* each entry points to the next */ 394 else 395 off += reclen; 396 if ((off >> 32) != 0) { 397 compat_offseterr(vp, "svr4_32_getdents"); 398 error = EINVAL; 399 goto out; 400 } 401 if (bdp->d_fileno == 0) { 402 inp += reclen; /* it is a hole; squish it out */ 403 continue; 404 } 405 svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); 406 if (reclen > len || resid < svr4_reclen) { 407 /* entry too big for buffer, so just stop */ 408 outp++; 409 break; 410 } 411 /* 412 * Massage in place to make a SVR4-shaped dirent (otherwise 413 * we have to worry about touching user memory outside of 414 * the copyout() call). 415 */ 416 idb.d_ino = (svr4_32_ino_t)bdp->d_fileno; 417 idb.d_off = (svr4_32_off_t)off; 418 idb.d_reclen = (u_short)svr4_reclen; 419 strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); 420 if ((error = copyout((void *)&idb, outp, svr4_reclen))) 421 goto out; 422 /* advance past this real entry */ 423 inp += reclen; 424 /* advance output past SVR4-shaped entry */ 425 outp += svr4_reclen; 426 resid -= svr4_reclen; 427 } 428 429 /* if we squished out the whole block, try again */ 430 if (outp == SCARG_P32(uap, buf)) { 431 if (cookiebuf) 432 free(cookiebuf, M_TEMP); 433 cookiebuf = NULL; 434 goto again; 435 } 436 fp->f_offset = off; /* update the vnode offset */ 437 438eof: 439 *retval = SCARG(uap, nbytes) - resid; 440out: 441 VOP_UNLOCK(vp); 442 if (cookiebuf) 443 free(cookiebuf, M_TEMP); 444 free(sbuf, M_TEMP); 445 out1: 446 fd_putfile(SCARG(uap, fd)); 447 return error; 448} 449 450 451static int 452svr4_to_bsd_mmap_flags(int f) 453{ 454 int type = f & SVR4_MAP_TYPE; 455 int nf; 456 457 if (type != MAP_PRIVATE && type != MAP_SHARED) 458 return -1; 459 460 nf = f & SVR4_MAP_COPYFLAGS; 461 if (f & SVR4_MAP_ANON) 462 nf |= MAP_ANON; 463 464 return nf; 465} 466 467 468int 469svr4_32_sys_mmap(struct lwp *l, const struct svr4_32_sys_mmap_args *uap, register_t *retval) 470{ 471 struct sys_mmap_args mm; 472 int error; 473 /* 474 * Verify the arguments. 475 */ 476 if (SCARG(uap, prot) & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) 477 return EINVAL; /* XXX still needed? */ 478 479 if (SCARG(uap, len) == 0) 480 return EINVAL; 481 482 if ((SCARG(&mm, flags) = svr4_to_bsd_mmap_flags(SCARG(uap, flags))) == -1) 483 return EINVAL; 484 485 SCARG(&mm, prot) = SCARG(uap, prot); 486 SCARG(&mm, len) = SCARG(uap, len); 487 SCARG(&mm, fd) = SCARG(uap, fd); 488 SCARG(&mm, addr) = SCARG_P32(uap, addr); 489 SCARG(&mm, pos) = SCARG(uap, pos); 490 491 error = sys_mmap(l, &mm, retval); 492 if ((u_long)*retval > (u_long)UINT_MAX) { 493 printf("svr4_32_mmap: retval out of range: 0x%lx", 494 (u_long)*retval); 495 /* Should try to recover and return an error here. */ 496 } 497 return (error); 498} 499 500 501int 502svr4_32_sys_mmap64(struct lwp *l, const struct svr4_32_sys_mmap64_args *uap, register_t *retval) 503{ 504 struct sys_mmap_args mm; 505 int error; 506 /* 507 * Verify the arguments. 508 */ 509 if (SCARG(uap, prot) & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) 510 return EINVAL; /* XXX still needed? */ 511 512 if (SCARG(uap, len) == 0) 513 return EINVAL; 514 515 if ((SCARG(&mm, flags) = svr4_to_bsd_mmap_flags(SCARG(uap, flags))) == -1) 516 return EINVAL; 517 518 SCARG(&mm, prot) = SCARG(uap, prot); 519 SCARG(&mm, len) = SCARG(uap, len); 520 SCARG(&mm, fd) = SCARG(uap, fd); 521 SCARG(&mm, addr) = SCARG_P32(uap, addr); 522 SCARG(&mm, pos) = SCARG(uap, pos); 523 524 error = sys_mmap(l, &mm, retval); 525 if ((u_long)*retval > (u_long)UINT_MAX) { 526 printf("svr4_32_mmap64: retval out of range: 0x%lx", 527 (u_long)*retval); 528 /* Should try to recover and return an error here. */ 529 } 530 return (error); 531} 532 533 534static int 535svr4_32_mknod(struct lwp *l, register_t *retval, const char *path, svr4_32_mode_t mode, svr4_32_dev_t dev) 536{ 537 if (S_ISFIFO(mode)) { 538 struct sys_mkfifo_args ap; 539 SCARG(&ap, path) = path; 540 SCARG(&ap, mode) = mode; 541 return sys_mkfifo(l, &ap, retval); 542 } else { 543 return do_sys_mknod(l, path, mode, dev, retval, UIO_USERSPACE); 544 } 545} 546 547 548int 549svr4_32_sys_mknod(struct lwp *l, const struct svr4_32_sys_mknod_args *uap, register_t *retval) 550{ 551 return svr4_32_mknod(l, retval, 552 SCARG_P32(uap, path), SCARG(uap, mode), 553 svr4_32_to_bsd_odev_t(SCARG(uap, dev))); 554} 555 556 557int 558svr4_32_sys_xmknod(struct lwp *l, const struct svr4_32_sys_xmknod_args *uap, register_t *retval) 559{ 560 return svr4_32_mknod(l, retval, 561 SCARG_P32(uap, path), SCARG(uap, mode), 562 svr4_32_to_bsd_dev_t(SCARG(uap, dev))); 563} 564 565 566int 567svr4_32_sys_vhangup(struct lwp *l, const void *v, register_t *retval) 568{ 569 return 0; 570} 571 572 573int 574svr4_32_sys_sysconfig(struct lwp *l, const struct svr4_32_sys_sysconfig_args *uap, register_t *retval) 575{ 576 extern u_int maxfiles; 577 int active; 578 579 switch (SCARG(uap, name)) { 580 case SVR4_CONFIG_NGROUPS: 581 *retval = NGROUPS_MAX; 582 break; 583 case SVR4_CONFIG_CHILD_MAX: 584 *retval = maxproc; 585 break; 586 case SVR4_CONFIG_OPEN_FILES: 587 *retval = maxfiles; 588 break; 589 case SVR4_CONFIG_POSIX_VER: 590 *retval = 198808; 591 break; 592 case SVR4_CONFIG_PAGESIZE: 593 *retval = PAGE_SIZE; 594 break; 595 case SVR4_CONFIG_CLK_TCK: 596 *retval = 60; /* should this be `hz', ie. 100? */ 597 break; 598 case SVR4_CONFIG_XOPEN_VER: 599 *retval = 2; /* XXX: What should that be? */ 600 break; 601 case SVR4_CONFIG_PROF_TCK: 602 *retval = 60; /* XXX: What should that be? */ 603 break; 604 case SVR4_CONFIG_NPROC_CONF: 605 *retval = 1; /* Only one processor for now */ 606 break; 607 case SVR4_CONFIG_NPROC_ONLN: 608 *retval = 1; /* And it better be online */ 609 break; 610 case SVR4_CONFIG_AIO_LISTIO_MAX: 611 case SVR4_CONFIG_AIO_MAX: 612 case SVR4_CONFIG_AIO_PRIO_DELTA_MAX: 613 *retval = 0; /* No aio support */ 614 break; 615 case SVR4_CONFIG_DELAYTIMER_MAX: 616 *retval = 0; /* No delaytimer support */ 617 break; 618 case SVR4_CONFIG_MQ_OPEN_MAX: 619#ifdef SYSVMSG 620 *retval = msginfo.msgmni; 621#else 622 *retval = 0; 623#endif 624 break; 625 case SVR4_CONFIG_MQ_PRIO_MAX: 626 *retval = 0; /* XXX: Don't know */ 627 break; 628 case SVR4_CONFIG_RTSIG_MAX: 629 *retval = 0; 630 break; 631 case SVR4_CONFIG_SEM_NSEMS_MAX: 632#ifdef SYSVSEM 633 *retval = seminfo.semmni; 634#else 635 *retval = 0; 636#endif 637 break; 638 case SVR4_CONFIG_SEM_VALUE_MAX: 639#ifdef SYSVSEM 640 *retval = seminfo.semvmx; 641#else 642 *retval = 0; 643#endif 644 break; 645 case SVR4_CONFIG_SIGQUEUE_MAX: 646 *retval = 0; /* XXX: Don't know */ 647 break; 648 case SVR4_CONFIG_SIGRT_MIN: 649 case SVR4_CONFIG_SIGRT_MAX: 650 *retval = 0; /* No real time signals */ 651 break; 652 case SVR4_CONFIG_TIMER_MAX: 653 *retval = 3; /* XXX: real, virtual, profiling */ 654 break; 655 case SVR4_CONFIG_PHYS_PAGES: 656 *retval = uvmexp.free; /* XXX: free instead of total */ 657 break; 658 case SVR4_CONFIG_AVPHYS_PAGES: 659 uvm_estimatepageable(&active, NULL); 660 *retval = active; /* XXX: active instead of avg */ 661 break; 662 case SVR4_CONFIG_COHERENCY: 663 *retval = 0; /* XXX */ 664 break; 665 case SVR4_CONFIG_SPLIT_CACHE: 666 *retval = 0; /* XXX */ 667 break; 668 case SVR4_CONFIG_ICACHESZ: 669 *retval = 256; /* XXX */ 670 break; 671 case SVR4_CONFIG_DCACHESZ: 672 *retval = 256; /* XXX */ 673 break; 674 case SVR4_CONFIG_ICACHELINESZ: 675 *retval = 64; /* XXX */ 676 break; 677 case SVR4_CONFIG_DCACHELINESZ: 678 *retval = 64; /* XXX */ 679 break; 680 case SVR4_CONFIG_ICACHEBLKSZ: 681 *retval = 64; /* XXX */ 682 break; 683 case SVR4_CONFIG_DCACHEBLKSZ: 684 *retval = 64; /* XXX */ 685 break; 686 case SVR4_CONFIG_DCACHETBLKSZ: 687 *retval = 64; /* XXX */ 688 break; 689 case SVR4_CONFIG_ICACHE_ASSOC: 690 *retval = 1; /* XXX */ 691 break; 692 case SVR4_CONFIG_DCACHE_ASSOC: 693 *retval = 1; /* XXX */ 694 break; 695 case SVR4_CONFIG_MAXPID: 696 *retval = PID_MAX; 697 break; 698 case SVR4_CONFIG_STACK_PROT: 699 *retval = PROT_READ|PROT_WRITE|PROT_EXEC; 700 break; 701 default: 702 return EINVAL; 703 } 704 return 0; 705} 706 707 708/* ARGSUSED */ 709int 710svr4_32_sys_break(struct lwp *l, const struct svr4_32_sys_break_args *uap, register_t *retval) 711{ 712 struct proc *p = l->l_proc; 713 struct vmspace *vm = p->p_vmspace; 714 vaddr_t new, old; 715 int error; 716 717 old = (vaddr_t) vm->vm_daddr; 718 new = round_page((vaddr_t)SCARG_P32(uap, nsize)); 719 720 if (new - old > p->p_rlimit[RLIMIT_DATA].rlim_cur && new > old) 721 return ENOMEM; 722 723 old = round_page(old + ctob(vm->vm_dsize)); 724 DPRINTF(("break(2): dsize = %x ctob %x\n", 725 vm->vm_dsize, ctob(vm->vm_dsize))); 726 727 if (new > old) { 728 error = uvm_map(&vm->vm_map, &old, new - old, NULL, 729 UVM_UNKNOWN_OFFSET, 0, 730 UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY, 731 UVM_ADV_NORMAL, 732 UVM_FLAG_AMAPPAD|UVM_FLAG_FIXED| 733 UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)); 734 if (error) { 735 uprintf("sbrk: grow failed, return = %d\n", error); 736 return error; 737 } 738 vm->vm_dsize += btoc(new - old); 739 } else if (new < old) { 740 uvm_deallocate(&vm->vm_map, new, old - new); 741 vm->vm_dsize -= btoc(old - new); 742 } 743 return 0; 744} 745 746 747static inline clock_t 748timeval_to_clock_t(struct timeval *tv) 749{ 750 return tv->tv_sec * hz + tv->tv_usec / (1000000 / hz); 751} 752 753int 754svr4_32_sys_times(struct lwp *l, const struct svr4_32_sys_times_args *uap, register_t *retval) 755{ 756 struct tms tms; 757 struct timeval t; 758 struct rusage ru, *rup; 759 struct proc *p = l->l_proc; 760 761 ru = l->l_proc->p_stats->p_ru; 762 mutex_enter(p->p_lock); 763 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); 764 rulwps(p, &ru); 765 mutex_exit(p->p_lock); 766 767 tms.tms_utime = timeval_to_clock_t(&ru.ru_utime); 768 tms.tms_stime = timeval_to_clock_t(&ru.ru_stime); 769 770 rup = &l->l_proc->p_stats->p_cru; 771 tms.tms_cutime = timeval_to_clock_t(&rup->ru_utime); 772 tms.tms_cstime = timeval_to_clock_t(&rup->ru_stime); 773 774 microtime(&t); 775 *retval = timeval_to_clock_t(&t); 776 777 return copyout(&tms, SCARG_P32(uap, tp), sizeof(tms)); 778} 779 780 781int 782svr4_32_sys_ulimit(struct lwp *l, const struct svr4_32_sys_ulimit_args *uap, register_t *retval) 783{ 784 struct proc *p = l->l_proc; 785 int error; 786 struct rlimit krl; 787 register_t r; 788 789 switch (SCARG(uap, cmd)) { 790 case SVR4_GFILLIM: 791 r = p->p_rlimit[RLIMIT_FSIZE].rlim_cur / 512; 792 break; 793 794 case SVR4_SFILLIM: 795 krl.rlim_cur = SCARG(uap, newlimit) * 512; 796 krl.rlim_max = p->p_rlimit[RLIMIT_FSIZE].rlim_max; 797 798 error = dosetrlimit(l, l->l_proc, RLIMIT_FSIZE, &krl); 799 if (error) 800 return error; 801 802 r = p->p_rlimit[RLIMIT_FSIZE].rlim_cur; 803 break; 804 805 case SVR4_GMEMLIM: 806 r = p->p_rlimit[RLIMIT_DATA].rlim_cur; 807 if (r > 0x7fffffff) 808 r = 0x7fffffff; 809 r += (long)p->p_vmspace->vm_daddr; 810 break; 811 812 case SVR4_GDESLIM: 813 r = p->p_rlimit[RLIMIT_NOFILE].rlim_cur; 814 break; 815 816 default: 817 return EINVAL; 818 } 819 820 *retval = r > 0x7fffffff ? 0x7fffffff : r; 821 return 0; 822} 823 824 825int 826svr4_32_sys_pgrpsys(struct lwp *l, const struct svr4_32_sys_pgrpsys_args *uap, register_t *retval) 827{ 828 struct proc *p = l->l_proc; 829 pid_t pid; 830 831 switch (SCARG(uap, cmd)) { 832 case 1: /* setpgrp() */ 833 /* 834 * SVR4 setpgrp() (which takes no arguments) has the 835 * semantics that the session ID is also created anew, so 836 * in almost every sense, setpgrp() is identical to 837 * setsid() for SVR4. (Under BSD, the difference is that 838 * a setpgid(0,0) will not create a new session.) 839 */ 840 sys_setsid(l, NULL, retval); 841 /*FALLTHROUGH*/ 842 843 case 0: /* getpgrp() */ 844 *retval = p->p_pgrp->pg_id; 845 return 0; 846 847 case 2: /* getsid(pid) */ 848 mutex_enter(proc_lock); 849 pid = SCARG(uap, pid); 850 if (pid && (p = proc_find(pid)) == NULL) { 851 mutex_exit(proc_lock); 852 return ESRCH; 853 } 854 mutex_exit(proc_lock); 855 /* 856 * This has already been initialized to the pid of 857 * the session leader. 858 */ 859 *retval = (register_t) p->p_session->s_sid; 860 return 0; 861 862 case 3: /* setsid() */ 863 return sys_setsid(l, NULL, retval); 864 865 case 4: /* getpgid(pid) */ 866 mutex_enter(proc_lock); 867 pid = SCARG(uap, pid); 868 if (pid && (p = proc_find(pid)) == NULL) { 869 mutex_exit(proc_lock); 870 return ESRCH; 871 } 872 *retval = (int) p->p_pgrp->pg_id; 873 mutex_exit(proc_lock); 874 return 0; 875 876 case 5: /* setpgid(pid, pgid); */ 877 { 878 struct sys_setpgid_args sa; 879 880 SCARG(&sa, pid) = SCARG(uap, pid); 881 SCARG(&sa, pgid) = SCARG(uap, pgid); 882 return sys_setpgid(l, &sa, retval); 883 } 884 885 default: 886 return EINVAL; 887 } 888} 889 890struct svr4_32_hrtcntl_args { 891 syscallarg(int) cmd; 892 syscallarg(int) fun; 893 syscallarg(int) clk; 894 syscallarg(svr4_32_hrt_interval_tp) iv; 895 syscallarg(svr4_32_hrt_time_tp) ti; 896}; 897 898 899static int 900svr4_32_hrtcntl(struct proc *p, const struct svr4_32_hrtcntl_args *uap, register_t *retval) 901{ 902 switch (SCARG(uap, fun)) { 903 case SVR4_HRT_CNTL_RES: 904 DPRINTF(("htrcntl(RES)\n")); 905 *retval = SVR4_HRT_USEC; 906 return 0; 907 908 case SVR4_HRT_CNTL_TOFD: 909 DPRINTF(("htrcntl(TOFD)\n")); 910 { 911 struct timeval tv; 912 svr4_hrt_time_t t; 913 if (SCARG(uap, clk) != SVR4_HRT_CLK_STD) { 914 DPRINTF(("clk == %d\n", SCARG(uap, clk))); 915 return EINVAL; 916 } 917 if (SCARG_P32(uap, ti) == 0) { 918 DPRINTF(("ti NULL\n")); 919 return EINVAL; 920 } 921 microtime(&tv); 922 t.h_sec = tv.tv_sec; 923 t.h_rem = tv.tv_usec; 924 t.h_res = SVR4_HRT_USEC; 925 return copyout(&t, SCARG_P32(uap, ti), 926 sizeof(t)); 927 } 928 929 case SVR4_HRT_CNTL_START: 930 DPRINTF(("htrcntl(START)\n")); 931 return ENOSYS; 932 933 case SVR4_HRT_CNTL_GET: 934 DPRINTF(("htrcntl(GET)\n")); 935 return ENOSYS; 936 default: 937 DPRINTF(("Bad htrcntl command %d\n", SCARG(uap, fun))); 938 return ENOSYS; 939 } 940} 941 942 943int 944svr4_32_sys_hrtsys(struct lwp *l, const struct svr4_32_sys_hrtsys_args *uap, register_t *retval) 945{ 946 947 switch (SCARG(uap, cmd)) { 948 case SVR4_HRT_CNTL: 949 return svr4_32_hrtcntl(l->l_proc, (const struct svr4_32_hrtcntl_args *) uap, 950 retval); 951 952 case SVR4_HRT_ALRM: 953 DPRINTF(("hrtalarm\n")); 954 return ENOSYS; 955 956 case SVR4_HRT_SLP: 957 DPRINTF(("hrtsleep\n")); 958 return ENOSYS; 959 960 case SVR4_HRT_CAN: 961 DPRINTF(("hrtcancel\n")); 962 return ENOSYS; 963 964 default: 965 DPRINTF(("Bad hrtsys command %d\n", SCARG(uap, cmd))); 966 return EINVAL; 967 } 968} 969 970 971static int 972svr4_32_setinfo(int pid, struct rusage *ru, int st, svr4_32_siginfo_tp si) 973{ 974 svr4_32_siginfo_t *s = NETBSD32PTR64(si); 975 svr4_32_siginfo_t i; 976 int sig; 977 978 memset(&i, 0, sizeof(i)); 979 980 i.si_signo = SVR4_SIGCHLD; 981 i.si_errno = 0; /* XXX? */ 982 983 if (pid != 0) { 984 i.si_pid = pid; 985 i.si_stime = ru->ru_stime.tv_sec; 986 i.si_utime = ru->ru_utime.tv_sec; 987 } 988 989 if (WIFEXITED(st)) { 990 i.si_status = WEXITSTATUS(st); 991 i.si_code = SVR4_CLD_EXITED; 992 } else if (WIFSTOPPED(st)) { 993 sig = WSTOPSIG(st); 994 if (sig >= 0 && sig < NSIG) 995 i.si_status = native_to_svr4_signo[sig]; 996 997 if (i.si_status == SVR4_SIGCONT) 998 i.si_code = SVR4_CLD_CONTINUED; 999 else 1000 i.si_code = SVR4_CLD_STOPPED; 1001 } else { 1002 sig = WTERMSIG(st); 1003 if (sig >= 0 && sig < NSIG) 1004 i.si_status = native_to_svr4_signo[sig]; 1005 1006 if (WCOREDUMP(st)) 1007 i.si_code = SVR4_CLD_DUMPED; 1008 else 1009 i.si_code = SVR4_CLD_KILLED; 1010 } 1011 1012 DPRINTF(("siginfo [pid %ld signo %d code %d errno %d status %d]\n", 1013 i.si_pid, i.si_signo, i.si_code, i.si_errno, i.si_status)); 1014 1015 return copyout(&i, s, sizeof(i)); 1016} 1017 1018 1019int 1020svr4_32_sys_waitsys(struct lwp *l, const struct svr4_32_sys_waitsys_args *uap, register_t *retval) 1021{ 1022 int options, error, status; 1023 struct rusage ru; 1024 int id = SCARG(uap, id); 1025 1026 switch (SCARG(uap, grp)) { 1027 case SVR4_P_PID: 1028 break; 1029 1030 case SVR4_P_PGID: 1031 id = -l->l_proc->p_pgid; 1032 break; 1033 1034 case SVR4_P_ALL: 1035 id = WAIT_ANY; 1036 break; 1037 1038 default: 1039 return EINVAL; 1040 } 1041 1042 DPRINTF(("waitsys(%d, %d, %p, %x)\n", 1043 SCARG(uap, grp), id, 1044 SCARG(uap, info), SCARG(uap, options))); 1045 1046 /* Translate options */ 1047 options = WOPTSCHECKED; 1048 if (SCARG(uap, options) & SVR4_WNOWAIT) 1049 options |= WNOWAIT; 1050 if (SCARG(uap, options) & SVR4_WNOHANG) 1051 options |= WNOHANG; 1052 if ((SCARG(uap, options) & (SVR4_WEXITED|SVR4_WTRAPPED)) == 0) 1053 options |= WNOZOMBIE; 1054 if (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)) 1055 options |= WUNTRACED; 1056 1057 error = do_sys_wait(&id, &status, options, &ru); 1058 1059 retval[0] = id; 1060 if (error != 0) 1061 return error; 1062 1063 return svr4_32_setinfo(id, &ru, status, SCARG(uap, info)); 1064} 1065 1066static int 1067svr4_32_copyout_statvfs(const struct statvfs *bfs, struct svr4_32_statvfs *sufs) 1068{ 1069 struct svr4_32_statvfs *sfs = malloc(sizeof(*sfs), M_TEMP, M_WAITOK); 1070 int error; 1071 1072 sfs->f_bsize = bfs->f_iosize; /* XXX */ 1073 sfs->f_frsize = bfs->f_bsize; 1074 sfs->f_blocks = bfs->f_blocks; 1075 sfs->f_bfree = bfs->f_bfree; 1076 sfs->f_bavail = bfs->f_bavail; 1077 sfs->f_files = bfs->f_files; 1078 sfs->f_ffree = bfs->f_ffree; 1079 sfs->f_favail = bfs->f_ffree; 1080 sfs->f_fsid = bfs->f_fsidx.__fsid_val[0]; 1081 memcpy(sfs->f_basetype, bfs->f_fstypename, sizeof(sfs->f_basetype)); 1082 sfs->f_flag = 0; 1083 if (bfs->f_flag & MNT_RDONLY) 1084 sfs->f_flag |= SVR4_ST_RDONLY; 1085 if (bfs->f_flag & MNT_NOSUID) 1086 sfs->f_flag |= SVR4_ST_NOSUID; 1087 sfs->f_namemax = bfs->f_namemax; 1088 memcpy(sfs->f_fstr, bfs->f_fstypename, sizeof(sfs->f_fstr)); /* XXX */ 1089 memset(sfs->f_filler, 0, sizeof(sfs->f_filler)); 1090 1091 error = copyout(sfs, sufs, sizeof(*sfs)); 1092 1093 free(sfs, M_TEMP); 1094 return error; 1095} 1096 1097 1098static int 1099svr4_32_copyout_statvfs64(const struct statvfs *bfs, struct svr4_32_statvfs64 *sufs) 1100{ 1101 struct svr4_32_statvfs64 *sfs = malloc(sizeof(*sfs), M_TEMP, M_WAITOK); 1102 int error; 1103 1104 sfs->f_bsize = bfs->f_iosize; /* XXX */ 1105 sfs->f_frsize = bfs->f_bsize; 1106 sfs->f_blocks = bfs->f_blocks; 1107 sfs->f_bfree = bfs->f_bfree; 1108 sfs->f_bavail = bfs->f_bavail; 1109 sfs->f_files = bfs->f_files; 1110 sfs->f_ffree = bfs->f_ffree; 1111 sfs->f_favail = bfs->f_ffree; 1112 sfs->f_fsid = bfs->f_fsidx.__fsid_val[0]; 1113 memcpy(sfs->f_basetype, bfs->f_fstypename, sizeof(sfs->f_basetype)); 1114 sfs->f_flag = 0; 1115 if (bfs->f_flag & MNT_RDONLY) 1116 sfs->f_flag |= SVR4_ST_RDONLY; 1117 if (bfs->f_flag & MNT_NOSUID) 1118 sfs->f_flag |= SVR4_ST_NOSUID; 1119 sfs->f_namemax = bfs->f_namemax; 1120 memcpy(sfs->f_fstr, bfs->f_fstypename, sizeof(sfs->f_fstr)); /* XXX */ 1121 memset(sfs->f_filler, 0, sizeof(sfs->f_filler)); 1122 1123 error = copyout(sfs, sufs, sizeof(*sfs)); 1124 1125 free(sfs, M_TEMP); 1126 return error; 1127} 1128 1129 1130int 1131svr4_32_sys_statvfs(struct lwp *l, const struct svr4_32_sys_statvfs_args *uap, register_t *retval) 1132{ 1133 struct statvfs *sb; 1134 int error; 1135 1136 sb = STATVFSBUF_GET(); 1137 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 1138 if (error == 0) 1139 error = svr4_32_copyout_statvfs(sb, SCARG_P32(uap, fs)); 1140 STATVFSBUF_PUT(sb); 1141 return error; 1142} 1143 1144 1145int 1146svr4_32_sys_fstatvfs(struct lwp *l, const struct svr4_32_sys_fstatvfs_args *uap, register_t *retval) 1147{ 1148 struct statvfs *sb; 1149 int error; 1150 1151 sb = STATVFSBUF_GET(); 1152 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 1153 if (error == 0) 1154 error = svr4_32_copyout_statvfs(sb, SCARG_P32(uap, fs)); 1155 STATVFSBUF_PUT(sb); 1156 return error; 1157} 1158 1159 1160int 1161svr4_32_sys_statvfs64(struct lwp *l, const struct svr4_32_sys_statvfs64_args *uap, register_t *retval) 1162{ 1163 struct statvfs *sb; 1164 int error; 1165 1166 sb = STATVFSBUF_GET(); 1167 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 1168 if (error == 0) 1169 error = svr4_32_copyout_statvfs64(sb, SCARG_P32(uap, fs)); 1170 STATVFSBUF_PUT(sb); 1171 return error; 1172} 1173 1174 1175int 1176svr4_32_sys_fstatvfs64(struct lwp *l, const struct svr4_32_sys_fstatvfs64_args *uap, register_t *retval) 1177{ 1178 struct statvfs *sb; 1179 int error; 1180 1181 sb = STATVFSBUF_GET(); 1182 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 1183 if (error == 0) 1184 error = svr4_32_copyout_statvfs64(sb, SCARG_P32(uap, fs)); 1185 STATVFSBUF_PUT(sb); 1186 return error; 1187} 1188 1189 1190 1191int 1192svr4_32_sys_alarm(struct lwp *l, const struct svr4_32_sys_alarm_args *uap, register_t *retval) 1193{ 1194 struct itimerval tp; 1195 1196 dogetitimer(l->l_proc, ITIMER_REAL, &tp); 1197 if (tp.it_value.tv_usec) 1198 tp.it_value.tv_sec++; 1199 *retval = (register_t)tp.it_value.tv_sec; 1200 1201 timerclear(&tp.it_interval); 1202 tp.it_value.tv_sec = SCARG(uap, sec); 1203 tp.it_value.tv_usec = 0; 1204 1205 return dosetitimer(l->l_proc, ITIMER_REAL, &tp); 1206} 1207 1208 1209int 1210svr4_32_sys_gettimeofday(struct lwp *l, const struct svr4_32_sys_gettimeofday_args *uap, register_t *retval) 1211{ 1212 1213 if (SCARG_P32(uap, tp)) { 1214 struct timeval atv; 1215 1216 microtime(&atv); 1217 return copyout(&atv, SCARG_P32(uap, tp), sizeof (atv)); 1218 } 1219 1220 return 0; 1221} 1222 1223 1224int 1225svr4_32_sys_facl(struct lwp *l, const struct svr4_32_sys_facl_args *uap, register_t *retval) 1226{ 1227 1228 *retval = 0; 1229 1230 switch (SCARG(uap, cmd)) { 1231 case SVR4_SYS_SETACL: 1232 /* We don't support acls on any filesystem */ 1233 return ENOSYS; 1234 1235 case SVR4_SYS_GETACL: 1236 return 0; 1237/* 1238 return copyout(retval, &SCARG(uap, num), 1239 sizeof(SCARG(uap, num))); 1240*/ 1241 1242 case SVR4_SYS_GETACLCNT: 1243 return 0; 1244 1245 default: 1246 return EINVAL; 1247 } 1248} 1249 1250 1251int 1252svr4_32_sys_acl(struct lwp *l, const struct svr4_32_sys_acl_args *uap, register_t *retval) 1253{ 1254 return svr4_32_sys_facl(l, (const void *)uap, retval); /* XXX: for now the same */ 1255} 1256 1257 1258int 1259svr4_32_sys_auditsys(struct lwp *l, const struct svr4_32_sys_auditsys_args *uap, register_t *retval) 1260{ 1261 /* 1262 * XXX: Big brother is *not* watching. 1263 */ 1264 return 0; 1265} 1266 1267 1268int 1269svr4_32_sys_memcntl(struct lwp *l, const struct svr4_32_sys_memcntl_args *uap, register_t *retval) 1270{ 1271 switch (SCARG(uap, cmd)) { 1272 case SVR4_MC_SYNC: 1273 { 1274 struct sys___msync13_args msa; 1275 1276 SCARG(&msa, addr) = SCARG_P32(uap, addr); 1277 SCARG(&msa, len) = SCARG(uap, len); 1278 SCARG(&msa, flags) = (uintptr_t)SCARG_P32(uap, arg); 1279 1280 return sys___msync13(l, &msa, retval); 1281 } 1282 case SVR4_MC_ADVISE: 1283 { 1284 struct sys_madvise_args maa; 1285 1286 SCARG(&maa, addr) = SCARG_P32(uap, addr); 1287 SCARG(&maa, len) = SCARG(uap, len); 1288 SCARG(&maa, behav) = (uintptr_t)SCARG_P32(uap, arg); 1289 1290 return sys_madvise(l, &maa, retval); 1291 } 1292 case SVR4_MC_LOCK: 1293 case SVR4_MC_UNLOCK: 1294 case SVR4_MC_LOCKAS: 1295 case SVR4_MC_UNLOCKAS: 1296 return EOPNOTSUPP; 1297 default: 1298 return ENOSYS; 1299 } 1300} 1301 1302 1303int 1304svr4_32_sys_nice(struct lwp *l, const struct svr4_32_sys_nice_args *uap, register_t *retval) 1305{ 1306 struct sys_setpriority_args ap; 1307 int error; 1308 1309 SCARG(&ap, which) = PRIO_PROCESS; 1310 SCARG(&ap, who) = 0; 1311 SCARG(&ap, prio) = SCARG(uap, prio); 1312 1313 if ((error = sys_setpriority(l, &ap, retval)) != 0) 1314 return error; 1315 1316 if ((error = sys_getpriority(l, (const void *)&ap, retval)) != 0) 1317 return error; 1318 1319 return 0; 1320} 1321 1322 1323int 1324svr4_32_sys_resolvepath(struct lwp *l, const struct svr4_32_sys_resolvepath_args *uap, register_t *retval) 1325{ 1326 struct pathbuf *pb; 1327 struct nameidata nd; 1328 int error; 1329 size_t len; 1330 1331 error = pathbuf_copyin(SCARG_P32(uap, path), &pb); 1332 if (error) { 1333 return error; 1334 } 1335 1336 NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, pb); 1337 if ((error = namei(&nd)) != 0) { 1338 pathbuf_destroy(pb); 1339 return error; 1340 } 1341 1342 if ((error = copyoutstr(nd.ni_pnbuf, 1343 SCARG_P32(uap, buf), 1344 SCARG(uap, bufsiz), &len)) != 0) 1345 goto bad; 1346 1347 *retval = len; 1348bad: 1349 vrele(nd.ni_vp); 1350 pathbuf_destroy(pb); 1351 return error; 1352} 1353