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