void cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { extern register_t switch_tramp_p; struct pcb *pcbp; struct trapframe *tf; register_t sp, osp; #ifdef DIAGNOSTIC if (round_page(sizeof(struct user) + sizeof(*tf)) > PAGE_SIZE) panic("USPACE too small for user"); #endif fpu_proc_save(p1); pcbp = &p2->p_addr->u_pcb; bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp)); /* space is cached for the copy{in,out}'s pleasure */ pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space; pcbp->pcb_fpstate = pool_get(&hppa_fppl, PR_WAITOK); *pcbp->pcb_fpstate = *p1->p_addr->u_pcb.pcb_fpstate; /* reset any of the pending FPU exceptions from parent */ pcbp->pcb_fpstate->hfp_regs.fpr_regs[0] = HPPA_FPU_FORK(pcbp->pcb_fpstate->hfp_regs.fpr_regs[0]); pcbp->pcb_fpstate->hfp_regs.fpr_regs[1] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[2] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[3] = 0; sp = (register_t)p2->p_addr + PAGE_SIZE; p2->p_md.md_regs = tf = (struct trapframe *)sp; sp += sizeof(struct trapframe); bcopy(p1->p_md.md_regs, tf, sizeof(*tf)); tf->tf_vtop = (paddr_t)p2->p_vmspace->vm_map.pmap->pm_pdir; tf->tf_cr30 = (paddr_t)pcbp->pcb_fpstate; tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 = tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = tf->tf_iisq[0] = tf->tf_iisq[1] = p2->p_vmspace->vm_map.pmap->pm_space; tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0); /* * theoretically these could be inherited from the father, * but just in case. */ tf->tf_sr7 = HPPA_SID_KERNEL; tf->tf_eiem = mfctl(CR_EIEM); tf->tf_ipsw = PSL_C | PSL_Q | PSL_P | PSL_D | PSL_I /* | PSL_L */ | PSL_O | PSL_W; /* * If specified, give the child a different stack. */ if (stack != NULL) setstack(tf, (u_long)stack, 0); /* XXX ignore error? */ /* * Build stack frames for the cpu_switchto & co. */ osp = sp + HPPA_FRAME_SIZE; *(register_t*)(osp - HPPA_FRAME_SIZE) = 0; *(register_t*)(osp + HPPA_FRAME_RP) = switch_tramp_p; *(register_t*)(osp) = (osp - HPPA_FRAME_SIZE); sp = osp + HPPA_FRAME_SIZE + 20*8; /* frame + callee-saved registers */ *(register_t*)(sp - HPPA_FRAME_SIZE + 0) = (register_t)arg; *(register_t*)(sp - HPPA_FRAME_SIZE + 8) = KERNMODE(func); *(register_t*)(sp - HPPA_FRAME_SIZE + 16) = 0; /* cpl */ pcbp->pcb_ksp = sp; }
void copylink(char *source, char *dest, int mode, int owner, int group) { struct stat sst, dst; int sfd, dfd, n; int r, same= 0, change= 0, docopy= 1; char buf[4096]; # define hdr ((struct exec *) buf) pid_t pid; int status; /* Source must exist as a plain file, dest may exist as a plain file. */ if (stat(source, &sst) < 0) { report(source); return; } if (mode == -1) { mode= sst.st_mode & 07777; if (!lflag || cflag) { mode|= 0444; if (mode & 0111) mode|= 0111; } } if (owner == -1) owner= sst.st_uid; if (group == -1) group= sst.st_gid; if (!S_ISREG(sst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", source); excode= 1; return; } r= stat(dest, &dst); if (r < 0) { if (errno != ENOENT) { report(dest); return; } } else { if (!S_ISREG(dst.st_mode)) { fprintf(stderr, "install: %s is not a regular file\n", dest); excode= 1; return; } /* Are the files the same? */ if (sst.st_dev == dst.st_dev && sst.st_ino == dst.st_ino) { if (!lflag && cflag) { fprintf(stderr, "install: %s and %s are the same, can't copy\n", source, dest); excode= 1; return; } same= 1; } } if (lflag && !same) { /* Try to link the files. */ if (r >= 0 && unlink(dest) < 0) { report(dest); return; } if (link(source, dest) >= 0) { docopy= 0; } else { if (!cflag || errno != EXDEV) { fprintf(stderr, "install: can't link %s to %s: %s\n", source, dest, strerror(errno)); excode= 1; return; } } } if (docopy && !same) { /* Copy the files, stripping if necessary. */ long count= LONG_MAX; int first= 1; if ((sfd= open(source, O_RDONLY)) < 0) { report(source); return; } /* Open for write is less simple, its mode may be 444. */ dfd= open(dest, O_WRONLY|O_CREAT|O_TRUNC, mode | 0600); if (dfd < 0 && errno == EACCES) { (void) chmod(dest, mode | 0600); dfd= open(dest, O_WRONLY|O_TRUNC); } if (dfd < 0) { report(dest); close(sfd); return; } pid= 0; while (count > 0 && (n= read(sfd, buf, sizeof(buf))) > 0) { if (first && n >= A_MINHDR && !BADMAG(*hdr)) { if (strip) { count= hdr->a_hdrlen + hdr->a_text + hdr->a_data; #ifdef A_NSYM hdr->a_flags &= ~A_NSYM; #endif hdr->a_syms= 0; } if (stack != -1 && setstack(hdr)) change= 1; if (compress != nil) { /* Write first #! line. */ (void) write(dfd, zcat, strlen(zcat)); /* Put a compressor in between. */ if ((pid= filter(dfd, compress)) < 0) { close(sfd); close(dfd); return; } change= 1; } } if (count < n) n= count; if (write(dfd, buf, n) < 0) { report(dest); close(sfd); close(dfd); if (pid != 0) (void) waitpid(pid, nil, 0); return; } count-= n; first= 0; } if (n < 0) report(source); close(sfd); close(dfd); if (pid != 0 && waitpid(pid, &status, 0) < 0 || status != 0) { excode= 1; return; } if (n < 0) return; } else { if (stack != -1) { /* The file has been linked into place. Set the * stack size. */ if ((dfd= open(dest, O_RDWR)) < 0) { report(dest); return; } if ((n= read(dfd, buf, sizeof(*hdr))) < 0) { report(dest); return; } if (n >= A_MINHDR && !BADMAG(*hdr) && setstack(hdr)) { if (lseek(dfd, (off_t) 0, SEEK_SET) == -1 || write(dfd, buf, n) < 0 ) { report(dest); close(dfd); return; } change= 1; } close(dfd); } } if (stat(dest, &dst) < 0) { report(dest); return; } if ((dst.st_mode & 07777) != mode) { if (chmod(dest, mode) < 0) { report(dest); return; } } if (dst.st_uid != owner || dst.st_gid != group) { if (chown(dest, owner, group) < 0 && errno != EPERM) { report(dest); return; } /* Set the mode again, chown may have wrecked it. */ (void) chmod(dest, mode); } if (!change) { struct utimbuf ubuf; ubuf.actime= dst.st_atime; ubuf.modtime= sst.st_mtime; if (utime(dest, &ubuf) < 0 && errno != EPERM) { report(dest); return; } } }