00001
00002
00003
00004
00005
00006 #include "inc.h"
00007 #include <unistd.h>
00008 #include <sys/types.h>
00009 #include <sys/wait.h>
00010 #include <minix/dmap.h>
00011 #include <minix/endpoint.h>
00012
00013
00014 struct rproc rproc[NR_SYS_PROCS];
00015 struct rproc *rproc_ptr[NR_PROCS];
00016 int nr_in_use;
00017 extern int errno;
00018
00019
00020 FORWARD _PROTOTYPE( int start_service, (struct rproc *rp) );
00021 FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
00022
00023 PRIVATE int shutting_down = FALSE;
00024
00025 #define EXEC_FAILED 49
00026
00027
00028
00029
00030 PUBLIC int do_up(m_ptr)
00031 message *m_ptr;
00032 {
00033
00034
00035
00036
00037 register struct rproc *rp;
00038 int slot_nr;
00039 int arg_count;
00040 char *cmd_ptr;
00041 enum dev_style dev_style;
00042 int s;
00043
00044
00045 if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN);
00046 for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
00047 rp = &rproc[slot_nr];
00048 if (! rp->r_flags & RS_IN_USE)
00049 break;
00050 }
00051 nr_in_use ++;
00052
00053
00054
00055
00056 if (m_ptr->RS_CMD_LEN > MAX_COMMAND_LEN) return(E2BIG);
00057 if (OK!=(s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
00058 SELF, (vir_bytes) rp->r_cmd, m_ptr->RS_CMD_LEN))) return(s);
00059 rp->r_cmd[m_ptr->RS_CMD_LEN] = '\0';
00060 if (rp->r_cmd[0] != '/') return(EINVAL);
00061
00062
00063
00064
00065 arg_count = 0;
00066 rp->r_argv[arg_count++] = rp->r_cmd;
00067 cmd_ptr = rp->r_cmd;
00068 while(*cmd_ptr != '\0') {
00069 if (*cmd_ptr == ' ') {
00070 *cmd_ptr = '\0';
00071 while (*++cmd_ptr == ' ') ;
00072 if (*cmd_ptr == '\0') break;
00073 if (arg_count>MAX_NR_ARGS+1) break;
00074 rp->r_argv[arg_count++] = cmd_ptr;
00075 }
00076 cmd_ptr ++;
00077 }
00078 rp->r_argv[arg_count] = NULL;
00079 rp->r_argc = arg_count;
00080
00081
00082 rp->r_period = m_ptr->RS_PERIOD;
00083 rp->r_dev_nr = m_ptr->RS_DEV_MAJOR;
00084 rp->r_dev_style = STYLE_DEV;
00085 rp->r_restarts = -1;
00086
00087
00088 return(start_service(rp));
00089 }
00090
00091
00092
00093
00094
00095 PUBLIC int do_down(message *m_ptr)
00096 {
00097 register struct rproc *rp;
00098 pid_t pid = (pid_t) m_ptr->RS_PID;
00099
00100 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
00101 if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
00102 #if VERBOSE
00103 printf("stopping %d (%d)\n", pid, m_ptr->RS_PID);
00104 #endif
00105 stop_service(rp,RS_EXITING);
00106 return(OK);
00107 }
00108 }
00109 #if VERBOSE
00110 printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
00111 #endif
00112 return(ESRCH);
00113 }
00114
00115
00116
00117
00118
00119 PUBLIC int do_refresh(message *m_ptr)
00120 {
00121 register struct rproc *rp;
00122 pid_t pid = (pid_t) m_ptr->RS_PID;
00123
00124 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
00125 if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
00126 #if VERBOSE
00127 printf("refreshing %d (%d)\n", pid, m_ptr->RS_PID);
00128 #endif
00129 stop_service(rp,RS_REFRESHING);
00130 return(OK);
00131 }
00132 }
00133 #if VERBOSE
00134 printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
00135 #endif
00136 return(ESRCH);
00137 }
00138
00139
00140
00141
00142 PUBLIC int do_rescue(message *m_ptr)
00143 {
00144 char rescue_dir[MAX_RESCUE_DIR_LEN];
00145 int s;
00146
00147
00148 if (m_ptr->RS_CMD_LEN > MAX_RESCUE_DIR_LEN) return(E2BIG);
00149 if (OK!=(s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
00150 SELF, (vir_bytes) rescue_dir, m_ptr->RS_CMD_LEN))) return(s);
00151 rescue_dir[m_ptr->RS_CMD_LEN] = '\0';
00152 if (rescue_dir[0] != '/') return(EINVAL);
00153
00154
00155
00156
00157
00158
00159
00160 if (chdir(rescue_dir) != 0) return(errno);
00161 return(OK);
00162 }
00163
00164
00165
00166
00167 PUBLIC int do_shutdown(message *m_ptr)
00168 {
00169
00170 shutting_down = TRUE;
00171 return(OK);
00172 }
00173
00174
00175
00176
00177 PUBLIC void do_exit(message *m_ptr)
00178 {
00179 register struct rproc *rp;
00180 pid_t exit_pid;
00181 int exit_status;
00182
00183 #if VERBOSE
00184 printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
00185 #endif
00186
00187
00188
00189
00190
00191
00192 while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) {
00193
00194 #if VERBOSE
00195 printf("RS: proc %d, pid %d, ", rp->r_proc_nr_e, exit_pid);
00196 if (WIFSIGNALED(exit_status)) {
00197 printf("killed, signal number %d\n", WTERMSIG(exit_status));
00198 }
00199 else if (WIFEXITED(exit_status)) {
00200 printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
00201 }
00202 #endif
00203
00204
00205
00206
00207 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
00208 if ((rp->r_flags & RS_IN_USE) && rp->r_pid == exit_pid) {
00209 int proc;
00210 proc = _ENDPOINT_P(rp->r_proc_nr_e);
00211
00212 rproc_ptr[proc] = NULL;
00213
00214 if ((rp->r_flags & RS_EXITING) || shutting_down) {
00215 rp->r_flags = 0;
00216 rproc_ptr[proc] = NULL;
00217 }
00218 else if(rp->r_flags & RS_REFRESHING) {
00219 rp->r_restarts = -1;
00220 start_service(rp);
00221 }
00222 else if (WIFEXITED(exit_status) &&
00223 WEXITSTATUS(exit_status) == EXEC_FAILED) {
00224 rp->r_flags = 0;
00225 }
00226 else {
00227 #if VERBOSE
00228 printf("Unexpected exit. Restarting %s\n", rp->r_cmd);
00229 #endif
00230
00231
00232
00233
00234 if (rp->r_restarts > 0) {
00235 rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-1));
00236 rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
00237 }
00238 else {
00239 start_service(rp);
00240 }
00241 }
00242 break;
00243 }
00244 }
00245 }
00246 }
00247
00248
00249
00250
00251 PUBLIC void do_period(m_ptr)
00252 message *m_ptr;
00253 {
00254 register struct rproc *rp;
00255 clock_t now = m_ptr->NOTIFY_TIMESTAMP;
00256 int s;
00257
00258
00259 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
00260 if (rp->r_flags & RS_IN_USE) {
00261
00262
00263
00264
00265
00266 if (rp->r_backoff > 0) {
00267 rp->r_backoff -= 1;
00268 if (rp->r_backoff == 0) {
00269 start_service(rp);
00270 }
00271 }
00272
00273
00274
00275
00276 else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
00277 && rp->r_pid > 0) {
00278 kill(rp->r_pid, SIGKILL);
00279 }
00280
00281
00282
00283
00284 else if (rp->r_period > 0) {
00285
00286
00287
00288
00289
00290
00291 if (rp->r_alive_tm < rp->r_check_tm) {
00292 if (now - rp->r_alive_tm > 2*rp->r_period &&
00293 rp->r_pid > 0) {
00294 #if VERBOSE
00295 printf("RS: service %d reported late\n", rp->r_proc_nr_e);
00296 #endif
00297 kill(rp->r_pid, SIGKILL);
00298 }
00299 }
00300
00301
00302
00303
00304 else if (now - rp->r_check_tm > rp->r_period) {
00305 #if VERBOSE
00306 printf("RS: status request sent to %d\n", rp->r_proc_nr_e);
00307 #endif
00308 notify(rp->r_proc_nr_e);
00309 rp->r_check_tm = now;
00310 }
00311 }
00312 }
00313 }
00314
00315
00316 if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
00317 panic("RS", "couldn't set alarm", s);
00318 }
00319
00320
00321
00322
00323
00324 PRIVATE int start_service(rp)
00325 struct rproc *rp;
00326 {
00327
00328
00329
00330
00331 int child_proc_nr_e, child_proc_nr_n;
00332 pid_t child_pid;
00333 char *file_only;
00334 int s;
00335 message m;
00336
00337
00338 child_pid = fork();
00339 switch(child_pid) {
00340 case -1:
00341 report("RS", "warning, fork() failed", errno);
00342 return(errno);
00343
00344 case 0:
00345
00346
00347
00348
00349 execve(rp->r_argv[0], rp->r_argv, NULL);
00350 file_only = strrchr(rp->r_argv[0], '/') + 1;
00351 execve(file_only, rp->r_argv, NULL);
00352 printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
00353 exit(EXEC_FAILED);
00354
00355 default:
00356 child_proc_nr_e = getnprocnr(child_pid);
00357 break;
00358 }
00359
00360
00361
00362
00363
00364 if (rp->r_dev_nr > 0) {
00365 if ((s=mapdriver(child_proc_nr_e, rp->r_dev_nr, rp->r_dev_style)) < 0) {
00366 report("RS", "couldn't map driver", errno);
00367 rp->r_flags |= RS_EXITING;
00368 if(child_pid > 0) kill(child_pid, SIGKILL);
00369 else report("RS", "didn't kill pid", child_pid);
00370 return(s);
00371 }
00372 }
00373
00374
00375
00376
00377
00378 if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_INIT, 0, NULL)) < 0) {
00379 report("RS","call to SYSTEM failed", s);
00380 rp->r_flags |= RS_EXITING;
00381 if(child_pid > 0) kill(child_pid, SIGKILL);
00382 else report("RS", "didn't kill pid", child_pid);
00383 return(s);
00384 }
00385
00386 #if VERBOSE
00387 printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n",
00388 rp->r_cmd, rp->r_dev_nr, child_pid,
00389 child_proc_nr_e, child_proc_nr_n);
00390 #endif
00391
00392
00393
00394
00395
00396
00397 child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
00398 rp->r_flags = RS_IN_USE;
00399 rp->r_restarts += 1;
00400 rp->r_proc_nr_e = child_proc_nr_e;
00401 rp->r_pid = child_pid;
00402 rp->r_check_tm = 0;
00403 getuptime(&rp->r_alive_tm);
00404 rp->r_stop_tm = 0;
00405 rproc_ptr[child_proc_nr_n] = rp;
00406 return(OK);
00407 }
00408
00409
00410
00411
00412 PRIVATE int stop_service(rp,how)
00413 struct rproc *rp;
00414 int how;
00415 {
00416
00417
00418
00419
00420
00421 #if VERBOSE
00422 printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid);
00423 #endif
00424
00425 rp->r_flags |= how;
00426 if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM);
00427 else report("RS", "didn't kill pid", rp->r_pid);
00428 getuptime(&rp->r_stop_tm);
00429 }
00430
00431
00432
00433
00434
00435 PUBLIC int do_getsysinfo(m_ptr)
00436 message *m_ptr;
00437 {
00438 vir_bytes src_addr, dst_addr;
00439 int dst_proc;
00440 size_t len;
00441 int s;
00442
00443 switch(m_ptr->m1_i1) {
00444 case SI_PROC_TAB:
00445 src_addr = (vir_bytes) rproc;
00446 len = sizeof(struct rproc) * NR_SYS_PROCS;
00447 break;
00448 default:
00449 return(EINVAL);
00450 }
00451
00452 dst_proc = m_ptr->m_source;
00453 dst_addr = (vir_bytes) m_ptr->m1_p1;
00454 if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
00455 return(s);
00456 return(OK);
00457 }
00458