3 * Jul 22, 2005: Created (Jorrit N. Herder)
12 #include <minix/dmap.h>
13 #include <minix/endpoint.h>
17 #include <timers.h> /* For priv.h */
18 #include "../../kernel/priv.h"
20 /* Allocate variables. */
21 struct rproc rproc
[NR_SYS_PROCS
]; /* system process table */
22 struct rproc
*rproc_ptr
[NR_PROCS
]; /* mapping for fast access */
24 /* Prototypes for internal functions that do the hard work. */
25 FORWARD
_PROTOTYPE( int start_service
, (struct rproc
*rp
, int flags
,
27 FORWARD
_PROTOTYPE( int stop_service
, (struct rproc
*rp
,int how
) );
28 FORWARD
_PROTOTYPE( int fork_nb
, (void) );
29 FORWARD
_PROTOTYPE( int read_exec
, (struct rproc
*rp
) );
30 FORWARD
_PROTOTYPE( void run_script
, (struct rproc
*rp
) );
31 FORWARD
_PROTOTYPE( void init_privs
, (struct rproc
*rp
, struct priv
*privp
) );
32 FORWARD
_PROTOTYPE( void init_pci
, (struct rproc
*rp
, int endpoint
) );
34 PRIVATE
int shutting_down
= FALSE
;
36 #define EXEC_FAILED 49 /* recognizable status */
38 extern int rs_verbose
;
40 /*===========================================================================*
42 *===========================================================================*/
43 PUBLIC
int do_up(m_ptr
, do_copy
, flags
)
44 message
*m_ptr
; /* request message pointer */
45 int do_copy
; /* keep copy in memory */
46 int flags
; /* extra flags, if any */
48 /* A request was made to start a new system service. Dismember the request
49 * message and gather all information needed to start the service. Starting
50 * is done by a helper routine.
52 register struct rproc
*rp
; /* system process table */
53 int slot_nr
; /* local table entry */
54 int arg_count
; /* number of arguments */
55 char *cmd_ptr
; /* parse command string */
56 char *label
; /* unique name of command */
57 enum dev_style dev_style
; /* device style */
58 int s
; /* status variable */
59 int len
; /* length of string */
61 endpoint_t ep
; /* new endpoint no. */
63 /* See if there is a free entry in the table with system processes. */
64 for (slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
65 rp
= &rproc
[slot_nr
]; /* get pointer to slot */
66 if (! rp
->r_flags
& RS_IN_USE
) /* check if available */
70 /* Obtain command name and parameters. This is a space-separated string
71 * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
73 if (m_ptr
->RS_CMD_LEN
> MAX_COMMAND_LEN
) return(E2BIG
);
74 if (OK
!=(s
=sys_datacopy(m_ptr
->m_source
, (vir_bytes
) m_ptr
->RS_CMD_ADDR
,
75 SELF
, (vir_bytes
) rp
->r_cmd
, m_ptr
->RS_CMD_LEN
))) return(s
);
76 rp
->r_cmd
[m_ptr
->RS_CMD_LEN
] = '\0'; /* ensure it is terminated */
77 if (rp
->r_cmd
[0] != '/') return(EINVAL
); /* insist on absolute path */
79 rp
->r_script
[0]= '\0';
81 /* Build argument vector to be passed to execute call. The format of the
82 * arguments vector is: path, arguments, NULL.
84 arg_count
= 0; /* initialize arg count */
85 rp
->r_argv
[arg_count
++] = rp
->r_cmd
; /* start with path */
86 cmd_ptr
= rp
->r_cmd
; /* do some parsing */
87 while(*cmd_ptr
!= '\0') { /* stop at end of string */
88 if (*cmd_ptr
== ' ') { /* next argument */
89 *cmd_ptr
= '\0'; /* terminate previous */
90 while (*++cmd_ptr
== ' ') ; /* skip spaces */
91 if (*cmd_ptr
== '\0') break; /* no arg following */
92 if (arg_count
>MAX_NR_ARGS
+1) break; /* arg vector full */
93 rp
->r_argv
[arg_count
++] = cmd_ptr
; /* add to arg vector */
95 cmd_ptr
++; /* continue parsing */
97 rp
->r_argv
[arg_count
] = NULL
; /* end with NULL pointer */
98 rp
->r_argc
= arg_count
;
100 /* Default label for the driver */
101 label
= strrchr(rp
->r_argv
[0], '/');
105 label
= rp
->r_argv
[0];
107 if (len
> MAX_LABEL_LEN
-1)
108 len
= MAX_LABEL_LEN
-1; /* truncate name */
109 memcpy(rp
->r_label
, label
, len
);
110 rp
->r_label
[len
]= '\0';
111 if(rs_verbose
) printf("RS: do_up: using label '%s'\n", rp
->r_label
);
124 /* Initialize some fields. */
125 rp
->r_period
= m_ptr
->RS_PERIOD
;
126 rp
->r_dev_nr
= m_ptr
->RS_DEV_MAJOR
;
127 rp
->r_dev_style
= STYLE_DEV
;
128 rp
->r_restarts
= -1; /* will be incremented */
129 rp
->r_set_resources
= 0; /* old style */
131 /* All information was gathered. Now try to start the system service. */
133 r
= start_service(rp
, flags
, &ep
);
134 m_ptr
->RS_ENDPOINT
= ep
;
139 /*===========================================================================*
141 *===========================================================================*/
142 PUBLIC
int do_start(m_ptr
)
143 message
*m_ptr
; /* request message pointer */
145 /* A request was made to start a new system service.
147 register struct rproc
*rp
; /* system process table */
148 int slot_nr
; /* local table entry */
149 int arg_count
; /* number of arguments */
150 char *cmd_ptr
; /* parse command string */
151 char *label
; /* unique name of command */
152 enum dev_style dev_style
; /* device style */
153 int s
; /* status variable */
154 int len
; /* length of string */
158 struct rproc
*tmp_rp
;
159 struct rs_start rs_start
;
161 /* Get the request structure */
162 s
= sys_datacopy(m_ptr
->m_source
, (vir_bytes
) m_ptr
->RS_CMD_ADDR
,
163 SELF
, (vir_bytes
) &rs_start
, sizeof(rs_start
));
164 if (s
!= OK
) return(s
);
166 /* See if there is a free entry in the table with system processes. */
167 for (slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
168 rp
= &rproc
[slot_nr
]; /* get pointer to slot */
169 if (! rp
->r_flags
& RS_IN_USE
) /* check if available */
173 /* Obtain command name and parameters. This is a space-separated string
174 * that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
176 if (rs_start
.rss_cmdlen
> MAX_COMMAND_LEN
-1) return(E2BIG
);
177 s
=sys_datacopy(m_ptr
->m_source
, (vir_bytes
) rs_start
.rss_cmd
,
178 SELF
, (vir_bytes
) rp
->r_cmd
, rs_start
.rss_cmdlen
);
179 if (s
!= OK
) return(s
);
180 rp
->r_cmd
[rs_start
.rss_cmdlen
] = '\0'; /* ensure it is terminated */
181 if (rp
->r_cmd
[0] != '/') return(EINVAL
); /* insist on absolute path */
183 /* Build argument vector to be passed to execute call. The format of the
184 * arguments vector is: path, arguments, NULL.
186 arg_count
= 0; /* initialize arg count */
187 rp
->r_argv
[arg_count
++] = rp
->r_cmd
; /* start with path */
188 cmd_ptr
= rp
->r_cmd
; /* do some parsing */
189 while(*cmd_ptr
!= '\0') { /* stop at end of string */
190 if (*cmd_ptr
== ' ') { /* next argument */
191 *cmd_ptr
= '\0'; /* terminate previous */
192 while (*++cmd_ptr
== ' ') ; /* skip spaces */
193 if (*cmd_ptr
== '\0') break; /* no arg following */
194 if (arg_count
>MAX_NR_ARGS
+1) break; /* arg vector full */
195 rp
->r_argv
[arg_count
++] = cmd_ptr
; /* add to arg vector */
197 cmd_ptr
++; /* continue parsing */
199 rp
->r_argv
[arg_count
] = NULL
; /* end with NULL pointer */
200 rp
->r_argc
= arg_count
;
202 if(rs_start
.rss_label
) {
204 /* RS_START caller has supplied a custom label for this driver. */
205 len
= MIN(sizeof(rp
->r_label
)-1, rs_start
.rss_labellen
);
206 s
=sys_datacopy(m_ptr
->m_source
, (vir_bytes
) rs_start
.rss_label
,
207 SELF
, (vir_bytes
) rp
->r_label
, len
);
210 rp
->r_label
[len
] = '\0';
212 printf("RS: do_start: using label (custom) '%s'\n", rp
->r_label
);
214 /* Default label for the driver. */
215 label
= strrchr(rp
->r_argv
[0], '/');
219 label
= rp
->r_argv
[0];
221 if (len
> MAX_LABEL_LEN
-1)
222 len
= MAX_LABEL_LEN
-1; /* truncate name */
223 memcpy(rp
->r_label
, label
, len
);
224 rp
->r_label
[len
]= '\0';
226 printf("RS: do_start: using label (from binary %s) '%s'\n",
227 rp
->r_argv
[0], rp
->r_label
);
230 /* Check for duplicates */
231 for (slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
232 tmp_rp
= &rproc
[slot_nr
]; /* get pointer to slot */
233 if (!(tmp_rp
->r_flags
& RS_IN_USE
)) /* check if available */
236 continue; /* Our slot */
237 if (strcmp(tmp_rp
->r_label
, rp
->r_label
) == 0)
239 printf("RS: found duplicate label '%s': slot %d\n",
240 rp
->r_label
, slot_nr
);
245 rp
->r_script
[0]= '\0';
246 if (rs_start
.rss_scriptlen
> MAX_SCRIPT_LEN
-1) return(E2BIG
);
247 if (rs_start
.rss_script
!= NULL
)
249 s
=sys_datacopy(m_ptr
->m_source
, (vir_bytes
) rs_start
.rss_script
,
250 SELF
, (vir_bytes
) rp
->r_script
, rs_start
.rss_scriptlen
);
251 if (s
!= OK
) return(s
);
252 rp
->r_script
[rs_start
.rss_scriptlen
] = '\0';
254 rp
->r_uid
= rs_start
.rss_uid
;
255 rp
->r_nice
= rs_start
.rss_nice
;
258 if (rs_start
.rss_flags
& RF_COPY
)
265 /* Copy granted resources */
266 if (rs_start
.rss_nr_irq
> NR_IRQ
)
268 printf("RS: do_start: too many IRQs requested\n");
271 rp
->r_priv
.s_nr_irq
= rs_start
.rss_nr_irq
;
272 for (i
= 0; i
<rp
->r_priv
.s_nr_irq
; i
++)
274 rp
->r_priv
.s_irq_tab
[i
]= rs_start
.rss_irq
[i
];
276 printf("RS: do_start: IRQ %d\n", rp
->r_priv
.s_irq_tab
[i
]);
279 if (rs_start
.rss_nr_io
> NR_IO_RANGE
)
281 printf("RS: do_start: too many I/O ranges requested\n");
284 rp
->r_priv
.s_nr_io_range
= rs_start
.rss_nr_io
;
285 for (i
= 0; i
<rp
->r_priv
.s_nr_io_range
; i
++)
287 rp
->r_priv
.s_io_tab
[i
].ior_base
= rs_start
.rss_io
[i
].base
;
288 rp
->r_priv
.s_io_tab
[i
].ior_limit
=
289 rs_start
.rss_io
[i
].base
+rs_start
.rss_io
[i
].len
-1;
291 printf("RS: do_start: I/O [%x..%x]\n",
292 rp
->r_priv
.s_io_tab
[i
].ior_base
,
293 rp
->r_priv
.s_io_tab
[i
].ior_limit
);
296 if (rs_start
.rss_nr_pci_id
> MAX_NR_PCI_ID
)
298 printf("RS: do_start: too many PCI device IDs\n");
301 rp
->r_nr_pci_id
= rs_start
.rss_nr_pci_id
;
302 for (i
= 0; i
<rp
->r_nr_pci_id
; i
++)
304 rp
->r_pci_id
[i
].vid
= rs_start
.rss_pci_id
[i
].vid
;
305 rp
->r_pci_id
[i
].did
= rs_start
.rss_pci_id
[i
].did
;
307 printf("RS: do_start: PCI %04x/%04x\n",
308 rp
->r_pci_id
[i
].vid
, rp
->r_pci_id
[i
].did
);
310 if (rs_start
.rss_nr_pci_class
> MAX_NR_PCI_CLASS
)
312 printf("RS: do_start: too many PCI class IDs\n");
315 rp
->r_nr_pci_class
= rs_start
.rss_nr_pci_class
;
316 for (i
= 0; i
<rp
->r_nr_pci_class
; i
++)
318 rp
->r_pci_class
[i
].class= rs_start
.rss_pci_class
[i
].class;
319 rp
->r_pci_class
[i
].mask
= rs_start
.rss_pci_class
[i
].mask
;
321 printf("RS: do_start: PCI class %06x mask %06x\n",
322 rp
->r_pci_class
[i
].class, rp
->r_pci_class
[i
].mask
);
325 /* Copy 'system' call number bits */
326 if (sizeof(rs_start
.rss_system
[0]) == sizeof(rp
->r_call_mask
[0]) &&
327 sizeof(rs_start
.rss_system
) == sizeof(rp
->r_call_mask
))
329 for (i
= 0; i
<RSS_NR_SYSTEM
; i
++)
330 rp
->r_call_mask
[i
]= rs_start
.rss_system
[i
];
335 "RS: do_start: internal inconsistency: bad size of r_call_mask\n");
336 memset(rp
->r_call_mask
, '\0', sizeof(rp
->r_call_mask
));
339 /* Initialize some fields. */
340 rp
->r_period
= rs_start
.rss_period
;
341 rp
->r_dev_nr
= rs_start
.rss_major
;
342 rp
->r_dev_style
= STYLE_DEV
;
343 rp
->r_restarts
= -1; /* will be incremented */
344 rp
->r_set_resources
= 1; /* new style, enforece
348 /* All information was gathered. Now try to start the system service. */
349 r
= start_service(rp
, 0, &ep
);
350 m_ptr
->RS_ENDPOINT
= ep
;
355 /*===========================================================================*
357 *===========================================================================*/
358 PUBLIC
int do_down(message
*m_ptr
)
360 register struct rproc
*rp
;
363 char label
[MAX_LABEL_LEN
];
365 len
= m_ptr
->RS_CMD_LEN
;
366 if (len
>= sizeof(label
))
367 return EINVAL
; /* Too long */
369 s
= sys_datacopy(m_ptr
->m_source
, (vir_bytes
) m_ptr
->RS_CMD_ADDR
,
370 SELF
, (vir_bytes
) label
, len
);
371 if (s
!= OK
) return(s
);
374 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
375 if (rp
->r_flags
& RS_IN_USE
&& strcmp(rp
->r_label
, label
) == 0) {
377 printf("RS: stopping '%s' (%d)\n", label
, rp
->r_pid
);
378 stop_service(rp
,RS_EXITING
);
381 /* Process is already gone */
382 rp
->r_flags
= 0; /* release slot */
388 proc
= _ENDPOINT_P(rp
->r_proc_nr_e
);
389 rproc_ptr
[proc
] = NULL
;
393 /* Late reply - send a reply when process dies. */
394 rp
->r_flags
|= RS_LATEREPLY
;
395 rp
->r_caller
= m_ptr
->m_source
;
399 if(rs_verbose
) printf("RS: do_down: '%s' not found\n", label
);
404 /*===========================================================================*
406 *===========================================================================*/
407 PUBLIC
int do_restart(message
*m_ptr
)
409 register struct rproc
*rp
;
412 char label
[MAX_LABEL_LEN
];
415 len
= m_ptr
->RS_CMD_LEN
;
416 if (len
>= sizeof(label
))
417 return EINVAL
; /* Too long */
419 s
= sys_datacopy(m_ptr
->m_source
, (vir_bytes
) m_ptr
->RS_CMD_ADDR
,
420 SELF
, (vir_bytes
) label
, len
);
421 if (s
!= OK
) return(s
);
424 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
425 if (rp
->r_flags
& RS_IN_USE
&& strcmp(rp
->r_label
, label
) == 0) {
426 if(rs_verbose
) printf("RS: restarting '%s' (%d)\n", label
, rp
->r_pid
);
430 printf("RS: do_restart: '%s' is (still) running, pid = %d\n",
434 rp
->r_flags
&= ~(RS_EXITING
|RS_REFRESHING
|RS_NOPINGREPLY
);
435 r
= start_service(rp
, 0, &ep
);
436 m_ptr
->RS_ENDPOINT
= ep
;
441 printf("RS: do_restart: '%s' not found\n", label
);
447 /*===========================================================================*
449 *===========================================================================*/
450 PUBLIC
int do_refresh(message
*m_ptr
)
452 register struct rproc
*rp
;
455 char label
[MAX_LABEL_LEN
];
457 len
= m_ptr
->RS_CMD_LEN
;
458 if (len
>= sizeof(label
))
459 return EINVAL
; /* Too long */
461 s
= sys_datacopy(m_ptr
->m_source
, (vir_bytes
) m_ptr
->RS_CMD_ADDR
,
462 SELF
, (vir_bytes
) label
, len
);
463 if (s
!= OK
) return(s
);
466 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
467 if (rp
->r_flags
& RS_IN_USE
&& strcmp(rp
->r_label
, label
) == 0) {
469 printf("RS: refreshing %s (%d)\n", rp
->r_label
, rp
->r_pid
);
471 stop_service(rp
,RS_REFRESHING
);
476 printf("RS: do_refresh: '%s' not found\n", label
);
481 /*===========================================================================*
483 *===========================================================================*/
484 PUBLIC
int do_shutdown(message
*m_ptr
)
486 /* Set flag so that RS server knows services shouldn't be restarted. */
487 shutting_down
= TRUE
;
491 /*===========================================================================*
493 *===========================================================================*/
494 PUBLIC
void do_exit(message
*m_ptr
)
496 register struct rproc
*rp
;
502 printf("RS: got SIGCHLD signal, doing wait to get exited child.\n");
504 /* See which child exited and what the exit status is. This is done in a
505 * loop because multiple childs may have exited, all reported by one
506 * SIGCHLD signal. The WNOHANG options is used to prevent blocking if,
507 * somehow, no exited child can be found.
509 while ( (exit_pid
= waitpid(-1, &exit_status
, WNOHANG
)) != 0 ) {
512 printf("RS: pid %d, ", exit_pid
);
513 if (WIFSIGNALED(exit_status
)) {
514 printf("killed, signal number %d\n", WTERMSIG(exit_status
));
516 else if (WIFEXITED(exit_status
)) {
517 printf("normal exit, status %d\n", WEXITSTATUS(exit_status
));
521 /* Search the system process table to see who exited.
522 * This should always succeed.
524 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
525 if ((rp
->r_flags
& RS_IN_USE
) && rp
->r_pid
== exit_pid
) {
527 proc
= _ENDPOINT_P(rp
->r_proc_nr_e
);
529 rproc_ptr
[proc
] = NULL
; /* invalidate */
532 if ((rp
->r_flags
& RS_EXITING
) || shutting_down
) {
533 /* No reply sent to RS_DOWN yet. */
534 if(rp
->r_flags
& RS_LATEREPLY
) {
537 send(rp
->r_caller
, &rsm
);
547 rproc_ptr
[proc
] = NULL
;
550 else if(rp
->r_flags
& RS_REFRESHING
) {
551 rp
->r_restarts
= -1; /* reset counter */
552 if (rp
->r_script
[0] != '\0')
555 start_service(rp
, 0, &ep
); /* direct restart */
556 m_ptr
->RS_ENDPOINT
= ep
;
559 else if (WIFEXITED(exit_status
) &&
560 WEXITSTATUS(exit_status
) == EXEC_FAILED
) {
561 rp
->r_flags
= 0; /* release slot */
565 printf("RS: unexpected exit. Restarting %s\n", rp
->r_cmd
);
566 /* Determine what to do. If this is the first unexpected
567 * exit, immediately restart this service. Otherwise use
568 * a binary exponetial backoff.
573 if (WIFSIGNALED(exit_status
)) {
574 switch(WTERMSIG(exit_status
))
576 case SIGKILL
: rp
->r_flags
|= RS_KILLED
; break;
577 default: rp
->r_flags
|= RS_CRASHED
; break;
581 rp
->r_flags
|= RS_CRASHED
;
583 if (rp
->r_script
[0] != '\0')
585 else if (rp
->r_restarts
> 0) {
586 rp
->r_backoff
= 1 << MIN(rp
->r_restarts
,(BACKOFF_BITS
-2));
587 rp
->r_backoff
= MIN(rp
->r_backoff
,MAX_BACKOFF
);
588 if (rp
->r_exec
!= NULL
&& rp
->r_backoff
> 1)
592 start_service(rp
, 0, &ep
); /* direct restart */
593 m_ptr
->RS_ENDPOINT
= ep
;
594 /* Do this even if no I/O happens with the ioctl, in
595 * order to disambiguate requests with DEV_IOCTL_S.
605 /*===========================================================================*
607 *===========================================================================*/
608 PUBLIC
void do_period(m_ptr
)
611 register struct rproc
*rp
;
612 clock_t now
= m_ptr
->NOTIFY_TIMESTAMP
;
616 /* Search system services table. Only check slots that are in use. */
617 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
618 if (rp
->r_flags
& RS_IN_USE
) {
620 /* If the service is to be revived (because it repeatedly exited,
621 * and was not directly restarted), the binary backoff field is
624 if (rp
->r_backoff
> 0) {
626 if (rp
->r_backoff
== 0) {
627 start_service(rp
, 0, &ep
);
628 m_ptr
->RS_ENDPOINT
= ep
;
632 /* If the service was signaled with a SIGTERM and fails to respond,
633 * kill the system service with a SIGKILL signal.
635 else if (rp
->r_stop_tm
> 0 && now
- rp
->r_stop_tm
> 2*RS_DELTA_T
637 kill(rp
->r_pid
, SIGKILL
); /* terminate */
640 /* There seems to be no special conditions. If the service has a
641 * period assigned check its status.
643 else if (rp
->r_period
> 0) {
645 /* Check if an answer to a status request is still pending. If
646 * the driver didn't respond within time, kill it to simulate
647 * a crash. The failure will be detected and the service will
648 * be restarted automatically.
650 if (rp
->r_alive_tm
< rp
->r_check_tm
) {
651 if (now
- rp
->r_alive_tm
> 2*rp
->r_period
&&
652 rp
->r_pid
> 0 && !(rp
->r_flags
& RS_NOPINGREPLY
)) {
654 printf("RS: service %d reported late\n",
656 rp
->r_flags
|= RS_NOPINGREPLY
;
657 kill(rp
->r_pid
, SIGKILL
); /* simulate crash */
661 /* No answer pending. Check if a period expired since the last
662 * check and, if so request the system service's status.
664 else if (now
- rp
->r_check_tm
> rp
->r_period
) {
666 printf("RS: status request sent to %d\n", rp
->r_proc_nr_e
);
667 notify(rp
->r_proc_nr_e
); /* request status */
668 rp
->r_check_tm
= now
; /* mark time */
674 /* Reschedule a synchronous alarm for the next period. */
675 if (OK
!= (s
=sys_setalarm(RS_DELTA_T
, 0)))
676 panic("RS", "couldn't set alarm", s
);
680 /*===========================================================================*
682 *===========================================================================*/
683 PRIVATE
int start_service(rp
, flags
, endpoint
)
686 endpoint_t
*endpoint
;
688 /* Try to execute the given system service. Fork a new process. The child
689 * process will be inhibited from running by the NO_PRIV flag. Only let the
690 * child run once its privileges have been set by the parent.
692 int child_proc_nr_e
, child_proc_nr_n
; /* child process slot */
693 pid_t child_pid
; /* child's process id */
699 use_copy
= (rp
->r_exec
!= NULL
);
701 /* Now fork and branch for parent and child process (and check for error). */
703 child_pid
= fork_nb();
707 switch(child_pid
) { /* see fork(2) */
708 case -1: /* fork failed */
709 report("RS", "warning, fork() failed", errno
); /* shouldn't happen */
710 return(errno
); /* return error */
712 case 0: /* child process */
713 /* Try to execute the binary that has an absolute path. If this fails,
714 * e.g., because the root file system cannot be read, try to strip of
715 * the path, and see if the command is in RS' current working dir.
717 nice(rp
->r_nice
); /* Nice before setuid, to allow negative
723 execve(rp
->r_argv
[0], rp
->r_argv
, NULL
); /* POSIX execute */
724 file_only
= strrchr(rp
->r_argv
[0], '/') + 1;
725 execve(file_only
, rp
->r_argv
, NULL
); /* POSIX execute */
727 printf("RS: exec failed for %s: %d\n", rp
->r_argv
[0], errno
);
728 exit(EXEC_FAILED
); /* terminate child */
730 default: /* parent process */
731 child_proc_nr_e
= getnprocnr(child_pid
); /* get child slot */
732 break; /* continue below */
737 extern char **environ
;
738 dev_execve(child_proc_nr_e
, rp
->r_exec
, rp
->r_exec_len
, rp
->r_argv
,
743 if (rp
->r_set_resources
)
745 init_privs(rp
, &rp
->r_priv
);
748 /* Inform the PCI server about the driver */
749 init_pci(rp
, child_proc_nr_e
);
752 /* Set the privilege structure for the child process to let is run.
753 * This should succeed: we tested number in use above.
755 if ((s
= sys_privctl(child_proc_nr_e
, SYS_PRIV_INIT
, 0, privp
)) < 0) {
756 report("RS","sys_privctl call failed", s
); /* to let child run */
757 rp
->r_flags
|= RS_EXITING
; /* expect exit */
758 if(child_pid
> 0) kill(child_pid
, SIGKILL
); /* kill driver */
759 else report("RS", "didn't kill pid", child_pid
);
760 return(s
); /* return error */
763 if (rp
->r_dev_nr
> 0) { /* set driver map */
764 if ((s
=mapdriver(child_proc_nr_e
, rp
->r_dev_nr
, rp
->r_dev_style
,
765 !!use_copy
/* force */)) < 0) {
766 report("RS", "couldn't map driver", errno
);
767 rp
->r_flags
|= RS_EXITING
; /* expect exit */
768 if(child_pid
> 0) kill(child_pid
, SIGKILL
); /* kill driver */
769 else report("RS", "didn't kill pid", child_pid
);
770 return(s
); /* return error */
775 printf("RS: started '%s', major %d, pid %d, endpoint %d, proc %d\n",
776 rp
->r_cmd
, rp
->r_dev_nr
, child_pid
,
777 child_proc_nr_e
, child_proc_nr_n
);
779 /* The system service now has been successfully started. Update the rest
780 * of the system process table that is maintain by the RS server. The only
781 * thing that can go wrong now, is that execution fails at the child. If
782 * that's the case, the child will exit.
784 child_proc_nr_n
= _ENDPOINT_P(child_proc_nr_e
);
785 rp
->r_flags
= RS_IN_USE
| flags
; /* mark slot in use */
786 rp
->r_restarts
+= 1; /* raise nr of restarts */
787 rp
->r_proc_nr_e
= child_proc_nr_e
; /* set child details */
788 rp
->r_pid
= child_pid
;
789 rp
->r_check_tm
= 0; /* not check yet */
790 getuptime(&rp
->r_alive_tm
); /* currently alive */
791 rp
->r_stop_tm
= 0; /* not exiting yet */
792 rproc_ptr
[child_proc_nr_n
] = rp
; /* mapping for fast access */
794 if(endpoint
) *endpoint
= child_proc_nr_e
; /* send back child endpoint */
798 /*===========================================================================*
800 *===========================================================================*/
801 PRIVATE
int stop_service(rp
,how
)
805 /* Try to stop the system service. First send a SIGTERM signal to ask the
806 * system service to terminate. If the service didn't install a signal
807 * handler, it will be killed. If it did and ignores the signal, we'll
808 * find out because we record the time here and send a SIGKILL.
810 if(rs_verbose
) printf("RS tries to stop %s (pid %d)\n", rp
->r_cmd
, rp
->r_pid
);
812 rp
->r_flags
|= how
; /* what to on exit? */
813 if(rp
->r_pid
> 0) kill(rp
->r_pid
, SIGTERM
); /* first try friendly */
814 else if(rs_verbose
) printf("RS: no process to kill\n");
815 getuptime(&rp
->r_stop_tm
); /* record current time */
819 /*===========================================================================*
821 *===========================================================================*/
822 PUBLIC
int do_getsysinfo(m_ptr
)
825 vir_bytes src_addr
, dst_addr
;
830 switch(m_ptr
->m1_i1
) {
832 src_addr
= (vir_bytes
) rproc
;
833 len
= sizeof(struct rproc
) * NR_SYS_PROCS
;
839 dst_proc
= m_ptr
->m_source
;
840 dst_addr
= (vir_bytes
) m_ptr
->m1_p1
;
841 if (OK
!= (s
=sys_datacopy(SELF
, src_addr
, dst_proc
, dst_addr
, len
)))
846 PRIVATE pid_t
fork_nb()
850 return(_syscall(PM_PROC_NR
, FORK_NB
, &m
));
853 PRIVATE
int read_exec(rp
)
860 e_name
= rp
->r_argv
[0];
861 r
= stat(e_name
, &sb
);
865 fd
= open(e_name
, O_RDONLY
);
869 rp
->r_exec_len
= sb
.st_size
;
870 rp
->r_exec
= malloc(rp
->r_exec_len
);
871 if (rp
->r_exec
== NULL
)
873 printf("RS: read_exec: unable to allocate %d bytes\n",
879 r
= read(fd
, rp
->r_exec
, rp
->r_exec_len
);
882 if (r
== rp
->r_exec_len
)
885 printf("RS: read_exec: read failed %d, errno %d\n", r
, e
);
896 /*===========================================================================*
898 *===========================================================================*/
899 PRIVATE
void run_script(rp
)
905 char incarnation_str
[20]; /* Enough for a counter? */
907 if (rp
->r_flags
& RS_EXITING
)
909 else if (rp
->r_flags
& RS_REFRESHING
)
911 else if (rp
->r_flags
& RS_NOPINGREPLY
)
912 reason
= "no-heartbeat";
913 else if (rp
->r_flags
& RS_KILLED
)
915 else if (rp
->r_flags
& RS_CRASHED
)
920 "RS: run_script: can't find reason for termination of '%s'\n",
924 sprintf(incarnation_str
, "%d", rp
->r_restarts
);
927 printf("RS: should call script '%s'\n", rp
->r_script
);
928 printf("RS: sevice name: '%s'\n", rp
->r_label
);
929 printf("RS: reason: '%s'\n", reason
);
930 printf("RS: incarnation: '%s'\n", incarnation_str
);
937 printf("RS: run_script: fork failed: %s\n", strerror(errno
));
940 execle(rp
->r_script
, rp
->r_script
, rp
->r_label
, reason
,
941 incarnation_str
, NULL
, NULL
);
943 extern int kputc_use_private_grants
;
944 kputc_use_private_grants
= 1;
946 printf("RS: run_script: execl '%s' failed: %s\n",
947 rp
->r_script
, strerror(errno
));
950 /* Set the privilege structure for the child process to let it
953 proc_nr_e
= getnprocnr(pid
);
954 r
= sys_privctl(proc_nr_e
, SYS_PRIV_USER
, 0, NULL
);
956 printf("RS: run_script: sys_privctl call failed: %d\n", r
);
958 /* Do not wait for the child */
964 /*===========================================================================*
966 *===========================================================================*/
967 PRIVATE
void init_privs(rp
, privp
)
971 int i
, src_bits_per_word
, dst_bits_per_word
, src_word
, dst_word
,
975 /* Clear s_k_call_mask */
976 memset(privp
->s_k_call_mask
, '\0', sizeof(privp
->s_k_call_mask
));
978 src_bits_per_word
= 8*sizeof(rp
->r_call_mask
[0]);
979 dst_bits_per_word
= 8*sizeof(privp
->s_k_call_mask
[0]);
980 for (src_word
= 0; src_word
< MAX_NR_SYSTEM
; src_word
++)
982 for (src_bit
= 0; src_bit
< src_bits_per_word
; src_bit
++)
984 mask
= (1UL << src_bit
);
985 if (!(rp
->r_call_mask
[src_word
] & mask
))
987 call_nr
= src_word
*src_bits_per_word
+src_bit
;
989 printf("RS: init_privs: system call %d\n", call_nr
);
990 dst_word
= call_nr
/ dst_bits_per_word
;
991 mask
= (1UL << (call_nr
% dst_bits_per_word
));
992 if (dst_word
>= CALL_MASK_SIZE
)
995 "RS: init_privs: call number %d doesn't fit\n",
998 privp
->s_k_call_mask
[dst_word
] |= mask
;
1004 /*===========================================================================*
1006 *===========================================================================*/
1007 PRIVATE
void init_pci(rp
, endpoint
)
1011 /* Tell the PCI driver about the new driver */
1014 struct rs_pci rs_pci
;
1016 if (strcmp(rp
->r_label
, "pci") == 0)
1019 printf("RS: init_pci: not when starting 'pci'\n");
1023 len
= strlen(rp
->r_label
);
1024 if (len
+1 > sizeof(rs_pci
.rsp_label
))
1027 printf("RS: init_pci: label '%s' too long for rsp_label\n",
1031 strcpy(rs_pci
.rsp_label
, rp
->r_label
);
1032 rs_pci
.rsp_endpoint
= endpoint
;
1034 rs_pci
.rsp_nr_device
= rp
->r_nr_pci_id
;
1035 if (rs_pci
.rsp_nr_device
> RSP_NR_DEVICE
)
1037 printf("RS: init_pci: too many PCI devices (max %d) "
1040 rs_pci
.rsp_nr_device
= RSP_NR_DEVICE
;
1042 for (i
= 0; i
<rs_pci
.rsp_nr_device
; i
++)
1044 rs_pci
.rsp_device
[i
].vid
= rp
->r_pci_id
[i
].vid
;
1045 rs_pci
.rsp_device
[i
].did
= rp
->r_pci_id
[i
].did
;
1048 rs_pci
.rsp_nr_class
= rp
->r_nr_pci_class
;
1049 if (rs_pci
.rsp_nr_class
> RSP_NR_CLASS
)
1051 printf("RS: init_pci: too many PCI classes "
1052 "(max %d) truncating\n",
1054 rs_pci
.rsp_nr_class
= RSP_NR_CLASS
;
1056 for (i
= 0; i
<rs_pci
.rsp_nr_class
; i
++)
1058 rs_pci
.rsp_class
[i
].class= rp
->r_pci_class
[i
].class;
1059 rs_pci
.rsp_class
[i
].mask
= rp
->r_pci_class
[i
].mask
;
1063 printf("RS: init_pci: calling pci_set_acl\n");
1065 r
= pci_set_acl(&rs_pci
);
1068 printf("RS: init_pci: after pci_set_acl\n");
1072 printf("RS: init_pci: pci_set_acl failed: %s\n",