/* Reincarnation Server. This servers starts new system services and detects * they are exiting. In case of errors, system services can be restarted. * The RS server periodically checks the status of all registered services * services to see whether they are still alive. The system services are * expected to periodically send a heartbeat message. * * Created: * Jul 22, 2005 by Jorrit N. Herder */ #include "inc.h" #include #include #include #include "../../kernel/const.h" #include "../../kernel/type.h" /* Declare some local functions. */ FORWARD _PROTOTYPE(void init_server, (void) ); FORWARD _PROTOTYPE(void sig_handler, (void) ); FORWARD _PROTOTYPE(void get_work, (message *m) ); FORWARD _PROTOTYPE(void reply, (int whom, message *m_out) ); /* Data buffers to retrieve info during initialization. */ PRIVATE struct boot_image image[NR_BOOT_PROCS]; PUBLIC struct dmap dmap[NR_DEVICES]; long rs_verbose = 0; /*===========================================================================* * main * *===========================================================================*/ PUBLIC int main(void) { /* This is the main routine of this service. The main loop consists of * three major activities: getting new work, processing the work, and * sending the reply. The loop never terminates, unless a panic occurs. */ message m; /* request message */ int call_nr, who_e,who_p; /* call number and caller */ int result; /* result to return */ sigset_t sigset; /* system signal set */ int s; uid_t euid; /* Initialize the server, then go to work. */ init_server(); /* Main loop - get work and do it, forever. */ while (TRUE) { /* Wait for request message. */ get_work(&m); who_e = m.m_source; who_p = _ENDPOINT_P(who_e); if(who_p < -NR_TASKS || who_p >= NR_PROCS) panic("RS","message from bogus source", who_e); call_nr = m.m_type; /* Now determine what to do. Three types of requests are expected: * - Heartbeat messages (notifications from registered system services) * - System notifications (POSIX signals or synchronous alarm) * - User requests (control messages to manage system services) */ /* Notification messages are control messages and do not need a reply. * These include heartbeat messages and system notifications. */ if (m.m_type & NOTIFY_MESSAGE) { switch (call_nr) { case SYN_ALARM: do_period(&m); /* check drivers status */ continue; case PROC_EVENT: sig_handler(); continue; default: /* heartbeat notification */ if (rproc_ptr[who_p] != NULL) /* mark heartbeat time */ rproc_ptr[who_p]->r_alive_tm = m.NOTIFY_TIMESTAMP; } } /* If this is not a notification message, it is a normal request. * Handle the request and send a reply to the caller. */ else { /* Only root can make calls to rs */ euid= getpeuid(m.m_source); if (euid != 0) { printf("RS: got unauthorized request from endpoint %d\n", m.m_source); m.m_type = EPERM; reply(who_e, &m); continue; } switch(call_nr) { case RS_UP: result = do_up(&m, FALSE, 0); break; case RS_UP_COPY: result = do_up(&m, TRUE, 0); break; case RS_START: result = do_start(&m); break; case RS_DOWN: result = do_down(&m); break; case RS_REFRESH: result = do_refresh(&m); break; case RS_RESTART: result = do_restart(&m); break; case RS_SHUTDOWN: result = do_shutdown(&m); break; case GETSYSINFO: result = do_getsysinfo(&m); break; default: printf("Warning, RS got unexpected request %d from %d\n", m.m_type, m.m_source); result = EINVAL; } /* Finally send reply message, unless disabled. */ if (result != EDONTREPLY) { m.m_type = result; reply(who_e, &m); } } } } /*===========================================================================* * init_server * *===========================================================================*/ PRIVATE void init_server(void) { /* Initialize the reincarnation server. */ struct sigaction sa; struct boot_image *ip; int s,t; /* Install signal handlers. Ask PM to transform signal into message. */ sa.sa_handler = SIG_MESS; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno); if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno); /* Initialize the system process table. Use the boot image from the kernel * and the device map from the FS to gather all needed information. */ if ((s = sys_getimage(image)) != OK) panic("RS","warning: couldn't get copy of image table", s); if ((s = getsysinfo(FS_PROC_NR, SI_DMAP_TAB, dmap)) < 0) panic("RS","warning: couldn't get copy of dmap table", errno); #if 0 /* Now initialize the table with the processes in the system image. * Prepend /sbin/ to the binaries so that we can actually find them. */ for (s=0; s< NR_BOOT_PROCS; s++) { ip = &image[s]; if (ip->proc_nr >= 0) { rproc[s].r_flags = RS_IN_USE; rproc[s].r_proc_nr_e = ip->endpoint; rproc[s].r_pid = getnpid(ip->proc_nr); for(t=0; t< NR_DEVICES; t++) if (dmap[t].dmap_driver == ip->proc_nr) rproc[s].r_dev_nr = t; strcpy(rproc[s].r_cmd, "/sbin/"); strcpy(rproc[s].r_cmd+6, ip->proc_name); rproc[s].r_argc = 1; rproc[s].r_argv[0] = rproc[s].r_cmd; rproc[s].r_argv[1] = NULL; } } #endif /* Set alarm to periodically check driver status. */ if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) panic("RS", "couldn't set alarm", s); /* See if we run in verbose mode. */ env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1); /* Initialize the exec pipe. */ if (pipe(exec_pipe) == -1) panic("RS", "pipe failed", errno); if (fcntl(exec_pipe[0], F_SETFD, fcntl(exec_pipe[0], F_GETFD) | FD_CLOEXEC) == -1) { panic("RS", "fcntl set FD_CLOEXEC on pipe input failed", errno); } if (fcntl(exec_pipe[1], F_SETFD, fcntl(exec_pipe[1], F_GETFD) | FD_CLOEXEC) == -1) { panic("RS", "fcntl set FD_CLOEXEC on pipe output failed", errno); } if (fcntl(exec_pipe[0], F_SETFL, fcntl(exec_pipe[0], F_GETFL) | O_NONBLOCK) == -1) { panic("RS", "fcntl set O_NONBLOCK on pipe input failed", errno); } } /*===========================================================================* * sig_handler * *===========================================================================*/ PRIVATE void sig_handler() { sigset_t sigset; int sig; /* Try to obtain signal set from PM. */ if (getsigset(&sigset) != 0) return; /* Check for known signals. */ if (sigismember(&sigset, SIGCHLD)) do_exit(NULL); if (sigismember(&sigset, SIGTERM)) do_shutdown(NULL); } /*===========================================================================* * get_work * *===========================================================================*/ PRIVATE void get_work(m_in) message *m_in; /* pointer to message */ { int s; /* receive status */ if (OK != (s=receive(ANY, m_in))) /* wait for message */ panic("RS","receive failed", s); } /*===========================================================================* * reply * *===========================================================================*/ PRIVATE void reply(who, m_out) int who; /* replyee */ message *m_out; /* reply message */ { /*message m_out;*/ /* reply message */ int s; /* send status */ /*m_out.m_type = result;*/ /* build reply message */ if (OK != (s=send(who, m_out))) /* send the message */ panic("RS", "unable to send reply", s); }