1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * 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.3 90/09/17$ 13 * 14 * @(#)hpux_compat.c 7.13 (Berkeley) 04/20/91 15 */ 16 17 /* 18 * Various HPUX compatibility routines 19 */ 20 21 #ifdef HPUXCOMPAT 22 23 #include "sys/param.h" 24 #include "sys/systm.h" 25 #include "sys/signalvar.h" 26 #include "sys/kernel.h" 27 #include "sys/filedesc.h" 28 #include "sys/proc.h" 29 #include "sys/buf.h" 30 #include "sys/wait.h" 31 #include "sys/file.h" 32 #include "sys/namei.h" 33 #include "sys/vnode.h" 34 #include "sys/ioctl.h" 35 #include "sys/ptrace.h" 36 #include "sys/stat.h" 37 #include "sys/syslog.h" 38 #include "sys/malloc.h" 39 #include "sys/mount.h" 40 #include "sys/ipc.h" 41 #include "sys/user.h" 42 43 #include "machine/cpu.h" 44 #include "machine/reg.h" 45 #include "machine/psl.h" 46 #include "machine/vmparam.h" 47 #include "hpux.h" 48 #include "hpux_termio.h" 49 50 #ifdef DEBUG 51 int unimpresponse = 0; 52 #endif 53 54 /* SYS5 style UTSNAME info */ 55 struct hpuxutsname protoutsname = { 56 "4.4bsd", "", "2.0", "B", "9000/3?0", "" 57 }; 58 59 /* 6.0 and later style context */ 60 #ifdef FPCOPROC 61 char hpuxcontext[] = 62 "standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default"; 63 #else 64 char hpuxcontext[] = 65 "standalone HP-MC68020 HP-MC68010 localroot default"; 66 #endif 67 68 /* YP domainname */ 69 char domainname[MAXHOSTNAMELEN] = "unknown"; 70 int domainnamelen = 7; 71 72 #define NERR 79 73 #define BERR 1000 74 75 /* indexed by BSD errno */ 76 short bsdtohpuxerrnomap[NERR] = { 77 /*00*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 78 /*10*/ 10, 45, 12, 13, 14, 15, 16, 17, 18, 19, 79 /*20*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 80 /*30*/ 30, 31, 32, 33, 34, 246, 245, 244, 216, 217, 81 /*40*/ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 82 /*50*/ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 83 /*60*/ 238, 239, 249, 248, 241, 242, 247,BERR,BERR,BERR, 84 /*70*/ 70, 71,BERR,BERR,BERR,BERR,BERR, 46,BERR 85 }; 86 87 notimp(p, uap, retval, code, nargs) 88 struct proc *p; 89 int *uap, *retval; 90 int code, nargs; 91 { 92 int error = 0; 93 #ifdef DEBUG 94 register int *argp = uap; 95 extern char *hpuxsyscallnames[]; 96 97 printf("HPUX %s(", hpuxsyscallnames[code]); 98 if (nargs) 99 while (nargs--) 100 printf("%x%c", *argp++, nargs? ',' : ')'); 101 else 102 printf(")"); 103 printf("\n"); 104 switch (unimpresponse) { 105 case 0: 106 error = nosys(p, uap, retval); 107 break; 108 case 1: 109 error = EINVAL; 110 break; 111 } 112 #else 113 error = nosys(p, uap, retval); 114 #endif 115 uprintf("HP-UX system call %d not implemented\n", code); 116 return (error); 117 } 118 119 hpuxexecv(p, uap, retval) 120 struct proc *p; 121 struct args { 122 char *fname; 123 char **argp; 124 char **envp; 125 } *uap; 126 int *retval; 127 { 128 extern int execve(); 129 130 uap->envp = NULL; 131 return (execve(p, uap, retval)); 132 } 133 134 /* 135 * HPUX versions of wait and wait3 actually pass the parameters 136 * (status pointer, options, rusage) into the kernel rather than 137 * handling it in the C library stub. We also need to map any 138 * termination signal from BSD to HPUX. 139 */ 140 hpuxwait3(p, uap, retval) 141 struct proc *p; 142 struct args { 143 int *status; 144 int options; 145 int rusage; 146 } *uap; 147 int *retval; 148 { 149 /* rusage pointer must be zero */ 150 if (uap->rusage) 151 return (EINVAL); 152 p->p_regs[PS] = PSL_ALLCC; 153 p->p_regs[R0] = uap->options; 154 p->p_regs[R1] = uap->rusage; 155 return (hpuxwait(p, uap, retval)); 156 } 157 158 hpuxwait(p, uap, retval) 159 struct proc *p; 160 struct args { 161 int *status; 162 } *uap; 163 int *retval; 164 { 165 int sig, *statp, error; 166 167 statp = uap->status; /* owait clobbers first arg */ 168 error = owait(p, uap, retval); 169 /* 170 * HP-UX wait always returns EINTR when interrupted by a signal 171 * (well, unless its emulating a BSD process, but we don't bother...) 172 */ 173 if (error == ERESTART) 174 error = EINTR; 175 if (error) 176 return (error); 177 sig = retval[1] & 0xFF; 178 if (sig == WSTOPPED) { 179 sig = (retval[1] >> 8) & 0xFF; 180 retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED; 181 } else if (sig) 182 retval[1] = (retval[1] & 0xFF00) | 183 bsdtohpuxsig(sig & 0x7F) | (sig & 0x80); 184 if (statp) 185 if (suword((caddr_t)statp, retval[1])) 186 error = EFAULT; 187 return (error); 188 } 189 190 hpuxwaitpid(p, uap, retval) 191 struct proc *p; 192 struct args { 193 int pid; 194 int *status; 195 int options; 196 struct rusage *rusage; /* wait4 arg */ 197 } *uap; 198 int *retval; 199 { 200 int sig, *statp, error; 201 202 uap->rusage = 0; 203 error = wait4(p, uap, retval); 204 /* 205 * HP-UX wait always returns EINTR when interrupted by a signal 206 * (well, unless its emulating a BSD process, but we don't bother...) 207 */ 208 if (error == ERESTART) 209 error = EINTR; 210 if (error) 211 return (error); 212 sig = retval[1] & 0xFF; 213 if (sig == WSTOPPED) { 214 sig = (retval[1] >> 8) & 0xFF; 215 retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED; 216 } else if (sig) 217 retval[1] = (retval[1] & 0xFF00) | 218 bsdtohpuxsig(sig & 0x7F) | (sig & 0x80); 219 if (statp) 220 if (suword((caddr_t)statp, retval[1])) 221 error = EFAULT; 222 return (error); 223 } 224 225 /* 226 * Must remap some bits in the mode mask. 227 * O_CREAT, O_TRUNC, and O_EXCL must be remapped, 228 * O_SYNCIO (0100000) is removed entirely. 229 */ 230 hpuxopen(p, uap, retval) 231 struct proc *p; 232 register struct args { 233 char *fname; 234 int mode; 235 int crtmode; 236 } *uap; 237 int *retval; 238 { 239 int mode; 240 241 mode = uap->mode; 242 uap->mode &= ~(HPUXFSYNCIO|HPUXFEXCL|HPUXFTRUNC|HPUXFCREAT); 243 if (mode & HPUXFCREAT) { 244 /* 245 * simulate the pre-NFS behavior that opening a 246 * file for READ+CREATE ignores the CREATE (unless 247 * EXCL is set in which case we will return the 248 * proper error). 249 */ 250 if ((mode & HPUXFEXCL) || (FFLAGS(mode) & FWRITE)) 251 uap->mode |= FCREAT; 252 } 253 if (mode & HPUXFTRUNC) 254 uap->mode |= FTRUNC; 255 if (mode & HPUXFEXCL) 256 uap->mode |= FEXCL; 257 return (open(p, uap, retval)); 258 } 259 260 hpuxfcntl(p, uap, retval) 261 struct proc *p; 262 register struct args { 263 int fdes; 264 int cmd; 265 int arg; 266 } *uap; 267 int *retval; 268 { 269 int mode, error; 270 271 switch (uap->cmd) { 272 case F_SETFL: 273 uap->arg &= ~(HPUXFSYNCIO|HPUXFREMOTE|FUSECACHE); 274 break; 275 case F_GETFL: 276 case F_DUPFD: 277 case F_GETFD: 278 case F_SETFD: 279 break; 280 default: 281 return (EINVAL); 282 } 283 error = fcntl(p, uap, retval); 284 if (error == 0 && uap->arg == F_GETFL) { 285 mode = *retval; 286 *retval &= ~(FCREAT|FTRUNC|FEXCL|FUSECACHE); 287 if (mode & FCREAT) 288 *retval |= HPUXFCREAT; 289 if (mode & FTRUNC) 290 *retval |= HPUXFTRUNC; 291 if (mode & FEXCL) 292 *retval |= HPUXFEXCL; 293 } 294 return (error); 295 } 296 297 /* 298 * Read and write should return a 0 count when an operation 299 * on a VNODE would block, not an error. Sockets appear to 300 * return EWOULDBLOCK (at least in 6.2). This is probably 301 * not entirely correct, since the behavior is only defined 302 * for pipes and tty type devices. 303 */ 304 hpuxread(p, uap, retval) 305 struct proc *p; 306 struct args { 307 int fd; 308 } *uap; 309 int *retval; 310 { 311 int error; 312 313 error = read(p, uap, retval); 314 if (error == EWOULDBLOCK && 315 p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE) { 316 error = 0; 317 *retval = 0; 318 } 319 return (error); 320 } 321 322 hpuxwrite(p, uap, retval) 323 struct proc *p; 324 struct args { 325 int fd; 326 } *uap; 327 int *retval; 328 { 329 int error; 330 331 error = write(p, uap, retval); 332 if (error == EWOULDBLOCK && 333 p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE) { 334 error = 0; 335 *retval = 0; 336 } 337 return (error); 338 } 339 340 hpuxreadv(p, uap, retval) 341 struct proc *p; 342 struct args { 343 int fd; 344 } *uap; 345 int *retval; 346 { 347 int error; 348 349 error = readv(p, uap, retval); 350 if (error == EWOULDBLOCK && 351 p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE) { 352 error = 0; 353 *retval = 0; 354 } 355 return (error); 356 } 357 358 hpuxwritev(p, uap, retval) 359 struct proc *p; 360 struct args { 361 int fd; 362 } *uap; 363 int *retval; 364 { 365 int error; 366 367 error = writev(p, uap, retval); 368 if (error == EWOULDBLOCK && 369 p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE) { 370 error = 0; 371 *retval = 0; 372 } 373 return (error); 374 } 375 376 /* 377 * 4.3bsd dup allows dup2 to come in on the same syscall entry 378 * and hence allows two arguments. HPUX dup has only one arg. 379 */ 380 hpuxdup(p, uap, retval) 381 struct proc *p; 382 register struct args { 383 int i; 384 } *uap; 385 int *retval; 386 { 387 register struct filedesc *fdp = p->p_fd; 388 struct file *fp; 389 int fd, error; 390 391 if (((unsigned)uap->i) >= fdp->fd_nfiles || 392 (fp = fdp->fd_ofiles[uap->i]) == NULL) 393 return (EBADF); 394 if (error = fdalloc(p, 0, &fd)) 395 return (error); 396 fdp->fd_ofiles[fd] = fp; 397 fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE; 398 fp->f_count++; 399 if (fd > fdp->fd_lastfile) 400 fdp->fd_lastfile = fd; 401 *retval = fd; 402 return (0); 403 } 404 405 hpuxutssys(p, uap, retval) 406 struct proc *p; 407 register struct args { 408 struct hpuxutsname *uts; 409 int dev; 410 int request; 411 } *uap; 412 int *retval; 413 { 414 register int i; 415 int error; 416 417 switch (uap->request) { 418 /* uname */ 419 case 0: 420 /* fill in machine type */ 421 switch (machineid) { 422 case HP_320: 423 protoutsname.machine[6] = '2'; 424 break; 425 /* includes 318 and 319 */ 426 case HP_330: 427 protoutsname.machine[6] = '3'; 428 break; 429 case HP_340: 430 protoutsname.machine[6] = '4'; 431 break; 432 case HP_350: 433 protoutsname.machine[6] = '5'; 434 break; 435 case HP_360: 436 protoutsname.machine[6] = '6'; 437 break; 438 case HP_370: 439 protoutsname.machine[6] = '7'; 440 break; 441 /* includes 345 */ 442 case HP_375: 443 protoutsname.machine[6] = '7'; 444 protoutsname.machine[7] = '5'; 445 break; 446 } 447 /* copy hostname (sans domain) to nodename */ 448 for (i = 0; i < 9 && hostname[i] != '.'; i++) 449 protoutsname.nodename[i] = hostname[i]; 450 error = copyout((caddr_t)&protoutsname, (caddr_t)uap->uts, 451 sizeof(struct hpuxutsname)); 452 break; 453 454 /* gethostname */ 455 case 5: 456 /* uap->dev is length */ 457 if (uap->dev > hostnamelen + 1) 458 uap->dev = hostnamelen + 1; 459 error = copyout((caddr_t)hostname, (caddr_t)uap->uts, 460 uap->dev); 461 break; 462 463 case 1: /* ?? */ 464 case 2: /* ustat */ 465 case 3: /* ?? */ 466 case 4: /* sethostname */ 467 default: 468 error = EINVAL; 469 break; 470 } 471 return (error); 472 } 473 474 hpuxstat(p, uap, retval) 475 struct proc *p; 476 struct args { 477 char *fname; 478 struct hpuxstat *hsb; 479 } *uap; 480 int *retval; 481 { 482 return (hpuxstat1(uap->fname, uap->hsb, FOLLOW)); 483 } 484 485 hpuxlstat(p, uap, retval) 486 struct proc *p; 487 struct args { 488 char *fname; 489 struct hpuxstat *hsb; 490 } *uap; 491 int *retval; 492 { 493 return (hpuxstat1(uap->fname, uap->hsb, NOFOLLOW)); 494 } 495 496 hpuxfstat(p, uap, retval) 497 struct proc *p; 498 register struct args { 499 int fdes; 500 struct hpuxstat *hsb; 501 } *uap; 502 int *retval; 503 { 504 register struct filedesc *fdp = p->p_fd; 505 register struct file *fp; 506 struct stat sb; 507 int error; 508 509 if (((unsigned)uap->fdes) >= fdp->fd_nfiles || 510 (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 511 return (EBADF); 512 513 switch (fp->f_type) { 514 515 case DTYPE_VNODE: 516 error = vn_stat((struct vnode *)fp->f_data, &sb); 517 break; 518 519 case DTYPE_SOCKET: 520 error = soo_stat((struct socket *)fp->f_data, &sb); 521 break; 522 523 default: 524 panic("fstat"); 525 /*NOTREACHED*/ 526 } 527 /* is this right for sockets?? */ 528 if (error == 0) 529 error = bsdtohpuxstat(&sb, uap->hsb); 530 return (error); 531 } 532 533 hpuxulimit(p, uap, retval) 534 struct proc *p; 535 register struct args { 536 int cmd; 537 long newlimit; 538 } *uap; 539 off_t *retval; 540 { 541 struct rlimit *limp; 542 int error = 0; 543 544 limp = &p->p_rlimit[RLIMIT_FSIZE]; 545 switch (uap->cmd) { 546 case 2: 547 uap->newlimit *= 512; 548 if (uap->newlimit > limp->rlim_max && 549 (error = suser(p->p_ucred, &p->p_acflag))) 550 break; 551 limp->rlim_cur = limp->rlim_max = uap->newlimit; 552 /* else fall into... */ 553 554 case 1: 555 *retval = limp->rlim_max / 512; 556 break; 557 558 case 3: 559 limp = &p->p_rlimit[RLIMIT_DATA]; 560 *retval = ctob(p->p_vmspace->vm_tsize) + limp->rlim_max; 561 break; 562 563 default: 564 error = EINVAL; 565 break; 566 } 567 return (error); 568 } 569 570 /* 571 * Map "real time" priorities 0 (high) thru 127 (low) into nice 572 * values -16 (high) thru -1 (low). 573 */ 574 hpuxrtprio(cp, uap, retval) 575 struct proc *cp; 576 register struct args { 577 int pid; 578 int prio; 579 } *uap; 580 int *retval; 581 { 582 struct proc *p; 583 int nice, error; 584 585 if (uap->prio < RTPRIO_MIN && uap->prio > RTPRIO_MAX && 586 uap->prio != RTPRIO_NOCHG && uap->prio != RTPRIO_RTOFF) 587 return (EINVAL); 588 if (uap->pid == 0) 589 p = cp; 590 else if ((p = pfind(uap->pid)) == 0) 591 return (ESRCH); 592 nice = p->p_nice; 593 if (nice < NZERO) 594 *retval = (nice + 16) << 3; 595 else 596 *retval = RTPRIO_RTOFF; 597 switch (uap->prio) { 598 599 case RTPRIO_NOCHG: 600 return (0); 601 602 case RTPRIO_RTOFF: 603 if (nice >= NZERO) 604 return (0); 605 nice = NZERO; 606 break; 607 608 default: 609 nice = (uap->prio >> 3) - 16; 610 break; 611 } 612 error = donice(cp, p, nice); 613 if (error == EACCES) 614 error = EPERM; 615 return (error); 616 } 617 618 hpuxadvise(p, uap, retval) 619 struct proc *p; 620 struct args { 621 int arg; 622 } *uap; 623 int *retval; 624 { 625 int error = 0; 626 627 switch (uap->arg) { 628 case 0: 629 u.u_pcb.pcb_flags |= PCB_HPUXMMAP; 630 break; 631 case 1: 632 ICIA(); 633 break; 634 case 2: 635 DCIA(); 636 break; 637 default: 638 error = EINVAL; 639 break; 640 } 641 return (error); 642 } 643 644 hpuxptrace(p, uap, retval) 645 struct proc *p; 646 struct args { 647 int req; 648 int pid; 649 int *addr; 650 int data; 651 } *uap; 652 int *retval; 653 { 654 int error; 655 656 if (uap->req == PT_STEP || uap->req == PT_CONTINUE) { 657 if (uap->data) { 658 uap->data = hpuxtobsdsig(uap->data); 659 if (uap->data == 0) 660 uap->data = NSIG; 661 } 662 } 663 error = ptrace(p, uap, retval); 664 return (error); 665 } 666 667 hpuxgetdomainname(p, uap, retval) 668 struct proc *p; 669 register struct args { 670 char *domainname; 671 u_int len; 672 } *uap; 673 int *retval; 674 { 675 if (uap->len > domainnamelen + 1) 676 uap->len = domainnamelen + 1; 677 return (copyout(domainname, uap->domainname, uap->len)); 678 } 679 680 hpuxsetdomainname(p, uap, retval) 681 struct proc *p; 682 register struct args { 683 char *domainname; 684 u_int len; 685 } *uap; 686 int *retval; 687 { 688 int error; 689 690 if (error = suser(p->p_ucred, &p->p_acflag)) 691 return (error); 692 if (uap->len > sizeof (domainname) - 1) 693 return (EINVAL); 694 domainnamelen = uap->len; 695 error = copyin(uap->domainname, domainname, uap->len); 696 domainname[domainnamelen] = 0; 697 return (error); 698 } 699 700 #ifdef SYSVSHM 701 hpuxshmat(p, uap, retval) 702 struct proc *p; 703 int *uap, *retval; 704 { 705 return (shmat(p, uap, retval)); 706 } 707 708 hpuxshmctl(p, uap, retval) 709 struct proc *p; 710 int *uap, *retval; 711 { 712 return (shmctl(p, uap, retval)); 713 } 714 715 hpuxshmdt(p, uap, retval) 716 struct proc *p; 717 int *uap, *retval; 718 { 719 return (shmdt(p, uap, retval)); 720 } 721 722 hpuxshmget(p, uap, retval) 723 struct proc *p; 724 int *uap, *retval; 725 { 726 return (shmget(p, uap, retval)); 727 } 728 #endif 729 730 /* 731 * Fake semaphore routines, just don't return an error. 732 * Should be adequate for starbase to run. 733 */ 734 hpuxsemctl(p, uap, retval) 735 struct proc *p; 736 struct args { 737 int semid; 738 u_int semnum; 739 int cmd; 740 int arg; 741 } *uap; 742 int *retval; 743 { 744 /* XXX: should do something here */ 745 return (0); 746 } 747 748 hpuxsemget(p, uap, retval) 749 struct proc *p; 750 struct args { 751 key_t key; 752 int nsems; 753 int semflg; 754 } *uap; 755 int *retval; 756 { 757 /* XXX: should do something here */ 758 return (0); 759 } 760 761 hpuxsemop(p, uap, retval) 762 struct proc *p; 763 struct args { 764 int semid; 765 struct sembuf *sops; 766 u_int nsops; 767 } *uap; 768 int *retval; 769 { 770 /* XXX: should do something here */ 771 return (0); 772 } 773 774 /* convert from BSD to HPUX errno */ 775 bsdtohpuxerrno(err) 776 int err; 777 { 778 if (err < 0 || err >= NERR) 779 return(BERR); 780 return((int)bsdtohpuxerrnomap[err]); 781 } 782 783 hpuxstat1(fname, hsb, follow) 784 char *fname; 785 struct hpuxstat *hsb; 786 int follow; 787 { 788 register struct nameidata *ndp; 789 int error; 790 struct stat sb; 791 struct nameidata nd; 792 793 ndp = &nd; 794 ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 795 ndp->ni_segflg = UIO_USERSPACE; 796 ndp->ni_dirp = fname; 797 if (error = namei(ndp, curproc)) 798 return (error); 799 error = vn_stat(ndp->ni_vp, &sb); 800 vput(ndp->ni_vp); 801 if (error == 0) 802 error = bsdtohpuxstat(&sb, hsb); 803 return (error); 804 } 805 806 #include "grf.h" 807 808 bsdtohpuxstat(sb, hsb) 809 struct stat *sb; 810 struct hpuxstat *hsb; 811 { 812 struct hpuxstat ds; 813 814 bzero((caddr_t)&ds, sizeof(ds)); 815 ds.hst_dev = sb->st_dev; 816 ds.hst_ino = (u_long)sb->st_ino; 817 ds.hst_mode = sb->st_mode; 818 ds.hst_nlink = sb->st_nlink; 819 ds.hst_uid = (u_short)sb->st_uid; 820 ds.hst_gid = (u_short)sb->st_gid; 821 #if NGRF > 0 822 /* XXX: I don't want to talk about it... */ 823 if ((sb->st_mode & S_IFMT) == S_IFCHR && major(sb->st_rdev) == 10) 824 ds.hst_rdev = grfdevno(sb->st_rdev); 825 else 826 #endif 827 ds.hst_rdev = bsdtohpuxdev(sb->st_rdev); 828 ds.hst_size = sb->st_size; 829 ds.hst_atime = sb->st_atime; 830 ds.hst_mtime = sb->st_mtime; 831 ds.hst_ctime = sb->st_ctime; 832 ds.hst_blksize = sb->st_blksize; 833 ds.hst_blocks = sb->st_blocks; 834 return(copyout((caddr_t)&ds, (caddr_t)hsb, sizeof(ds))); 835 } 836 837 hpuxtobsdioctl(com) 838 int com; 839 { 840 switch (com) { 841 case HPUXTIOCSLTC: 842 com = TIOCSLTC; break; 843 case HPUXTIOCGLTC: 844 com = TIOCGLTC; break; 845 case HPUXTIOCSPGRP: 846 com = TIOCSPGRP; break; 847 case HPUXTIOCGPGRP: 848 com = TIOCGPGRP; break; 849 case HPUXTIOCLBIS: 850 com = TIOCLBIS; break; 851 case HPUXTIOCLBIC: 852 com = TIOCLBIC; break; 853 case HPUXTIOCLSET: 854 com = TIOCLSET; break; 855 case HPUXTIOCLGET: 856 com = TIOCLGET; break; 857 } 858 return(com); 859 } 860 861 /* 862 * HPUX ioctl system call. The differences here are: 863 * IOC_IN also means IOC_VOID if the size portion is zero. 864 * no FIOCLEX/FIONCLEX/FIONBIO/FIOASYNC/FIOGETOWN/FIOSETOWN 865 * the sgttyb struct is 2 bytes longer 866 */ 867 hpuxioctl(p, uap, retval) 868 struct proc *p; 869 register struct args { 870 int fdes; 871 int cmd; 872 caddr_t cmarg; 873 } *uap; 874 int *retval; 875 { 876 register struct filedesc *fdp = p->p_fd; 877 register struct file *fp; 878 register int com, error; 879 register u_int size; 880 caddr_t memp = 0; 881 #define STK_PARAMS 128 882 char stkbuf[STK_PARAMS]; 883 caddr_t data = stkbuf; 884 885 com = uap->cmd; 886 887 /* XXX */ 888 if (com == HPUXTIOCGETP || com == HPUXTIOCSETP) 889 return (getsettty(p, uap->fdes, com, uap->cmarg)); 890 891 if (((unsigned)uap->fdes) >= fdp->fd_nfiles || 892 (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 893 return (EBADF); 894 if ((fp->f_flag & (FREAD|FWRITE)) == 0) 895 return (EBADF); 896 897 /* 898 * Interpret high order word to find 899 * amount of data to be copied to/from the 900 * user's address space. 901 */ 902 size = IOCPARM_LEN(com); 903 if (size > IOCPARM_MAX) 904 return (ENOTTY); 905 if (size > sizeof (stkbuf)) { 906 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); 907 data = memp; 908 } 909 if (com&IOC_IN) { 910 if (size) { 911 error = copyin(uap->cmarg, data, (u_int)size); 912 if (error) { 913 if (memp) 914 free(memp, M_IOCTLOPS); 915 return (error); 916 } 917 } else 918 *(caddr_t *)data = uap->cmarg; 919 } else if ((com&IOC_OUT) && size) 920 /* 921 * Zero the buffer so the user always 922 * gets back something deterministic. 923 */ 924 bzero(data, size); 925 else if (com&IOC_VOID) 926 *(caddr_t *)data = uap->cmarg; 927 928 switch (com) { 929 930 case HPUXTIOCCONS: 931 *(int *)data = 1; 932 error = (*fp->f_ops->fo_ioctl)(fp, TIOCCONS, data, p); 933 break; 934 935 /* BSD-style job control ioctls */ 936 case HPUXTIOCLBIS: 937 case HPUXTIOCLBIC: 938 case HPUXTIOCLSET: 939 *(int *)data &= HPUXLTOSTOP; 940 if (*(int *)data & HPUXLTOSTOP) 941 *(int *)data = LTOSTOP; 942 /* fall into */ 943 case HPUXTIOCLGET: 944 case HPUXTIOCSLTC: 945 case HPUXTIOCGLTC: 946 case HPUXTIOCSPGRP: 947 case HPUXTIOCGPGRP: 948 error = (*fp->f_ops->fo_ioctl) 949 (fp, hpuxtobsdioctl(com), data, p); 950 if (error == 0 && com == HPUXTIOCLGET) { 951 *(int *)data &= LTOSTOP; 952 if (*(int *)data & LTOSTOP) 953 *(int *)data = HPUXLTOSTOP; 954 } 955 break; 956 957 /* SYS 5 termio */ 958 case HPUXTCGETA: 959 case HPUXTCSETA: 960 case HPUXTCSETAW: 961 case HPUXTCSETAF: 962 error = hpuxtermio(fp, com, data, p); 963 break; 964 965 default: 966 error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); 967 break; 968 } 969 /* 970 * Copy any data to user, size was 971 * already set and checked above. 972 */ 973 if (error == 0 && (com&IOC_OUT) && size) 974 error = copyout(data, uap->cmarg, (u_int)size); 975 if (memp) 976 free(memp, M_IOCTLOPS); 977 return (error); 978 } 979 980 /* 981 * Man page lies, behaviour here is based on observed behaviour. 982 */ 983 hpuxgetcontext(p, uap, retval) 984 struct proc *p; 985 struct args { 986 char *buf; 987 int len; 988 } *uap; 989 int *retval; 990 { 991 int error = 0; 992 register int len; 993 994 len = MIN(uap->len, sizeof(hpuxcontext)); 995 if (len) 996 error = copyout(hpuxcontext, uap->buf, (u_int)len); 997 if (error == 0) 998 *retval = sizeof(hpuxcontext); 999 return (error); 1000 } 1001 1002 /* 1003 * This is the equivalent of BSD getpgrp but with more restrictions. 1004 * Note we do not check the real uid or "saved" uid. 1005 */ 1006 hpuxgetpgrp2(cp, uap, retval) 1007 struct proc *cp; 1008 register struct args { 1009 int pid; 1010 } *uap; 1011 int *retval; 1012 { 1013 register struct proc *p; 1014 1015 if (uap->pid == 0) 1016 uap->pid = cp->p_pid; 1017 p = pfind(uap->pid); 1018 if (p == 0) 1019 return (ESRCH); 1020 if (cp->p_ucred->cr_uid && p->p_ucred->cr_uid != cp->p_ucred->cr_uid && 1021 !inferior(p)) 1022 return (EPERM); 1023 *retval = p->p_pgid; 1024 return (0); 1025 } 1026 1027 /* 1028 * This is the equivalent of BSD setpgrp but with more restrictions. 1029 * Note we do not check the real uid or "saved" uid or pgrp. 1030 */ 1031 hpuxsetpgrp2(p, uap, retval) 1032 struct proc *p; 1033 struct args { 1034 int pid; 1035 int pgrp; 1036 } *uap; 1037 int *retval; 1038 { 1039 /* empirically determined */ 1040 if (uap->pgrp < 0 || uap->pgrp >= 30000) 1041 return (EINVAL); 1042 return (setpgid(p, uap, retval)); 1043 } 1044 1045 /* 1046 * XXX Same as BSD setre[ug]id right now. Need to consider saved ids. 1047 */ 1048 hpuxsetresuid(p, uap, retval) 1049 struct proc *p; 1050 struct args { 1051 int ruid; 1052 int euid; 1053 int suid; 1054 } *uap; 1055 int *retval; 1056 { 1057 return (osetreuid(p, uap, retval)); 1058 } 1059 1060 hpuxsetresgid(p, uap, retval) 1061 struct proc *p; 1062 struct args { 1063 int rgid; 1064 int egid; 1065 int sgid; 1066 } *uap; 1067 int *retval; 1068 { 1069 return (osetregid(p, uap, retval)); 1070 } 1071 1072 /* 1073 * XXX: simple recognition hack to see if we can make grmd work. 1074 */ 1075 hpuxlockf(p, uap, retval) 1076 struct proc *p; 1077 struct args { 1078 int fd; 1079 int func; 1080 long size; 1081 } *uap; 1082 int *retval; 1083 { 1084 #ifdef DEBUG 1085 log(LOG_DEBUG, "%d: lockf(%d, %d, %d)\n", 1086 p->p_pid, uap->fd, uap->func, uap->size); 1087 #endif 1088 return (0); 1089 } 1090 1091 hpuxgetaccess(p, uap, retval) 1092 register struct proc *p; 1093 register struct args { 1094 char *path; 1095 int uid; 1096 int ngroups; 1097 int *gidset; 1098 void *label; 1099 void *privs; 1100 } *uap; 1101 int *retval; 1102 { 1103 struct nameidata *ndp; 1104 int lgroups[NGROUPS]; 1105 int error = 0; 1106 register struct ucred *cred; 1107 register struct vnode *vp; 1108 1109 /* 1110 * Build an appropriate credential structure 1111 */ 1112 cred = crdup(p->p_ucred); 1113 switch (uap->uid) { 1114 case 65502: /* UID_EUID */ 1115 break; 1116 case 65503: /* UID_RUID */ 1117 cred->cr_uid = p->p_cred->p_ruid; 1118 break; 1119 case 65504: /* UID_SUID */ 1120 error = EINVAL; 1121 break; 1122 default: 1123 if (uap->uid > 65504) 1124 error = EINVAL; 1125 cred->cr_uid = uap->uid; 1126 break; 1127 } 1128 switch (uap->ngroups) { 1129 case -1: /* NGROUPS_EGID */ 1130 cred->cr_ngroups = 1; 1131 break; 1132 case -5: /* NGROUPS_EGID_SUPP */ 1133 break; 1134 case -2: /* NGROUPS_RGID */ 1135 cred->cr_ngroups = 1; 1136 cred->cr_gid = p->p_cred->p_rgid; 1137 break; 1138 case -6: /* NGROUPS_RGID_SUPP */ 1139 cred->cr_gid = p->p_cred->p_rgid; 1140 break; 1141 case -3: /* NGROUPS_SGID */ 1142 case -7: /* NGROUPS_SGID_SUPP */ 1143 error = EINVAL; 1144 break; 1145 case -4: /* NGROUPS_SUPP */ 1146 if (cred->cr_ngroups > 1) 1147 cred->cr_gid = cred->cr_groups[1]; 1148 else 1149 error = EINVAL; 1150 break; 1151 default: 1152 if (uap->ngroups > 0 && uap->ngroups <= NGROUPS) 1153 error = copyin((caddr_t)uap->gidset, 1154 (caddr_t)&lgroups[0], 1155 uap->ngroups * sizeof(lgroups[0])); 1156 else 1157 error = EINVAL; 1158 if (error == 0) { 1159 int gid; 1160 1161 for (gid = 0; gid < uap->ngroups; gid++) 1162 cred->cr_groups[gid] = lgroups[gid]; 1163 cred->cr_ngroups = uap->ngroups; 1164 } 1165 break; 1166 } 1167 /* 1168 * Lookup file using caller's effective IDs. 1169 */ 1170 if (error == 0) { 1171 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 1172 ndp->ni_segflg = UIO_USERSPACE; 1173 ndp->ni_dirp = uap->path; 1174 error = namei(ndp, p); 1175 } 1176 if (error) { 1177 crfree(cred); 1178 return (error); 1179 } 1180 /* 1181 * Use the constructed credentials for access checks. 1182 */ 1183 vp = ndp->ni_vp; 1184 *retval = 0; 1185 if (VOP_ACCESS(vp, VREAD, cred, p) == 0) 1186 *retval |= R_OK; 1187 if (vn_writechk(vp) == 0 && VOP_ACCESS(vp, VWRITE, cred, p) == 0) 1188 *retval |= W_OK; 1189 /* XXX we return X_OK for root on VREG even if not */ 1190 if (VOP_ACCESS(vp, VEXEC, cred, p) == 0) 1191 *retval |= X_OK; 1192 vput(vp); 1193 crfree(cred); 1194 return (error); 1195 } 1196 1197 /* 1198 * Brutal hack! Map HPUX u-area offsets into BSD u offsets. 1199 * No apologies offered, if you don't like it, rewrite it! 1200 */ 1201 1202 #define UOFF(f) ((int)&((struct user *)0)->f) 1203 #define HPUOFF(f) ((int)&((struct hpuxuser *)0)->f) 1204 1205 /* simplified FP structure */ 1206 struct bsdfp { 1207 int save[54]; 1208 int reg[24]; 1209 int ctrl[3]; 1210 }; 1211 1212 hpuxtobsduoff(off) 1213 int *off; 1214 { 1215 register int *ar0 = curproc->p_regs; 1216 struct hpuxfp *hp; 1217 struct bsdfp *bp; 1218 register u_int raddr; 1219 1220 /* u_ar0 field; procxmt puts in U_ar0 */ 1221 if ((int)off == HPUOFF(hpuxu_ar0)) 1222 return(UOFF(U_ar0)); 1223 1224 #ifdef FPCOPROC 1225 /* 68881 registers from PCB */ 1226 hp = (struct hpuxfp *)HPUOFF(hpuxu_fp); 1227 bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs); 1228 if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3]) 1229 return((int)&bp->ctrl[off - hp->hpfp_ctrl]); 1230 if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24]) 1231 return((int)&bp->reg[off - hp->hpfp_reg]); 1232 #endif 1233 1234 /* 1235 * Everything else we recognize comes from the kernel stack, 1236 * so we convert off to an absolute address (if not already) 1237 * for simplicity. 1238 */ 1239 if (off < (int *)ctob(UPAGES)) 1240 off = (int *)((u_int)off + (u_int)&u); 1241 1242 /* 1243 * 68020 registers. 1244 * We know that the HPUX registers are in the same order as ours. 1245 * The only difference is that their PS is 2 bytes instead of a 1246 * padded 4 like ours throwing the alignment off. 1247 */ 1248 if (off >= ar0 && off < &ar0[18]) { 1249 /* 1250 * PS: return low word and high word of PC as HP-UX would 1251 * (e.g. &u.u_ar0[16.5]). 1252 */ 1253 if (off == &ar0[PS]) 1254 raddr = (u_int) &((short *)ar0)[PS*2+1]; 1255 /* 1256 * PC: off will be &u.u_ar0[16.5] 1257 */ 1258 else if (off == (int *)&(((short *)ar0)[PS*2+1])) 1259 raddr = (u_int) &ar0[PC]; 1260 /* 1261 * D0-D7, A0-A7: easy 1262 */ 1263 else 1264 raddr = (u_int) &ar0[(int)(off - ar0)]; 1265 return((int)(raddr - (u_int)&u)); 1266 } 1267 1268 /* everything else */ 1269 return(-1); 1270 } 1271 1272 /* 1273 * Kludge up a uarea dump so that HPUX debuggers can find out 1274 * what they need. IMPORTANT NOTE: we do not EVEN attempt to 1275 * convert the entire user struct. 1276 */ 1277 hpuxdumpu(vp, cred) 1278 struct vnode *vp; 1279 struct ucred *cred; 1280 { 1281 struct proc *p = curproc; 1282 int error; 1283 struct hpuxuser *faku; 1284 struct bsdfp *bp; 1285 short *foop; 1286 1287 faku = (struct hpuxuser *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK); 1288 /* 1289 * Make sure there is no mistake about this 1290 * being a real user structure. 1291 */ 1292 bzero((caddr_t)faku, ctob(1)); 1293 /* 1294 * Fill in the process sizes. 1295 */ 1296 faku->hpuxu_tsize = p->p_vmspace->vm_tsize; 1297 faku->hpuxu_dsize = p->p_vmspace->vm_dsize; 1298 faku->hpuxu_ssize = p->p_vmspace->vm_ssize; 1299 /* 1300 * Fill in the exec header for CDB. 1301 * This was saved back in exec(). As far as I can tell CDB 1302 * only uses this information to verify that a particular 1303 * core file goes with a particular binary. 1304 */ 1305 bcopy((caddr_t)u.u_pcb.pcb_exec, 1306 (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec)); 1307 /* 1308 * Adjust user's saved registers (on kernel stack) to reflect 1309 * HPUX order. Note that HPUX saves the SR as 2 bytes not 4 1310 * so we have to move it up. 1311 */ 1312 faku->hpuxu_ar0 = p->p_regs; 1313 foop = (short *) p->p_regs; 1314 foop[32] = foop[33]; 1315 foop[33] = foop[34]; 1316 foop[34] = foop[35]; 1317 #ifdef FPCOPROC 1318 /* 1319 * Copy 68881 registers from our PCB format to HPUX format 1320 */ 1321 bp = (struct bsdfp *) &u.u_pcb.pcb_fpregs; 1322 bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save, 1323 sizeof(bp->save)); 1324 bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl, 1325 sizeof(bp->ctrl)); 1326 bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg, 1327 sizeof(bp->reg)); 1328 #endif 1329 /* 1330 * Slay the dragon 1331 */ 1332 faku->hpuxu_dragon = -1; 1333 /* 1334 * Dump this artfully constructed page in place of the 1335 * user struct page. 1336 */ 1337 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)faku, ctob(1), (off_t)0, 1338 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, 1339 (int *)0, (struct proc *)0); 1340 /* 1341 * Dump the remaining UPAGES-1 pages normally 1342 */ 1343 if (!error) 1344 error = vn_rdwr(UIO_WRITE, vp, ((caddr_t)&u)+ctob(1), 1345 ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE, 1346 IO_NODELOCKED|IO_UNIT, cred, (int *)0, 1347 (struct proc *)0); 1348 free((caddr_t)faku, M_TEMP); 1349 return(error); 1350 } 1351 1352 /* 1353 * The remaining routines are essentially the same as those in kern_xxx.c 1354 * and vfs_xxx.c as defined under "#ifdef COMPAT". We replicate them here 1355 * to avoid HPUXCOMPAT dependencies in those files and to make sure that 1356 * HP-UX compatibility still works even when COMPAT is not defined. 1357 */ 1358 /* #ifdef COMPAT */ 1359 1360 #define HPUX_HZ 50 1361 1362 #include "sys/times.h" 1363 1364 /* from old timeb.h */ 1365 struct hpuxtimeb { 1366 time_t time; 1367 u_short millitm; 1368 short timezone; 1369 short dstflag; 1370 }; 1371 1372 /* ye ole stat structure */ 1373 struct ohpuxstat { 1374 dev_t ohst_dev; 1375 u_short ohst_ino; 1376 u_short ohst_mode; 1377 short ohst_nlink; 1378 short ohst_uid; 1379 short ohst_gid; 1380 dev_t ohst_rdev; 1381 int ohst_size; 1382 int ohst_atime; 1383 int ohst_mtime; 1384 int ohst_ctime; 1385 }; 1386 1387 /* 1388 * SYS V style setpgrp() 1389 */ 1390 ohpuxsetpgrp(p, uap, retval) 1391 register struct proc *p; 1392 int *uap, *retval; 1393 { 1394 if (p->p_pid != p->p_pgid) 1395 enterpgrp(p, p->p_pid, 0); 1396 *retval = p->p_pgid; 1397 return (0); 1398 } 1399 1400 ohpuxtime(p, uap, retval) 1401 struct proc *p; 1402 register struct args { 1403 long *tp; 1404 } *uap; 1405 time_t *retval; 1406 { 1407 int error = 0; 1408 1409 if (uap->tp) 1410 error = copyout((caddr_t)&time.tv_sec, (caddr_t)uap->tp, 1411 sizeof (long)); 1412 *retval = time.tv_sec; 1413 return (error); 1414 } 1415 1416 ohpuxstime(p, uap, retval) 1417 struct proc *p; 1418 register struct args { 1419 int time; 1420 } *uap; 1421 int *retval; 1422 { 1423 struct timeval tv; 1424 int s, error; 1425 1426 tv.tv_sec = uap->time; 1427 tv.tv_usec = 0; 1428 if (error = suser(p->p_ucred, &p->p_acflag)) 1429 return (error); 1430 1431 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 1432 boottime.tv_sec += tv.tv_sec - time.tv_sec; 1433 s = splhigh(); time = tv; splx(s); 1434 resettodr(); 1435 return (0); 1436 } 1437 1438 ohpuxftime(p, uap, retval) 1439 struct proc *p; 1440 register struct args { 1441 struct hpuxtimeb *tp; 1442 } *uap; 1443 int *retval; 1444 { 1445 struct hpuxtimeb tb; 1446 int s; 1447 1448 s = splhigh(); 1449 tb.time = time.tv_sec; 1450 tb.millitm = time.tv_usec / 1000; 1451 splx(s); 1452 tb.timezone = tz.tz_minuteswest; 1453 tb.dstflag = tz.tz_dsttime; 1454 return (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb))); 1455 } 1456 1457 ohpuxalarm(p, uap, retval) 1458 register struct proc *p; 1459 register struct args { 1460 int deltat; 1461 } *uap; 1462 int *retval; 1463 { 1464 int s = splhigh(); 1465 1466 untimeout(realitexpire, (caddr_t)p); 1467 timerclear(&p->p_realtimer.it_interval); 1468 *retval = 0; 1469 if (timerisset(&p->p_realtimer.it_value) && 1470 timercmp(&p->p_realtimer.it_value, &time, >)) 1471 *retval = p->p_realtimer.it_value.tv_sec - time.tv_sec; 1472 if (uap->deltat == 0) { 1473 timerclear(&p->p_realtimer.it_value); 1474 splx(s); 1475 return (0); 1476 } 1477 p->p_realtimer.it_value = time; 1478 p->p_realtimer.it_value.tv_sec += uap->deltat; 1479 timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value)); 1480 splx(s); 1481 return (0); 1482 } 1483 1484 ohpuxnice(p, uap, retval) 1485 register struct proc *p; 1486 register struct args { 1487 int niceness; 1488 } *uap; 1489 int *retval; 1490 { 1491 int error; 1492 1493 error = donice(p, p, (p->p_nice-NZERO)+uap->niceness); 1494 if (error == 0) 1495 *retval = p->p_nice - NZERO; 1496 return (error); 1497 } 1498 1499 ohpuxtimes(p, uap, retval) 1500 struct proc *p; 1501 register struct args { 1502 struct tms *tmsb; 1503 } *uap; 1504 time_t *retval; 1505 { 1506 struct tms atms; 1507 int error; 1508 1509 atms.tms_utime = hpuxscale(&p->p_utime); 1510 atms.tms_stime = hpuxscale(&p->p_stime); 1511 atms.tms_cutime = hpuxscale(&p->p_stats->p_cru.ru_utime); 1512 atms.tms_cstime = hpuxscale(&p->p_stats->p_cru.ru_stime); 1513 error = copyout((caddr_t)&atms, (caddr_t)uap->tmsb, sizeof (atms)); 1514 if (error == 0) 1515 *retval = hpuxscale(&time) - hpuxscale(&boottime); 1516 return (error); 1517 } 1518 1519 /* 1520 * Doesn't exactly do what the documentation says. 1521 * What we really do is return 1/HPUX_HZ-th of a second since that 1522 * is what HP-UX returns. 1523 */ 1524 hpuxscale(tvp) 1525 register struct timeval *tvp; 1526 { 1527 return (tvp->tv_sec * HPUX_HZ + tvp->tv_usec * HPUX_HZ / 1000000); 1528 } 1529 1530 /* 1531 * Set IUPD and IACC times on file. 1532 * Can't set ICHG. 1533 */ 1534 ohpuxutime(p, uap, retval) 1535 struct proc *p; 1536 register struct a { 1537 char *fname; 1538 time_t *tptr; 1539 } *uap; 1540 int *retval; 1541 { 1542 register struct vnode *vp; 1543 register struct nameidata *ndp; 1544 struct vattr vattr; 1545 time_t tv[2]; 1546 int error; 1547 struct nameidata nd; 1548 1549 ndp = &nd; 1550 if (uap->tptr) { 1551 error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 1552 if (error) 1553 return (error); 1554 } else 1555 tv[0] = tv[1] = time.tv_sec; 1556 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 1557 ndp->ni_segflg = UIO_USERSPACE; 1558 ndp->ni_dirp = uap->fname; 1559 vattr_null(&vattr); 1560 vattr.va_atime.tv_sec = tv[0]; 1561 vattr.va_atime.tv_usec = 0; 1562 vattr.va_mtime.tv_sec = tv[1]; 1563 vattr.va_mtime.tv_usec = 0; 1564 if (error = namei(ndp, p)) 1565 return (error); 1566 vp = ndp->ni_vp; 1567 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1568 error = EROFS; 1569 else 1570 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred, p); 1571 vput(vp); 1572 return (error); 1573 } 1574 1575 ohpuxpause(p, uap, retval) 1576 struct proc *p; 1577 int *uap, *retval; 1578 { 1579 (void) tsleep((caddr_t)&u, PPAUSE | PCATCH, "pause", 0); 1580 /* always return EINTR rather than ERESTART... */ 1581 return (EINTR); 1582 } 1583 1584 /* 1585 * The old fstat system call. 1586 */ 1587 ohpuxfstat(p, uap, retval) 1588 struct proc *p; 1589 register struct args { 1590 int fd; 1591 struct ohpuxstat *sb; 1592 } *uap; 1593 int *retval; 1594 { 1595 register struct filedesc *fdp = p->p_fd; 1596 struct file *fp; 1597 1598 if (((unsigned)uap->fd) >= fdp->fd_nfiles || 1599 (fp = fdp->fd_ofiles[uap->fd]) == NULL) 1600 return (EBADF); 1601 if (fp->f_type != DTYPE_VNODE) 1602 return (EINVAL); 1603 return (ohpuxstat1((struct vnode *)fp->f_data, uap->sb)); 1604 } 1605 1606 /* 1607 * Old stat system call. This version follows links. 1608 */ 1609 ohpuxstat(p, uap, retval) 1610 struct proc *p; 1611 register struct args { 1612 char *fname; 1613 struct ohpuxstat *sb; 1614 } *uap; 1615 int *retval; 1616 { 1617 register struct nameidata *ndp; 1618 int error; 1619 struct nameidata nd; 1620 1621 ndp = &nd; 1622 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 1623 ndp->ni_segflg = UIO_USERSPACE; 1624 ndp->ni_dirp = uap->fname; 1625 if (error = namei(ndp, p)) 1626 return (error); 1627 error = ohpuxstat1(ndp->ni_vp, uap->sb); 1628 vput(ndp->ni_vp); 1629 return (error); 1630 } 1631 1632 int 1633 ohpuxstat1(vp, ub) 1634 register struct vnode *vp; 1635 struct ohpuxstat *ub; 1636 { 1637 struct ohpuxstat ds; 1638 struct vattr vattr; 1639 register int error; 1640 1641 error = VOP_GETATTR(vp, &vattr, curproc->p_ucred, curproc); 1642 if (error) 1643 return(error); 1644 /* 1645 * Copy from inode table 1646 */ 1647 ds.ohst_dev = vattr.va_fsid; 1648 ds.ohst_ino = (short)vattr.va_fileid; 1649 ds.ohst_mode = (u_short)vattr.va_mode; 1650 ds.ohst_nlink = vattr.va_nlink; 1651 ds.ohst_uid = (short)vattr.va_uid; 1652 ds.ohst_gid = (short)vattr.va_gid; 1653 ds.ohst_rdev = (dev_t)vattr.va_rdev; 1654 ds.ohst_size = (int)vattr.va_size; 1655 ds.ohst_atime = (int)vattr.va_atime.tv_sec; 1656 ds.ohst_mtime = (int)vattr.va_mtime.tv_sec; 1657 ds.ohst_ctime = (int)vattr.va_ctime.tv_sec; 1658 return (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds))); 1659 } 1660 /* #endif */ 1661 1662 #endif 1663