1 /* Reincarnation Server. This servers starts new system services and detects
2 * they are exiting. In case of errors, system services can be restarted.
3 * The RS server periodically checks the status of all registered services
4 * services to see whether they are still alive. The system services are
5 * expected to periodically send a heartbeat message.
8 * Nov 22, 2009: rewrite of boot process (Cristiano Giuffrida)
9 * Jul 22, 2005: Created (Jorrit N. Herder)
14 #include <minix/crtso.h>
15 #include "../../kernel/const.h"
16 #include "../../kernel/type.h"
17 #include "../../kernel/proc.h"
18 #include "../pm/mproc.h"
19 #include "../pm/const.h"
21 /* Declare some local functions. */
22 FORWARD
_PROTOTYPE(void exec_image_copy
, ( int boot_proc_idx
,
23 struct boot_image
*ip
, struct rproc
*rp
) );
24 FORWARD
_PROTOTYPE(void boot_image_info_lookup
, ( endpoint_t endpoint
,
25 struct boot_image
*image
,
26 struct boot_image
**ip
, struct boot_image_priv
**pp
,
27 struct boot_image_sys
**sp
, struct boot_image_dev
**dp
) );
28 FORWARD
_PROTOTYPE(void catch_boot_init_ready
, (endpoint_t endpoint
) );
29 FORWARD
_PROTOTYPE(void sig_handler
, (void) );
30 FORWARD
_PROTOTYPE(void get_work
, (message
*m
) );
31 FORWARD
_PROTOTYPE(void reply
, (int whom
, message
*m_out
) );
33 /* The buffer where the boot image is copied during initialization. */
34 PRIVATE
int boot_image_buffer_size
;
35 PRIVATE
char *boot_image_buffer
;
37 /* Flag set when memory unmapping can be done. */
40 /* SEF functions and variables. */
41 FORWARD
_PROTOTYPE( void sef_local_startup
, (void) );
42 FORWARD
_PROTOTYPE( int sef_cb_init_fresh
, (int type
, sef_init_info_t
*info
) );
44 /*===========================================================================*
46 *===========================================================================*/
49 /* This is the main routine of this service. The main loop consists of
50 * three major activities: getting new work, processing the work, and
51 * sending the reply. The loop never terminates, unless a panic occurs.
53 message m
; /* request message */
54 int call_nr
, who_e
,who_p
; /* call number and caller */
55 int result
; /* result to return */
57 /* SEF local startup. */
60 /* Main loop - get work and do it, forever. */
63 /* Wait for request message. */
66 who_p
= _ENDPOINT_P(who_e
);
67 if(who_p
< -NR_TASKS
|| who_p
>= NR_PROCS
)
68 panic("RS","message from bogus source", who_e
);
72 /* Now determine what to do. Four types of requests are expected:
73 * - Heartbeat messages (notifications from registered system services)
74 * - System notifications (POSIX signals or synchronous alarm)
75 * - User requests (control messages to manage system services)
76 * - Ready messages (reply messages from registered services)
79 /* Notification messages are control messages and do not need a reply.
80 * These include heartbeat messages and system notifications.
82 if (is_notify(m
.m_type
)) {
85 do_period(&m
); /* check services status */
87 case PM_PROC_NR
: /* signal or PM heartbeat */
89 default: /* heartbeat notification */
90 if (rproc_ptr
[who_p
] != NULL
) { /* mark heartbeat time */
91 rproc_ptr
[who_p
]->r_alive_tm
= m
.NOTIFY_TIMESTAMP
;
93 printf("Warning, RS got unexpected notify message from %d\n",
99 /* If we get this far, this is a normal request.
100 * Handle the request and send a reply to the caller.
103 if (call_nr
!= GETSYSINFO
&&
104 (call_nr
< RS_RQ_BASE
|| call_nr
>= RS_RQ_BASE
+0x100))
106 /* Ignore invalid requests. Do not try to reply. */
107 printf("RS: got invalid request %d from endpoint %d\n",
108 call_nr
, m
.m_source
);
112 /* Handler functions are responsible for permission checking. */
115 case RS_UP
: result
= do_up(&m
); break;
116 case RS_DOWN
: result
= do_down(&m
); break;
117 case RS_REFRESH
: result
= do_refresh(&m
); break;
118 case RS_RESTART
: result
= do_restart(&m
); break;
119 case RS_SHUTDOWN
: result
= do_shutdown(&m
); break;
120 case RS_UPDATE
: result
= do_update(&m
); break;
121 case GETSYSINFO
: result
= do_getsysinfo(&m
); break;
122 case RS_LOOKUP
: result
= do_lookup(&m
); break;
123 /* Ready messages. */
124 case RS_INIT
: result
= do_init_ready(&m
); break;
125 case RS_LU_PREPARE
: result
= do_upd_ready(&m
); break;
127 printf("Warning, RS got unexpected request %d from %d\n",
128 m
.m_type
, m
.m_source
);
132 /* Finally send reply message, unless disabled. */
133 if (result
!= EDONTREPLY
) {
141 /*===========================================================================*
142 * sef_local_startup *
143 *===========================================================================*/
144 PRIVATE
void sef_local_startup()
146 /* Register init callbacks. */
147 sef_setcb_init_fresh(sef_cb_init_fresh
); /* RS can only start fresh. */
149 /* Let SEF perform startup. */
153 /*===========================================================================*
154 * sef_cb_init_fresh *
155 *===========================================================================*/
156 PRIVATE
int sef_cb_init_fresh(int type
, sef_init_info_t
*info
)
158 /* Initialize the reincarnation server. */
160 struct boot_image
*ip
;
162 int nr_image_srvs
, nr_image_priv_srvs
, nr_uncaught_init_srvs
;
164 struct rprocpub
*rpub
;
165 struct boot_image image
[NR_BOOT_PROCS
];
166 struct mproc mproc
[NR_PROCS
];
168 struct boot_image_priv
*boot_image_priv
;
169 struct boot_image_sys
*boot_image_sys
;
170 struct boot_image_dev
*boot_image_dev
;
172 /* See if we run in verbose mode. */
173 env_parse("rs_verbose", "d", 0, &rs_verbose
, 0, 1);
175 /* Initialize the global init descriptor. */
176 rinit
.rproctab_gid
= cpf_grant_direct(ANY
, (vir_bytes
) rprocpub
,
177 sizeof(rprocpub
), CPF_READ
);
178 if(!GRANT_VALID(rinit
.rproctab_gid
)) {
179 panic("RS", "unable to create rprocpub table grant", rinit
.rproctab_gid
);
182 /* Initialize the global update descriptor. */
185 /* Get a copy of the boot image table. */
186 if ((s
= sys_getimage(image
)) != OK
) {
187 panic("RS", "unable to get copy of boot image table", s
);
190 /* Determine the number of system services in the boot image table and
191 * compute the size required for the boot image buffer.
194 boot_image_buffer_size
= 0;
195 for(i
=0;i
<NR_BOOT_PROCS
;i
++) {
198 /* System services only. */
199 if(iskerneln(_ENDPOINT_P(ip
->endpoint
))) {
204 /* Lookup the corresponding entry in the boot image sys table. */
205 boot_image_info_lookup(ip
->endpoint
, image
,
206 NULL
, NULL
, &boot_image_sys
, NULL
);
208 /* If we must keep a copy of this system service, read the header
209 * and increase the size of the boot image buffer.
211 if(boot_image_sys
->flags
& SF_USE_COPY
) {
212 if((s
= sys_getaoutheader(&header
, i
)) != OK
) {
213 panic("RS", "unable to get copy of a.out header", s
);
215 boot_image_buffer_size
+= header
.a_hdrlen
216 + header
.a_text
+ header
.a_data
;
220 /* Determine the number of entries in the boot image priv table and make sure
221 * it matches the number of system services in the boot image table.
223 nr_image_priv_srvs
= 0;
224 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
225 boot_image_priv
= &boot_image_priv_table
[i
];
227 /* System services only. */
228 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
231 nr_image_priv_srvs
++;
233 if(nr_image_srvs
!= nr_image_priv_srvs
) {
234 panic("RS", "boot image table and boot image priv table mismatch",
238 /* Allocate boot image buffer. */
239 if(boot_image_buffer_size
> 0) {
240 boot_image_buffer
= rs_startup_sbrk(boot_image_buffer_size
);
241 if(boot_image_buffer
== (char *) -1) {
242 panic("RS", "unable to allocate boot image buffer", NO_NUM
);
246 /* Reset the system process table. */
247 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
249 rp
->r_pub
= &rprocpub
[rp
- rproc
];
250 rp
->r_pub
->in_use
= FALSE
;
253 /* Initialize the system process table in 4 steps, each of them following
254 * the appearance of system services in the boot image priv table.
255 * - Step 1: get a copy of the executable image of every system service that
256 * requires it while it is not yet running.
257 * In addition, set priviliges, sys properties, and dev properties (if any)
258 * for every system service.
260 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
261 boot_image_priv
= &boot_image_priv_table
[i
];
263 /* System services only. */
264 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
268 /* Lookup the corresponding entries in other tables. */
269 boot_image_info_lookup(boot_image_priv
->endpoint
, image
,
270 &ip
, NULL
, &boot_image_sys
, &boot_image_dev
);
271 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
275 * Get a copy of the executable image if required.
279 if(boot_image_sys
->flags
& SF_USE_COPY
) {
280 exec_image_copy(ip
- image
, ip
, rp
);
287 strcpy(rpub
->label
, boot_image_priv
->label
);
289 if(boot_image_priv
->endpoint
!= RS_PROC_NR
) {
290 /* Force a static priv id for system services in the boot image. */
291 rp
->r_priv
.s_id
= static_priv_id(
292 _ENDPOINT_P(boot_image_priv
->endpoint
));
294 /* Initialize privilege bitmaps. */
295 rp
->r_priv
.s_flags
= boot_image_priv
->flags
; /* priv flags */
296 rp
->r_priv
.s_trap_mask
= boot_image_priv
->trap_mask
; /* traps */
297 memcpy(&rp
->r_priv
.s_ipc_to
, &boot_image_priv
->ipc_to
,
298 sizeof(rp
->r_priv
.s_ipc_to
)); /* targets */
300 /* Initialize kernel call mask bitmap from unordered set. */
301 fill_call_mask(boot_image_priv
->k_calls
, NR_SYS_CALLS
,
302 rp
->r_priv
.s_k_call_mask
, KERNEL_CALL
, TRUE
);
304 /* Set the privilege structure. */
305 if ((s
= sys_privctl(ip
->endpoint
, SYS_PRIV_SET_SYS
, &(rp
->r_priv
)))
307 panic("RS", "unable to set privilege structure", s
);
311 /* Synch the privilege structure with the kernel. */
312 if ((s
= sys_getpriv(&(rp
->r_priv
), ip
->endpoint
)) != OK
) {
313 panic("RS", "unable to synch privilege structure", s
);
317 * Set sys properties.
319 rpub
->sys_flags
= boot_image_sys
->flags
; /* sys flags */
322 * Set dev properties.
324 rpub
->dev_nr
= boot_image_dev
->dev_nr
; /* major device number */
325 rpub
->dev_style
= boot_image_dev
->dev_style
; /* device style */
326 rpub
->period
= boot_image_dev
->period
; /* heartbeat period */
328 /* Get process name. */
329 strcpy(rpub
->proc_name
, ip
->proc_name
);
331 /* Get command settings. */
333 rp
->r_argv
[0] = rp
->r_cmd
;
334 rp
->r_argv
[1] = NULL
;
336 rp
->r_script
[0]= '\0';
338 /* Initialize vm call mask bitmap from unordered set. */
339 fill_call_mask(boot_image_priv
->vm_calls
, NR_VM_CALLS
,
340 rpub
->vm_call_mask
, VM_RQ_BASE
, TRUE
);
342 /* Get some settings from the boot image table. */
343 rp
->r_nice
= ip
->priority
;
344 rpub
->endpoint
= ip
->endpoint
;
346 /* Set some defaults. */
347 rp
->r_uid
= 0; /* root */
348 rp
->r_check_tm
= 0; /* not checked yet */
349 getuptime(&rp
->r_alive_tm
); /* currently alive */
350 rp
->r_stop_tm
= 0; /* not exiting yet */
351 rp
->r_restarts
= 0; /* no restarts so far */
352 rp
->r_set_resources
= 0; /* don't set resources */
354 /* Mark as in use. */
355 rp
->r_flags
= RS_IN_USE
;
356 rproc_ptr
[_ENDPOINT_P(rpub
->endpoint
)]= rp
;
360 /* - Step 2: allow every system service in the boot image to run.
362 nr_uncaught_init_srvs
= 0;
363 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
364 boot_image_priv
= &boot_image_priv_table
[i
];
366 /* System services only. */
367 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
372 if(boot_image_priv
->endpoint
== RS_PROC_NR
) {
376 /* Lookup the corresponding slot in the system process table. */
377 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
380 /* Allow the service to run. */
381 if ((s
= sys_privctl(rpub
->endpoint
, SYS_PRIV_ALLOW
, NULL
)) != OK
) {
382 panic("RS", "unable to initialize privileges", s
);
385 /* Initialize service. We assume every service will always get
386 * back to us here at boot time.
388 if(boot_image_priv
->flags
& SYS_PROC
) {
389 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
390 panic("RS", "unable to initialize service", s
);
392 if(rpub
->sys_flags
& SF_SYNCH_BOOT
) {
393 /* Catch init ready message now to synchronize. */
394 catch_boot_init_ready(rpub
->endpoint
);
397 /* Catch init ready message later. */
398 nr_uncaught_init_srvs
++;
403 /* - Step 3: let every system service complete initialization by
404 * catching all the init ready messages left.
406 while(nr_uncaught_init_srvs
) {
407 catch_boot_init_ready(ANY
);
408 nr_uncaught_init_srvs
--;
411 /* - Step 4: all the system services in the boot image are now running.
412 * Complete the initialization of the system process table in collaboration
413 * with other system processes.
415 if ((s
= getsysinfo(PM_PROC_NR
, SI_PROC_TAB
, mproc
)) != OK
) {
416 panic("RS", "unable to get copy of PM process table", s
);
418 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
419 boot_image_priv
= &boot_image_priv_table
[i
];
421 /* System services only. */
422 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
426 /* Lookup the corresponding slot in the system process table. */
427 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
430 /* Get pid from PM process table. */
432 for (j
= 0; j
< NR_PROCS
; j
++) {
433 if (mproc
[j
].mp_endpoint
== rpub
->endpoint
) {
434 rp
->r_pid
= mproc
[j
].mp_pid
;
439 panic("RS", "unable to get pid", NO_NUM
);
444 * Now complete RS initialization process in collaboration with other
447 /* Let the rest of the system know about our dynamically allocated buffer. */
448 if(boot_image_buffer_size
> 0) {
449 boot_image_buffer
= rs_startup_sbrk_synch(boot_image_buffer_size
);
450 if(boot_image_buffer
== (char *) -1) {
451 panic("RS", "unable to synch boot image buffer", NO_NUM
);
455 /* Set alarm to periodically check service status. */
456 if (OK
!= (s
=sys_setalarm(RS_DELTA_T
, 0)))
457 panic("RS", "couldn't set alarm", s
);
459 /* Install signal handlers. Ask PM to transform signal into message. */
460 sa
.sa_handler
= SIG_MESS
;
461 sigemptyset(&sa
.sa_mask
);
463 if (sigaction(SIGCHLD
,&sa
,NULL
)<0) panic("RS","sigaction failed", errno
);
464 if (sigaction(SIGTERM
,&sa
,NULL
)<0) panic("RS","sigaction failed", errno
);
466 /* Initialize the exec pipe. */
467 if (pipe(exec_pipe
) == -1)
468 panic("RS", "pipe failed", errno
);
469 if (fcntl(exec_pipe
[0], F_SETFD
,
470 fcntl(exec_pipe
[0], F_GETFD
) | FD_CLOEXEC
) == -1)
472 panic("RS", "fcntl set FD_CLOEXEC on pipe input failed", errno
);
474 if (fcntl(exec_pipe
[1], F_SETFD
,
475 fcntl(exec_pipe
[1], F_GETFD
) | FD_CLOEXEC
) == -1)
477 panic("RS", "fcntl set FD_CLOEXEC on pipe output failed", errno
);
479 if (fcntl(exec_pipe
[0], F_SETFL
,
480 fcntl(exec_pipe
[0], F_GETFL
) | O_NONBLOCK
) == -1)
482 panic("RS", "fcntl set O_NONBLOCK on pipe input failed", errno
);
485 /* Map out our own text and data. This is normally done in crtso.o
486 * but RS is an exception - we don't get to talk to VM so early on.
487 * That's why we override munmap() and munmap_text() in utility.c.
489 * _minix_unmapzero() is the same code in crtso.o that normally does
490 * it on startup. It's best that it's there as crtso.o knows exactly
491 * what the ranges are of the filler data.
499 /*===========================================================================*
501 *===========================================================================*/
502 PRIVATE
void exec_image_copy(boot_proc_idx
, ip
, rp
)
504 struct boot_image
*ip
;
507 /* Copy the executable image of the given boot process. */
510 static char *boot_image_ptr
= NULL
;
512 if(boot_image_ptr
== NULL
) {
513 boot_image_ptr
= boot_image_buffer
;
517 /* Get a.out header. */
518 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< sizeof(header
)
519 || (s
= sys_getaoutheader(&header
, boot_proc_idx
)) != OK
) {
520 panic("RS", "unable to get copy of a.out header", s
);
522 memcpy(boot_image_ptr
, &header
, header
.a_hdrlen
);
523 boot_image_ptr
+= header
.a_hdrlen
;
525 /* Get text segment. */
526 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< header
.a_text
527 || (s
= rs_startup_segcopy(ip
->endpoint
, T
, D
, (vir_bytes
) boot_image_ptr
,
528 header
.a_text
)) != OK
) {
529 panic("RS", "unable to get copy of text segment", s
);
531 boot_image_ptr
+= header
.a_text
;
533 /* Get data segment. */
534 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< header
.a_data
535 || (s
= rs_startup_segcopy(ip
->endpoint
, D
, D
, (vir_bytes
) boot_image_ptr
,
536 header
.a_data
)) != OK
) {
537 panic("RS", "unable to get copy of data segment", s
);
539 boot_image_ptr
+= header
.a_data
;
541 /* Set the executable image for the given boot process. */
542 rp
->r_exec_len
= header
.a_hdrlen
+ header
.a_text
+ header
.a_data
;
543 rp
->r_exec
= boot_image_ptr
- rp
->r_exec_len
;
546 /*===========================================================================*
547 * boot_image_info_lookup *
548 *===========================================================================*/
549 PRIVATE
void boot_image_info_lookup(endpoint
, image
, ip
, pp
, sp
, dp
)
551 struct boot_image
*image
;
552 struct boot_image
**ip
;
553 struct boot_image_priv
**pp
;
554 struct boot_image_sys
**sp
;
555 struct boot_image_dev
**dp
;
557 /* Lookup entries in boot image tables. */
560 /* When requested, locate the corresponding entry in the boot image table
561 * or panic if not found.
564 for (i
=0; i
< NR_BOOT_PROCS
; i
++) {
565 if(image
[i
].endpoint
== endpoint
) {
570 if(i
== NR_BOOT_PROCS
) {
571 panic("RS", "boot image table lookup failed", NO_NUM
);
575 /* When requested, locate the corresponding entry in the boot image priv table
576 * or panic if not found.
579 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
580 if(boot_image_priv_table
[i
].endpoint
== endpoint
) {
581 *pp
= &boot_image_priv_table
[i
];
585 if(i
== NULL_BOOT_NR
) {
586 panic("RS", "boot image priv table lookup failed", NO_NUM
);
590 /* When requested, locate the corresponding entry in the boot image sys table
591 * or resort to the default entry if not found.
594 for (i
=0; boot_image_sys_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
595 if(boot_image_sys_table
[i
].endpoint
== endpoint
) {
596 *sp
= &boot_image_sys_table
[i
];
600 if(boot_image_sys_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
601 *sp
= &boot_image_sys_table
[i
]; /* accept the default entry */
605 /* When requested, locate the corresponding entry in the boot image dev table
606 * or resort to the default entry if not found.
609 for (i
=0; boot_image_dev_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
610 if(boot_image_dev_table
[i
].endpoint
== endpoint
) {
611 *dp
= &boot_image_dev_table
[i
];
615 if(boot_image_dev_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
616 *dp
= &boot_image_dev_table
[i
]; /* accept the default entry */
621 /*===========================================================================*
622 * catch_boot_init_ready *
623 *===========================================================================*/
624 PRIVATE
void catch_boot_init_ready(endpoint
)
627 /* Block and catch an init ready message from the given source. */
633 /* Receive init ready message. */
634 if ((r
= receive(endpoint
, &m
)) != OK
) {
635 panic("RS", "unable to receive init reply", r
);
637 if(m
.m_type
!= RS_INIT
) {
638 panic("RS", "unexpected reply from service", m
.m_source
);
640 result
= m
.RS_INIT_RESULT
;
641 rp
= rproc_ptr
[_ENDPOINT_P(m
.m_source
)];
645 panic("RS", "unable to complete init for service", m
.m_source
);
648 /* Mark the slot as no longer initializing. */
649 rp
->r_flags
&= ~RS_INITIALIZING
;
651 getuptime(&rp
->r_alive_tm
);
654 /*===========================================================================*
656 *===========================================================================*/
657 PRIVATE
void sig_handler()
662 /* Try to obtain signal set from PM. */
663 if (getsigset(&sigset
) != 0) return;
665 /* Check for known signals. */
666 if (sigismember(&sigset
, SIGCHLD
)) do_exit(NULL
);
667 if (sigismember(&sigset
, SIGTERM
)) do_shutdown(NULL
);
670 /*===========================================================================*
672 *===========================================================================*/
673 PRIVATE
void get_work(m_in
)
674 message
*m_in
; /* pointer to message */
676 int s
; /* receive status */
677 if (OK
!= (s
=sef_receive(ANY
, m_in
))) /* wait for message */
678 panic("RS", "sef_receive failed", s
);
681 /*===========================================================================*
683 *===========================================================================*/
684 PRIVATE
void reply(who
, m_out
)
685 int who
; /* replyee */
686 message
*m_out
; /* reply message */
688 int s
; /* send status */
690 s
= sendnb(who
, m_out
); /* send the message */
692 printf("RS: unable to send reply to %d: %d\n", who
, s
);