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