/* * If pid is positive, then signal sig is sent to the process with the ID specified by pid. * If pid equals 0, then sig is sent to every process in the process group of the calling process. * If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below. * If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid. * If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID. * */ int do_kill(int pid, int sig){ struct proc *p; int nr, ret; if (pid>0) return sigsend(pid, sig, 0); if (pid==0) return sigsend_g(cu->p_pid, sig, 0); if (pid < -1) return sigsend_g(-pid, sig, 0); if (pid==-1) { for (nr=1; nr<NPROC; nr++) { if ((p=proc[nr])) ret = sigsend(nr, sig, 0); } return ret; } syserr(EINVAL); return -1; }
/* send a signal to a process group. */ int sigsend_g(int pgrp, int n, int priv){ int nr; struct proc *p; for (nr=0; nr<NPROC; nr++) { if ((p=proc[nr]) && p->p_pgrp==pgrp) { sigsend(p->p_pid, n, priv); } } return 0; }
int sys_sigsend(void) { int dest_pid; int value; if (argint(0, &dest_pid) < 0 || argint(1, &value) < 0) return -1; return sigsend(dest_pid, value); }
int sys_sigsend(void){ int pid,signum; if (argint(0, &pid) <0) { return -1; } if (argint(1, &signum) <0 ) { return -1; } return sigsend(pid, signum); }
/* ARGSUSED */ static void childcleanup(int sig) { int i; /* Only need to kill the child that became the shell. */ for (i = 0; i < nchild; i++) { /* Don't kill gramps before his time */ if (pidlist[i] != getppid()) (void) sigsend(P_PID, pidlist[i], SIGHUP); } }
/* * Tells the threadflow's thread to stop and optionally signals * its associated process to end the thread. */ static void threadflow_kill(threadflow_t *threadflow) { /* Tell thread to finish */ threadflow->tf_abort = 1; #ifdef USE_PROCESS_MODEL #ifdef HAVE_SIGSEND (void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1); #else (void) kill(threadflow->tf_process->pf_pid, SIGUSR1); #endif #else /* USE_PROCESS_MODEL */ threadflow->tf_process->pf_running = 0; #endif /* USE_PROCESS_MODEL */ }
int main(int argc, char *argv[]) { int pid; void (*fp)(void) = death; printf(2,"death = %d",(int)fp); pid = fork(); if (pid==0) { printf(2,"death = %d",(int)fp); signal(5,death); while(1); } sleep(100); int j = sigsend(pid,5); printf(2,"return val %d",j); wait(); return 0; }
uint32 runtime·ctrlhandler1(uint32 type) { int32 s; switch(type) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: s = SIGINT; break; default: return 0; } if(runtime·sigsend(s)) return 1; runtime·exit(2); // SIGINT, SIGTERM, etc return 0; }
// Exit the current process. Does not return. // An exited process remains in the zombie state // until its parent calls wait() to find out it exited. void exit(void) { struct proc *p; int fd; if(proc == initproc) panic("init exiting"); // Close all open files. for(fd = 0; fd < NOFILE; fd++) { if(proc->ofile[fd]) { fileclose(proc->ofile[fd]); proc->ofile[fd] = 0; } } iput(proc->cwd); proc->cwd = 0; acquire(&ptable.lock); //A&T sent a SIGCHLD to the parent process sigsend(proc->parent->pid,SIGCHLD); // Parent might be sleeping in wait(). wakeup1(proc->parent); // Pass abandoned children to init. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) { if(p->parent == proc) { p->parent = initproc; if(p->state == ZOMBIE) wakeup1(initproc); } } // Jump into the scheduler, never to return. proc->state = ZOMBIE; sched(); panic("zombie exit"); }
/* terminate the currenct proccess into ZOMBIE, and tell its parent. * the struct proc is freed by each proc's parent. * */ int do_exit(int ret){ struct file *fp; struct proc *p; uint fd, nr; cu->p_ret = ret; // clear all the signal handlers for (nr=0; nr<NSIG; nr++) { cu->p_sigact[nr].sa_handler = SIG_DFL; cu->p_sigact[nr].sa_flags = 0; } // close all the opened files, and iput the directories. for (fd=0; fd<NOFILE; fd++){ fp = cu->p_ofile[fd]; if (fp != NULL) { do_close(fd); } cu->p_ofile[fd] = NULL; } iput(cu->p_iroot); iput(cu->p_wdir); // tell its parent sigsend(cu->p_ppid, SIGCHLD, 1); // free the address space vm_clear(&cu->p_vm); kfree(cu->p_vm.vm_pgd, PAGE); // make this process Zombie, give all the children to proc[1] // and tell its parent cu->p_chan = 0; cu->p_stat = SZOMB; for (nr=1; nr<NPROC; nr++) { if ((p=proc[nr]) && p!=cu && (p->p_ppid==cu->p_pid)) { p->p_ppid = 1; } } // wakeup proc[1] and its parent p = proc[cu->p_ppid]; wakeup(p); wakeup(proc[1]); return 0; }
void sighandler(int32 sig, Siginfo *info, void *context) { Ucontext *uc; Mcontext *mc; Regs *r; if(sigtab[sig].flags & SigQueue) { if(sigsend(sig) || (sigtab[sig].flags & SigIgnore)) return; exit(2); // SIGINT, SIGTERM, etc } if(panicking) // traceback already printed exit(2); panicking = 1; if(sig < 0 || sig >= NSIG){ printf("Signal %d\n", sig); }else{ printf("%s\n", sigtab[sig].name); } uc = context; mc = uc->uc_mcontext; r = &mc->ss; printf("Faulting address: %p\n", info->si_addr); printf("pc: %X\n", r->rip); printf("\n"); if(gotraceback()){ traceback((void*)r->rip, (void*)r->rsp, (void*)r->r15); tracebackothers((void*)r->r15); dumpregs(r); } breakpoint(); exit(2); }
/* * Tells the threadflow's thread to stop and optionally signals * its associated process to end the thread. */ static void threadflow_kill(threadflow_t *threadflow, int wait_cnt) { /* Tell thread to finish */ threadflow->tf_abort = 1; /* wait a bit for threadflow to stop */ while (wait_cnt && threadflow->tf_running) { (void) sleep(1); wait_cnt--; } #ifdef USE_PROCESS_MODEL #ifdef HAVE_SIGSEND (void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1); #else (void) kill(threadflow->tf_process->pf_pid, SIGUSR1); #endif #else /* USE_PROCESS_MODEL */ threadflow->tf_process->pf_running = 0; #endif /* USE_PROCESS_MODEL */ }
void sighandler(int32 sig, Siginfo* info, void* context) { Ucontext *uc; Mcontext *mc; if(sigtab[sig].flags & SigQueue) { if(sigsend(sig) || (sigtab[sig].flags & SigIgnore)) return; exit(2); // SIGINT, SIGTERM, etc } if(panicking) // traceback already printed exit(2); panicking = 1; uc = context; mc = &uc->uc_mcontext; if(sig < 0 || sig >= NSIG) printf("Signal %d\n", sig); else printf("%s\n", sigtab[sig].name); printf("Faulting address: %p\n", info->si_addr); printf("PC=%X\n", mc->mc_eip); printf("\n"); if(gotraceback()){ traceback((void*)mc->mc_eip, (void*)mc->mc_esp, m->curg); tracebackothers(m->curg); dumpregs(mc); } breakpoint(); exit(2); }
/* ARGSUSED */ static void parenthandler(int sig, siginfo_t *si, ucontext_t *uc) { int i; /* * We get here if someone has successfully entered a password * from the auxiliary console and is getting the single-user shell. * When this happens, the parent needs to kill the children * that didn't get the shell. * */ for (i = 0; i < nchild; i++) { if (pidlist[i] != si->__data.__proc.__pid) (void) sigsend(P_PID, pidlist[i], SIGTERM); } sa.sa_handler = SIG_IGN; sa.sa_flags = 0; (void) sigemptyset(&sa.sa_mask); (void) sigaction(SIGINT, &sa, NULL); (void) sigaction(SIGQUIT, &sa, NULL); (void) sigaction(SIGTERM, &sa, NULL); (void) wait(NULL); }
void sighandler(int32 sig, Siginfo *info, void *context) { Ucontext *uc; Mcontext *mc; Regs *r; G *gp; uintptr *sp; byte *pc; uc = context; mc = uc->uc_mcontext; r = &mc->ss; if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) { // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). if(sig == SIGFPE && info->si_code == 0) { pc = (byte*)r->rip; if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix pc++; if(pc[0] == 0xF7) info->si_code = FPE_INTDIV; } // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; // Only push sigpanic if r->rip != 0. // If r->rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to sigpanic instead. // (Otherwise the trace will end at sigpanic and we // won't get to see who faulted.) if(r->rip != 0) { sp = (uintptr*)r->rsp; *--sp = r->rip; r->rsp = (uintptr)sp; } r->rip = (uintptr)sigpanic; return; } if(sigtab[sig].flags & SigQueue) { if(sigsend(sig) || (sigtab[sig].flags & SigIgnore)) return; exit(2); // SIGINT, SIGTERM, etc } if(panicking) // traceback already printed exit(2); panicking = 1; if(sig < 0 || sig >= NSIG){ printf("Signal %d\n", sig); }else{ printf("%s\n", sigtab[sig].name); } printf("pc: %X\n", r->rip); printf("\n"); if(gotraceback()){ traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15); tracebackothers((void*)r->r15); dumpregs(r); } breakpoint(); exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { UcontextT *uc = context; McontextT *mc = &uc->uc_mcontext; uintptr *sp; SigTab *t; if(sig == SIGPROF) { runtime·sigprof((uint8*)mc->__gregs[REG_EIP], (uint8*)mc->__gregs[REG_UESP], nil, gp); return; } t = &runtime·sigtab[sig]; if(info->_code != SI_USER && (t->flags & SigPanic)) { if(gp == nil || gp == m->g0) goto Throw; // Make it look like a call to the signal func. // We need to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->_code; gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */ gp->sigpc = mc->__gregs[REG_EIP]; // Only push runtime·sigpanic if __gregs[REG_EIP] != 0. // If __gregs[REG_EIP] == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will make the // trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic // and we won't get to see who faulted.) if(mc->__gregs[REG_EIP] != 0) { sp = (uintptr*)mc->__gregs[REG_UESP]; *--sp = mc->__gregs[REG_EIP]; mc->__gregs[REG_UESP] = (uintptr)sp; } mc->__gregs[REG_EIP] = (uintptr)runtime·sigpanic; return; } if(info->_code == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: runtime·startpanic(); if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%X\n", mc->__gregs[REG_EIP]); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)mc->__gregs[REG_EIP], (void*)mc->__gregs[REG_UESP], 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(mc); } runtime·exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Sigcontext *r; SigTab *t; uc = context; r = &uc->uc_mcontext; if(sig == SIGPROF) { runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp); return; } t = &runtime·sigtab[sig]; if(info->si_code != SI_USER && (t->flags & SigPanic)) { if(gp == nil) goto Throw; // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = r->fault_address; gp->sigpc = r->arm_pc; // If this is a leaf function, we do smash LR, // but we're not going back there anyway. // Don't bother smashing if r->arm_pc is 0, // which is probably a call to a nil func: the // old link register is more useful in the stack trace. if(r->arm_pc != 0) r->arm_lr = r->arm_pc; // In case we are panicking from external C code r->arm_r10 = (uintptr)gp; r->arm_r9 = (uintptr)m; r->arm_pc = (uintptr)runtime·sigpanic; return; } if(info->si_code == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: if(runtime·panicking) // traceback already printed runtime·exit(2); runtime·panicking = 1; if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%x\n", r->arm_pc); runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp); runtime·tracebackothers(gp); runtime·printf("\n"); runtime·dumpregs(r); } // breakpoint(); runtime·exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Sigcontext *r; uintptr *sp; SigTab *t; uc = context; r = &uc->uc_mcontext; if(sig == SIGPROF) { runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp); return; } t = &runtime·sigtab[sig]; if(info->si_code != SI_USER && (t->flags & SigPanic)) { if(gp == nil) goto Throw; // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = ((uintptr*)info)[3]; gp->sigpc = r->eip; // Only push runtime·sigpanic if r->eip != 0. // If r->eip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(r->eip != 0) { sp = (uintptr*)r->esp; *--sp = r->eip; r->esp = (uintptr)sp; } r->eip = (uintptr)runtime·sigpanic; return; } if(info->si_code == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: runtime·startpanic(); if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%X\n", r->eip); runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(r); } runtime·exit(2); }
void ctrlc(void){ if(lastShInvokedPid != -1) sigsend(lastShInvokedPid, SIGINT); }
int main(int argc, char *argv[]) { int parent_pid = getpid(); int worker_pid; if(argc != 2){ printf(1,"Needs 2 arguments... Try again.\n"); exit(); } int n = atoi(argv[1]); if(n > NPROC){ printf(1,"Too many workers, can't handle it!!!! Goodbye...\n"); exit(); } int i = 0; sigset(&parent_handler); printf(1, "workers pids:\n"); for (i = 0; i < n; i++) { //creating n processes worker_pid = fork(); if (worker_pid < 0) break; if (worker_pid == 0) { //child process sigset(&worker_handler); // init sig_handler of the child process while (1) { sigpause(); } } else { workers[i].pid = worker_pid; workers[i].free = 1; printf(1, "%d\n", worker_pid); } } if (getpid() == parent_pid) { char buf[128]; for (;;) { // sleep(1); printf(1, "please enter a number: "); read(1, buf, 128); if (strlen(buf) == 1 && buf[0] == '\n') continue; int x = atoi(buf); if (x < 0){ //Doesn't support negative numbers (or bigger than max_integer) x = 1; printf(1,"Primsrv doesn't support your number :( changing it to 1...\n"); } memset(buf, '\0', 128); if (x == 0) { //need to exit program for (i = 0; i < n; i++) { sigsend(workers[i].pid, x); } int pid; while ((pid = wait()) > -1) printf(1, "worker %d exit\n", pid); printf(1, "primsrv exit\n"); break; } else { //search for idle worker i = 0; while (i < n && !workers[i].free) { i++; } if (i == n) { printf(1, "no idle workers\n"); continue; } else { workers[i].free = 0; workers[i].last_number = x; sigsend(workers[i].pid, x); } } } } exit(); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Sigcontext *r; SigTab *t; uc = context; r = &uc->uc_mcontext; if(sig == SIGPROF) { runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp); return; } t = &runtime·sigtab[sig]; if(info->si_code != SI_USER && (t->flags & SigPanic)) { if(gp == nil || gp == m->g0) goto Throw; // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = r->fault_address; gp->sigpc = r->arm_pc; // We arrange lr, and pc to pretend the panicking // function calls sigpanic directly. // Always save LR to stack so that panics in leaf // functions are correctly handled. This smashes // the stack frame but we're not going back there // anyway. r->arm_sp -= 4; *(uint32 *)r->arm_sp = r->arm_lr; // Don't bother saving PC if it's zero, which is // probably a call to a nil func: the old link register // is more useful in the stack trace. if(r->arm_pc != 0) r->arm_lr = r->arm_pc; // In case we are panicking from external C code r->arm_r10 = (uintptr)gp; r->arm_r9 = (uintptr)m; r->arm_pc = (uintptr)runtime·sigpanic; return; } if(info->si_code == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: if(runtime·panicking) // traceback already printed runtime·exit(2); runtime·panicking = 1; if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%x\n", r->arm_pc); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback()) { runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp); runtime·tracebackothers(gp); runtime·printf("\n"); runtime·dumpregs(r); } // breakpoint(); runtime·exit(2); }
int pkgexecv(char *filein, char *fileout, char *uname, char *gname, char *arg[]) { int exit_no; int n; int status; pid_t pid; pid_t waitstat; struct group *grp; struct passwd *pwp; struct sigaction nact; struct sigaction oact; void (*funcSighup)(int); void (*funcSigint)(int); /* flush standard i/o before creating new process */ (void) fflush(stdout); (void) fflush(stderr); /* * hold SIGINT/SIGHUP signals and reset signal received counter; * after the vfork() the parent and child need to setup their respective * interrupt handling and release the hold on the signals */ (void) sighold(SIGINT); (void) sighold(SIGHUP); sig_received = 0; /* * create new process to execute command in; * vfork() is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * call to exec(). */ pid = vfork(); if (pid < 0) { /* * ************************************************************* * fork failed! * ************************************************************* */ progerr(pkg_gt(ERR_FORK_FAILED), errno, strerror(errno)); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); return (-1); } if (pid > 0) { /* * ************************************************************* * This is the forking (parent) process * ************************************************************* */ /* close datastream if any portion read */ if (ds_curpartcnt >= 0) { if (ds_close(0) != 0) { /* kill child process */ (void) sigsend(P_PID, pid, SIGKILL); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); return (-1); } } /* * setup signal handlers for SIGINT and SIGHUP and release hold */ /* hook SIGINT to sig_trap() */ nact.sa_handler = sig_trap; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); if (sigaction(SIGINT, &nact, &oact) < 0) { funcSigint = SIG_DFL; } else { funcSigint = oact.sa_handler; } /* hook SIGHUP to sig_trap() */ nact.sa_handler = sig_trap; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); if (sigaction(SIGHUP, &nact, &oact) < 0) { funcSighup = SIG_DFL; } else { funcSighup = oact.sa_handler; } /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); /* * wait for the process to exit, reap child exit status */ for (;;) { status = 0; waitstat = waitpid(pid, (int *)&status, 0); if (waitstat < 0) { /* waitpid returned error */ if (errno == EAGAIN) { /* try again */ continue; } if (errno == EINTR) { continue; } /* error from waitpid: bail */ break; } else if (waitstat == pid) { /* child exit status available */ break; } } /* * reset signal handlers */ /* reset SIGINT */ nact.sa_handler = funcSigint; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGINT, &nact, (struct sigaction *)NULL); /* reset SIGHUP */ nact.sa_handler = funcSighup; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL); /* error if child process does not match */ if (waitstat != pid) { progerr(pkg_gt(ERR_WAIT_FAILED), pid, waitstat, status, errno, strerror(errno)); return (-1); } /* * determine final exit code: * - if signal received, then return interrupted (3) * - if child exit status is available, return exit child status * - otherwise return error (-1) */ if (sig_received != 0) { exit_no = 3; /* interrupted */ } else if (WIFEXITED(status)) { exit_no = WEXITSTATUS(status); } else { exit_no = -1; /* exec() or other process error */ } return (exit_no); } /* * ********************************************************************* * This is the forked (child) process * ********************************************************************* */ /* reset all signals to default */ for (n = 0; n < NSIG; n++) { (void) sigset(n, SIG_DFL); } /* release hold on signals held by parent before fork() */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); /* * The caller wants to have stdin connected to filein. */ if (filein && *filein) { /* * If input is supposed to be connected to /dev/tty */ if (strncmp(filein, "/dev/tty", 8) == 0) { /* * If stdin is connected to a tty device. */ if (isatty(STDIN_FILENO)) { /* * Reopen it to /dev/tty. */ n = open(filein, O_RDONLY); if (n >= 0) { (void) dup2(n, STDIN_FILENO); } } } else { /* * If we did not want to be connected to /dev/tty, we * connect input to the requested file no questions. */ n = open(filein, O_RDONLY); if (n >= 0) { (void) dup2(n, STDIN_FILENO); } } } /* * The caller wants to have stdout and stderr connected to fileout. * If "fileout" is "/dev/tty" then reconnect stdout to "/dev/tty" * only if /dev/tty is not already associated with "a tty". */ if (fileout && *fileout) { /* * If output is supposed to be connected to /dev/tty */ if (strncmp(fileout, "/dev/tty", 8) == 0) { /* * If stdout is connected to a tty device. */ if (isatty(STDOUT_FILENO)) { /* * Reopen it to /dev/tty if /dev/tty available. */ n = open(fileout, O_WRONLY); if (n >= 0) { /* * /dev/tty is available - close the * current standard output stream, and * reopen it on /dev/tty */ (void) dup2(n, STDOUT_FILENO); } } /* * not connected to tty device - probably redirect to * file - preserve existing output device */ } else { /* * If we did not want to be connected to /dev/tty, we * connect output to the requested file no questions. */ /* LINTED O_CREAT without O_EXCL specified in call to */ n = open(fileout, O_WRONLY|O_CREAT|O_APPEND, 0666); if (n >= 0) { (void) dup2(n, STDOUT_FILENO); } } /* * Dup stderr from stdout. */ (void) dup2(STDOUT_FILENO, STDERR_FILENO); } /* * do NOT close all file descriptors except stdio * file descriptors are passed in to some subcommands * (see dstream:ds_getinfo() and dstream:ds_putinfo()) */ /* set group/user i.d. if requested */ if (gname && *gname && (grp = cgrnam(gname)) != NULL) { if (setgid(grp->gr_gid) == -1) { progerr(pkg_gt(ERR_SETGID), grp->gr_gid); } } if (uname && *uname && (pwp = cpwnam(uname)) != NULL) { if (setuid(pwp->pw_uid) == -1) { progerr(pkg_gt(ERR_SETUID), pwp->pw_uid); } } /* execute target executable */ (void) execve(arg[0], arg, environ); progerr(pkg_gt(ERR_EX_FAIL), arg[0], errno); _exit(99); /*NOTREACHED*/ }
static void main_loop(char *devname, boolean_t cttyflag) { int fd, fb, i; char *user = NULL; /* authorized user */ char *pass; /* password from user */ char *cpass; /* crypted password */ struct spwd spwd; struct spwd *lshpw; /* local shadow */ char shadow[NSS_BUFLEN_SHADOW]; FILE *sysmsgfd; for (i = 0; i < 3; i++) (void) close(i); if (cttyflag == B_FALSE) { if (setsid() == -1) exit(EXIT_FAILURE); } if ((fd = open(devname, O_RDWR)) < 0) exit(EXIT_FAILURE); /* * In system maintenance mode, all virtual console instances * of the svc:/system/console-login service are not available * any more, and only the system console is available. So here * we always switch to the system console in case at the moment * the active console isn't it. */ (void) ioctl(fd, VT_ACTIVATE, 1); if (fd != 0) (void) dup2(fd, STDIN_FILENO); if (fd != 1) (void) dup2(fd, STDOUT_FILENO); if (fd != 2) (void) dup2(fd, STDERR_FILENO); if (fd > 2) (void) close(fd); /* Stop progress bar and reset console mode to text */ if ((fb = open("/dev/fb", O_RDONLY)) >= 0) { (void) ioctl(fb, KDSETMODE, KD_RESETTEXT); (void) close(fb); } sysmsgfd = fopen("/dev/sysmsg", "w"); sanitize_tty(fileno(stdin)); for (;;) { do { (void) printf("\nEnter user name for system " "maintenance (control-d to bypass): "); user = sulogin_getinput(devname, ECHOON); if (user == NULL) { /* signal other children to exit */ (void) sigsend(P_PID, masterpid, SIGUSR1); /* ^D, so straight to default init state */ exit(EXIT_FAILURE); } } while (user[0] == '\0'); (void) printf("Enter %s password (control-d to bypass): ", user); if ((pass = sulogin_getinput(devname, ECHOOFF)) == NULL) { /* signal other children to exit */ (void) sigsend(P_PID, masterpid, SIGUSR1); /* ^D, so straight to default init state */ free(user); exit(EXIT_FAILURE); } lshpw = getspnam_r(user, &spwd, shadow, sizeof (shadow)); if (lshpw == NULL) { /* * the user entered doesn't exist, too bad. */ goto sorry; } /* * There is a special case error to catch here: * If the password is hashed with an algorithm * other than the old unix crypt the call to crypt(3c) * could fail if /usr is corrupt or not available * since by default /etc/security/crypt.conf will * have the crypt_ modules located under /usr/lib. * Or it could happen if /etc/security/crypt.conf * is corrupted. * * If this happens crypt(3c) will return NULL and * set errno to ELIBACC for the former condition or * EINVAL for the latter, in this case we bypass * authentication and just verify that the user is * authorized. */ errno = 0; cpass = crypt(pass, lshpw->sp_pwdp); if (((cpass == NULL) && (lshpw->sp_pwdp[0] == '$')) && ((errno == ELIBACC) || (errno == EINVAL))) { goto checkauth; } else if ((cpass == NULL) || (strcmp(cpass, lshpw->sp_pwdp) != 0)) { goto sorry; } checkauth: /* * There is a special case error here as well. * If /etc/user_attr is corrupt, getusernam("root") * returns NULL. * In this case, we just give access because this is similar * to the case of root not existing in /etc/passwd. */ if ((getusernam("root") != NULL) && (chkauthattr(MAINTENANCE_AUTH, user) != 1)) { goto sorry; } (void) fprintf(sysmsgfd, "\nsingle-user privilege " "assigned to %s on %s.\n", user, devname); (void) sigsend(P_PID, masterpid, SIGUSR1); (void) wait(NULL); free(user); free(pass); single(su, devname); /* single never returns */ sorry: (void) printf("\nLogin incorrect or user %s not authorized\n", user); free(user); free(pass); (void) sleep(sleeptime); } }
void runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) { uintptr *sp; SigTab *t; bool crash; if(sig == SIGPROF) { if(gp != m->g0 && gp != m->gsignal) runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp); return; } t = &runtime·sigtab[sig]; if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { if(gp == nil || gp == m->g0) goto Throw; // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = SIG_CODE0(info, ctxt); gp->sigcode1 = SIG_CODE1(info, ctxt); gp->sigpc = SIG_RIP(info, ctxt); #ifdef GOOS_darwin // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). if(sig == SIGFPE && gp->sigcode0 == 0) { byte *pc; pc = (byte*)gp->sigpc; if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix pc++; else if(pc[0] == 0x66) // 16-bit instruction prefix pc++; if(pc[0] == 0xF6 || pc[0] == 0xF7) gp->sigcode0 = FPE_INTDIV; } #endif // Only push runtime·sigpanic if rip != 0. // If rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(SIG_RIP(info, ctxt) != 0) { sp = (uintptr*)SIG_RSP(info, ctxt); *--sp = SIG_RIP(info, ctxt); SIG_RSP(info, ctxt) = (uintptr)sp; } SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic; return; } if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: m->throwing = 1; m->caughtsig = gp; runtime·startpanic(); if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%X\n", SIG_RIP(info, ctxt)); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback(&crash)){ runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp); runtime·tracebackothers(gp); runtime·printf("\n"); runtime·dumpregs(info, ctxt); } if(crash) runtime·crash(); runtime·exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *mc; Sigcontext *r; uintptr *sp; uc = context; mc = &uc->uc_mcontext; r = (Sigcontext*)mc; // same layout, more conveient names if(sig == SIGPROF) { runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp); return; } if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = ((uintptr*)info)[2]; gp->sigpc = r->rip; // Only push runtime·sigpanic if r->rip != 0. // If r->rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(r->rip != 0) { sp = (uintptr*)r->rsp; *--sp = r->rip; r->rsp = (uintptr)sp; } r->rip = (uintptr)runtime·sigpanic; return; } if(runtime·sigtab[sig].flags & SigQueue) { if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore)) return; runtime·exit(2); // SIGINT, SIGTERM, etc } if(runtime·panicking) // traceback already printed runtime·exit(2); runtime·panicking = 1; if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%X\n", r->rip); runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(r); } runtime·exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext32 *mc; Regs32 *r; uintptr *sp; byte *pc; SigTab *t; uc = context; mc = uc->uc_mcontext; r = &mc->ss; if(sig == SIGPROF) { if(gp != m->g0 && gp != m->gsignal) runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp); return; } t = &runtime·sigtab[sig]; if(info->si_code != SI_USER && (t->flags & SigPanic)) { if(gp == nil || gp == m->g0) goto Throw; // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). if(sig == SIGFPE && info->si_code == 0) { pc = (byte*)r->eip; if(pc[0] == 0x66) // 16-bit instruction prefix pc++; if(pc[0] == 0xF6 || pc[0] == 0xF7) info->si_code = FPE_INTDIV; } // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; gp->sigpc = r->eip; // Only push runtime·sigpanic if r->eip != 0. // If r->eip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(r->eip != 0) { sp = (uintptr*)r->esp; *--sp = r->eip; r->esp = (uintptr)sp; } r->eip = (uintptr)runtime·sigpanic; return; } if(info->si_code == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; Throw: runtime·startpanic(); if(sig < 0 || sig >= NSIG){ runtime·printf("Signal %d\n", sig); }else{ runtime·printf("%s\n", runtime·sigtab[sig].name); } runtime·printf("PC=%x\n", r->eip); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(r); } runtime·exit(2); }
void runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) { uintptr *sp; SigTab *t; bool crash; if(sig == SIGPROF) { runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, g->m); return; } #ifdef GOOS_darwin // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47. // The hardware delivers a different kind of fault for a malformed address // than it does for an attempt to access a valid but unmapped address. // OS X 10.9.2 mishandles the malformed address case, making it look like // a user-generated signal (like someone ran kill -SEGV ourpid). // We pass user-generated signals to os/signal, or else ignore them. // Doing that here - and returning to the faulting code - results in an // infinite loop. It appears the best we can do is rewrite what the kernel // delivers into something more like the truth. The address used below // has very little chance of being the one that caused the fault, but it is // malformed, it is clearly not a real pointer, and if it does get printed // in real life, people will probably search for it and find this code. // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e // as I type this comment. if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) { SIG_CODE0(info, ctxt) = SI_USER+1; info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL; } #endif t = &runtime·sigtab[sig]; if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = SIG_CODE0(info, ctxt); gp->sigcode1 = SIG_CODE1(info, ctxt); gp->sigpc = SIG_RIP(info, ctxt); #ifdef GOOS_darwin // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). if(sig == SIGFPE && gp->sigcode0 == 0) { byte *pc; pc = (byte*)gp->sigpc; if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix pc++; else if(pc[0] == 0x66) // 16-bit instruction prefix pc++; if(pc[0] == 0xF6 || pc[0] == 0xF7) gp->sigcode0 = FPE_INTDIV; } #endif // Only push runtime·sigpanic if rip != 0. // If rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(SIG_RIP(info, ctxt) != 0) { sp = (uintptr*)SIG_RSP(info, ctxt); if(sizeof(uintreg) > sizeof(uintptr)) *--sp = 0; *--sp = SIG_RIP(info, ctxt); SIG_RSP(info, ctxt) = (uintptr)sp; } SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic; return; } if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) if(runtime·sigsend(sig)) return; if(t->flags & SigKill) runtime·exit(2); if(!(t->flags & SigThrow)) return; g->m->throwing = 1; g->m->caughtsig = gp; runtime·startpanic(); if(sig < 0 || sig >= NSIG) runtime·printf("Signal %d\n", sig); else runtime·printf("%s\n", runtime·sigtab[sig].name); runtime·printf("PC=%X\n", SIG_RIP(info, ctxt)); if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = g->m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback(&crash)){ runtime·goroutineheader(gp); runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp); runtime·tracebackothers(gp); runtime·printf("\n"); runtime·dumpregs(info, ctxt); } if(crash) runtime·crash(); runtime·exit(2); }
void sighandler(int32 sig, Siginfo* info, void* context) { Ucontext *uc; Mcontext *r; G *gp; uintptr *sp; uc = context; r = &uc->uc_mcontext; if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; // Only push sigpanic if r->mc_rip != 0. // If r->mc_rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to sigpanic instead. // (Otherwise the trace will end at sigpanic and we // won't get to see who faulted.) if(r->mc_rip != 0) { sp = (uintptr*)r->mc_rsp; *--sp = r->mc_rip; r->mc_rsp = (uintptr)sp; } r->mc_rip = (uintptr)sigpanic; return; } if(sigtab[sig].flags & SigQueue) { if(sigsend(sig) || (sigtab[sig].flags & SigIgnore)) return; exit(2); // SIGINT, SIGTERM, etc } if(panicking) // traceback already printed exit(2); panicking = 1; if(sig < 0 || sig >= NSIG) printf("Signal %d\n", sig); else printf("%s\n", sigtab[sig].name); printf("PC=%X\n", r->mc_rip); printf("\n"); if(gotraceback()){ traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, (void*)r->mc_r15); tracebackothers((void*)r->mc_r15); dumpregs(r); } breakpoint(); exit(2); }