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