xref: /minix3/minix/servers/rs/request.c (revision 0eabb93c0c1d18ee661e6ed51798f14d2dfd3f92)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Changes:
3433d6423SLionel Sambuc  *   Jan 22, 2010:  Created  (Cristiano Giuffrida)
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include "inc.h"
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #include "kernel/proc.h"
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start);
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc /*===========================================================================*
13433d6423SLionel Sambuc  *				   do_up				     *
14433d6423SLionel Sambuc  *===========================================================================*/
15433d6423SLionel Sambuc int do_up(m_ptr)
16433d6423SLionel Sambuc message *m_ptr;					/* request message pointer */
17433d6423SLionel Sambuc {
18433d6423SLionel Sambuc /* A request was made to start a new system service. */
19433d6423SLionel Sambuc   struct rproc *rp;
20433d6423SLionel Sambuc   struct rprocpub *rpub;
21433d6423SLionel Sambuc   int r;
22433d6423SLionel Sambuc   struct rs_start rs_start;
23433d6423SLionel Sambuc   int noblock;
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc   /* Check if the call can be allowed. */
26433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
27433d6423SLionel Sambuc       return r;
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc   /* Allocate a new system service slot. */
30433d6423SLionel Sambuc   r = alloc_slot(&rp);
31433d6423SLionel Sambuc   if(r != OK) {
32433d6423SLionel Sambuc       printf("RS: do_up: unable to allocate a new slot: %d\n", r);
33433d6423SLionel Sambuc       return r;
34433d6423SLionel Sambuc   }
35433d6423SLionel Sambuc   rpub = rp->r_pub;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc   /* Copy the request structure. */
38433d6423SLionel Sambuc   r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
39433d6423SLionel Sambuc   if (r != OK) {
40433d6423SLionel Sambuc       return r;
41433d6423SLionel Sambuc   }
42433d6423SLionel Sambuc   r = check_request(&rs_start);
43433d6423SLionel Sambuc   if (r != OK) {
44433d6423SLionel Sambuc       return r;
45433d6423SLionel Sambuc   }
46433d6423SLionel Sambuc   noblock = (rs_start.rss_flags & RSS_NOBLOCK);
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc   /* Initialize the slot as requested. */
49433d6423SLionel Sambuc   r = init_slot(rp, &rs_start, m_ptr->m_source);
50433d6423SLionel Sambuc   if(r != OK) {
51433d6423SLionel Sambuc       printf("RS: do_up: unable to init the new slot: %d\n", r);
52433d6423SLionel Sambuc       return r;
53433d6423SLionel Sambuc   }
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc   /* Check for duplicates */
56433d6423SLionel Sambuc   if(lookup_slot_by_label(rpub->label)) {
57433d6423SLionel Sambuc       printf("RS: service with the same label '%s' already exists\n",
58433d6423SLionel Sambuc           rpub->label);
59433d6423SLionel Sambuc       return EBUSY;
60433d6423SLionel Sambuc   }
61433d6423SLionel Sambuc   if(rpub->dev_nr>0 && lookup_slot_by_dev_nr(rpub->dev_nr)) {
62433d6423SLionel Sambuc       printf("RS: service with the same device number %d already exists\n",
63433d6423SLionel Sambuc           rpub->dev_nr);
64433d6423SLionel Sambuc       return EBUSY;
65433d6423SLionel Sambuc   }
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc   /* All information was gathered. Now try to start the system service. */
68433d6423SLionel Sambuc   r = start_service(rp);
69433d6423SLionel Sambuc   if(r != OK) {
70433d6423SLionel Sambuc       return r;
71433d6423SLionel Sambuc   }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc   /* Unblock the caller immediately if requested. */
74433d6423SLionel Sambuc   if(noblock) {
75433d6423SLionel Sambuc       return OK;
76433d6423SLionel Sambuc   }
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc   /* Late reply - send a reply when service completes initialization. */
79433d6423SLionel Sambuc   rp->r_flags |= RS_LATEREPLY;
80433d6423SLionel Sambuc   rp->r_caller = m_ptr->m_source;
81433d6423SLionel Sambuc   rp->r_caller_request = RS_UP;
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc   return EDONTREPLY;
84433d6423SLionel Sambuc }
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc /*===========================================================================*
87433d6423SLionel Sambuc  *				do_down					     *
88433d6423SLionel Sambuc  *===========================================================================*/
89433d6423SLionel Sambuc int do_down(message *m_ptr)
90433d6423SLionel Sambuc {
91433d6423SLionel Sambuc   register struct rproc *rp;
92433d6423SLionel Sambuc   int s;
93433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc   /* Copy label. */
96433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
97433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
98433d6423SLionel Sambuc   if(s != OK) {
99433d6423SLionel Sambuc       return s;
100433d6423SLionel Sambuc   }
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc   /* Lookup slot by label. */
103433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
104433d6423SLionel Sambuc   if(!rp) {
105433d6423SLionel Sambuc       if(rs_verbose)
106433d6423SLionel Sambuc           printf("RS: do_down: service '%s' not found\n", label);
107433d6423SLionel Sambuc       return(ESRCH);
108433d6423SLionel Sambuc   }
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   /* Check if the call can be allowed. */
111433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
112433d6423SLionel Sambuc       return s;
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc   /* Stop service. */
115433d6423SLionel Sambuc   if (rp->r_flags & RS_TERMINATED) {
116433d6423SLionel Sambuc         /* A recovery script is requesting us to bring down the service.
117433d6423SLionel Sambuc          * The service is already gone, simply perform cleanup.
118433d6423SLionel Sambuc          */
119433d6423SLionel Sambuc         if(rs_verbose)
120433d6423SLionel Sambuc             printf("RS: recovery script performs service down...\n");
121433d6423SLionel Sambuc   	unpublish_service(rp);
122433d6423SLionel Sambuc   	cleanup_service(rp);
123433d6423SLionel Sambuc     	return(OK);
124433d6423SLionel Sambuc   }
125433d6423SLionel Sambuc   stop_service(rp,RS_EXITING);
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc   /* Late reply - send a reply when service dies. */
128433d6423SLionel Sambuc   rp->r_flags |= RS_LATEREPLY;
129433d6423SLionel Sambuc   rp->r_caller = m_ptr->m_source;
130433d6423SLionel Sambuc   rp->r_caller_request = RS_DOWN;
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc   return EDONTREPLY;
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc /*===========================================================================*
136433d6423SLionel Sambuc  *				do_restart				     *
137433d6423SLionel Sambuc  *===========================================================================*/
138433d6423SLionel Sambuc int do_restart(message *m_ptr)
139433d6423SLionel Sambuc {
140433d6423SLionel Sambuc   struct rproc *rp;
141433d6423SLionel Sambuc   int s, r;
142433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
143433d6423SLionel Sambuc   char script[MAX_SCRIPT_LEN];
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc   /* Copy label. */
146433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
147433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
148433d6423SLionel Sambuc   if(s != OK) {
149433d6423SLionel Sambuc       return s;
150433d6423SLionel Sambuc   }
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc   /* Lookup slot by label. */
153433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
154433d6423SLionel Sambuc   if(!rp) {
155433d6423SLionel Sambuc       if(rs_verbose)
156433d6423SLionel Sambuc           printf("RS: do_restart: service '%s' not found\n", label);
157433d6423SLionel Sambuc       return(ESRCH);
158433d6423SLionel Sambuc   }
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc   /* Check if the call can be allowed. */
161433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
162433d6423SLionel Sambuc       return r;
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc   /* We can only be asked to restart a service from a recovery script. */
165433d6423SLionel Sambuc   if (! (rp->r_flags & RS_TERMINATED) ) {
166433d6423SLionel Sambuc       if(rs_verbose)
167433d6423SLionel Sambuc           printf("RS: %s is still running\n", srv_to_string(rp));
168433d6423SLionel Sambuc       return EBUSY;
169433d6423SLionel Sambuc   }
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc   if(rs_verbose)
172433d6423SLionel Sambuc       printf("RS: recovery script performs service restart...\n");
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc   /* Restart the service, but make sure we don't call the script again. */
175433d6423SLionel Sambuc   strcpy(script, rp->r_script);
176433d6423SLionel Sambuc   rp->r_script[0] = '\0';
177433d6423SLionel Sambuc   restart_service(rp);
178433d6423SLionel Sambuc   strcpy(rp->r_script, script);
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc   return OK;
181433d6423SLionel Sambuc }
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc /*===========================================================================*
184433d6423SLionel Sambuc  *				do_clone				     *
185433d6423SLionel Sambuc  *===========================================================================*/
186433d6423SLionel Sambuc int do_clone(message *m_ptr)
187433d6423SLionel Sambuc {
188433d6423SLionel Sambuc   struct rproc *rp;
189433d6423SLionel Sambuc   struct rprocpub *rpub;
190433d6423SLionel Sambuc   int s, r;
191433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc   /* Copy label. */
194433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
195433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
196433d6423SLionel Sambuc   if(s != OK) {
197433d6423SLionel Sambuc       return s;
198433d6423SLionel Sambuc   }
199433d6423SLionel Sambuc 
200433d6423SLionel Sambuc   /* Lookup slot by label. */
201433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
202433d6423SLionel Sambuc   if(!rp) {
203433d6423SLionel Sambuc       if(rs_verbose)
204433d6423SLionel Sambuc           printf("RS: do_clone: service '%s' not found\n", label);
205433d6423SLionel Sambuc       return(ESRCH);
206433d6423SLionel Sambuc   }
207433d6423SLionel Sambuc   rpub = rp->r_pub;
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc   /* Check if the call can be allowed. */
210433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_CLONE, rp)) != OK)
211433d6423SLionel Sambuc       return r;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc   /* Don't clone if a replica is already available. */
214433d6423SLionel Sambuc   if(rp->r_next_rp) {
215433d6423SLionel Sambuc       return EEXIST;
216433d6423SLionel Sambuc   }
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc   /* Clone the service as requested. */
219433d6423SLionel Sambuc   rpub->sys_flags |= SF_USE_REPL;
220433d6423SLionel Sambuc   if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
221433d6423SLionel Sambuc       rpub->sys_flags &= ~SF_USE_REPL;
222433d6423SLionel Sambuc       return r;
223433d6423SLionel Sambuc   }
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc   return OK;
226433d6423SLionel Sambuc }
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc /*===========================================================================*
229433d6423SLionel Sambuc  *				    do_edit				     *
230433d6423SLionel Sambuc  *===========================================================================*/
231433d6423SLionel Sambuc int do_edit(message *m_ptr)
232433d6423SLionel Sambuc {
233433d6423SLionel Sambuc   struct rproc *rp;
234433d6423SLionel Sambuc   struct rprocpub *rpub;
235433d6423SLionel Sambuc   struct rs_start rs_start;
236433d6423SLionel Sambuc   int r;
237433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc   /* Copy the request structure. */
240433d6423SLionel Sambuc   r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
241433d6423SLionel Sambuc   if (r != OK) {
242433d6423SLionel Sambuc       return r;
243433d6423SLionel Sambuc   }
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc   /* Copy label. */
246433d6423SLionel Sambuc   r = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
247433d6423SLionel Sambuc       rs_start.rss_label.l_len, label, sizeof(label));
248433d6423SLionel Sambuc   if(r != OK) {
249433d6423SLionel Sambuc       return r;
250433d6423SLionel Sambuc   }
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc   /* Lookup slot by label. */
253433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
254433d6423SLionel Sambuc   if(!rp) {
255433d6423SLionel Sambuc       if(rs_verbose)
256433d6423SLionel Sambuc           printf("RS: do_edit: service '%s' not found\n", label);
257433d6423SLionel Sambuc       return ESRCH;
258433d6423SLionel Sambuc   }
259433d6423SLionel Sambuc   rpub = rp->r_pub;
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc   /* Check if the call can be allowed. */
262433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_EDIT, rp)) != OK)
263433d6423SLionel Sambuc       return r;
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc   if(rs_verbose)
266433d6423SLionel Sambuc       printf("RS: %s edits settings\n", srv_to_string(rp));
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc   /* Synch the privilege structure with the kernel. */
269433d6423SLionel Sambuc   if ((r = sys_getpriv(&rp->r_priv, rpub->endpoint)) != OK) {
270433d6423SLionel Sambuc       printf("RS: do_edit: unable to synch privilege structure: %d\n", r);
271433d6423SLionel Sambuc       return r;
272433d6423SLionel Sambuc   }
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc   /* Tell scheduler this process is finished */
275433d6423SLionel Sambuc   if ((r = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
276433d6423SLionel Sambuc       printf("RS: do_edit: scheduler won't give up process: %d\n", r);
277433d6423SLionel Sambuc       return r;
278433d6423SLionel Sambuc   }
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc   /* Edit the slot as requested. */
281433d6423SLionel Sambuc   if((r = edit_slot(rp, &rs_start, m_ptr->m_source)) != OK) {
282433d6423SLionel Sambuc       printf("RS: do_edit: unable to edit the existing slot: %d\n", r);
283433d6423SLionel Sambuc       return r;
284433d6423SLionel Sambuc   }
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc   /* Update privilege structure. */
287433d6423SLionel Sambuc   r = sys_privctl(rpub->endpoint, SYS_PRIV_UPDATE_SYS, &rp->r_priv);
288433d6423SLionel Sambuc   if(r != OK) {
289433d6423SLionel Sambuc       printf("RS: do_edit: unable to update privilege structure: %d\n", r);
290433d6423SLionel Sambuc       return r;
291433d6423SLionel Sambuc   }
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc   /* Update VM calls. */
294433d6423SLionel Sambuc   if ((r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0],
295433d6423SLionel Sambuc     !!(rp->r_priv.s_flags & SYS_PROC))) != OK) {
296433d6423SLionel Sambuc       printf("RS: do_edit: failed: %d\n", r);
297433d6423SLionel Sambuc       return r;
298433d6423SLionel Sambuc   }
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc   /* Reinitialize scheduling. */
301433d6423SLionel Sambuc   if ((r = sched_init_proc(rp)) != OK) {
302433d6423SLionel Sambuc       printf("RS: do_edit: unable to reinitialize scheduling: %d\n", r);
303433d6423SLionel Sambuc       return r;
304433d6423SLionel Sambuc   }
305433d6423SLionel Sambuc 
306433d6423SLionel Sambuc   /* Cleanup old replicas and create a new one, if necessary. */
307433d6423SLionel Sambuc   if(rpub->sys_flags & SF_USE_REPL) {
308433d6423SLionel Sambuc       if(rp->r_next_rp) {
309433d6423SLionel Sambuc           cleanup_service(rp->r_next_rp);
310433d6423SLionel Sambuc           rp->r_next_rp = NULL;
311433d6423SLionel Sambuc       }
312433d6423SLionel Sambuc       if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
313433d6423SLionel Sambuc           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
314433d6423SLionel Sambuc       }
315433d6423SLionel Sambuc   }
316433d6423SLionel Sambuc 
317433d6423SLionel Sambuc   return OK;
318433d6423SLionel Sambuc }
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc /*===========================================================================*
321433d6423SLionel Sambuc  *				do_refresh				     *
322433d6423SLionel Sambuc  *===========================================================================*/
323433d6423SLionel Sambuc int do_refresh(message *m_ptr)
324433d6423SLionel Sambuc {
325433d6423SLionel Sambuc   register struct rproc *rp;
326433d6423SLionel Sambuc   int s;
327433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc   /* Copy label. */
330433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
331433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
332433d6423SLionel Sambuc   if(s != OK) {
333433d6423SLionel Sambuc       return s;
334433d6423SLionel Sambuc   }
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc   /* Lookup slot by label. */
337433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
338433d6423SLionel Sambuc   if(!rp) {
339433d6423SLionel Sambuc       if(rs_verbose)
340433d6423SLionel Sambuc           printf("RS: do_refresh: service '%s' not found\n", label);
341433d6423SLionel Sambuc       return(ESRCH);
342433d6423SLionel Sambuc   }
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc   /* Check if the call can be allowed. */
345433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
346433d6423SLionel Sambuc       return s;
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc   /* Refresh service. */
349433d6423SLionel Sambuc   if(rs_verbose)
350433d6423SLionel Sambuc       printf("RS: %s refreshing\n", srv_to_string(rp));
351433d6423SLionel Sambuc   stop_service(rp,RS_REFRESHING);
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   return OK;
354433d6423SLionel Sambuc }
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc /*===========================================================================*
357433d6423SLionel Sambuc  *				do_shutdown				     *
358433d6423SLionel Sambuc  *===========================================================================*/
359433d6423SLionel Sambuc int do_shutdown(message *m_ptr)
360433d6423SLionel Sambuc {
361433d6423SLionel Sambuc   int slot_nr;
362433d6423SLionel Sambuc   struct rproc *rp;
363433d6423SLionel Sambuc   int r;
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc   /* Check if the call can be allowed. */
366433d6423SLionel Sambuc   if (m_ptr != NULL) {
367433d6423SLionel Sambuc       if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
368433d6423SLionel Sambuc           return r;
369433d6423SLionel Sambuc   }
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc   if(rs_verbose)
372433d6423SLionel Sambuc       printf("RS: shutting down...\n");
373433d6423SLionel Sambuc 
374433d6423SLionel Sambuc   /* Set flag to tell RS we are shutting down. */
375433d6423SLionel Sambuc   shutting_down = TRUE;
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc   /* Don't restart dead services. */
378433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
379433d6423SLionel Sambuc       rp = &rproc[slot_nr];
380433d6423SLionel Sambuc       if (rp->r_flags & RS_IN_USE) {
381433d6423SLionel Sambuc           rp->r_flags |= RS_EXITING;
382433d6423SLionel Sambuc       }
383433d6423SLionel Sambuc   }
384433d6423SLionel Sambuc   return(OK);
385433d6423SLionel Sambuc }
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc /*===========================================================================*
388433d6423SLionel Sambuc  *				do_init_ready				     *
389433d6423SLionel Sambuc  *===========================================================================*/
390433d6423SLionel Sambuc int do_init_ready(message *m_ptr)
391433d6423SLionel Sambuc {
392433d6423SLionel Sambuc   int who_p;
393433d6423SLionel Sambuc   message m;
394433d6423SLionel Sambuc   struct rproc *rp;
395433d6423SLionel Sambuc   struct rprocpub *rpub;
396433d6423SLionel Sambuc   int result, is_rs;
397433d6423SLionel Sambuc   int r;
398433d6423SLionel Sambuc 
399433d6423SLionel Sambuc   is_rs = (m_ptr->m_source == RS_PROC_NR);
400433d6423SLionel Sambuc   who_p = _ENDPOINT_P(m_ptr->m_source);
401433d6423SLionel Sambuc   result = m_ptr->m_rs_init.result;
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc   /* Check for RS failing initialization first. */
404433d6423SLionel Sambuc   if(is_rs && result != OK) {
405433d6423SLionel Sambuc       return result;
406433d6423SLionel Sambuc   }
407433d6423SLionel Sambuc 
408433d6423SLionel Sambuc   rp = rproc_ptr[who_p];
409433d6423SLionel Sambuc   rpub = rp->r_pub;
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc   /* Make sure the originating service was requested to initialize. */
412433d6423SLionel Sambuc   if(! (rp->r_flags & RS_INITIALIZING) ) {
413433d6423SLionel Sambuc       if(rs_verbose)
414433d6423SLionel Sambuc           printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
415433d6423SLionel Sambuc               m_ptr->m_source);
416433d6423SLionel Sambuc       return EINVAL;
417433d6423SLionel Sambuc   }
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc   /* Check if something went wrong and the service failed to init.
420433d6423SLionel Sambuc    * In that case, kill the service.
421433d6423SLionel Sambuc    */
422433d6423SLionel Sambuc   if(result != OK) {
423433d6423SLionel Sambuc       if(rs_verbose)
424433d6423SLionel Sambuc           printf("RS: %s initialization error: %s\n", srv_to_string(rp),
425433d6423SLionel Sambuc               init_strerror(result));
426433d6423SLionel Sambuc       if (result == ERESTART)
427433d6423SLionel Sambuc           rp->r_flags |= RS_REINCARNATE;
428433d6423SLionel Sambuc       crash_service(rp); /* simulate crash */
429433d6423SLionel Sambuc       return EDONTREPLY;
430433d6423SLionel Sambuc   }
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc   /* Mark the slot as no longer initializing. */
433433d6423SLionel Sambuc   rp->r_flags &= ~RS_INITIALIZING;
434433d6423SLionel Sambuc   rp->r_check_tm = 0;
435433d6423SLionel Sambuc   getticks(&rp->r_alive_tm);
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc   /* Reply and unblock the service before doing anything else. */
438433d6423SLionel Sambuc   m.m_type = OK;
439433d6423SLionel Sambuc   reply(rpub->endpoint, rp, &m);
440433d6423SLionel Sambuc 
441433d6423SLionel Sambuc   /* See if a late reply has to be sent. */
442433d6423SLionel Sambuc   late_reply(rp, OK);
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc   if(rs_verbose)
445433d6423SLionel Sambuc       printf("RS: %s initialized\n", srv_to_string(rp));
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc   /* If the service has completed initialization after a live
448433d6423SLionel Sambuc    * update, end the update now.
449433d6423SLionel Sambuc    */
450433d6423SLionel Sambuc   if(rp->r_flags & RS_UPDATING) {
451433d6423SLionel Sambuc       printf("RS: update succeeded\n");
452433d6423SLionel Sambuc       end_update(OK, RS_DONTREPLY);
453433d6423SLionel Sambuc   }
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc   /* If the service has completed initialization after a crash
456433d6423SLionel Sambuc    * make the new instance active and cleanup the old replica.
457433d6423SLionel Sambuc    */
458433d6423SLionel Sambuc   if(rp->r_prev_rp) {
459433d6423SLionel Sambuc       cleanup_service(rp->r_prev_rp);
460433d6423SLionel Sambuc       rp->r_prev_rp = NULL;
461433d6423SLionel Sambuc       rp->r_restarts += 1;
462433d6423SLionel Sambuc 
463433d6423SLionel Sambuc       if(rs_verbose)
464433d6423SLionel Sambuc           printf("RS: %s completed restart\n", srv_to_string(rp));
465433d6423SLionel Sambuc   }
466433d6423SLionel Sambuc 
467433d6423SLionel Sambuc   /* If we must keep a replica of this system service, create it now. */
468433d6423SLionel Sambuc   if(rpub->sys_flags & SF_USE_REPL) {
469433d6423SLionel Sambuc       if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
470433d6423SLionel Sambuc           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
471433d6423SLionel Sambuc       }
472433d6423SLionel Sambuc   }
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc   return is_rs ? OK : EDONTREPLY; /* return what the caller expects */
475433d6423SLionel Sambuc }
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc /*===========================================================================*
478433d6423SLionel Sambuc  *				do_update				     *
479433d6423SLionel Sambuc  *===========================================================================*/
480433d6423SLionel Sambuc int do_update(message *m_ptr)
481433d6423SLionel Sambuc {
482433d6423SLionel Sambuc   struct rproc *rp;
483433d6423SLionel Sambuc   struct rproc *new_rp;
484433d6423SLionel Sambuc   struct rprocpub *rpub;
485433d6423SLionel Sambuc   struct rs_start rs_start;
486433d6423SLionel Sambuc   int noblock, do_self_update;
487433d6423SLionel Sambuc   int s;
488433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
489433d6423SLionel Sambuc   int lu_state;
490433d6423SLionel Sambuc   int prepare_maxtime;
491433d6423SLionel Sambuc 
492433d6423SLionel Sambuc   /* Copy the request structure. */
493433d6423SLionel Sambuc   s = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
494433d6423SLionel Sambuc   if (s != OK) {
495433d6423SLionel Sambuc       return s;
496433d6423SLionel Sambuc   }
497433d6423SLionel Sambuc   noblock = (rs_start.rss_flags & RSS_NOBLOCK);
498433d6423SLionel Sambuc   do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
499433d6423SLionel Sambuc   s = check_request(&rs_start);
500433d6423SLionel Sambuc   if (s != OK) {
501433d6423SLionel Sambuc       return s;
502433d6423SLionel Sambuc   }
503433d6423SLionel Sambuc 
504433d6423SLionel Sambuc   /* Copy label. */
505433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
506433d6423SLionel Sambuc       rs_start.rss_label.l_len, label, sizeof(label));
507433d6423SLionel Sambuc   if(s != OK) {
508433d6423SLionel Sambuc       return s;
509433d6423SLionel Sambuc   }
510433d6423SLionel Sambuc 
511433d6423SLionel Sambuc   /* Lookup slot by label. */
512433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
513433d6423SLionel Sambuc   if(!rp) {
514433d6423SLionel Sambuc       if(rs_verbose)
515433d6423SLionel Sambuc           printf("RS: do_update: service '%s' not found\n", label);
516433d6423SLionel Sambuc       return ESRCH;
517433d6423SLionel Sambuc   }
518433d6423SLionel Sambuc   rpub = rp->r_pub;
519433d6423SLionel Sambuc 
520433d6423SLionel Sambuc   /* Check if the call can be allowed. */
521433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
522433d6423SLionel Sambuc       return s;
523433d6423SLionel Sambuc 
524433d6423SLionel Sambuc   /* Retrieve live update state. */
525433d6423SLionel Sambuc   lu_state = m_ptr->m_rs_update.state;
526433d6423SLionel Sambuc   if(lu_state == SEF_LU_STATE_NULL) {
527433d6423SLionel Sambuc       return(EINVAL);
528433d6423SLionel Sambuc   }
529433d6423SLionel Sambuc 
530433d6423SLionel Sambuc   /* Retrieve prepare max time. */
531433d6423SLionel Sambuc   prepare_maxtime = m_ptr->m_rs_update.prepare_maxtime;
532433d6423SLionel Sambuc   if(prepare_maxtime) {
533433d6423SLionel Sambuc       if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
534433d6423SLionel Sambuc           return(EINVAL);
535433d6423SLionel Sambuc       }
536433d6423SLionel Sambuc   }
537433d6423SLionel Sambuc   else {
538433d6423SLionel Sambuc       prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
539433d6423SLionel Sambuc   }
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc   /* Make sure we are not already updating. */
542433d6423SLionel Sambuc   if(rupdate.flags & RS_UPDATING) {
543433d6423SLionel Sambuc       if(rs_verbose)
544433d6423SLionel Sambuc 	  printf("RS: do_update: an update is already in progress\n");
545433d6423SLionel Sambuc       return EBUSY;
546433d6423SLionel Sambuc   }
547433d6423SLionel Sambuc 
548433d6423SLionel Sambuc   /* A self update live updates a service instance into a replica, a regular
549433d6423SLionel Sambuc    * update live updates a service instance into a new version, as specified
550433d6423SLionel Sambuc    * by the given binary.
551433d6423SLionel Sambuc    */
552433d6423SLionel Sambuc   if(do_self_update) {
553433d6423SLionel Sambuc       if(rs_verbose)
554433d6423SLionel Sambuc           printf("RS: %s performs self update\n", srv_to_string(rp));
555433d6423SLionel Sambuc 
556433d6423SLionel Sambuc       /* Clone the system service and use the replica as the new version. */
557433d6423SLionel Sambuc       s = clone_service(rp, LU_SYS_PROC);
558433d6423SLionel Sambuc       if(s != OK) {
559433d6423SLionel Sambuc           printf("RS: do_update: unable to clone service: %d\n", s);
560433d6423SLionel Sambuc           return s;
561433d6423SLionel Sambuc       }
562433d6423SLionel Sambuc   }
563433d6423SLionel Sambuc   else {
564433d6423SLionel Sambuc       if(rs_verbose)
565433d6423SLionel Sambuc           printf("RS: %s performs regular update\n", srv_to_string(rp));
566433d6423SLionel Sambuc 
567433d6423SLionel Sambuc       /* Allocate a system service slot for the new version. */
568433d6423SLionel Sambuc       s = alloc_slot(&new_rp);
569433d6423SLionel Sambuc       if(s != OK) {
570433d6423SLionel Sambuc           printf("RS: do_update: unable to allocate a new slot: %d\n", s);
571433d6423SLionel Sambuc           return s;
572433d6423SLionel Sambuc       }
573433d6423SLionel Sambuc 
574433d6423SLionel Sambuc       /* Initialize the slot as requested. */
575433d6423SLionel Sambuc       s = init_slot(new_rp, &rs_start, m_ptr->m_source);
576433d6423SLionel Sambuc       if(s != OK) {
577433d6423SLionel Sambuc           printf("RS: do_update: unable to init the new slot: %d\n", s);
578433d6423SLionel Sambuc           return s;
579433d6423SLionel Sambuc       }
580433d6423SLionel Sambuc 
581433d6423SLionel Sambuc       /* Let the new version inherit defaults from the old one. */
582433d6423SLionel Sambuc       inherit_service_defaults(rp, new_rp);
583433d6423SLionel Sambuc 
584433d6423SLionel Sambuc       /* Link the two versions. */
585433d6423SLionel Sambuc       rp->r_new_rp = new_rp;
586433d6423SLionel Sambuc       new_rp->r_old_rp = rp;
587433d6423SLionel Sambuc 
588433d6423SLionel Sambuc       /* Create new version of the service but don't let it run. */
589433d6423SLionel Sambuc       new_rp->r_priv.s_flags |= LU_SYS_PROC;
590433d6423SLionel Sambuc       s = create_service(new_rp);
591433d6423SLionel Sambuc       if(s != OK) {
592433d6423SLionel Sambuc           printf("RS: do_update: unable to create a new service: %d\n", s);
593433d6423SLionel Sambuc           return s;
594433d6423SLionel Sambuc       }
595433d6423SLionel Sambuc   }
596433d6423SLionel Sambuc 
597433d6423SLionel Sambuc   /* Mark both versions as updating. */
598433d6423SLionel Sambuc   rp->r_flags |= RS_UPDATING;
599433d6423SLionel Sambuc   rp->r_new_rp->r_flags |= RS_UPDATING;
600433d6423SLionel Sambuc   rupdate.flags |= RS_UPDATING;
601433d6423SLionel Sambuc   getticks(&rupdate.prepare_tm);
602433d6423SLionel Sambuc   rupdate.prepare_maxtime = prepare_maxtime;
603433d6423SLionel Sambuc   rupdate.rp = rp;
604433d6423SLionel Sambuc 
605433d6423SLionel Sambuc   if(rs_verbose)
606433d6423SLionel Sambuc     printf("RS: %s updating\n", srv_to_string(rp));
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc   /* If RS is updating, set up signal managers for the new instance.
609433d6423SLionel Sambuc    * The current RS instance must be made the backup signal manager to
610433d6423SLionel Sambuc    * support rollback in case of a crash during initialization.
611433d6423SLionel Sambuc    */
612433d6423SLionel Sambuc   if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
613433d6423SLionel Sambuc       new_rp = rp->r_new_rp;
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc       s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
616433d6423SLionel Sambuc       if(s != OK) {
617433d6423SLionel Sambuc           cleanup_service(new_rp);
618433d6423SLionel Sambuc           return s;
619433d6423SLionel Sambuc       }
620433d6423SLionel Sambuc   }
621433d6423SLionel Sambuc 
622433d6423SLionel Sambuc   if(noblock) {
623433d6423SLionel Sambuc       /* Unblock the caller immediately if requested. */
624433d6423SLionel Sambuc       m_ptr->m_type = OK;
625433d6423SLionel Sambuc       reply(m_ptr->m_source, NULL, m_ptr);
626433d6423SLionel Sambuc   }
627433d6423SLionel Sambuc   else {
628433d6423SLionel Sambuc       /* Send a reply when the new version completes initialization. */
629433d6423SLionel Sambuc       rp->r_flags |= RS_LATEREPLY;
630433d6423SLionel Sambuc       rp->r_caller = m_ptr->m_source;
631433d6423SLionel Sambuc       rp->r_caller_request = RS_UPDATE;
632433d6423SLionel Sambuc   }
633433d6423SLionel Sambuc 
634433d6423SLionel Sambuc   /* Request to update. */
635433d6423SLionel Sambuc   m_ptr->m_type = RS_LU_PREPARE;
636433d6423SLionel Sambuc   if(rpub->endpoint == RS_PROC_NR) {
637433d6423SLionel Sambuc       /* RS can process the request directly. */
638433d6423SLionel Sambuc       do_sef_lu_request(m_ptr);
639433d6423SLionel Sambuc   }
640433d6423SLionel Sambuc   else {
641433d6423SLionel Sambuc       /* Send request message to the system service. */
642433d6423SLionel Sambuc       asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
643433d6423SLionel Sambuc   }
644433d6423SLionel Sambuc 
645433d6423SLionel Sambuc   return EDONTREPLY;
646433d6423SLionel Sambuc }
647433d6423SLionel Sambuc 
648433d6423SLionel Sambuc /*===========================================================================*
649433d6423SLionel Sambuc  *				do_upd_ready				     *
650433d6423SLionel Sambuc  *===========================================================================*/
651433d6423SLionel Sambuc int do_upd_ready(message *m_ptr)
652433d6423SLionel Sambuc {
653433d6423SLionel Sambuc   struct rproc *rp, *old_rp, *new_rp;
654433d6423SLionel Sambuc   int who_p;
655433d6423SLionel Sambuc   int result;
656433d6423SLionel Sambuc   int is_rs;
657433d6423SLionel Sambuc   int r;
658433d6423SLionel Sambuc 
659433d6423SLionel Sambuc   who_p = _ENDPOINT_P(m_ptr->m_source);
660433d6423SLionel Sambuc   rp = rproc_ptr[who_p];
661433d6423SLionel Sambuc   result = m_ptr->m_rs_update.result;
662433d6423SLionel Sambuc   is_rs = (m_ptr->m_source == RS_PROC_NR);
663433d6423SLionel Sambuc 
664433d6423SLionel Sambuc   /* Make sure the originating service was requested to prepare for update. */
665433d6423SLionel Sambuc   if(rp != rupdate.rp) {
666433d6423SLionel Sambuc       if(rs_verbose)
667433d6423SLionel Sambuc           printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
668433d6423SLionel Sambuc               m_ptr->m_source);
669433d6423SLionel Sambuc       return EINVAL;
670433d6423SLionel Sambuc   }
671433d6423SLionel Sambuc 
672433d6423SLionel Sambuc   /* Check if something went wrong and the service failed to prepare
673433d6423SLionel Sambuc    * for the update. In that case, end the update process. The old version will
674433d6423SLionel Sambuc    * be replied to and continue executing.
675433d6423SLionel Sambuc    */
676433d6423SLionel Sambuc   if(result != OK) {
677433d6423SLionel Sambuc       end_update(result, RS_REPLY);
678433d6423SLionel Sambuc 
679433d6423SLionel Sambuc       printf("RS: update failed: %s\n", lu_strerror(result));
680433d6423SLionel Sambuc       return is_rs ? result : EDONTREPLY; /* return what the caller expects */
681433d6423SLionel Sambuc   }
682433d6423SLionel Sambuc 
683433d6423SLionel Sambuc   old_rp = rp;
684433d6423SLionel Sambuc   new_rp = rp->r_new_rp;
685433d6423SLionel Sambuc 
686433d6423SLionel Sambuc   /* If RS itself is updating, yield control to the new version immediately. */
687433d6423SLionel Sambuc   if(is_rs) {
688433d6423SLionel Sambuc       r = init_service(new_rp, SEF_INIT_LU);
689433d6423SLionel Sambuc       if(r != OK) {
690433d6423SLionel Sambuc           panic("unable to initialize the new RS instance: %d", r);
691433d6423SLionel Sambuc       }
692433d6423SLionel Sambuc       r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
693433d6423SLionel Sambuc       if(r != OK) {
694433d6423SLionel Sambuc           panic("unable to yield control to the new RS instance: %d", r);
695433d6423SLionel Sambuc       }
696433d6423SLionel Sambuc       /* If we get this far, the new version failed to initialize. Rollback. */
697433d6423SLionel Sambuc       r = srv_update(RS_PROC_NR, new_rp->r_pub->endpoint);
698433d6423SLionel Sambuc       assert(r == OK); /* can't fail */
699433d6423SLionel Sambuc       end_update(ERESTART, RS_REPLY);
700433d6423SLionel Sambuc       return ERESTART;
701433d6423SLionel Sambuc   }
702433d6423SLionel Sambuc 
703433d6423SLionel Sambuc   /* Perform the update. */
704433d6423SLionel Sambuc   r = update_service(&old_rp, &new_rp, RS_SWAP);
705433d6423SLionel Sambuc   if(r != OK) {
706433d6423SLionel Sambuc       end_update(r, RS_REPLY);
707433d6423SLionel Sambuc       printf("RS: update failed: error %d\n", r);
708433d6423SLionel Sambuc       return EDONTREPLY;
709433d6423SLionel Sambuc   }
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc   /* Let the new version run. */
712433d6423SLionel Sambuc   r = run_service(new_rp, SEF_INIT_LU);
713433d6423SLionel Sambuc   if(r != OK) {
714433d6423SLionel Sambuc       /* Something went wrong. Rollback. */
715433d6423SLionel Sambuc       r = update_service(&new_rp, &old_rp, RS_SWAP);
716433d6423SLionel Sambuc       assert(r == OK); /* can't fail */
717433d6423SLionel Sambuc       end_update(r, RS_REPLY);
718433d6423SLionel Sambuc       printf("RS: update failed: error %d\n", r);
719433d6423SLionel Sambuc       return EDONTREPLY;
720433d6423SLionel Sambuc   }
721433d6423SLionel Sambuc 
722433d6423SLionel Sambuc   return EDONTREPLY;
723433d6423SLionel Sambuc }
724433d6423SLionel Sambuc 
725433d6423SLionel Sambuc /*===========================================================================*
726433d6423SLionel Sambuc  *				do_period				     *
727433d6423SLionel Sambuc  *===========================================================================*/
728433d6423SLionel Sambuc void do_period(m_ptr)
729433d6423SLionel Sambuc message *m_ptr;
730433d6423SLionel Sambuc {
731433d6423SLionel Sambuc   register struct rproc *rp;
732433d6423SLionel Sambuc   register struct rprocpub *rpub;
733433d6423SLionel Sambuc   clock_t now = m_ptr->m_notify.timestamp;
734433d6423SLionel Sambuc   int s;
735433d6423SLionel Sambuc   long period;
736433d6423SLionel Sambuc 
737433d6423SLionel Sambuc   /* If an update is in progress, check its status. */
738433d6423SLionel Sambuc   if(rupdate.flags & RS_UPDATING) {
739433d6423SLionel Sambuc       update_period(m_ptr);
740433d6423SLionel Sambuc   }
741433d6423SLionel Sambuc 
742433d6423SLionel Sambuc   /* Search system services table. Only check slots that are in use and not
743433d6423SLionel Sambuc    * updating.
744433d6423SLionel Sambuc    */
745433d6423SLionel Sambuc   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
746433d6423SLionel Sambuc       rpub = rp->r_pub;
747433d6423SLionel Sambuc       if ((rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_UPDATING)) {
748433d6423SLionel Sambuc 
749433d6423SLionel Sambuc           /* Compute period. */
750433d6423SLionel Sambuc           period = rp->r_period;
751433d6423SLionel Sambuc           if(rp->r_flags & RS_INITIALIZING) {
752433d6423SLionel Sambuc               period = RS_INIT_T;
753433d6423SLionel Sambuc           }
754433d6423SLionel Sambuc 
755433d6423SLionel Sambuc           /* If the service is to be revived (because it repeatedly exited,
756433d6423SLionel Sambuc 	   * and was not directly restarted), the binary backoff field is
757433d6423SLionel Sambuc 	   * greater than zero.
758433d6423SLionel Sambuc 	   */
759433d6423SLionel Sambuc 	  if (rp->r_backoff > 0) {
760433d6423SLionel Sambuc               rp->r_backoff -= 1;
761433d6423SLionel Sambuc 	      if (rp->r_backoff == 0) {
762433d6423SLionel Sambuc 		  restart_service(rp);
763433d6423SLionel Sambuc 	      }
764433d6423SLionel Sambuc 	  }
765433d6423SLionel Sambuc 
766433d6423SLionel Sambuc 	  /* If the service was signaled with a SIGTERM and fails to respond,
767433d6423SLionel Sambuc 	   * kill the system service with a SIGKILL signal.
768433d6423SLionel Sambuc 	   */
769433d6423SLionel Sambuc 	  else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
770433d6423SLionel Sambuc 	   && rp->r_pid > 0) {
771433d6423SLionel Sambuc               rp->r_stop_tm = 0;
772433d6423SLionel Sambuc               crash_service(rp); /* simulate crash */
773433d6423SLionel Sambuc 	  }
774433d6423SLionel Sambuc 
775433d6423SLionel Sambuc 	  /* There seems to be no special conditions. If the service has a
776433d6423SLionel Sambuc 	   * period assigned check its status.
777433d6423SLionel Sambuc 	   */
778433d6423SLionel Sambuc 	  else if (period > 0) {
779433d6423SLionel Sambuc 
780433d6423SLionel Sambuc 	      /* Check if an answer to a status request is still pending. If
781433d6423SLionel Sambuc 	       * the service didn't respond within time, kill it to simulate
782433d6423SLionel Sambuc 	       * a crash. The failure will be detected and the service will
783433d6423SLionel Sambuc 	       * be restarted automatically. Give the service a free pass if
784433d6423SLionel Sambuc 	       * somebody is initializing. There may be some weird dependencies
785433d6423SLionel Sambuc 	       * if another service is, for example, restarting at the same
786433d6423SLionel Sambuc 	       * time.
787433d6423SLionel Sambuc 	       */
788433d6423SLionel Sambuc               if (rp->r_alive_tm < rp->r_check_tm) {
789433d6423SLionel Sambuc 	          if (now - rp->r_alive_tm > 2*period &&
790433d6423SLionel Sambuc 		      rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
791433d6423SLionel Sambuc 		      if(rs_verbose)
792433d6423SLionel Sambuc                            printf("RS: %s reported late\n", srv_to_string(rp));
793433d6423SLionel Sambuc 		      if(lookup_slot_by_flags(RS_INITIALIZING)) {
794433d6423SLionel Sambuc                            /* Skip for now. */
795433d6423SLionel Sambuc                            if(rs_verbose)
796433d6423SLionel Sambuc                                printf("RS: %s gets a free pass\n",
797433d6423SLionel Sambuc                                    srv_to_string(rp));
798433d6423SLionel Sambuc                            rp->r_alive_tm = now;
799433d6423SLionel Sambuc                            rp->r_check_tm = now+1;
800433d6423SLionel Sambuc                            continue;
801433d6423SLionel Sambuc 		      }
802433d6423SLionel Sambuc 		      rp->r_flags |= RS_NOPINGREPLY;
803433d6423SLionel Sambuc                       crash_service(rp); /* simulate crash */
804433d6423SLionel Sambuc 		  }
805433d6423SLionel Sambuc 	      }
806433d6423SLionel Sambuc 
807433d6423SLionel Sambuc 	      /* No answer pending. Check if a period expired since the last
808433d6423SLionel Sambuc 	       * check and, if so request the system service's status.
809433d6423SLionel Sambuc 	       */
810433d6423SLionel Sambuc 	      else if (now - rp->r_check_tm > rp->r_period) {
811433d6423SLionel Sambuc   		  ipc_notify(rpub->endpoint);		/* request status */
812433d6423SLionel Sambuc 		  rp->r_check_tm = now;			/* mark time */
813433d6423SLionel Sambuc               }
814433d6423SLionel Sambuc           }
815433d6423SLionel Sambuc       }
816433d6423SLionel Sambuc   }
817433d6423SLionel Sambuc 
818433d6423SLionel Sambuc   /* Reschedule a synchronous alarm for the next period. */
819433d6423SLionel Sambuc   if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
820433d6423SLionel Sambuc       panic("couldn't set alarm: %d", s);
821433d6423SLionel Sambuc }
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc /*===========================================================================*
824433d6423SLionel Sambuc  *			          do_sigchld				     *
825433d6423SLionel Sambuc  *===========================================================================*/
826433d6423SLionel Sambuc void do_sigchld()
827433d6423SLionel Sambuc {
828433d6423SLionel Sambuc /* PM informed us that there are dead children to cleanup. Go get them. */
829433d6423SLionel Sambuc   pid_t pid;
830433d6423SLionel Sambuc   int status;
831433d6423SLionel Sambuc   struct rproc *rp;
832433d6423SLionel Sambuc   struct rproc **rps;
833433d6423SLionel Sambuc   int i, nr_rps;
834433d6423SLionel Sambuc 
835433d6423SLionel Sambuc   if(rs_verbose)
836433d6423SLionel Sambuc      printf("RS: got SIGCHLD signal, cleaning up dead children\n");
837433d6423SLionel Sambuc 
838433d6423SLionel Sambuc   while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
839433d6423SLionel Sambuc       rp = lookup_slot_by_pid(pid);
840433d6423SLionel Sambuc       if(rp != NULL) {
841433d6423SLionel Sambuc 
842433d6423SLionel Sambuc           if(rs_verbose)
843433d6423SLionel Sambuc               printf("RS: %s exited via another signal manager\n",
844433d6423SLionel Sambuc                   srv_to_string(rp));
845433d6423SLionel Sambuc 
846433d6423SLionel Sambuc           /* The slot is still there. This means RS is not the signal
847433d6423SLionel Sambuc            * manager assigned to the process. Ignore the event but
848433d6423SLionel Sambuc            * free slots for all the service instances and send a late
849433d6423SLionel Sambuc            * reply if necessary.
850433d6423SLionel Sambuc            */
851433d6423SLionel Sambuc           get_service_instances(rp, &rps, &nr_rps);
852433d6423SLionel Sambuc           for(i=0;i<nr_rps;i++) {
853433d6423SLionel Sambuc               if(rupdate.flags & RS_UPDATING) {
854433d6423SLionel Sambuc                   rupdate.flags &= ~RS_UPDATING;
855433d6423SLionel Sambuc               }
856433d6423SLionel Sambuc               free_slot(rps[i]);
857433d6423SLionel Sambuc           }
858433d6423SLionel Sambuc       }
859433d6423SLionel Sambuc   }
860433d6423SLionel Sambuc }
861433d6423SLionel Sambuc 
862433d6423SLionel Sambuc /*===========================================================================*
863433d6423SLionel Sambuc  *				do_getsysinfo				     *
864433d6423SLionel Sambuc  *===========================================================================*/
865433d6423SLionel Sambuc int do_getsysinfo(m_ptr)
866433d6423SLionel Sambuc message *m_ptr;
867433d6423SLionel Sambuc {
868433d6423SLionel Sambuc   vir_bytes src_addr, dst_addr;
869433d6423SLionel Sambuc   int dst_proc;
870*0eabb93cSDavid van Moolenbroek   size_t size, len;
871433d6423SLionel Sambuc   int s;
872433d6423SLionel Sambuc 
873433d6423SLionel Sambuc   /* Check if the call can be allowed. */
874433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
875433d6423SLionel Sambuc       return s;
876433d6423SLionel Sambuc 
877*0eabb93cSDavid van Moolenbroek   dst_proc = m_ptr->m_source;
878*0eabb93cSDavid van Moolenbroek   dst_addr = m_ptr->m_lsys_getsysinfo.where;
879*0eabb93cSDavid van Moolenbroek   size = m_ptr->m_lsys_getsysinfo.size;
880*0eabb93cSDavid van Moolenbroek 
881433d6423SLionel Sambuc   switch(m_ptr->m_lsys_getsysinfo.what) {
882433d6423SLionel Sambuc   case SI_PROC_TAB:
883433d6423SLionel Sambuc   	src_addr = (vir_bytes) rproc;
884433d6423SLionel Sambuc   	len = sizeof(struct rproc) * NR_SYS_PROCS;
885433d6423SLionel Sambuc   	break;
886*0eabb93cSDavid van Moolenbroek   case SI_PROCALL_TAB:
887*0eabb93cSDavid van Moolenbroek 	/* Copy out both tables, one after the other. */
888*0eabb93cSDavid van Moolenbroek 	src_addr = (vir_bytes) rproc;
889*0eabb93cSDavid van Moolenbroek 	len = sizeof(struct rproc) * NR_SYS_PROCS;
890*0eabb93cSDavid van Moolenbroek 	if (len > size)
891*0eabb93cSDavid van Moolenbroek 		return EINVAL;
892*0eabb93cSDavid van Moolenbroek 	if ((s = sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)) != OK)
893*0eabb93cSDavid van Moolenbroek 		return s;
894*0eabb93cSDavid van Moolenbroek 	dst_addr += len;
895*0eabb93cSDavid van Moolenbroek 	size -= len;
896*0eabb93cSDavid van Moolenbroek 	/* FALLTHROUGH */
897433d6423SLionel Sambuc   case SI_PROCPUB_TAB:
898433d6423SLionel Sambuc   	src_addr = (vir_bytes) rprocpub;
899433d6423SLionel Sambuc   	len = sizeof(struct rprocpub) * NR_SYS_PROCS;
900433d6423SLionel Sambuc   	break;
901433d6423SLionel Sambuc   default:
902433d6423SLionel Sambuc   	return(EINVAL);
903433d6423SLionel Sambuc   }
904433d6423SLionel Sambuc 
905*0eabb93cSDavid van Moolenbroek   if (len != size)
906433d6423SLionel Sambuc 	return(EINVAL);
907433d6423SLionel Sambuc 
908433d6423SLionel Sambuc   return sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len);
909433d6423SLionel Sambuc }
910433d6423SLionel Sambuc 
911433d6423SLionel Sambuc /*===========================================================================*
912433d6423SLionel Sambuc  *				do_lookup				     *
913433d6423SLionel Sambuc  *===========================================================================*/
914433d6423SLionel Sambuc int do_lookup(m_ptr)
915433d6423SLionel Sambuc message *m_ptr;
916433d6423SLionel Sambuc {
917433d6423SLionel Sambuc 	static char namebuf[100];
918433d6423SLionel Sambuc 	int len, r;
919433d6423SLionel Sambuc 	struct rproc *rrp;
920433d6423SLionel Sambuc 	struct rprocpub *rrpub;
921433d6423SLionel Sambuc 
922433d6423SLionel Sambuc 	len = m_ptr->m_rs_req.name_len;
923433d6423SLionel Sambuc 
924433d6423SLionel Sambuc 	if(len < 2 || len >= sizeof(namebuf)) {
925433d6423SLionel Sambuc 		printf("RS: len too weird (%d)\n", len);
926433d6423SLionel Sambuc 		return EINVAL;
927433d6423SLionel Sambuc 	}
928433d6423SLionel Sambuc 
929433d6423SLionel Sambuc 	if((r=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->m_rs_req.name,
930433d6423SLionel Sambuc 		SELF, (vir_bytes) namebuf, len)) != OK) {
931433d6423SLionel Sambuc 		printf("RS: name copy failed\n");
932433d6423SLionel Sambuc 		return r;
933433d6423SLionel Sambuc 
934433d6423SLionel Sambuc 	}
935433d6423SLionel Sambuc 
936433d6423SLionel Sambuc 	namebuf[len] = '\0';
937433d6423SLionel Sambuc 
938433d6423SLionel Sambuc 	rrp = lookup_slot_by_label(namebuf);
939433d6423SLionel Sambuc 	if(!rrp) {
940433d6423SLionel Sambuc 		return ESRCH;
941433d6423SLionel Sambuc 	}
942433d6423SLionel Sambuc 	rrpub = rrp->r_pub;
943433d6423SLionel Sambuc 	m_ptr->m_rs_req.endpoint = rrpub->endpoint;
944433d6423SLionel Sambuc 
945433d6423SLionel Sambuc 	return OK;
946433d6423SLionel Sambuc }
947433d6423SLionel Sambuc 
948433d6423SLionel Sambuc /*===========================================================================*
949433d6423SLionel Sambuc  *				   check_request			     *
950433d6423SLionel Sambuc  *===========================================================================*/
951433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start)
952433d6423SLionel Sambuc {
953433d6423SLionel Sambuc   /* Verify scheduling parameters */
954433d6423SLionel Sambuc   if (rs_start->rss_scheduler != KERNEL &&
955433d6423SLionel Sambuc 	(rs_start->rss_scheduler < 0 ||
956433d6423SLionel Sambuc 	rs_start->rss_scheduler > LAST_SPECIAL_PROC_NR)) {
957433d6423SLionel Sambuc 	printf("RS: check_request: invalid scheduler %d\n",
958433d6423SLionel Sambuc 		rs_start->rss_scheduler);
959433d6423SLionel Sambuc 	return EINVAL;
960433d6423SLionel Sambuc   }
961433d6423SLionel Sambuc   if (rs_start->rss_priority >= NR_SCHED_QUEUES) {
962433d6423SLionel Sambuc 	printf("RS: check_request: priority %u out of range\n",
963433d6423SLionel Sambuc 		rs_start->rss_priority);
964433d6423SLionel Sambuc 	return EINVAL;
965433d6423SLionel Sambuc   }
966433d6423SLionel Sambuc   if (rs_start->rss_quantum <= 0) {
967433d6423SLionel Sambuc 	printf("RS: check_request: quantum %u out of range\n",
968433d6423SLionel Sambuc 		rs_start->rss_quantum);
969433d6423SLionel Sambuc 	return EINVAL;
970433d6423SLionel Sambuc   }
971433d6423SLionel Sambuc 
972433d6423SLionel Sambuc   if (rs_start->rss_cpu == RS_CPU_BSP)
973433d6423SLionel Sambuc 	  rs_start->rss_cpu = machine.bsp_id;
974433d6423SLionel Sambuc   else if (rs_start->rss_cpu == RS_CPU_DEFAULT) {
975433d6423SLionel Sambuc 	  /* keep the default value */
976433d6423SLionel Sambuc   } else if (rs_start->rss_cpu < 0)
977433d6423SLionel Sambuc 	  return EINVAL;
978433d6423SLionel Sambuc   else if (rs_start->rss_cpu > machine.processors_count) {
979433d6423SLionel Sambuc 	  printf("RS: cpu number %d out of range 0-%d, using BSP\n",
980433d6423SLionel Sambuc 			  rs_start->rss_cpu, machine.processors_count);
981433d6423SLionel Sambuc 	  rs_start->rss_cpu = machine.bsp_id;
982433d6423SLionel Sambuc   }
983433d6423SLionel Sambuc 
984433d6423SLionel Sambuc   /* Verify signal manager. */
985433d6423SLionel Sambuc   if (rs_start->rss_sigmgr != SELF &&
986433d6423SLionel Sambuc 	(rs_start->rss_sigmgr < 0 ||
987433d6423SLionel Sambuc 	rs_start->rss_sigmgr > LAST_SPECIAL_PROC_NR)) {
988433d6423SLionel Sambuc 	printf("RS: check_request: invalid signal manager %d\n",
989433d6423SLionel Sambuc 		rs_start->rss_sigmgr);
990433d6423SLionel Sambuc 	return EINVAL;
991433d6423SLionel Sambuc   }
992433d6423SLionel Sambuc 
993433d6423SLionel Sambuc   return OK;
994433d6423SLionel Sambuc }
995433d6423SLionel Sambuc 
996