[9] | 1 | /*
|
---|
| 2 | * Changes:
|
---|
| 3 | * Jul 22, 2005: Created (Jorrit N. Herder)
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | #include "inc.h"
|
---|
| 7 | #include <unistd.h>
|
---|
| 8 | #include <sys/types.h>
|
---|
| 9 | #include <sys/wait.h>
|
---|
| 10 | #include <minix/dmap.h>
|
---|
| 11 | #include <minix/endpoint.h>
|
---|
| 12 |
|
---|
| 13 | /* Allocate variables. */
|
---|
| 14 | struct rproc rproc[NR_SYS_PROCS]; /* system process table */
|
---|
| 15 | struct rproc *rproc_ptr[NR_PROCS]; /* mapping for fast access */
|
---|
| 16 | int nr_in_use; /* number of services */
|
---|
| 17 | extern int errno; /* error status */
|
---|
| 18 |
|
---|
| 19 | /* Prototypes for internal functions that do the hard work. */
|
---|
| 20 | FORWARD _PROTOTYPE( int start_service, (struct rproc *rp) );
|
---|
| 21 | FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
|
---|
| 22 |
|
---|
| 23 | PRIVATE int shutting_down = FALSE;
|
---|
| 24 |
|
---|
| 25 | #define EXEC_FAILED 49 /* recognizable status */
|
---|
| 26 |
|
---|
| 27 | /*===========================================================================*
|
---|
| 28 | * do_up *
|
---|
| 29 | *===========================================================================*/
|
---|
| 30 | PUBLIC int do_up(m_ptr)
|
---|
| 31 | message *m_ptr; /* request message pointer */
|
---|
| 32 | {
|
---|
| 33 | /* A request was made to start a new system service. Dismember the request
|
---|
| 34 | * message and gather all information needed to start the service. Starting
|
---|
| 35 | * is done by a helper routine.
|
---|
| 36 | */
|
---|
| 37 | register struct rproc *rp; /* system process table */
|
---|
| 38 | int slot_nr; /* local table entry */
|
---|
| 39 | int arg_count; /* number of arguments */
|
---|
| 40 | char *cmd_ptr; /* parse command string */
|
---|
| 41 | enum dev_style dev_style; /* device style */
|
---|
| 42 | int s; /* status variable */
|
---|
| 43 |
|
---|
| 44 | /* See if there is a free entry in the table with system processes. */
|
---|
| 45 | if (nr_in_use >= NR_SYS_PROCS) return(EAGAIN);
|
---|
| 46 | for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
|
---|
| 47 | rp = &rproc[slot_nr]; /* get pointer to slot */
|
---|
| 48 | if (! rp->r_flags & RS_IN_USE) /* check if available */
|
---|
| 49 | break;
|
---|
| 50 | }
|
---|
| 51 | nr_in_use ++; /* update administration */
|
---|
| 52 |
|
---|
| 53 | /* Obtain command name and parameters. This is a space-separated string
|
---|
| 54 | * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
|
---|
| 55 | */
|
---|
| 56 | if (m_ptr->RS_CMD_LEN > MAX_COMMAND_LEN) return(E2BIG);
|
---|
| 57 | if (OK!=(s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
---|
| 58 | SELF, (vir_bytes) rp->r_cmd, m_ptr->RS_CMD_LEN))) return(s);
|
---|
| 59 | rp->r_cmd[m_ptr->RS_CMD_LEN] = '\0'; /* ensure it is terminated */
|
---|
| 60 | if (rp->r_cmd[0] != '/') return(EINVAL); /* insist on absolute path */
|
---|
| 61 |
|
---|
| 62 | /* Build argument vector to be passed to execute call. The format of the
|
---|
| 63 | * arguments vector is: path, arguments, NULL.
|
---|
| 64 | */
|
---|
| 65 | arg_count = 0; /* initialize arg count */
|
---|
| 66 | rp->r_argv[arg_count++] = rp->r_cmd; /* start with path */
|
---|
| 67 | cmd_ptr = rp->r_cmd; /* do some parsing */
|
---|
| 68 | while(*cmd_ptr != '\0') { /* stop at end of string */
|
---|
| 69 | if (*cmd_ptr == ' ') { /* next argument */
|
---|
| 70 | *cmd_ptr = '\0'; /* terminate previous */
|
---|
| 71 | while (*++cmd_ptr == ' ') ; /* skip spaces */
|
---|
| 72 | if (*cmd_ptr == '\0') break; /* no arg following */
|
---|
| 73 | if (arg_count>MAX_NR_ARGS+1) break; /* arg vector full */
|
---|
| 74 | rp->r_argv[arg_count++] = cmd_ptr; /* add to arg vector */
|
---|
| 75 | }
|
---|
| 76 | cmd_ptr ++; /* continue parsing */
|
---|
| 77 | }
|
---|
| 78 | rp->r_argv[arg_count] = NULL; /* end with NULL pointer */
|
---|
| 79 | rp->r_argc = arg_count;
|
---|
| 80 |
|
---|
| 81 | /* Initialize some fields. */
|
---|
| 82 | rp->r_period = m_ptr->RS_PERIOD;
|
---|
| 83 | rp->r_dev_nr = m_ptr->RS_DEV_MAJOR;
|
---|
| 84 | rp->r_dev_style = STYLE_DEV;
|
---|
| 85 | rp->r_restarts = -1; /* will be incremented */
|
---|
| 86 |
|
---|
| 87 | /* All information was gathered. Now try to start the system service. */
|
---|
| 88 | return(start_service(rp));
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 |
|
---|
| 92 | /*===========================================================================*
|
---|
| 93 | * do_down *
|
---|
| 94 | *===========================================================================*/
|
---|
| 95 | PUBLIC int do_down(message *m_ptr)
|
---|
| 96 | {
|
---|
| 97 | register struct rproc *rp;
|
---|
| 98 | pid_t pid = (pid_t) m_ptr->RS_PID;
|
---|
| 99 |
|
---|
| 100 | for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
---|
| 101 | if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
|
---|
| 102 | #if VERBOSE
|
---|
| 103 | printf("stopping %d (%d)\n", pid, m_ptr->RS_PID);
|
---|
| 104 | #endif
|
---|
| 105 | stop_service(rp,RS_EXITING);
|
---|
| 106 | return(OK);
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 | #if VERBOSE
|
---|
| 110 | printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
|
---|
| 111 | #endif
|
---|
| 112 | return(ESRCH);
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 |
|
---|
| 116 | /*===========================================================================*
|
---|
| 117 | * do_refresh *
|
---|
| 118 | *===========================================================================*/
|
---|
| 119 | PUBLIC int do_refresh(message *m_ptr)
|
---|
| 120 | {
|
---|
| 121 | register struct rproc *rp;
|
---|
| 122 | pid_t pid = (pid_t) m_ptr->RS_PID;
|
---|
| 123 |
|
---|
| 124 | for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
---|
| 125 | if (rp->r_flags & RS_IN_USE && rp->r_pid == pid) {
|
---|
| 126 | #if VERBOSE
|
---|
| 127 | printf("refreshing %d (%d)\n", pid, m_ptr->RS_PID);
|
---|
| 128 | #endif
|
---|
| 129 | stop_service(rp,RS_REFRESHING);
|
---|
| 130 | return(OK);
|
---|
| 131 | }
|
---|
| 132 | }
|
---|
| 133 | #if VERBOSE
|
---|
| 134 | printf("not found %d (%d)\n", pid, m_ptr->RS_PID);
|
---|
| 135 | #endif
|
---|
| 136 | return(ESRCH);
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | /*===========================================================================*
|
---|
| 140 | * do_rescue *
|
---|
| 141 | *===========================================================================*/
|
---|
| 142 | PUBLIC int do_rescue(message *m_ptr)
|
---|
| 143 | {
|
---|
| 144 | char rescue_dir[MAX_RESCUE_DIR_LEN];
|
---|
| 145 | int s;
|
---|
| 146 |
|
---|
| 147 | /* Copy rescue directory from user. */
|
---|
| 148 | if (m_ptr->RS_CMD_LEN > MAX_RESCUE_DIR_LEN) return(E2BIG);
|
---|
| 149 | if (OK!=(s=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
|
---|
| 150 | SELF, (vir_bytes) rescue_dir, m_ptr->RS_CMD_LEN))) return(s);
|
---|
| 151 | rescue_dir[m_ptr->RS_CMD_LEN] = '\0'; /* ensure it is terminated */
|
---|
| 152 | if (rescue_dir[0] != '/') return(EINVAL); /* insist on absolute path */
|
---|
| 153 |
|
---|
| 154 | /* Change RS' directory to the rescue directory. Provided that the needed
|
---|
| 155 | * binaries are in the rescue dir, this makes recovery possible even if the
|
---|
| 156 | * (root) file system is no longer available, because no directory lookups
|
---|
| 157 | * are required. Thus if an absolute path fails, we can try to strip the
|
---|
| 158 | * path an see if the command is in the rescue dir.
|
---|
| 159 | */
|
---|
| 160 | if (chdir(rescue_dir) != 0) return(errno);
|
---|
| 161 | return(OK);
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | /*===========================================================================*
|
---|
| 165 | * do_shutdown *
|
---|
| 166 | *===========================================================================*/
|
---|
| 167 | PUBLIC int do_shutdown(message *m_ptr)
|
---|
| 168 | {
|
---|
| 169 | /* Set flag so that RS server knows services shouldn't be restarted. */
|
---|
| 170 | shutting_down = TRUE;
|
---|
| 171 | return(OK);
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | /*===========================================================================*
|
---|
| 175 | * do_exit *
|
---|
| 176 | *===========================================================================*/
|
---|
| 177 | PUBLIC void do_exit(message *m_ptr)
|
---|
| 178 | {
|
---|
| 179 | register struct rproc *rp;
|
---|
| 180 | pid_t exit_pid;
|
---|
| 181 | int exit_status;
|
---|
| 182 |
|
---|
| 183 | #if VERBOSE
|
---|
| 184 | printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
|
---|
| 185 | #endif
|
---|
| 186 |
|
---|
| 187 | /* See which child exited and what the exit status is. This is done in a
|
---|
| 188 | * loop because multiple childs may have exited, all reported by one
|
---|
| 189 | * SIGCHLD signal. The WNOHANG options is used to prevent blocking if,
|
---|
| 190 | * somehow, no exited child can be found.
|
---|
| 191 | */
|
---|
| 192 | while ( (exit_pid = waitpid(-1, &exit_status, WNOHANG)) != 0 ) {
|
---|
| 193 |
|
---|
| 194 | #if VERBOSE
|
---|
| 195 | printf("RS: proc %d, pid %d, ", rp->r_proc_nr_e, exit_pid);
|
---|
| 196 | if (WIFSIGNALED(exit_status)) {
|
---|
| 197 | printf("killed, signal number %d\n", WTERMSIG(exit_status));
|
---|
| 198 | }
|
---|
| 199 | else if (WIFEXITED(exit_status)) {
|
---|
| 200 | printf("normal exit, status %d\n", WEXITSTATUS(exit_status));
|
---|
| 201 | }
|
---|
| 202 | #endif
|
---|
| 203 |
|
---|
| 204 | /* Search the system process table to see who exited.
|
---|
| 205 | * This should always succeed.
|
---|
| 206 | */
|
---|
| 207 | for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
---|
| 208 | if ((rp->r_flags & RS_IN_USE) && rp->r_pid == exit_pid) {
|
---|
| 209 | int proc;
|
---|
| 210 | proc = _ENDPOINT_P(rp->r_proc_nr_e);
|
---|
| 211 |
|
---|
| 212 | rproc_ptr[proc] = NULL; /* invalidate */
|
---|
| 213 |
|
---|
| 214 | if ((rp->r_flags & RS_EXITING) || shutting_down) {
|
---|
| 215 | rp->r_flags = 0; /* release slot */
|
---|
| 216 | rproc_ptr[proc] = NULL;
|
---|
| 217 | }
|
---|
| 218 | else if(rp->r_flags & RS_REFRESHING) {
|
---|
| 219 | rp->r_restarts = -1; /* reset counter */
|
---|
| 220 | start_service(rp); /* direct restart */
|
---|
| 221 | }
|
---|
| 222 | else if (WIFEXITED(exit_status) &&
|
---|
| 223 | WEXITSTATUS(exit_status) == EXEC_FAILED) {
|
---|
| 224 | rp->r_flags = 0; /* release slot */
|
---|
| 225 | }
|
---|
| 226 | else {
|
---|
| 227 | #if VERBOSE
|
---|
| 228 | printf("Unexpected exit. Restarting %s\n", rp->r_cmd);
|
---|
| 229 | #endif
|
---|
| 230 | /* Determine what to do. If this is the first unexpected
|
---|
| 231 | * exit, immediately restart this service. Otherwise use
|
---|
| 232 | * a binary exponetial backoff.
|
---|
| 233 | */
|
---|
| 234 | if (rp->r_restarts > 0) {
|
---|
| 235 | rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-1));
|
---|
| 236 | rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
|
---|
| 237 | }
|
---|
| 238 | else {
|
---|
| 239 | start_service(rp); /* direct restart */
|
---|
| 240 | }
|
---|
| 241 | }
|
---|
| 242 | break;
|
---|
| 243 | }
|
---|
| 244 | }
|
---|
| 245 | }
|
---|
| 246 | }
|
---|
| 247 |
|
---|
| 248 | /*===========================================================================*
|
---|
| 249 | * do_period *
|
---|
| 250 | *===========================================================================*/
|
---|
| 251 | PUBLIC void do_period(m_ptr)
|
---|
| 252 | message *m_ptr;
|
---|
| 253 | {
|
---|
| 254 | register struct rproc *rp;
|
---|
| 255 | clock_t now = m_ptr->NOTIFY_TIMESTAMP;
|
---|
| 256 | int s;
|
---|
| 257 |
|
---|
| 258 | /* Search system services table. Only check slots that are in use. */
|
---|
| 259 | for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
|
---|
| 260 | if (rp->r_flags & RS_IN_USE) {
|
---|
| 261 |
|
---|
| 262 | /* If the service is to be revived (because it repeatedly exited,
|
---|
| 263 | * and was not directly restarted), the binary backoff field is
|
---|
| 264 | * greater than zero.
|
---|
| 265 | */
|
---|
| 266 | if (rp->r_backoff > 0) {
|
---|
| 267 | rp->r_backoff -= 1;
|
---|
| 268 | if (rp->r_backoff == 0) {
|
---|
| 269 | start_service(rp);
|
---|
| 270 | }
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | /* If the service was signaled with a SIGTERM and fails to respond,
|
---|
| 274 | * kill the system service with a SIGKILL signal.
|
---|
| 275 | */
|
---|
| 276 | else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
|
---|
| 277 | && rp->r_pid > 0) {
|
---|
| 278 | kill(rp->r_pid, SIGKILL); /* terminate */
|
---|
| 279 | }
|
---|
| 280 |
|
---|
| 281 | /* There seems to be no special conditions. If the service has a
|
---|
| 282 | * period assigned check its status.
|
---|
| 283 | */
|
---|
| 284 | else if (rp->r_period > 0) {
|
---|
| 285 |
|
---|
| 286 | /* Check if an answer to a status request is still pending. If
|
---|
| 287 | * the driver didn't respond within time, kill it to simulate
|
---|
| 288 | * a crash. The failure will be detected and the service will
|
---|
| 289 | * be restarted automatically.
|
---|
| 290 | */
|
---|
| 291 | if (rp->r_alive_tm < rp->r_check_tm) {
|
---|
| 292 | if (now - rp->r_alive_tm > 2*rp->r_period &&
|
---|
| 293 | rp->r_pid > 0) {
|
---|
| 294 | #if VERBOSE
|
---|
| 295 | printf("RS: service %d reported late\n", rp->r_proc_nr_e);
|
---|
| 296 | #endif
|
---|
| 297 | kill(rp->r_pid, SIGKILL); /* simulate crash */
|
---|
| 298 | }
|
---|
| 299 | }
|
---|
| 300 |
|
---|
| 301 | /* No answer pending. Check if a period expired since the last
|
---|
| 302 | * check and, if so request the system service's status.
|
---|
| 303 | */
|
---|
| 304 | else if (now - rp->r_check_tm > rp->r_period) {
|
---|
| 305 | #if VERBOSE
|
---|
| 306 | printf("RS: status request sent to %d\n", rp->r_proc_nr_e);
|
---|
| 307 | #endif
|
---|
| 308 | notify(rp->r_proc_nr_e); /* request status */
|
---|
| 309 | rp->r_check_tm = now; /* mark time */
|
---|
| 310 | }
|
---|
| 311 | }
|
---|
| 312 | }
|
---|
| 313 | }
|
---|
| 314 |
|
---|
| 315 | /* Reschedule a synchronous alarm for the next period. */
|
---|
| 316 | if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
|
---|
| 317 | panic("RS", "couldn't set alarm", s);
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 |
|
---|
| 321 | /*===========================================================================*
|
---|
| 322 | * start_service *
|
---|
| 323 | *===========================================================================*/
|
---|
| 324 | PRIVATE int start_service(rp)
|
---|
| 325 | struct rproc *rp;
|
---|
| 326 | {
|
---|
| 327 | /* Try to execute the given system service. Fork a new process. The child
|
---|
| 328 | * process will be inhibited from running by the NO_PRIV flag. Only let the
|
---|
| 329 | * child run once its privileges have been set by the parent.
|
---|
| 330 | */
|
---|
| 331 | int child_proc_nr_e, child_proc_nr_n; /* child process slot */
|
---|
| 332 | pid_t child_pid; /* child's process id */
|
---|
| 333 | char *file_only;
|
---|
| 334 | int s;
|
---|
| 335 | message m;
|
---|
| 336 |
|
---|
| 337 | /* Now fork and branch for parent and child process (and check for error). */
|
---|
| 338 | child_pid = fork();
|
---|
| 339 | switch(child_pid) { /* see fork(2) */
|
---|
| 340 | case -1: /* fork failed */
|
---|
| 341 | report("RS", "warning, fork() failed", errno); /* shouldn't happen */
|
---|
| 342 | return(errno); /* return error */
|
---|
| 343 |
|
---|
| 344 | case 0: /* child process */
|
---|
| 345 | /* Try to execute the binary that has an absolute path. If this fails,
|
---|
| 346 | * e.g., because the root file system cannot be read, try to strip of
|
---|
| 347 | * the path, and see if the command is in RS' current working dir.
|
---|
| 348 | */
|
---|
| 349 | execve(rp->r_argv[0], rp->r_argv, NULL); /* POSIX execute */
|
---|
| 350 | file_only = strrchr(rp->r_argv[0], '/') + 1;
|
---|
| 351 | execve(file_only, rp->r_argv, NULL); /* POSIX execute */
|
---|
| 352 | printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
|
---|
| 353 | exit(EXEC_FAILED); /* terminate child */
|
---|
| 354 |
|
---|
| 355 | default: /* parent process */
|
---|
| 356 | child_proc_nr_e = getnprocnr(child_pid); /* get child slot */
|
---|
| 357 | break; /* continue below */
|
---|
| 358 | }
|
---|
| 359 |
|
---|
| 360 | /* Only the parent process (the RS server) gets to this point. The child
|
---|
| 361 | * is still inhibited from running because it's privilege structure is
|
---|
| 362 | * not yet set. First try to set the device driver mapping at the FS.
|
---|
| 363 | */
|
---|
| 364 | if (rp->r_dev_nr > 0) { /* set driver map */
|
---|
| 365 | if ((s=mapdriver(child_proc_nr_e, rp->r_dev_nr, rp->r_dev_style)) < 0) {
|
---|
| 366 | report("RS", "couldn't map driver", errno);
|
---|
| 367 | rp->r_flags |= RS_EXITING; /* expect exit */
|
---|
| 368 | if(child_pid > 0) kill(child_pid, SIGKILL); /* kill driver */
|
---|
| 369 | else report("RS", "didn't kill pid", child_pid);
|
---|
| 370 | return(s); /* return error */
|
---|
| 371 | }
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | /* The device driver mapping has been set, or the service was not a driver.
|
---|
| 375 | * Now, set the privilege structure for the child process to let is run.
|
---|
| 376 | * This should succeed: we tested number in use above.
|
---|
| 377 | */
|
---|
| 378 | if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_INIT, 0, NULL)) < 0) {
|
---|
| 379 | report("RS","call to SYSTEM failed", s); /* to let child run */
|
---|
| 380 | rp->r_flags |= RS_EXITING; /* expect exit */
|
---|
| 381 | if(child_pid > 0) kill(child_pid, SIGKILL); /* kill driver */
|
---|
| 382 | else report("RS", "didn't kill pid", child_pid);
|
---|
| 383 | return(s); /* return error */
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 | #if VERBOSE
|
---|
| 387 | printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n",
|
---|
| 388 | rp->r_cmd, rp->r_dev_nr, child_pid,
|
---|
| 389 | child_proc_nr_e, child_proc_nr_n);
|
---|
| 390 | #endif
|
---|
| 391 |
|
---|
| 392 | /* The system service now has been successfully started. Update the rest
|
---|
| 393 | * of the system process table that is maintain by the RS server. The only
|
---|
| 394 | * thing that can go wrong now, is that execution fails at the child. If
|
---|
| 395 | * that's the case, the child will exit.
|
---|
| 396 | */
|
---|
| 397 | child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
|
---|
| 398 | rp->r_flags = RS_IN_USE; /* mark slot in use */
|
---|
| 399 | rp->r_restarts += 1; /* raise nr of restarts */
|
---|
| 400 | rp->r_proc_nr_e = child_proc_nr_e; /* set child details */
|
---|
| 401 | rp->r_pid = child_pid;
|
---|
| 402 | rp->r_check_tm = 0; /* not check yet */
|
---|
| 403 | getuptime(&rp->r_alive_tm); /* currently alive */
|
---|
| 404 | rp->r_stop_tm = 0; /* not exiting yet */
|
---|
| 405 | rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
|
---|
| 406 | return(OK);
|
---|
| 407 | }
|
---|
| 408 |
|
---|
| 409 | /*===========================================================================*
|
---|
| 410 | * stop_service *
|
---|
| 411 | *===========================================================================*/
|
---|
| 412 | PRIVATE int stop_service(rp,how)
|
---|
| 413 | struct rproc *rp;
|
---|
| 414 | int how;
|
---|
| 415 | {
|
---|
| 416 | /* Try to stop the system service. First send a SIGTERM signal to ask the
|
---|
| 417 | * system service to terminate. If the service didn't install a signal
|
---|
| 418 | * handler, it will be killed. If it did and ignores the signal, we'll
|
---|
| 419 | * find out because we record the time here and send a SIGKILL.
|
---|
| 420 | */
|
---|
| 421 | #if VERBOSE
|
---|
| 422 | printf("RS tries to stop %s (pid %d)\n", rp->r_cmd, rp->r_pid);
|
---|
| 423 | #endif
|
---|
| 424 |
|
---|
| 425 | rp->r_flags |= how; /* what to on exit? */
|
---|
| 426 | if(rp->r_pid > 0) kill(rp->r_pid, SIGTERM); /* first try friendly */
|
---|
| 427 | else report("RS", "didn't kill pid", rp->r_pid);
|
---|
| 428 | getuptime(&rp->r_stop_tm); /* record current time */
|
---|
| 429 | }
|
---|
| 430 |
|
---|
| 431 |
|
---|
| 432 | /*===========================================================================*
|
---|
| 433 | * do_getsysinfo *
|
---|
| 434 | *===========================================================================*/
|
---|
| 435 | PUBLIC int do_getsysinfo(m_ptr)
|
---|
| 436 | message *m_ptr;
|
---|
| 437 | {
|
---|
| 438 | vir_bytes src_addr, dst_addr;
|
---|
| 439 | int dst_proc;
|
---|
| 440 | size_t len;
|
---|
| 441 | int s;
|
---|
| 442 |
|
---|
| 443 | switch(m_ptr->m1_i1) {
|
---|
| 444 | case SI_PROC_TAB:
|
---|
| 445 | src_addr = (vir_bytes) rproc;
|
---|
| 446 | len = sizeof(struct rproc) * NR_SYS_PROCS;
|
---|
| 447 | break;
|
---|
| 448 | default:
|
---|
| 449 | return(EINVAL);
|
---|
| 450 | }
|
---|
| 451 |
|
---|
| 452 | dst_proc = m_ptr->m_source;
|
---|
| 453 | dst_addr = (vir_bytes) m_ptr->m1_p1;
|
---|
| 454 | if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
|
---|
| 455 | return(s);
|
---|
| 456 | return(OK);
|
---|
| 457 | }
|
---|
| 458 |
|
---|