1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: hpux_compat.c 1.64 93/08/05$ 13 * 14 * @(#)hpux_compat.c 8.5 (Berkeley) 02/19/95 15 */ 16 17 /* 18 * Various HP-UX compatibility routines 19 */ 20 21 #ifdef HPUXCOMPAT 22 #ifndef COMPAT_43 23 #define COMPAT_43 24 #endif 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/signalvar.h> 29 #include <sys/kernel.h> 30 #include <sys/filedesc.h> 31 #include <sys/proc.h> 32 #include <sys/buf.h> 33 #include <sys/wait.h> 34 #include <sys/file.h> 35 #include <sys/namei.h> 36 #include <sys/vnode.h> 37 #include <sys/ioctl.h> 38 #include <sys/ptrace.h> 39 #include <sys/stat.h> 40 #include <sys/syslog.h> 41 #include <sys/malloc.h> 42 #include <sys/mount.h> 43 #include <sys/ipc.h> 44 #include <sys/user.h> 45 #include <sys/mman.h> 46 47 #include <machine/cpu.h> 48 #include <machine/reg.h> 49 #include <machine/psl.h> 50 #include <machine/vmparam.h> 51 #include <hp/hpux/hpux.h> 52 #include <hp/hpux/hpux_termio.h> 53 54 #ifdef DEBUG 55 int unimpresponse = 0; 56 #endif 57 58 /* SYS5 style UTSNAME info */ 59 struct hpuxutsname protoutsname = { 60 "4.4bsd", "", "0.5", "B", "9000/3?0", "" 61 }; 62 63 /* 6.0 and later style context */ 64 #if defined(HP380) 65 char hpux040context[] = 66 "standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default"; 67 #endif 68 #ifdef FPCOPROC 69 char hpuxcontext[] = 70 "standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default"; 71 #else 72 char hpuxcontext[] = 73 "standalone HP-MC68020 HP-MC68010 localroot default"; 74 #endif 75 76 /* YP domainname */ 77 char domainname[MAXHOSTNAMELEN] = "unknown"; 78 int domainnamelen = 7; 79 80 #define NERR 83 81 #define BERR 1000 82 83 /* indexed by BSD errno */ 84 short bsdtohpuxerrnomap[NERR] = { 85 /*00*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 86 /*10*/ 10, 45, 12, 13, 14, 15, 16, 17, 18, 19, 87 /*20*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 88 /*30*/ 30, 31, 32, 33, 34, 246, 245, 244, 216, 217, 89 /*40*/ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 90 /*50*/ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 91 /*60*/ 238, 239, 249, 248, 241, 242, 247,BERR,BERR,BERR, 92 /*70*/ 70, 71,BERR,BERR,BERR,BERR,BERR, 46, 251,BERR, 93 /*80*/ BERR,BERR, 11 94 }; 95 96 notimp(p, uap, retval, code, argsize) 97 struct proc *p; 98 register_t *uap, *retval; 99 int code, argsize; 100 { 101 int error = 0; 102 #ifdef DEBUG 103 register int *argp = uap; 104 extern char *hpuxsyscallnames[]; 105 106 printf("HP-UX %s(", hpuxsyscallnames[code]); 107 if (argsize) 108 while (argsize -= sizeof (register_t)) 109 printf("%x%c", *argp++, argsize? ',' : ')'); 110 else 111 printf(")"); 112 printf("\n"); 113 switch (unimpresponse) { 114 case 0: 115 error = nosys(p, uap, retval); 116 break; 117 case 1: 118 error = EINVAL; 119 break; 120 } 121 #else 122 error = nosys(p, uap, retval); 123 #endif 124 uprintf("HP-UX system call %d not implemented\n", code); 125 return (error); 126 } 127 128 /* 129 * HP-UX fork and vfork need to map the EAGAIN return value appropriately. 130 */ 131 hpuxfork(p, uap, retval) 132 struct proc *p; 133 struct hpuxwait3_args *uap; 134 int *retval; 135 { 136 int error; 137 138 error = fork(p, uap, retval); 139 if (error == EAGAIN) 140 error = OEAGAIN; 141 return (error); 142 } 143 144 hpuxvfork(p, uap, retval) 145 struct proc *p; 146 struct hpuxwait3_args *uap; 147 int *retval; 148 149 { 150 int error; 151 152 error = vfork(p, uap, retval); 153 if (error == EAGAIN) 154 error = OEAGAIN; 155 return (error); 156 } 157 158 struct hpuxexecv_args { 159 char *fname; 160 char **argp; 161 char **envp; 162 }; 163 hpuxexecv(p, uap, retval) 164 struct proc *p; 165 struct hpuxexecv_args *uap; 166 int *retval; 167 { 168 extern int execve(); 169 170 uap->envp = NULL; 171 return (execve(p, uap, retval)); 172 } 173 174 /* 175 * HP-UX versions of wait and wait3 actually pass the parameters 176 * (status pointer, options, rusage) into the kernel rather than 177 * handling it in the C library stub. We also need to map any 178 * termination signal from BSD to HP-UX. 179 */ 180 struct hpuxwait3_args { 181 int *status; 182 int options; 183 int rusage; 184 }; 185 hpuxwait3(p, uap, retval) 186 struct proc *p; 187 struct hpuxwait3_args *uap; 188 int *retval; 189 { 190 /* rusage pointer must be zero */ 191 if (uap->rusage) 192 return (EINVAL); 193 p->p_md.md_regs[PS] = PSL_ALLCC; 194 p->p_md.md_regs[R0] = uap->options; 195 p->p_md.md_regs[R1] = uap->rusage; 196 return (hpuxwait(p, uap, retval)); 197 } 198 199 struct hpuxwait_args { 200 int *status; 201 }; 202 hpuxwait(p, uap, retval) 203 struct proc *p; 204 struct hpuxwait_args *uap; 205 int *retval; 206 { 207 int sig, *statp, error; 208 209 statp = uap->status; /* owait clobbers first arg */ 210 error = compat_43_wait(p, uap, retval); 211 /* 212 * HP-UX wait always returns EINTR when interrupted by a signal 213 * (well, unless its emulating a BSD process, but we don't bother...) 214 */ 215 if (error == ERESTART) 216 error = EINTR; 217 if (error) 218 return (error); 219 sig = retval[1] & 0xFF; 220 if (sig == WSTOPPED) { 221 sig = (retval[1] >> 8) & 0xFF; 222 retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED; 223 } else if (sig) 224 retval[1] = (retval[1] & 0xFF00) | 225 bsdtohpuxsig(sig & 0x7F) | (sig & 0x80); 226 if (statp) 227 if (suword((caddr_t)statp, retval[1])) 228 error = EFAULT; 229 return (error); 230 } 231 232 struct hpuxwaitpid_args { 233 int pid; 234 int *status; 235 int options; 236 struct rusage *rusage; /* wait4 arg */ 237 }; 238 hpuxwaitpid(p, uap, retval) 239 struct proc *p; 240 struct hpuxwaitpid_args *uap; 241 int *retval; 242 { 243 int rv, sig, xstat, error; 244 245 uap->rusage = 0; 246 error = wait4(p, uap, retval); 247 /* 248 * HP-UX wait always returns EINTR when interrupted by a signal 249 * (well, unless its emulating a BSD process, but we don't bother...) 250 */ 251 if (error == ERESTART) 252 error = EINTR; 253 if (error) 254 return (error); 255 if (uap->status) { 256 /* 257 * Wait4 already wrote the status out to user space, 258 * pull it back, change the signal portion, and write 259 * it back out. 260 */ 261 rv = fuword((caddr_t)uap->status); 262 if (WIFSTOPPED(rv)) { 263 sig = WSTOPSIG(rv); 264 rv = W_STOPCODE(bsdtohpuxsig(sig)); 265 } else if (WIFSIGNALED(rv)) { 266 sig = WTERMSIG(rv); 267 xstat = WEXITSTATUS(rv); 268 rv = W_EXITCODE(xstat, bsdtohpuxsig(sig)) | 269 WCOREDUMP(rv); 270 } 271 (void)suword((caddr_t)uap->status, rv); 272 } 273 return (error); 274 } 275 276 /* 277 * Old creat system call. 278 */ 279 struct hpuxcreat_args { 280 char *fname; 281 int fmode; 282 }; 283 hpuxcreat(p, uap, retval) 284 struct proc *p; 285 register struct hpuxcreat_args *uap; 286 int *retval; 287 { 288 struct nargs { 289 char *fname; 290 int mode; 291 int crtmode; 292 } openuap; 293 294 openuap.fname = uap->fname; 295 openuap.crtmode = uap->fmode; 296 openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 297 return (open(p, &openuap, retval)); 298 } 299 300 /* 301 * XXX extensions to the fd_ofileflags flags. 302 * Hate to put this there, but they do need to be per-file. 303 */ 304 #define UF_NONBLOCK_ON 0x10 305 #define UF_FNDELAY_ON 0x20 306 #define UF_FIONBIO_ON 0x40 307 308 /* 309 * Must remap some bits in the mode mask. 310 * O_CREAT, O_TRUNC, and O_EXCL must be remapped, 311 * O_NONBLOCK is remapped and remembered, 312 * O_FNDELAY is remembered, 313 * O_SYNCIO is removed entirely. 314 */ 315 struct hpuxopen_args { 316 char *fname; 317 int mode; 318 int crtmode; 319 }; 320 hpuxopen(p, uap, retval) 321 struct proc *p; 322 register struct hpuxopen_args *uap; 323 int *retval; 324 { 325 int mode, error; 326 327 mode = uap->mode; 328 uap->mode &= 329 ~(HPUXNONBLOCK|HPUXFSYNCIO|HPUXFEXCL|HPUXFTRUNC|HPUXFCREAT); 330 if (mode & HPUXFCREAT) { 331 /* 332 * simulate the pre-NFS behavior that opening a 333 * file for READ+CREATE ignores the CREATE (unless 334 * EXCL is set in which case we will return the 335 * proper error). 336 */ 337 if ((mode & HPUXFEXCL) || (FFLAGS(mode) & FWRITE)) 338 uap->mode |= O_CREAT; 339 } 340 if (mode & HPUXFTRUNC) 341 uap->mode |= O_TRUNC; 342 if (mode & HPUXFEXCL) 343 uap->mode |= O_EXCL; 344 if (mode & HPUXNONBLOCK) 345 uap->mode |= O_NDELAY; 346 error = open(p, uap, retval); 347 /* 348 * Record non-blocking mode for fcntl, read, write, etc. 349 */ 350 if (error == 0 && (uap->mode & O_NDELAY)) 351 p->p_fd->fd_ofileflags[*retval] |= 352 (mode & HPUXNONBLOCK) ? UF_NONBLOCK_ON : UF_FNDELAY_ON; 353 return (error); 354 } 355 356 struct hpuxfcntl_args { 357 int fdes; 358 int cmd; 359 int arg; 360 }; 361 hpuxfcntl(p, uap, retval) 362 struct proc *p; 363 register struct hpuxfcntl_args *uap; 364 int *retval; 365 { 366 int mode, error, flg = F_POSIX; 367 struct file *fp; 368 char *pop; 369 struct hpuxflock hfl; 370 struct flock fl; 371 struct vnode *vp; 372 373 if ((unsigned)uap->fdes >= p->p_fd->fd_nfiles || 374 (fp = p->p_fd->fd_ofiles[uap->fdes]) == NULL) 375 return (EBADF); 376 pop = &p->p_fd->fd_ofileflags[uap->fdes]; 377 switch (uap->cmd) { 378 case F_SETFL: 379 if (uap->arg & HPUXNONBLOCK) 380 *pop |= UF_NONBLOCK_ON; 381 else 382 *pop &= ~UF_NONBLOCK_ON; 383 if (uap->arg & HPUXNDELAY) 384 *pop |= UF_FNDELAY_ON; 385 else 386 *pop &= ~UF_FNDELAY_ON; 387 if (*pop & (UF_NONBLOCK_ON|UF_FNDELAY_ON|UF_FIONBIO_ON)) 388 uap->arg |= FNONBLOCK; 389 else 390 uap->arg &= ~FNONBLOCK; 391 uap->arg &= ~(HPUXNONBLOCK|HPUXFSYNCIO|HPUXFREMOTE); 392 break; 393 case F_GETFL: 394 case F_DUPFD: 395 case F_GETFD: 396 case F_SETFD: 397 break; 398 399 case HPUXF_SETLKW: 400 flg |= F_WAIT; 401 /* Fall into F_SETLK */ 402 403 case HPUXF_SETLK: 404 if (fp->f_type != DTYPE_VNODE) 405 return (EBADF); 406 vp = (struct vnode *)fp->f_data; 407 /* Copy in the lock structure */ 408 error = copyin((caddr_t)uap->arg, (caddr_t)&hfl, sizeof (hfl)); 409 if (error) 410 return (error); 411 fl.l_start = hfl.hl_start; 412 fl.l_len = hfl.hl_len; 413 fl.l_pid = hfl.hl_pid; 414 fl.l_type = hfl.hl_type; 415 fl.l_whence = hfl.hl_whence; 416 if (fl.l_whence == SEEK_CUR) 417 fl.l_start += fp->f_offset; 418 switch (fl.l_type) { 419 420 case F_RDLCK: 421 if ((fp->f_flag & FREAD) == 0) 422 return (EBADF); 423 p->p_flag |= P_ADVLOCK; 424 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 425 426 case F_WRLCK: 427 if ((fp->f_flag & FWRITE) == 0) 428 return (EBADF); 429 p->p_flag |= P_ADVLOCK; 430 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 431 432 case F_UNLCK: 433 return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, 434 F_POSIX)); 435 436 default: 437 return (EINVAL); 438 } 439 440 case F_GETLK: 441 if (fp->f_type != DTYPE_VNODE) 442 return (EBADF); 443 vp = (struct vnode *)fp->f_data; 444 /* Copy in the lock structure */ 445 error = copyin((caddr_t)uap->arg, (caddr_t)&hfl, sizeof (hfl)); 446 if (error) 447 return (error); 448 fl.l_start = hfl.hl_start; 449 fl.l_len = hfl.hl_len; 450 fl.l_pid = hfl.hl_pid; 451 fl.l_type = hfl.hl_type; 452 fl.l_whence = hfl.hl_whence; 453 if (fl.l_whence == SEEK_CUR) 454 fl.l_start += fp->f_offset; 455 if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) 456 return (error); 457 hfl.hl_start = fl.l_start; 458 hfl.hl_len = fl.l_len; 459 hfl.hl_pid = fl.l_pid; 460 hfl.hl_type = fl.l_type; 461 hfl.hl_whence = fl.l_whence; 462 return (copyout((caddr_t)&hfl, (caddr_t)uap->arg, sizeof (hfl))); 463 464 default: 465 return (EINVAL); 466 } 467 error = fcntl(p, uap, retval); 468 if (error == 0 && uap->cmd == F_GETFL) { 469 mode = *retval; 470 *retval &= ~(O_CREAT|O_TRUNC|O_EXCL); 471 if (mode & FNONBLOCK) { 472 if (*pop & UF_NONBLOCK_ON) 473 *retval |= HPUXNONBLOCK; 474 if ((*pop & UF_FNDELAY_ON) == 0) 475 *retval &= ~HPUXNDELAY; 476 } 477 if (mode & O_CREAT) 478 *retval |= HPUXFCREAT; 479 if (mode & O_TRUNC) 480 *retval |= HPUXFTRUNC; 481 if (mode & O_EXCL) 482 *retval |= HPUXFEXCL; 483 } 484 return (error); 485 } 486 487 /* 488 * Read and write calls. Same as BSD except for non-blocking behavior. 489 * There are three types of non-blocking reads/writes in HP-UX checked 490 * in the following order: 491 * 492 * O_NONBLOCK: return -1 and errno == EAGAIN 493 * O_NDELAY: return 0 494 * FIOSNBIO: return -1 and errno == EWOULDBLOCK 495 */ 496 struct hpuxrw_args { 497 int fd; 498 }; 499 500 hpuxread(p, uap, retval) 501 struct proc *p; 502 struct hpuxrw_args *uap; 503 int *retval; 504 { 505 int error; 506 507 error = read(p, uap, retval); 508 if (error == EWOULDBLOCK) { 509 char *fp = &p->p_fd->fd_ofileflags[uap->fd]; 510 511 if (*fp & UF_NONBLOCK_ON) { 512 *retval = -1; 513 error = OEAGAIN; 514 } else if (*fp & UF_FNDELAY_ON) { 515 *retval = 0; 516 error = 0; 517 } 518 } 519 return (error); 520 } 521 522 hpuxwrite(p, uap, retval) 523 struct proc *p; 524 struct hpuxrw_args *uap; 525 int *retval; 526 { 527 int error; 528 529 error = write(p, uap, retval); 530 if (error == EWOULDBLOCK) { 531 char *fp = &p->p_fd->fd_ofileflags[uap->fd]; 532 533 if (*fp & UF_NONBLOCK_ON) { 534 *retval = -1; 535 error = OEAGAIN; 536 } else if (*fp & UF_FNDELAY_ON) { 537 *retval = 0; 538 error = 0; 539 } 540 } 541 return (error); 542 } 543 544 hpuxreadv(p, uap, retval) 545 struct proc *p; 546 struct hpuxrw_args *uap; 547 int *retval; 548 { 549 int error; 550 551 error = readv(p, uap, retval); 552 if (error == EWOULDBLOCK) { 553 char *fp = &p->p_fd->fd_ofileflags[uap->fd]; 554 555 if (*fp & UF_NONBLOCK_ON) { 556 *retval = -1; 557 error = OEAGAIN; 558 } else if (*fp & UF_FNDELAY_ON) { 559 *retval = 0; 560 error = 0; 561 } 562 } 563 return (error); 564 } 565 566 hpuxwritev(p, uap, retval) 567 struct proc *p; 568 struct hpuxrw_args *uap; 569 int *retval; 570 { 571 int error; 572 573 error = writev(p, uap, retval); 574 if (error == EWOULDBLOCK) { 575 char *fp = &p->p_fd->fd_ofileflags[uap->fd]; 576 577 if (*fp & UF_NONBLOCK_ON) { 578 *retval = -1; 579 error = OEAGAIN; 580 } else if (*fp & UF_FNDELAY_ON) { 581 *retval = 0; 582 error = 0; 583 } 584 } 585 return (error); 586 } 587 588 /* 589 * 4.3bsd dup allows dup2 to come in on the same syscall entry 590 * and hence allows two arguments. HP-UX dup has only one arg. 591 */ 592 struct hpuxdup_args { 593 int i; 594 }; 595 hpuxdup(p, uap, retval) 596 struct proc *p; 597 register struct hpuxdup_args *uap; 598 int *retval; 599 { 600 register struct filedesc *fdp = p->p_fd; 601 struct file *fp; 602 int fd, error; 603 604 if (((unsigned)uap->i) >= fdp->fd_nfiles || 605 (fp = fdp->fd_ofiles[uap->i]) == NULL) 606 return (EBADF); 607 if (error = fdalloc(p, 0, &fd)) 608 return (error); 609 fdp->fd_ofiles[fd] = fp; 610 fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE; 611 fp->f_count++; 612 if (fd > fdp->fd_lastfile) 613 fdp->fd_lastfile = fd; 614 *retval = fd; 615 return (0); 616 } 617 618 struct hpuxutssys_args { 619 struct hpuxutsname *uts; 620 int dev; 621 int request; 622 }; 623 hpuxutssys(p, uap, retval) 624 struct proc *p; 625 register struct hpuxutssys_args *uap; 626 int *retval; 627 { 628 register int i; 629 int error; 630 631 switch (uap->request) { 632 /* uname */ 633 case 0: 634 /* fill in machine type */ 635 switch (machineid) { 636 case HP_320: 637 protoutsname.machine[6] = '2'; 638 break; 639 /* includes 318 and 319 */ 640 case HP_330: 641 protoutsname.machine[6] = '3'; 642 break; 643 case HP_340: 644 protoutsname.machine[6] = '4'; 645 break; 646 case HP_350: 647 protoutsname.machine[6] = '5'; 648 break; 649 case HP_360: 650 protoutsname.machine[6] = '6'; 651 break; 652 case HP_370: 653 protoutsname.machine[6] = '7'; 654 break; 655 /* includes 345 */ 656 case HP_375: 657 protoutsname.machine[6] = '7'; 658 protoutsname.machine[7] = '5'; 659 break; 660 /* includes 425 */ 661 case HP_380: 662 protoutsname.machine[6] = '8'; 663 break; 664 case HP_433: 665 protoutsname.machine[5] = '4'; 666 protoutsname.machine[6] = '3'; 667 protoutsname.machine[7] = '3'; 668 break; 669 } 670 /* copy hostname (sans domain) to nodename */ 671 for (i = 0; i < 8 && hostname[i] != '.'; i++) 672 protoutsname.nodename[i] = hostname[i]; 673 protoutsname.nodename[i] = '\0'; 674 error = copyout((caddr_t)&protoutsname, (caddr_t)uap->uts, 675 sizeof(struct hpuxutsname)); 676 break; 677 678 /* gethostname */ 679 case 5: 680 /* uap->dev is length */ 681 if (uap->dev > hostnamelen + 1) 682 uap->dev = hostnamelen + 1; 683 error = copyout((caddr_t)hostname, (caddr_t)uap->uts, 684 uap->dev); 685 break; 686 687 case 1: /* ?? */ 688 case 2: /* ustat */ 689 case 3: /* ?? */ 690 case 4: /* sethostname */ 691 default: 692 error = EINVAL; 693 break; 694 } 695 return (error); 696 } 697 698 struct hpuxsysconf_args { 699 int name; 700 }; 701 hpuxsysconf(p, uap, retval) 702 struct proc *p; 703 struct hpuxsysconf_args *uap; 704 int *retval; 705 { 706 switch (uap->name) { 707 708 /* clock ticks per second */ 709 case HPUX_SYSCONF_CLKTICK: 710 *retval = hz; 711 break; 712 713 /* open files */ 714 case HPUX_SYSCONF_OPENMAX: 715 *retval = NOFILE; 716 break; 717 718 /* architecture */ 719 case HPUX_SYSCONF_CPUTYPE: 720 switch (machineid) { 721 case HP_320: 722 case HP_330: 723 case HP_350: 724 *retval = HPUX_SYSCONF_CPUM020; 725 break; 726 case HP_340: 727 case HP_360: 728 case HP_370: 729 case HP_375: 730 *retval = HPUX_SYSCONF_CPUM030; 731 break; 732 case HP_380: 733 case HP_433: 734 *retval = HPUX_SYSCONF_CPUM040; 735 break; 736 } 737 break; 738 default: 739 uprintf("HP-UX sysconf(%d) not implemented\n", uap->name); 740 return (EINVAL); 741 } 742 return (0); 743 } 744 745 struct hpuxstat_args { 746 char *fname; 747 struct hpuxstat *hsb; 748 }; 749 hpuxstat(p, uap, retval) 750 struct proc *p; 751 struct hpuxstat_args *uap; 752 int *retval; 753 { 754 return (hpuxstat1(uap->fname, uap->hsb, FOLLOW, p)); 755 } 756 757 struct hpuxlstat_args { 758 char *fname; 759 struct hpuxstat *hsb; 760 }; 761 hpuxlstat(p, uap, retval) 762 struct proc *p; 763 struct hpuxlstat_args *uap; 764 int *retval; 765 { 766 return (hpuxstat1(uap->fname, uap->hsb, NOFOLLOW, p)); 767 } 768 769 struct hpuxfstat_args { 770 int fdes; 771 struct hpuxstat *hsb; 772 }; 773 hpuxfstat(p, uap, retval) 774 struct proc *p; 775 register struct hpuxfstat_args *uap; 776 int *retval; 777 { 778 register struct filedesc *fdp = p->p_fd; 779 register struct file *fp; 780 struct stat sb; 781 int error; 782 783 if (((unsigned)uap->fdes) >= fdp->fd_nfiles || 784 (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 785 return (EBADF); 786 787 switch (fp->f_type) { 788 789 case DTYPE_VNODE: 790 error = vn_stat((struct vnode *)fp->f_data, &sb, p); 791 break; 792 793 case DTYPE_SOCKET: 794 error = soo_stat((struct socket *)fp->f_data, &sb, p); 795 break; 796 797 default: 798 panic("fstat"); 799 /*NOTREACHED*/ 800 } 801 /* is this right for sockets?? */ 802 if (error == 0) 803 error = bsdtohpuxstat(&sb, uap->hsb); 804 return (error); 805 } 806 807 struct hpuxulimit_args { 808 int cmd; 809 long newlimit; 810 }; 811 hpuxulimit(p, uap, retval) 812 struct proc *p; 813 register struct hpuxulimit_args *uap; 814 long *retval; 815 { 816 struct rlimit *limp; 817 int error = 0; 818 819 limp = &p->p_rlimit[RLIMIT_FSIZE]; 820 switch (uap->cmd) { 821 case 2: 822 uap->newlimit *= 512; 823 if (uap->newlimit > limp->rlim_max && 824 (error = suser(p->p_ucred, &p->p_acflag))) 825 break; 826 limp->rlim_cur = limp->rlim_max = uap->newlimit; 827 /* else fall into... */ 828 829 case 1: 830 *retval = limp->rlim_max / 512; 831 break; 832 833 case 3: 834 limp = &p->p_rlimit[RLIMIT_DATA]; 835 *retval = ctob(p->p_vmspace->vm_tsize) + limp->rlim_max; 836 break; 837 838 default: 839 error = EINVAL; 840 break; 841 } 842 return (error); 843 } 844 845 /* 846 * Map "real time" priorities 0 (high) thru 127 (low) into nice 847 * values -16 (high) thru -1 (low). 848 */ 849 struct hpuxrtprio_args { 850 int pid; 851 int prio; 852 }; 853 hpuxrtprio(cp, uap, retval) 854 struct proc *cp; 855 register struct hpuxrtprio_args *uap; 856 int *retval; 857 { 858 struct proc *p; 859 int nice, error; 860 861 if (uap->prio < RTPRIO_MIN && uap->prio > RTPRIO_MAX && 862 uap->prio != RTPRIO_NOCHG && uap->prio != RTPRIO_RTOFF) 863 return (EINVAL); 864 if (uap->pid == 0) 865 p = cp; 866 else if ((p = pfind(uap->pid)) == 0) 867 return (ESRCH); 868 nice = p->p_nice; 869 if (nice < NZERO) 870 *retval = (nice + 16) << 3; 871 else 872 *retval = RTPRIO_RTOFF; 873 switch (uap->prio) { 874 875 case RTPRIO_NOCHG: 876 return (0); 877 878 case RTPRIO_RTOFF: 879 if (nice >= NZERO) 880 return (0); 881 nice = NZERO; 882 break; 883 884 default: 885 nice = (uap->prio >> 3) - 16; 886 break; 887 } 888 error = donice(cp, p, nice); 889 if (error == EACCES) 890 error = EPERM; 891 return (error); 892 } 893 894 struct hpuxadvise_args { 895 int arg; 896 }; 897 hpuxadvise(p, uap, retval) 898 struct proc *p; 899 struct hpuxadvise_args *uap; 900 int *retval; 901 { 902 int error = 0; 903 904 switch (uap->arg) { 905 case 0: 906 p->p_md.md_flags |= MDP_HPUXMMAP; 907 break; 908 case 1: 909 ICIA(); 910 break; 911 case 2: 912 DCIA(); 913 break; 914 default: 915 error = EINVAL; 916 break; 917 } 918 return (error); 919 } 920 921 struct hpuxptrace_args { 922 int req; 923 int pid; 924 int *addr; 925 int data; 926 }; 927 hpuxptrace(p, uap, retval) 928 struct proc *p; 929 struct hpuxptrace_args *uap; 930 int *retval; 931 { 932 int error, isps = 0; 933 struct proc *cp; 934 935 switch (uap->req) { 936 /* map signal */ 937 case PT_STEP: 938 case PT_CONTINUE: 939 if (uap->data) { 940 uap->data = hpuxtobsdsig(uap->data); 941 if (uap->data == 0) 942 uap->data = NSIG; 943 } 944 break; 945 /* map u-area offset */ 946 case PT_READ_U: 947 case PT_WRITE_U: 948 /* 949 * Big, cheezy hack: hpuxtobsduoff is really intended 950 * to be called in the child context (procxmt) but we 951 * do it here in the parent context to avoid hacks in 952 * the MI sys_process.c file. This works only because 953 * we can access the child's md_regs pointer and it 954 * has the correct value (the child has already trapped 955 * into the kernel). 956 */ 957 if ((cp = pfind(uap->pid)) == 0) 958 return (ESRCH); 959 uap->addr = (int *) hpuxtobsduoff(uap->addr, &isps, cp); 960 961 /* 962 * Since HP-UX PS is only 16-bits in ar0, requests 963 * to write PS actually contain the PS in the high word 964 * and the high half of the PC (the following register) 965 * in the low word. Move the PS value to where BSD 966 * expects it. 967 */ 968 if (isps && uap->req == PT_WRITE_U) 969 uap->data >>= 16; 970 break; 971 } 972 error = ptrace(p, uap, retval); 973 /* 974 * Align PS as HP-UX expects it (see WRITE_U comment above). 975 * Note that we do not return the high part of PC like HP-UX 976 * would, but the HP-UX debuggers don't require it. 977 */ 978 if (isps && error == 0 && uap->req == PT_READ_U) 979 *retval <<= 16; 980 return (error); 981 } 982 983 struct hpuxgetdomainname_args { 984 char *domainname; 985 u_int len; 986 }; 987 hpuxgetdomainname(p, uap, retval) 988 struct proc *p; 989 register struct hpuxgetdomainname_args *uap; 990 int *retval; 991 { 992 if (uap->len > domainnamelen + 1) 993 uap->len = domainnamelen + 1; 994 return (copyout(domainname, uap->domainname, uap->len)); 995 } 996 997 struct hpuxsetdomainname_args { 998 char *domainname; 999 u_int len; 1000 }; 1001 hpuxsetdomainname(p, uap, retval) 1002 struct proc *p; 1003 register struct hpuxsetdomainname_args *uap; 1004 int *retval; 1005 { 1006 int error; 1007 1008 if (error = suser(p->p_ucred, &p->p_acflag)) 1009 return (error); 1010 if (uap->len > sizeof (domainname) - 1) 1011 return (EINVAL); 1012 domainnamelen = uap->len; 1013 error = copyin(uap->domainname, domainname, uap->len); 1014 domainname[domainnamelen] = 0; 1015 return (error); 1016 } 1017 1018 #ifdef SYSVSHM 1019 #include <sys/shm.h> 1020 1021 hpuxshmat(p, uap, retval) 1022 struct proc *p; 1023 int *uap, *retval; 1024 { 1025 return (shmat(p, uap, retval)); 1026 } 1027 1028 hpuxshmdt(p, uap, retval) 1029 struct proc *p; 1030 int *uap, *retval; 1031 { 1032 return (shmdt(p, uap, retval)); 1033 } 1034 1035 hpuxshmget(p, uap, retval) 1036 struct proc *p; 1037 int *uap, *retval; 1038 { 1039 return (shmget(p, uap, retval)); 1040 } 1041 1042 hpuxshmctl(p, uap, retval) 1043 struct proc *p; 1044 int *uap, *retval; 1045 { 1046 return (hpuxshmctl1(p, uap, retval, 0)); 1047 } 1048 1049 hpuxnshmctl(p, uap, retval) 1050 struct proc *p; 1051 int *uap, *retval; 1052 { 1053 return (hpuxshmctl1(p, uap, retval, 1)); 1054 } 1055 1056 /* 1057 * Handle HP-UX specific commands. 1058 */ 1059 struct hpuxshmctl_args { 1060 int shmid; 1061 int cmd; 1062 caddr_t buf; 1063 }; 1064 hpuxshmctl1(p, uap, retval, isnew) 1065 struct proc *p; 1066 struct hpuxshmctl_args *uap; 1067 int *retval; 1068 int isnew; 1069 { 1070 register struct shmid_ds *shp; 1071 register struct ucred *cred = p->p_ucred; 1072 struct hpuxshmid_ds sbuf; 1073 int error; 1074 1075 if (error = shmvalid(uap->shmid)) 1076 return (error); 1077 shp = &shmsegs[uap->shmid % SHMMMNI]; 1078 switch (uap->cmd) { 1079 case SHM_LOCK: 1080 case SHM_UNLOCK: 1081 /* don't really do anything, but make them think we did */ 1082 if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid && 1083 cred->cr_uid != shp->shm_perm.cuid) 1084 return (EPERM); 1085 return (0); 1086 1087 case IPC_STAT: 1088 if (!isnew) 1089 break; 1090 error = ipcaccess(&shp->shm_perm, IPC_R, cred); 1091 if (error == 0) { 1092 sbuf.shm_perm.uid = shp->shm_perm.uid; 1093 sbuf.shm_perm.gid = shp->shm_perm.gid; 1094 sbuf.shm_perm.cuid = shp->shm_perm.cuid; 1095 sbuf.shm_perm.cgid = shp->shm_perm.cgid; 1096 sbuf.shm_perm.mode = shp->shm_perm.mode; 1097 sbuf.shm_perm.seq = shp->shm_perm.seq; 1098 sbuf.shm_perm.key = shp->shm_perm.key; 1099 sbuf.shm_segsz = shp->shm_segsz; 1100 sbuf.shm_ptbl = shp->shm_handle; /* XXX */ 1101 sbuf.shm_lpid = shp->shm_lpid; 1102 sbuf.shm_cpid = shp->shm_cpid; 1103 sbuf.shm_nattch = shp->shm_nattch; 1104 sbuf.shm_cnattch = shp->shm_nattch; /* XXX */ 1105 sbuf.shm_atime = shp->shm_atime; 1106 sbuf.shm_dtime = shp->shm_dtime; 1107 sbuf.shm_ctime = shp->shm_ctime; 1108 error = copyout((caddr_t)&sbuf, uap->buf, sizeof sbuf); 1109 } 1110 return (error); 1111 1112 case IPC_SET: 1113 if (!isnew) 1114 break; 1115 if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid && 1116 cred->cr_uid != shp->shm_perm.cuid) { 1117 return (EPERM); 1118 } 1119 error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf); 1120 if (error == 0) { 1121 shp->shm_perm.uid = sbuf.shm_perm.uid; 1122 shp->shm_perm.gid = sbuf.shm_perm.gid; 1123 shp->shm_perm.mode = (shp->shm_perm.mode & ~0777) 1124 | (sbuf.shm_perm.mode & 0777); 1125 shp->shm_ctime = time.tv_sec; 1126 } 1127 return (error); 1128 } 1129 return (shmctl(p, uap, retval)); 1130 } 1131 #endif 1132 1133 /* 1134 * Fake semaphore routines, just don't return an error. 1135 * Should be adequate for starbase to run. 1136 */ 1137 struct hpuxsemctl_args { 1138 int semid; 1139 u_int semnum; 1140 int cmd; 1141 int arg; 1142 }; 1143 hpuxsemctl(p, uap, retval) 1144 struct proc *p; 1145 struct hpuxsemctl_args *uap; 1146 int *retval; 1147 { 1148 /* XXX: should do something here */ 1149 return (0); 1150 } 1151 1152 struct hpuxsemget_args { 1153 key_t key; 1154 int nsems; 1155 int semflg; 1156 }; 1157 hpuxsemget(p, uap, retval) 1158 struct proc *p; 1159 struct hpuxsemget_args *uap; 1160 int *retval; 1161 { 1162 /* XXX: should do something here */ 1163 return (0); 1164 } 1165 1166 struct hpuxsemop_args { 1167 int semid; 1168 struct sembuf *sops; 1169 u_int nsops; 1170 }; 1171 hpuxsemop(p, uap, retval) 1172 struct proc *p; 1173 struct hpuxsemop_args *uap; 1174 int *retval; 1175 { 1176 /* XXX: should do something here */ 1177 return (0); 1178 } 1179 1180 /* 1181 * HP-UX mmap() emulation (mainly for shared library support). 1182 */ 1183 struct hpuxmmap_args { 1184 caddr_t addr; 1185 int len; 1186 int prot; 1187 int flags; 1188 int fd; 1189 long pos; 1190 }; 1191 hpuxmmap(p, uap, retval) 1192 struct proc *p; 1193 struct hpuxmmap_args *uap; 1194 int *retval; 1195 { 1196 struct mmap_args { 1197 caddr_t addr; 1198 int len; 1199 int prot; 1200 int flags; 1201 int fd; 1202 long pad; 1203 off_t pos; 1204 } nargs; 1205 1206 nargs.addr = uap->addr; 1207 nargs.len = uap->len; 1208 nargs.prot = uap->prot; 1209 nargs.flags = uap->flags & 1210 ~(HPUXMAP_FIXED|HPUXMAP_REPLACE|HPUXMAP_ANON); 1211 if (uap->flags & HPUXMAP_FIXED) 1212 nargs.flags |= MAP_FIXED; 1213 if (uap->flags & HPUXMAP_ANON) 1214 nargs.flags |= MAP_ANON; 1215 nargs.fd = (nargs.flags & MAP_ANON) ? -1 : uap->fd; 1216 nargs.pos = uap->pos; 1217 return (mmap(p, &nargs, retval)); 1218 } 1219 1220 /* convert from BSD to HP-UX errno */ 1221 bsdtohpuxerrno(err) 1222 int err; 1223 { 1224 if (err < 0 || err >= NERR) 1225 return(BERR); 1226 return((int)bsdtohpuxerrnomap[err]); 1227 } 1228 1229 hpuxstat1(fname, hsb, follow, p) 1230 char *fname; 1231 struct hpuxstat *hsb; 1232 int follow; 1233 struct proc *p; 1234 { 1235 int error; 1236 struct stat sb; 1237 struct nameidata nd; 1238 1239 NDINIT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fname, p); 1240 if (error = namei(&nd)) 1241 return (error); 1242 error = vn_stat(nd.ni_vp, &sb, p); 1243 vput(nd.ni_vp); 1244 if (error == 0) 1245 error = bsdtohpuxstat(&sb, hsb); 1246 return (error); 1247 } 1248 1249 #include "grf.h" 1250 #if NGRF > 0 1251 #ifdef __STDC__ 1252 extern int grfopen(dev_t dev, int oflags, int devtype, struct proc *p); 1253 #else 1254 extern int grfopen(); 1255 #endif 1256 #endif 1257 1258 #define NHIL 1 /* XXX */ 1259 #if NHIL > 0 1260 #ifdef __STDC__ 1261 extern int hilopen(dev_t dev, int oflags, int devtype, struct proc *p); 1262 #else 1263 extern int hilopen(); 1264 #endif 1265 #endif 1266 1267 #include <sys/conf.h> 1268 1269 bsdtohpuxstat(sb, hsb) 1270 struct stat *sb; 1271 struct hpuxstat *hsb; 1272 { 1273 struct hpuxstat ds; 1274 1275 bzero((caddr_t)&ds, sizeof(ds)); 1276 ds.hst_dev = (u_short)sb->st_dev; 1277 ds.hst_ino = (u_long)sb->st_ino; 1278 ds.hst_mode = sb->st_mode; 1279 ds.hst_nlink = sb->st_nlink; 1280 ds.hst_uid = (u_short)sb->st_uid; 1281 ds.hst_gid = (u_short)sb->st_gid; 1282 ds.hst_rdev = bsdtohpuxdev(sb->st_rdev); 1283 1284 /* XXX: I don't want to talk about it... */ 1285 if ((sb->st_mode & S_IFMT) == S_IFCHR) { 1286 #if NGRF > 0 1287 if (cdevsw[major(sb->st_rdev)].d_open == grfopen) 1288 ds.hst_rdev = grfdevno(sb->st_rdev); 1289 #endif 1290 #if NHIL > 0 1291 if (cdevsw[major(sb->st_rdev)].d_open == hilopen) 1292 ds.hst_rdev = hildevno(sb->st_rdev); 1293 #endif 1294 ; 1295 } 1296 if (sb->st_size < (quad_t)1 << 32) 1297 ds.hst_size = (long)sb->st_size; 1298 else 1299 ds.hst_size = -2; 1300 ds.hst_atime = sb->st_atime; 1301 ds.hst_mtime = sb->st_mtime; 1302 ds.hst_ctime = sb->st_ctime; 1303 ds.hst_blksize = sb->st_blksize; 1304 ds.hst_blocks = sb->st_blocks; 1305 return(copyout((caddr_t)&ds, (caddr_t)hsb, sizeof(ds))); 1306 } 1307 1308 hpuxtobsdioctl(com) 1309 int com; 1310 { 1311 switch (com) { 1312 case HPUXTIOCSLTC: 1313 com = TIOCSLTC; break; 1314 case HPUXTIOCGLTC: 1315 com = TIOCGLTC; break; 1316 case HPUXTIOCSPGRP: 1317 com = TIOCSPGRP; break; 1318 case HPUXTIOCGPGRP: 1319 com = TIOCGPGRP; break; 1320 case HPUXTIOCLBIS: 1321 com = TIOCLBIS; break; 1322 case HPUXTIOCLBIC: 1323 com = TIOCLBIC; break; 1324 case HPUXTIOCLSET: 1325 com = TIOCLSET; break; 1326 case HPUXTIOCLGET: 1327 com = TIOCLGET; break; 1328 case HPUXTIOCGWINSZ: 1329 com = TIOCGWINSZ; break; 1330 case HPUXTIOCSWINSZ: 1331 com = TIOCSWINSZ; break; 1332 } 1333 return(com); 1334 } 1335 1336 /* 1337 * HP-UX ioctl system call. The differences here are: 1338 * IOC_IN also means IOC_VOID if the size portion is zero. 1339 * no FIOCLEX/FIONCLEX/FIOASYNC/FIOGETOWN/FIOSETOWN 1340 * the sgttyb struct is 2 bytes longer 1341 */ 1342 struct hpuxioctl_args { 1343 int fdes; 1344 int cmd; 1345 caddr_t cmarg; 1346 }; 1347 hpuxioctl(p, uap, retval) 1348 struct proc *p; 1349 register struct hpuxioctl_args *uap; 1350 int *retval; 1351 { 1352 register struct filedesc *fdp = p->p_fd; 1353 register struct file *fp; 1354 register int com, error; 1355 register u_int size; 1356 caddr_t memp = 0; 1357 #define STK_PARAMS 128 1358 char stkbuf[STK_PARAMS]; 1359 caddr_t data = stkbuf; 1360 1361 com = uap->cmd; 1362 1363 /* XXX */ 1364 if (com == HPUXTIOCGETP || com == HPUXTIOCSETP) 1365 return (getsettty(p, uap->fdes, com, uap->cmarg)); 1366 1367 if (((unsigned)uap->fdes) >= fdp->fd_nfiles || 1368 (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 1369 return (EBADF); 1370 if ((fp->f_flag & (FREAD|FWRITE)) == 0) 1371 return (EBADF); 1372 1373 /* 1374 * Interpret high order word to find 1375 * amount of data to be copied to/from the 1376 * user's address space. 1377 */ 1378 size = IOCPARM_LEN(com); 1379 if (size > IOCPARM_MAX) 1380 return (ENOTTY); 1381 if (size > sizeof (stkbuf)) { 1382 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); 1383 data = memp; 1384 } 1385 if (com&IOC_IN) { 1386 if (size) { 1387 error = copyin(uap->cmarg, data, (u_int)size); 1388 if (error) { 1389 if (memp) 1390 free(memp, M_IOCTLOPS); 1391 return (error); 1392 } 1393 } else 1394 *(caddr_t *)data = uap->cmarg; 1395 } else if ((com&IOC_OUT) && size) 1396 /* 1397 * Zero the buffer so the user always 1398 * gets back something deterministic. 1399 */ 1400 bzero(data, size); 1401 else if (com&IOC_VOID) 1402 *(caddr_t *)data = uap->cmarg; 1403 1404 switch (com) { 1405 1406 case HPUXFIOSNBIO: 1407 { 1408 char *ofp = &fdp->fd_ofileflags[uap->fdes]; 1409 int tmp; 1410 1411 if (*(int *)data) 1412 *ofp |= UF_FIONBIO_ON; 1413 else 1414 *ofp &= ~UF_FIONBIO_ON; 1415 /* 1416 * Only set/clear if O_NONBLOCK/FNDELAY not in effect 1417 */ 1418 if ((*ofp & (UF_NONBLOCK_ON|UF_FNDELAY_ON)) == 0) { 1419 tmp = *ofp & UF_FIONBIO_ON; 1420 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, 1421 (caddr_t)&tmp, p); 1422 } 1423 break; 1424 } 1425 1426 case HPUXTIOCCONS: 1427 *(int *)data = 1; 1428 error = (*fp->f_ops->fo_ioctl)(fp, TIOCCONS, data, p); 1429 break; 1430 1431 /* BSD-style job control ioctls */ 1432 case HPUXTIOCLBIS: 1433 case HPUXTIOCLBIC: 1434 case HPUXTIOCLSET: 1435 *(int *)data &= HPUXLTOSTOP; 1436 if (*(int *)data & HPUXLTOSTOP) 1437 *(int *)data = LTOSTOP; 1438 /* fall into */ 1439 1440 /* simple mapping cases */ 1441 case HPUXTIOCLGET: 1442 case HPUXTIOCSLTC: 1443 case HPUXTIOCGLTC: 1444 case HPUXTIOCSPGRP: 1445 case HPUXTIOCGPGRP: 1446 case HPUXTIOCGWINSZ: 1447 case HPUXTIOCSWINSZ: 1448 error = (*fp->f_ops->fo_ioctl) 1449 (fp, hpuxtobsdioctl(com), data, p); 1450 if (error == 0 && com == HPUXTIOCLGET) { 1451 *(int *)data &= LTOSTOP; 1452 if (*(int *)data & LTOSTOP) 1453 *(int *)data = HPUXLTOSTOP; 1454 } 1455 break; 1456 1457 /* SYS 5 termio and POSIX termios */ 1458 case HPUXTCGETA: 1459 case HPUXTCSETA: 1460 case HPUXTCSETAW: 1461 case HPUXTCSETAF: 1462 case HPUXTCGETATTR: 1463 case HPUXTCSETATTR: 1464 case HPUXTCSETATTRD: 1465 case HPUXTCSETATTRF: 1466 error = hpuxtermio(uap->fdes, com, data, p); 1467 break; 1468 1469 default: 1470 error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); 1471 break; 1472 } 1473 /* 1474 * Copy any data to user, size was 1475 * already set and checked above. 1476 */ 1477 if (error == 0 && (com&IOC_OUT) && size) 1478 error = copyout(data, uap->cmarg, (u_int)size); 1479 if (memp) 1480 free(memp, M_IOCTLOPS); 1481 return (error); 1482 } 1483 1484 /* 1485 * Man page lies, behaviour here is based on observed behaviour. 1486 */ 1487 struct hpuxgetcontext_args { 1488 char *buf; 1489 int len; 1490 }; 1491 hpuxgetcontext(p, uap, retval) 1492 struct proc *p; 1493 struct hpuxgetcontext_args *uap; 1494 int *retval; 1495 { 1496 int error = 0; 1497 register int len; 1498 1499 #if defined(HP380) 1500 if (machineid == HP_380) { 1501 len = min(uap->len, sizeof(hpux040context)); 1502 if (len) 1503 error = copyout(hpux040context, uap->buf, len); 1504 if (error == 0) 1505 *retval = sizeof(hpux040context); 1506 return (error); 1507 } 1508 #endif 1509 len = min(uap->len, sizeof(hpuxcontext)); 1510 if (len) 1511 error = copyout(hpuxcontext, uap->buf, (u_int)len); 1512 if (error == 0) 1513 *retval = sizeof(hpuxcontext); 1514 return (error); 1515 } 1516 1517 /* 1518 * This is the equivalent of BSD getpgrp but with more restrictions. 1519 * Note we do not check the real uid or "saved" uid. 1520 */ 1521 struct hpuxgetpgrp2_args { 1522 int pid; 1523 }; 1524 hpuxgetpgrp2(cp, uap, retval) 1525 struct proc *cp; 1526 register struct hpuxgetpgrp2_args *uap; 1527 int *retval; 1528 { 1529 register struct proc *p; 1530 1531 if (uap->pid == 0) 1532 uap->pid = cp->p_pid; 1533 p = pfind(uap->pid); 1534 if (p == 0) 1535 return (ESRCH); 1536 if (cp->p_ucred->cr_uid && p->p_ucred->cr_uid != cp->p_ucred->cr_uid && 1537 !inferior(p)) 1538 return (EPERM); 1539 *retval = p->p_pgid; 1540 return (0); 1541 } 1542 1543 /* 1544 * This is the equivalent of BSD setpgrp but with more restrictions. 1545 * Note we do not check the real uid or "saved" uid or pgrp. 1546 */ 1547 struct hpuxsetpgrp2_args { 1548 int pid; 1549 int pgrp; 1550 }; 1551 hpuxsetpgrp2(p, uap, retval) 1552 struct proc *p; 1553 struct hpuxsetpgrp2_args *uap; 1554 int *retval; 1555 { 1556 /* empirically determined */ 1557 if (uap->pgrp < 0 || uap->pgrp >= 30000) 1558 return (EINVAL); 1559 return (setpgid(p, uap, retval)); 1560 } 1561 1562 /* 1563 * XXX Same as BSD setre[ug]id right now. Need to consider saved ids. 1564 */ 1565 struct hpuxsetresuid_args { 1566 int ruid; 1567 int euid; 1568 int suid; 1569 }; 1570 hpuxsetresuid(p, uap, retval) 1571 struct proc *p; 1572 struct hpuxsetresuid_args *uap; 1573 int *retval; 1574 { 1575 return (compat_43_setreuid(p, uap, retval)); 1576 } 1577 1578 struct hpuxsetresgid_args { 1579 int rgid; 1580 int egid; 1581 int sgid; 1582 }; 1583 hpuxsetresgid(p, uap, retval) 1584 struct proc *p; 1585 struct hpuxsetresgid_args *uap; 1586 int *retval; 1587 { 1588 return (compat_43_setregid(p, uap, retval)); 1589 } 1590 1591 struct hpuxrlimit_args { 1592 u_int which; 1593 struct orlimit *rlp; 1594 }; 1595 hpuxgetrlimit(p, uap, retval) 1596 struct proc *p; 1597 struct hpuxrlimit_args *uap; 1598 int *retval; 1599 { 1600 if (uap->which > HPUXRLIMIT_NOFILE) 1601 return (EINVAL); 1602 if (uap->which == HPUXRLIMIT_NOFILE) 1603 uap->which = RLIMIT_NOFILE; 1604 return (compat_43_getrlimit(p, uap, retval)); 1605 } 1606 1607 hpuxsetrlimit(p, uap, retval) 1608 struct proc *p; 1609 struct hpuxrlimit_args *uap; 1610 int *retval; 1611 { 1612 if (uap->which > HPUXRLIMIT_NOFILE) 1613 return (EINVAL); 1614 if (uap->which == HPUXRLIMIT_NOFILE) 1615 uap->which = RLIMIT_NOFILE; 1616 return (compat_43_setrlimit(p, uap, retval)); 1617 } 1618 1619 /* 1620 * XXX: simple recognition hack to see if we can make grmd work. 1621 */ 1622 struct hpuxlockf_args { 1623 int fd; 1624 int func; 1625 long size; 1626 }; 1627 hpuxlockf(p, uap, retval) 1628 struct proc *p; 1629 struct hpuxlockf_args *uap; 1630 int *retval; 1631 { 1632 return (0); 1633 } 1634 1635 struct hpuxgetaccess_args { 1636 char *path; 1637 int uid; 1638 int ngroups; 1639 int *gidset; 1640 void *label; 1641 void *privs; 1642 }; 1643 hpuxgetaccess(p, uap, retval) 1644 register struct proc *p; 1645 register struct hpuxgetaccess_args *uap; 1646 int *retval; 1647 { 1648 int lgroups[NGROUPS]; 1649 int error = 0; 1650 register struct ucred *cred; 1651 register struct vnode *vp; 1652 struct nameidata nd; 1653 1654 /* 1655 * Build an appropriate credential structure 1656 */ 1657 cred = crdup(p->p_ucred); 1658 switch (uap->uid) { 1659 case 65502: /* UID_EUID */ 1660 break; 1661 case 65503: /* UID_RUID */ 1662 cred->cr_uid = p->p_cred->p_ruid; 1663 break; 1664 case 65504: /* UID_SUID */ 1665 error = EINVAL; 1666 break; 1667 default: 1668 if (uap->uid > 65504) 1669 error = EINVAL; 1670 cred->cr_uid = uap->uid; 1671 break; 1672 } 1673 switch (uap->ngroups) { 1674 case -1: /* NGROUPS_EGID */ 1675 cred->cr_ngroups = 1; 1676 break; 1677 case -5: /* NGROUPS_EGID_SUPP */ 1678 break; 1679 case -2: /* NGROUPS_RGID */ 1680 cred->cr_ngroups = 1; 1681 cred->cr_gid = p->p_cred->p_rgid; 1682 break; 1683 case -6: /* NGROUPS_RGID_SUPP */ 1684 cred->cr_gid = p->p_cred->p_rgid; 1685 break; 1686 case -3: /* NGROUPS_SGID */ 1687 case -7: /* NGROUPS_SGID_SUPP */ 1688 error = EINVAL; 1689 break; 1690 case -4: /* NGROUPS_SUPP */ 1691 if (cred->cr_ngroups > 1) 1692 cred->cr_gid = cred->cr_groups[1]; 1693 else 1694 error = EINVAL; 1695 break; 1696 default: 1697 if (uap->ngroups > 0 && uap->ngroups <= NGROUPS) 1698 error = copyin((caddr_t)uap->gidset, 1699 (caddr_t)&lgroups[0], 1700 uap->ngroups * sizeof(lgroups[0])); 1701 else 1702 error = EINVAL; 1703 if (error == 0) { 1704 int gid; 1705 1706 for (gid = 0; gid < uap->ngroups; gid++) 1707 cred->cr_groups[gid] = lgroups[gid]; 1708 cred->cr_ngroups = uap->ngroups; 1709 } 1710 break; 1711 } 1712 /* 1713 * Lookup file using caller's effective IDs. 1714 */ 1715 if (error == 0) { 1716 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1717 uap->path, p); 1718 error = namei(&nd); 1719 } 1720 if (error) { 1721 crfree(cred); 1722 return (error); 1723 } 1724 /* 1725 * Use the constructed credentials for access checks. 1726 */ 1727 vp = nd.ni_vp; 1728 *retval = 0; 1729 if (VOP_ACCESS(vp, VREAD, cred, p) == 0) 1730 *retval |= R_OK; 1731 if (vn_writechk(vp) == 0 && VOP_ACCESS(vp, VWRITE, cred, p) == 0) 1732 *retval |= W_OK; 1733 /* XXX we return X_OK for root on VREG even if not */ 1734 if (VOP_ACCESS(vp, VEXEC, cred, p) == 0) 1735 *retval |= X_OK; 1736 vput(vp); 1737 crfree(cred); 1738 return (error); 1739 } 1740 1741 extern char kstack[]; 1742 #define UOFF(f) ((int)&((struct user *)0)->f) 1743 #define HPUOFF(f) ((int)&((struct hpuxuser *)0)->f) 1744 1745 /* simplified FP structure */ 1746 struct bsdfp { 1747 int save[54]; 1748 int reg[24]; 1749 int ctrl[3]; 1750 }; 1751 1752 /* 1753 * Brutal hack! Map HP-UX u-area offsets into BSD k-stack offsets. 1754 */ 1755 hpuxtobsduoff(off, isps, p) 1756 int *off, *isps; 1757 struct proc *p; 1758 { 1759 register int *ar0 = p->p_md.md_regs; 1760 struct hpuxfp *hp; 1761 struct bsdfp *bp; 1762 register u_int raddr; 1763 1764 *isps = 0; 1765 1766 /* u_ar0 field; procxmt puts in U_ar0 */ 1767 if ((int)off == HPUOFF(hpuxu_ar0)) 1768 return(UOFF(U_ar0)); 1769 1770 #ifdef FPCOPROC 1771 /* FP registers from PCB */ 1772 hp = (struct hpuxfp *)HPUOFF(hpuxu_fp); 1773 bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs); 1774 if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3]) 1775 return((int)&bp->ctrl[off - hp->hpfp_ctrl]); 1776 if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24]) 1777 return((int)&bp->reg[off - hp->hpfp_reg]); 1778 #endif 1779 1780 /* 1781 * Everything else we recognize comes from the kernel stack, 1782 * so we convert off to an absolute address (if not already) 1783 * for simplicity. 1784 */ 1785 if (off < (int *)ctob(UPAGES)) 1786 off = (int *)((u_int)off + (u_int)kstack); 1787 1788 /* 1789 * General registers. 1790 * We know that the HP-UX registers are in the same order as ours. 1791 * The only difference is that their PS is 2 bytes instead of a 1792 * padded 4 like ours throwing the alignment off. 1793 */ 1794 if (off >= ar0 && off < &ar0[18]) { 1795 /* 1796 * PS: return low word and high word of PC as HP-UX would 1797 * (e.g. &u.u_ar0[16.5]). 1798 * 1799 * XXX we don't do this since HP-UX adb doesn't rely on 1800 * it and passing such an offset to procxmt will cause 1801 * it to fail anyway. Instead, we just set the offset 1802 * to PS and let hpuxptrace() shift up the value returned. 1803 */ 1804 if (off == &ar0[PS]) { 1805 #if 0 1806 raddr = (u_int) &((short *)ar0)[PS*2+1]; 1807 #else 1808 raddr = (u_int) &ar0[(int)(off - ar0)]; 1809 #endif 1810 *isps = 1; 1811 } 1812 /* 1813 * PC: off will be &u.u_ar0[16.5] since HP-UX saved PS 1814 * is only 16 bits. 1815 */ 1816 else if (off == (int *)&(((short *)ar0)[PS*2+1])) 1817 raddr = (u_int) &ar0[PC]; 1818 /* 1819 * D0-D7, A0-A7: easy 1820 */ 1821 else 1822 raddr = (u_int) &ar0[(int)(off - ar0)]; 1823 return((int)(raddr - (u_int)kstack)); 1824 } 1825 1826 /* everything else */ 1827 return(-1); 1828 } 1829 1830 /* 1831 * Kludge up a uarea dump so that HP-UX debuggers can find out 1832 * what they need. IMPORTANT NOTE: we do not EVEN attempt to 1833 * convert the entire user struct. 1834 */ 1835 hpuxdumpu(vp, cred) 1836 struct vnode *vp; 1837 struct ucred *cred; 1838 { 1839 struct proc *p = curproc; 1840 int error; 1841 struct hpuxuser *faku; 1842 struct bsdfp *bp; 1843 short *foop; 1844 1845 faku = (struct hpuxuser *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK); 1846 /* 1847 * Make sure there is no mistake about this 1848 * being a real user structure. 1849 */ 1850 bzero((caddr_t)faku, ctob(1)); 1851 /* 1852 * Fill in the process sizes. 1853 */ 1854 faku->hpuxu_tsize = p->p_vmspace->vm_tsize; 1855 faku->hpuxu_dsize = p->p_vmspace->vm_dsize; 1856 faku->hpuxu_ssize = p->p_vmspace->vm_ssize; 1857 /* 1858 * Fill in the exec header for CDB. 1859 * This was saved back in exec(). As far as I can tell CDB 1860 * only uses this information to verify that a particular 1861 * core file goes with a particular binary. 1862 */ 1863 bcopy((caddr_t)p->p_addr->u_md.md_exec, 1864 (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec)); 1865 /* 1866 * Adjust user's saved registers (on kernel stack) to reflect 1867 * HP-UX order. Note that HP-UX saves the SR as 2 bytes not 4 1868 * so we have to move it up. 1869 */ 1870 faku->hpuxu_ar0 = p->p_md.md_regs; 1871 foop = (short *) p->p_md.md_regs; 1872 foop[32] = foop[33]; 1873 foop[33] = foop[34]; 1874 foop[34] = foop[35]; 1875 #ifdef FPCOPROC 1876 /* 1877 * Copy 68881 registers from our PCB format to HP-UX format 1878 */ 1879 bp = (struct bsdfp *) &p->p_addr->u_pcb.pcb_fpregs; 1880 bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save, 1881 sizeof(bp->save)); 1882 bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl, 1883 sizeof(bp->ctrl)); 1884 bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg, 1885 sizeof(bp->reg)); 1886 #endif 1887 /* 1888 * Slay the dragon 1889 */ 1890 faku->hpuxu_dragon = -1; 1891 /* 1892 * Dump this artfully constructed page in place of the 1893 * user struct page. 1894 */ 1895 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)faku, ctob(1), (off_t)0, 1896 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, 1897 (int *)NULL, p); 1898 /* 1899 * Dump the remaining UPAGES-1 pages normally 1900 */ 1901 if (!error) 1902 error = vn_rdwr(UIO_WRITE, vp, kstack + ctob(1), 1903 ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE, 1904 IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 1905 free((caddr_t)faku, M_TEMP); 1906 return(error); 1907 } 1908 1909 /* 1910 * The remaining routines are essentially the same as those in kern_xxx.c 1911 * and vfs_xxx.c as defined under "#ifdef COMPAT". We replicate them here 1912 * to avoid HPUXCOMPAT dependencies in those files and to make sure that 1913 * HP-UX compatibility still works even when COMPAT is not defined. 1914 * 1915 * These are still needed as of HP-UX 7.05. 1916 */ 1917 #ifdef COMPAT_OHPUX 1918 1919 #define HPUX_HZ 50 1920 1921 #include "sys/times.h" 1922 1923 /* from old timeb.h */ 1924 struct hpuxtimeb { 1925 time_t time; 1926 u_short millitm; 1927 short timezone; 1928 short dstflag; 1929 }; 1930 1931 /* ye ole stat structure */ 1932 struct ohpuxstat { 1933 u_short ohst_dev; 1934 u_short ohst_ino; 1935 u_short ohst_mode; 1936 short ohst_nlink; 1937 short ohst_uid; 1938 short ohst_gid; 1939 u_short ohst_rdev; 1940 int ohst_size; 1941 int ohst_atime; 1942 int ohst_mtime; 1943 int ohst_ctime; 1944 }; 1945 1946 /* 1947 * SYS V style setpgrp() 1948 */ 1949 compat_43_hpuxsetpgrp(p, uap, retval) 1950 register struct proc *p; 1951 int *uap, *retval; 1952 { 1953 if (p->p_pid != p->p_pgid) 1954 enterpgrp(p, p->p_pid, 0); 1955 *retval = p->p_pgid; 1956 return (0); 1957 } 1958 1959 struct ohpuxtime_args { 1960 long *tp; 1961 }; 1962 compat_43_hpuxtime(p, uap, retval) 1963 struct proc *p; 1964 register struct ohpuxtime_args *uap; 1965 int *retval; 1966 { 1967 int error = 0; 1968 1969 if (uap->tp) 1970 error = copyout((caddr_t)&time.tv_sec, (caddr_t)uap->tp, 1971 sizeof (long)); 1972 *(time_t *)retval = time.tv_sec; 1973 return (error); 1974 } 1975 1976 struct ohpuxstime_args { 1977 int time; 1978 }; 1979 compat_43_hpuxstime(p, uap, retval) 1980 struct proc *p; 1981 register struct ohpuxstime_args *uap; 1982 int *retval; 1983 { 1984 struct timeval tv; 1985 int s, error; 1986 1987 tv.tv_sec = uap->time; 1988 tv.tv_usec = 0; 1989 if (error = suser(p->p_ucred, &p->p_acflag)) 1990 return (error); 1991 1992 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 1993 boottime.tv_sec += tv.tv_sec - time.tv_sec; 1994 s = splhigh(); time = tv; splx(s); 1995 resettodr(); 1996 return (0); 1997 } 1998 1999 struct ohpuxftime_args { 2000 struct hpuxtimeb *tp; 2001 }; 2002 compat_43_hpuxftime(p, uap, retval) 2003 struct proc *p; 2004 register struct ohpuxftime_args *uap; 2005 int *retval; 2006 { 2007 struct hpuxtimeb tb; 2008 int s; 2009 2010 s = splhigh(); 2011 tb.time = time.tv_sec; 2012 tb.millitm = time.tv_usec / 1000; 2013 splx(s); 2014 tb.timezone = tz.tz_minuteswest; 2015 tb.dstflag = tz.tz_dsttime; 2016 return (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb))); 2017 } 2018 2019 struct ohpuxalarm_args { 2020 int deltat; 2021 }; 2022 compat_43_hpuxalarm(p, uap, retval) 2023 register struct proc *p; 2024 register struct ohpuxalarm_args *uap; 2025 int *retval; 2026 { 2027 int s = splhigh(); 2028 2029 untimeout(realitexpire, (caddr_t)p); 2030 timerclear(&p->p_realtimer.it_interval); 2031 *retval = 0; 2032 if (timerisset(&p->p_realtimer.it_value) && 2033 timercmp(&p->p_realtimer.it_value, &time, >)) 2034 *retval = p->p_realtimer.it_value.tv_sec - time.tv_sec; 2035 if (uap->deltat == 0) { 2036 timerclear(&p->p_realtimer.it_value); 2037 splx(s); 2038 return (0); 2039 } 2040 p->p_realtimer.it_value = time; 2041 p->p_realtimer.it_value.tv_sec += uap->deltat; 2042 timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value)); 2043 splx(s); 2044 return (0); 2045 } 2046 2047 struct ohpuxnice_args { 2048 int niceness; 2049 }; 2050 compat_43_hpuxnice(p, uap, retval) 2051 register struct proc *p; 2052 register struct ohpuxnice_args *uap; 2053 int *retval; 2054 { 2055 int error; 2056 2057 error = donice(p, p, (p->p_nice-NZERO)+uap->niceness); 2058 if (error == 0) 2059 *retval = p->p_nice - NZERO; 2060 return (error); 2061 } 2062 2063 struct ohpuxtimes_args { 2064 struct tms *tmsb; 2065 }; 2066 compat_43_hpuxtimes(p, uap, retval) 2067 struct proc *p; 2068 register struct ohpuxtimes_args *uap; 2069 int *retval; 2070 { 2071 struct timeval ru, rs; 2072 struct tms atms; 2073 int error; 2074 2075 calcru(p, &ru, &rs, NULL); 2076 atms.tms_utime = hpuxscale(&ru); 2077 atms.tms_stime = hpuxscale(&rs); 2078 atms.tms_cutime = hpuxscale(&p->p_stats->p_cru.ru_utime); 2079 atms.tms_cstime = hpuxscale(&p->p_stats->p_cru.ru_stime); 2080 error = copyout((caddr_t)&atms, (caddr_t)uap->tmsb, sizeof (atms)); 2081 if (error == 0) 2082 *(time_t *)retval = hpuxscale(&time) - hpuxscale(&boottime); 2083 return (error); 2084 } 2085 2086 /* 2087 * Doesn't exactly do what the documentation says. 2088 * What we really do is return 1/HPUX_HZ-th of a second since that 2089 * is what HP-UX returns. 2090 */ 2091 hpuxscale(tvp) 2092 register struct timeval *tvp; 2093 { 2094 return (tvp->tv_sec * HPUX_HZ + tvp->tv_usec * HPUX_HZ / 1000000); 2095 } 2096 2097 /* 2098 * Set IUPD and IACC times on file. 2099 * Can't set ICHG. 2100 */ 2101 struct ohpuxutime_args { 2102 char *fname; 2103 time_t *tptr; 2104 }; 2105 compat_43_hpuxutime(p, uap, retval) 2106 struct proc *p; 2107 register struct ohpuxutime_args *uap; 2108 int *retval; 2109 { 2110 register struct vnode *vp; 2111 struct vattr vattr; 2112 time_t tv[2]; 2113 int error; 2114 struct nameidata nd; 2115 2116 if (uap->tptr) { 2117 error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 2118 if (error) 2119 return (error); 2120 } else 2121 tv[0] = tv[1] = time.tv_sec; 2122 vattr_null(&vattr); 2123 vattr.va_atime.ts_sec = tv[0]; 2124 vattr.va_atime.ts_nsec = 0; 2125 vattr.va_mtime.ts_sec = tv[1]; 2126 vattr.va_mtime.ts_nsec = 0; 2127 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 2128 if (error = namei(&nd)) 2129 return (error); 2130 vp = nd.ni_vp; 2131 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2132 error = EROFS; 2133 else 2134 error = VOP_SETATTR(vp, &vattr, nd.ni_cnd.cn_cred, p); 2135 vput(vp); 2136 return (error); 2137 } 2138 2139 compat_43_hpuxpause(p, uap, retval) 2140 struct proc *p; 2141 int *uap, *retval; 2142 { 2143 (void) tsleep(kstack, PPAUSE | PCATCH, "pause", 0); 2144 /* always return EINTR rather than ERESTART... */ 2145 return (EINTR); 2146 } 2147 2148 /* 2149 * The old fstat system call. 2150 */ 2151 struct ohpuxfstat_args { 2152 int fd; 2153 struct ohpuxstat *sb; 2154 }; 2155 compat_43_hpuxfstat(p, uap, retval) 2156 struct proc *p; 2157 register struct ohpuxfstat_args *uap; 2158 int *retval; 2159 { 2160 register struct filedesc *fdp = p->p_fd; 2161 struct file *fp; 2162 2163 if (((unsigned)uap->fd) >= fdp->fd_nfiles || 2164 (fp = fdp->fd_ofiles[uap->fd]) == NULL) 2165 return (EBADF); 2166 if (fp->f_type != DTYPE_VNODE) 2167 return (EINVAL); 2168 return (compat_43_hpuxstat1((struct vnode *)fp->f_data, uap->sb, p)); 2169 } 2170 2171 /* 2172 * Old stat system call. This version follows links. 2173 */ 2174 struct ohpuxstat_args { 2175 char *fname; 2176 struct ohpuxstat *sb; 2177 }; 2178 compat_43_hpuxstat(p, uap, retval) 2179 struct proc *p; 2180 register struct ohpuxstat_args *uap; 2181 int *retval; 2182 { 2183 int error; 2184 struct nameidata nd; 2185 2186 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 2187 if (error = namei(&nd)) 2188 return (error); 2189 error = compat_43_hpuxstat1(nd.ni_vp, uap->sb, p); 2190 vput(nd.ni_vp); 2191 return (error); 2192 } 2193 2194 int 2195 compat_43_hpuxstat1(vp, ub, p) 2196 struct vnode *vp; 2197 struct ohpuxstat *ub; 2198 struct proc *p; 2199 { 2200 struct ohpuxstat ohsb; 2201 struct stat sb; 2202 int error; 2203 2204 error = vn_stat(vp, &sb, p); 2205 if (error) 2206 return (error); 2207 2208 ohsb.ohst_dev = sb.st_dev; 2209 ohsb.ohst_ino = sb.st_ino; 2210 ohsb.ohst_mode = sb.st_mode; 2211 ohsb.ohst_nlink = sb.st_nlink; 2212 ohsb.ohst_uid = sb.st_uid; 2213 ohsb.ohst_gid = sb.st_gid; 2214 ohsb.ohst_rdev = sb.st_rdev; 2215 if (sb.st_size < (quad_t)1 << 32) 2216 ohsb.ohst_size = sb.st_size; 2217 else 2218 ohsb.ohst_size = -2; 2219 ohsb.ohst_atime = sb.st_atime; 2220 ohsb.ohst_mtime = sb.st_mtime; 2221 ohsb.ohst_ctime = sb.st_ctime; 2222 return (copyout((caddr_t)&ohsb, (caddr_t)ub, sizeof(ohsb))); 2223 } 2224 #endif 2225 #endif 2226