xref: /minix3/minix/servers/rs/request.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*
2*433d6423SLionel Sambuc  * Changes:
3*433d6423SLionel Sambuc  *   Jan 22, 2010:  Created  (Cristiano Giuffrida)
4*433d6423SLionel Sambuc  */
5*433d6423SLionel Sambuc 
6*433d6423SLionel Sambuc #include "inc.h"
7*433d6423SLionel Sambuc 
8*433d6423SLionel Sambuc #include "kernel/proc.h"
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start);
11*433d6423SLionel Sambuc 
12*433d6423SLionel Sambuc /*===========================================================================*
13*433d6423SLionel Sambuc  *				   do_up				     *
14*433d6423SLionel Sambuc  *===========================================================================*/
15*433d6423SLionel Sambuc int do_up(m_ptr)
16*433d6423SLionel Sambuc message *m_ptr;					/* request message pointer */
17*433d6423SLionel Sambuc {
18*433d6423SLionel Sambuc /* A request was made to start a new system service. */
19*433d6423SLionel Sambuc   struct rproc *rp;
20*433d6423SLionel Sambuc   struct rprocpub *rpub;
21*433d6423SLionel Sambuc   int r;
22*433d6423SLionel Sambuc   struct rs_start rs_start;
23*433d6423SLionel Sambuc   int noblock;
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
26*433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_UP, NULL)) != OK)
27*433d6423SLionel Sambuc       return r;
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc   /* Allocate a new system service slot. */
30*433d6423SLionel Sambuc   r = alloc_slot(&rp);
31*433d6423SLionel Sambuc   if(r != OK) {
32*433d6423SLionel Sambuc       printf("RS: do_up: unable to allocate a new slot: %d\n", r);
33*433d6423SLionel Sambuc       return r;
34*433d6423SLionel Sambuc   }
35*433d6423SLionel Sambuc   rpub = rp->r_pub;
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc   /* Copy the request structure. */
38*433d6423SLionel Sambuc   r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
39*433d6423SLionel Sambuc   if (r != OK) {
40*433d6423SLionel Sambuc       return r;
41*433d6423SLionel Sambuc   }
42*433d6423SLionel Sambuc   r = check_request(&rs_start);
43*433d6423SLionel Sambuc   if (r != OK) {
44*433d6423SLionel Sambuc       return r;
45*433d6423SLionel Sambuc   }
46*433d6423SLionel Sambuc   noblock = (rs_start.rss_flags & RSS_NOBLOCK);
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc   /* Initialize the slot as requested. */
49*433d6423SLionel Sambuc   r = init_slot(rp, &rs_start, m_ptr->m_source);
50*433d6423SLionel Sambuc   if(r != OK) {
51*433d6423SLionel Sambuc       printf("RS: do_up: unable to init the new slot: %d\n", r);
52*433d6423SLionel Sambuc       return r;
53*433d6423SLionel Sambuc   }
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc   /* Check for duplicates */
56*433d6423SLionel Sambuc   if(lookup_slot_by_label(rpub->label)) {
57*433d6423SLionel Sambuc       printf("RS: service with the same label '%s' already exists\n",
58*433d6423SLionel Sambuc           rpub->label);
59*433d6423SLionel Sambuc       return EBUSY;
60*433d6423SLionel Sambuc   }
61*433d6423SLionel Sambuc   if(rpub->dev_nr>0 && lookup_slot_by_dev_nr(rpub->dev_nr)) {
62*433d6423SLionel Sambuc       printf("RS: service with the same device number %d already exists\n",
63*433d6423SLionel Sambuc           rpub->dev_nr);
64*433d6423SLionel Sambuc       return EBUSY;
65*433d6423SLionel Sambuc   }
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc   /* All information was gathered. Now try to start the system service. */
68*433d6423SLionel Sambuc   r = start_service(rp);
69*433d6423SLionel Sambuc   if(r != OK) {
70*433d6423SLionel Sambuc       return r;
71*433d6423SLionel Sambuc   }
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc   /* Unblock the caller immediately if requested. */
74*433d6423SLionel Sambuc   if(noblock) {
75*433d6423SLionel Sambuc       return OK;
76*433d6423SLionel Sambuc   }
77*433d6423SLionel Sambuc 
78*433d6423SLionel Sambuc   /* Late reply - send a reply when service completes initialization. */
79*433d6423SLionel Sambuc   rp->r_flags |= RS_LATEREPLY;
80*433d6423SLionel Sambuc   rp->r_caller = m_ptr->m_source;
81*433d6423SLionel Sambuc   rp->r_caller_request = RS_UP;
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc   return EDONTREPLY;
84*433d6423SLionel Sambuc }
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc /*===========================================================================*
87*433d6423SLionel Sambuc  *				do_down					     *
88*433d6423SLionel Sambuc  *===========================================================================*/
89*433d6423SLionel Sambuc int do_down(message *m_ptr)
90*433d6423SLionel Sambuc {
91*433d6423SLionel Sambuc   register struct rproc *rp;
92*433d6423SLionel Sambuc   int s;
93*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
94*433d6423SLionel Sambuc 
95*433d6423SLionel Sambuc   /* Copy label. */
96*433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
97*433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
98*433d6423SLionel Sambuc   if(s != OK) {
99*433d6423SLionel Sambuc       return s;
100*433d6423SLionel Sambuc   }
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc   /* Lookup slot by label. */
103*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
104*433d6423SLionel Sambuc   if(!rp) {
105*433d6423SLionel Sambuc       if(rs_verbose)
106*433d6423SLionel Sambuc           printf("RS: do_down: service '%s' not found\n", label);
107*433d6423SLionel Sambuc       return(ESRCH);
108*433d6423SLionel Sambuc   }
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
111*433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_DOWN, rp)) != OK)
112*433d6423SLionel Sambuc       return s;
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc   /* Stop service. */
115*433d6423SLionel Sambuc   if (rp->r_flags & RS_TERMINATED) {
116*433d6423SLionel Sambuc         /* A recovery script is requesting us to bring down the service.
117*433d6423SLionel Sambuc          * The service is already gone, simply perform cleanup.
118*433d6423SLionel Sambuc          */
119*433d6423SLionel Sambuc         if(rs_verbose)
120*433d6423SLionel Sambuc             printf("RS: recovery script performs service down...\n");
121*433d6423SLionel Sambuc   	unpublish_service(rp);
122*433d6423SLionel Sambuc   	cleanup_service(rp);
123*433d6423SLionel Sambuc     	return(OK);
124*433d6423SLionel Sambuc   }
125*433d6423SLionel Sambuc   stop_service(rp,RS_EXITING);
126*433d6423SLionel Sambuc 
127*433d6423SLionel Sambuc   /* Late reply - send a reply when service dies. */
128*433d6423SLionel Sambuc   rp->r_flags |= RS_LATEREPLY;
129*433d6423SLionel Sambuc   rp->r_caller = m_ptr->m_source;
130*433d6423SLionel Sambuc   rp->r_caller_request = RS_DOWN;
131*433d6423SLionel Sambuc 
132*433d6423SLionel Sambuc   return EDONTREPLY;
133*433d6423SLionel Sambuc }
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc /*===========================================================================*
136*433d6423SLionel Sambuc  *				do_restart				     *
137*433d6423SLionel Sambuc  *===========================================================================*/
138*433d6423SLionel Sambuc int do_restart(message *m_ptr)
139*433d6423SLionel Sambuc {
140*433d6423SLionel Sambuc   struct rproc *rp;
141*433d6423SLionel Sambuc   int s, r;
142*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
143*433d6423SLionel Sambuc   char script[MAX_SCRIPT_LEN];
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc   /* Copy label. */
146*433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
147*433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
148*433d6423SLionel Sambuc   if(s != OK) {
149*433d6423SLionel Sambuc       return s;
150*433d6423SLionel Sambuc   }
151*433d6423SLionel Sambuc 
152*433d6423SLionel Sambuc   /* Lookup slot by label. */
153*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
154*433d6423SLionel Sambuc   if(!rp) {
155*433d6423SLionel Sambuc       if(rs_verbose)
156*433d6423SLionel Sambuc           printf("RS: do_restart: service '%s' not found\n", label);
157*433d6423SLionel Sambuc       return(ESRCH);
158*433d6423SLionel Sambuc   }
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
161*433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_RESTART, rp)) != OK)
162*433d6423SLionel Sambuc       return r;
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc   /* We can only be asked to restart a service from a recovery script. */
165*433d6423SLionel Sambuc   if (! (rp->r_flags & RS_TERMINATED) ) {
166*433d6423SLionel Sambuc       if(rs_verbose)
167*433d6423SLionel Sambuc           printf("RS: %s is still running\n", srv_to_string(rp));
168*433d6423SLionel Sambuc       return EBUSY;
169*433d6423SLionel Sambuc   }
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc   if(rs_verbose)
172*433d6423SLionel Sambuc       printf("RS: recovery script performs service restart...\n");
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc   /* Restart the service, but make sure we don't call the script again. */
175*433d6423SLionel Sambuc   strcpy(script, rp->r_script);
176*433d6423SLionel Sambuc   rp->r_script[0] = '\0';
177*433d6423SLionel Sambuc   restart_service(rp);
178*433d6423SLionel Sambuc   strcpy(rp->r_script, script);
179*433d6423SLionel Sambuc 
180*433d6423SLionel Sambuc   return OK;
181*433d6423SLionel Sambuc }
182*433d6423SLionel Sambuc 
183*433d6423SLionel Sambuc /*===========================================================================*
184*433d6423SLionel Sambuc  *				do_clone				     *
185*433d6423SLionel Sambuc  *===========================================================================*/
186*433d6423SLionel Sambuc int do_clone(message *m_ptr)
187*433d6423SLionel Sambuc {
188*433d6423SLionel Sambuc   struct rproc *rp;
189*433d6423SLionel Sambuc   struct rprocpub *rpub;
190*433d6423SLionel Sambuc   int s, r;
191*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
192*433d6423SLionel Sambuc 
193*433d6423SLionel Sambuc   /* Copy label. */
194*433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
195*433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
196*433d6423SLionel Sambuc   if(s != OK) {
197*433d6423SLionel Sambuc       return s;
198*433d6423SLionel Sambuc   }
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc   /* Lookup slot by label. */
201*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
202*433d6423SLionel Sambuc   if(!rp) {
203*433d6423SLionel Sambuc       if(rs_verbose)
204*433d6423SLionel Sambuc           printf("RS: do_clone: service '%s' not found\n", label);
205*433d6423SLionel Sambuc       return(ESRCH);
206*433d6423SLionel Sambuc   }
207*433d6423SLionel Sambuc   rpub = rp->r_pub;
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
210*433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_CLONE, rp)) != OK)
211*433d6423SLionel Sambuc       return r;
212*433d6423SLionel Sambuc 
213*433d6423SLionel Sambuc   /* Don't clone if a replica is already available. */
214*433d6423SLionel Sambuc   if(rp->r_next_rp) {
215*433d6423SLionel Sambuc       return EEXIST;
216*433d6423SLionel Sambuc   }
217*433d6423SLionel Sambuc 
218*433d6423SLionel Sambuc   /* Clone the service as requested. */
219*433d6423SLionel Sambuc   rpub->sys_flags |= SF_USE_REPL;
220*433d6423SLionel Sambuc   if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
221*433d6423SLionel Sambuc       rpub->sys_flags &= ~SF_USE_REPL;
222*433d6423SLionel Sambuc       return r;
223*433d6423SLionel Sambuc   }
224*433d6423SLionel Sambuc 
225*433d6423SLionel Sambuc   return OK;
226*433d6423SLionel Sambuc }
227*433d6423SLionel Sambuc 
228*433d6423SLionel Sambuc /*===========================================================================*
229*433d6423SLionel Sambuc  *				    do_edit				     *
230*433d6423SLionel Sambuc  *===========================================================================*/
231*433d6423SLionel Sambuc int do_edit(message *m_ptr)
232*433d6423SLionel Sambuc {
233*433d6423SLionel Sambuc   struct rproc *rp;
234*433d6423SLionel Sambuc   struct rprocpub *rpub;
235*433d6423SLionel Sambuc   struct rs_start rs_start;
236*433d6423SLionel Sambuc   int r;
237*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc   /* Copy the request structure. */
240*433d6423SLionel Sambuc   r = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
241*433d6423SLionel Sambuc   if (r != OK) {
242*433d6423SLionel Sambuc       return r;
243*433d6423SLionel Sambuc   }
244*433d6423SLionel Sambuc 
245*433d6423SLionel Sambuc   /* Copy label. */
246*433d6423SLionel Sambuc   r = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
247*433d6423SLionel Sambuc       rs_start.rss_label.l_len, label, sizeof(label));
248*433d6423SLionel Sambuc   if(r != OK) {
249*433d6423SLionel Sambuc       return r;
250*433d6423SLionel Sambuc   }
251*433d6423SLionel Sambuc 
252*433d6423SLionel Sambuc   /* Lookup slot by label. */
253*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
254*433d6423SLionel Sambuc   if(!rp) {
255*433d6423SLionel Sambuc       if(rs_verbose)
256*433d6423SLionel Sambuc           printf("RS: do_edit: service '%s' not found\n", label);
257*433d6423SLionel Sambuc       return ESRCH;
258*433d6423SLionel Sambuc   }
259*433d6423SLionel Sambuc   rpub = rp->r_pub;
260*433d6423SLionel Sambuc 
261*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
262*433d6423SLionel Sambuc   if((r = check_call_permission(m_ptr->m_source, RS_EDIT, rp)) != OK)
263*433d6423SLionel Sambuc       return r;
264*433d6423SLionel Sambuc 
265*433d6423SLionel Sambuc   if(rs_verbose)
266*433d6423SLionel Sambuc       printf("RS: %s edits settings\n", srv_to_string(rp));
267*433d6423SLionel Sambuc 
268*433d6423SLionel Sambuc   /* Synch the privilege structure with the kernel. */
269*433d6423SLionel Sambuc   if ((r = sys_getpriv(&rp->r_priv, rpub->endpoint)) != OK) {
270*433d6423SLionel Sambuc       printf("RS: do_edit: unable to synch privilege structure: %d\n", r);
271*433d6423SLionel Sambuc       return r;
272*433d6423SLionel Sambuc   }
273*433d6423SLionel Sambuc 
274*433d6423SLionel Sambuc   /* Tell scheduler this process is finished */
275*433d6423SLionel Sambuc   if ((r = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
276*433d6423SLionel Sambuc       printf("RS: do_edit: scheduler won't give up process: %d\n", r);
277*433d6423SLionel Sambuc       return r;
278*433d6423SLionel Sambuc   }
279*433d6423SLionel Sambuc 
280*433d6423SLionel Sambuc   /* Edit the slot as requested. */
281*433d6423SLionel Sambuc   if((r = edit_slot(rp, &rs_start, m_ptr->m_source)) != OK) {
282*433d6423SLionel Sambuc       printf("RS: do_edit: unable to edit the existing slot: %d\n", r);
283*433d6423SLionel Sambuc       return r;
284*433d6423SLionel Sambuc   }
285*433d6423SLionel Sambuc 
286*433d6423SLionel Sambuc   /* Update privilege structure. */
287*433d6423SLionel Sambuc   r = sys_privctl(rpub->endpoint, SYS_PRIV_UPDATE_SYS, &rp->r_priv);
288*433d6423SLionel Sambuc   if(r != OK) {
289*433d6423SLionel Sambuc       printf("RS: do_edit: unable to update privilege structure: %d\n", r);
290*433d6423SLionel Sambuc       return r;
291*433d6423SLionel Sambuc   }
292*433d6423SLionel Sambuc 
293*433d6423SLionel Sambuc   /* Update VM calls. */
294*433d6423SLionel Sambuc   if ((r = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0],
295*433d6423SLionel Sambuc     !!(rp->r_priv.s_flags & SYS_PROC))) != OK) {
296*433d6423SLionel Sambuc       printf("RS: do_edit: failed: %d\n", r);
297*433d6423SLionel Sambuc       return r;
298*433d6423SLionel Sambuc   }
299*433d6423SLionel Sambuc 
300*433d6423SLionel Sambuc   /* Reinitialize scheduling. */
301*433d6423SLionel Sambuc   if ((r = sched_init_proc(rp)) != OK) {
302*433d6423SLionel Sambuc       printf("RS: do_edit: unable to reinitialize scheduling: %d\n", r);
303*433d6423SLionel Sambuc       return r;
304*433d6423SLionel Sambuc   }
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc   /* Cleanup old replicas and create a new one, if necessary. */
307*433d6423SLionel Sambuc   if(rpub->sys_flags & SF_USE_REPL) {
308*433d6423SLionel Sambuc       if(rp->r_next_rp) {
309*433d6423SLionel Sambuc           cleanup_service(rp->r_next_rp);
310*433d6423SLionel Sambuc           rp->r_next_rp = NULL;
311*433d6423SLionel Sambuc       }
312*433d6423SLionel Sambuc       if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
313*433d6423SLionel Sambuc           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
314*433d6423SLionel Sambuc       }
315*433d6423SLionel Sambuc   }
316*433d6423SLionel Sambuc 
317*433d6423SLionel Sambuc   return OK;
318*433d6423SLionel Sambuc }
319*433d6423SLionel Sambuc 
320*433d6423SLionel Sambuc /*===========================================================================*
321*433d6423SLionel Sambuc  *				do_refresh				     *
322*433d6423SLionel Sambuc  *===========================================================================*/
323*433d6423SLionel Sambuc int do_refresh(message *m_ptr)
324*433d6423SLionel Sambuc {
325*433d6423SLionel Sambuc   register struct rproc *rp;
326*433d6423SLionel Sambuc   int s;
327*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
328*433d6423SLionel Sambuc 
329*433d6423SLionel Sambuc   /* Copy label. */
330*433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, m_ptr->m_rs_req.addr,
331*433d6423SLionel Sambuc       m_ptr->m_rs_req.len, label, sizeof(label));
332*433d6423SLionel Sambuc   if(s != OK) {
333*433d6423SLionel Sambuc       return s;
334*433d6423SLionel Sambuc   }
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc   /* Lookup slot by label. */
337*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
338*433d6423SLionel Sambuc   if(!rp) {
339*433d6423SLionel Sambuc       if(rs_verbose)
340*433d6423SLionel Sambuc           printf("RS: do_refresh: service '%s' not found\n", label);
341*433d6423SLionel Sambuc       return(ESRCH);
342*433d6423SLionel Sambuc   }
343*433d6423SLionel Sambuc 
344*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
345*433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_REFRESH, rp)) != OK)
346*433d6423SLionel Sambuc       return s;
347*433d6423SLionel Sambuc 
348*433d6423SLionel Sambuc   /* Refresh service. */
349*433d6423SLionel Sambuc   if(rs_verbose)
350*433d6423SLionel Sambuc       printf("RS: %s refreshing\n", srv_to_string(rp));
351*433d6423SLionel Sambuc   stop_service(rp,RS_REFRESHING);
352*433d6423SLionel Sambuc 
353*433d6423SLionel Sambuc   return OK;
354*433d6423SLionel Sambuc }
355*433d6423SLionel Sambuc 
356*433d6423SLionel Sambuc /*===========================================================================*
357*433d6423SLionel Sambuc  *				do_shutdown				     *
358*433d6423SLionel Sambuc  *===========================================================================*/
359*433d6423SLionel Sambuc int do_shutdown(message *m_ptr)
360*433d6423SLionel Sambuc {
361*433d6423SLionel Sambuc   int slot_nr;
362*433d6423SLionel Sambuc   struct rproc *rp;
363*433d6423SLionel Sambuc   int r;
364*433d6423SLionel Sambuc 
365*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
366*433d6423SLionel Sambuc   if (m_ptr != NULL) {
367*433d6423SLionel Sambuc       if((r = check_call_permission(m_ptr->m_source, RS_SHUTDOWN, NULL)) != OK)
368*433d6423SLionel Sambuc           return r;
369*433d6423SLionel Sambuc   }
370*433d6423SLionel Sambuc 
371*433d6423SLionel Sambuc   if(rs_verbose)
372*433d6423SLionel Sambuc       printf("RS: shutting down...\n");
373*433d6423SLionel Sambuc 
374*433d6423SLionel Sambuc   /* Set flag to tell RS we are shutting down. */
375*433d6423SLionel Sambuc   shutting_down = TRUE;
376*433d6423SLionel Sambuc 
377*433d6423SLionel Sambuc   /* Don't restart dead services. */
378*433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
379*433d6423SLionel Sambuc       rp = &rproc[slot_nr];
380*433d6423SLionel Sambuc       if (rp->r_flags & RS_IN_USE) {
381*433d6423SLionel Sambuc           rp->r_flags |= RS_EXITING;
382*433d6423SLionel Sambuc       }
383*433d6423SLionel Sambuc   }
384*433d6423SLionel Sambuc   return(OK);
385*433d6423SLionel Sambuc }
386*433d6423SLionel Sambuc 
387*433d6423SLionel Sambuc /*===========================================================================*
388*433d6423SLionel Sambuc  *				do_init_ready				     *
389*433d6423SLionel Sambuc  *===========================================================================*/
390*433d6423SLionel Sambuc int do_init_ready(message *m_ptr)
391*433d6423SLionel Sambuc {
392*433d6423SLionel Sambuc   int who_p;
393*433d6423SLionel Sambuc   message m;
394*433d6423SLionel Sambuc   struct rproc *rp;
395*433d6423SLionel Sambuc   struct rprocpub *rpub;
396*433d6423SLionel Sambuc   int result, is_rs;
397*433d6423SLionel Sambuc   int r;
398*433d6423SLionel Sambuc 
399*433d6423SLionel Sambuc   is_rs = (m_ptr->m_source == RS_PROC_NR);
400*433d6423SLionel Sambuc   who_p = _ENDPOINT_P(m_ptr->m_source);
401*433d6423SLionel Sambuc   result = m_ptr->m_rs_init.result;
402*433d6423SLionel Sambuc 
403*433d6423SLionel Sambuc   /* Check for RS failing initialization first. */
404*433d6423SLionel Sambuc   if(is_rs && result != OK) {
405*433d6423SLionel Sambuc       return result;
406*433d6423SLionel Sambuc   }
407*433d6423SLionel Sambuc 
408*433d6423SLionel Sambuc   rp = rproc_ptr[who_p];
409*433d6423SLionel Sambuc   rpub = rp->r_pub;
410*433d6423SLionel Sambuc 
411*433d6423SLionel Sambuc   /* Make sure the originating service was requested to initialize. */
412*433d6423SLionel Sambuc   if(! (rp->r_flags & RS_INITIALIZING) ) {
413*433d6423SLionel Sambuc       if(rs_verbose)
414*433d6423SLionel Sambuc           printf("RS: do_init_ready: got unexpected init ready msg from %d\n",
415*433d6423SLionel Sambuc               m_ptr->m_source);
416*433d6423SLionel Sambuc       return EINVAL;
417*433d6423SLionel Sambuc   }
418*433d6423SLionel Sambuc 
419*433d6423SLionel Sambuc   /* Check if something went wrong and the service failed to init.
420*433d6423SLionel Sambuc    * In that case, kill the service.
421*433d6423SLionel Sambuc    */
422*433d6423SLionel Sambuc   if(result != OK) {
423*433d6423SLionel Sambuc       if(rs_verbose)
424*433d6423SLionel Sambuc           printf("RS: %s initialization error: %s\n", srv_to_string(rp),
425*433d6423SLionel Sambuc               init_strerror(result));
426*433d6423SLionel Sambuc       if (result == ERESTART)
427*433d6423SLionel Sambuc           rp->r_flags |= RS_REINCARNATE;
428*433d6423SLionel Sambuc       crash_service(rp); /* simulate crash */
429*433d6423SLionel Sambuc       return EDONTREPLY;
430*433d6423SLionel Sambuc   }
431*433d6423SLionel Sambuc 
432*433d6423SLionel Sambuc   /* Mark the slot as no longer initializing. */
433*433d6423SLionel Sambuc   rp->r_flags &= ~RS_INITIALIZING;
434*433d6423SLionel Sambuc   rp->r_check_tm = 0;
435*433d6423SLionel Sambuc   getticks(&rp->r_alive_tm);
436*433d6423SLionel Sambuc 
437*433d6423SLionel Sambuc   /* Reply and unblock the service before doing anything else. */
438*433d6423SLionel Sambuc   m.m_type = OK;
439*433d6423SLionel Sambuc   reply(rpub->endpoint, rp, &m);
440*433d6423SLionel Sambuc 
441*433d6423SLionel Sambuc   /* See if a late reply has to be sent. */
442*433d6423SLionel Sambuc   late_reply(rp, OK);
443*433d6423SLionel Sambuc 
444*433d6423SLionel Sambuc   if(rs_verbose)
445*433d6423SLionel Sambuc       printf("RS: %s initialized\n", srv_to_string(rp));
446*433d6423SLionel Sambuc 
447*433d6423SLionel Sambuc   /* If the service has completed initialization after a live
448*433d6423SLionel Sambuc    * update, end the update now.
449*433d6423SLionel Sambuc    */
450*433d6423SLionel Sambuc   if(rp->r_flags & RS_UPDATING) {
451*433d6423SLionel Sambuc       printf("RS: update succeeded\n");
452*433d6423SLionel Sambuc       end_update(OK, RS_DONTREPLY);
453*433d6423SLionel Sambuc   }
454*433d6423SLionel Sambuc 
455*433d6423SLionel Sambuc   /* If the service has completed initialization after a crash
456*433d6423SLionel Sambuc    * make the new instance active and cleanup the old replica.
457*433d6423SLionel Sambuc    */
458*433d6423SLionel Sambuc   if(rp->r_prev_rp) {
459*433d6423SLionel Sambuc       cleanup_service(rp->r_prev_rp);
460*433d6423SLionel Sambuc       rp->r_prev_rp = NULL;
461*433d6423SLionel Sambuc       rp->r_restarts += 1;
462*433d6423SLionel Sambuc 
463*433d6423SLionel Sambuc       if(rs_verbose)
464*433d6423SLionel Sambuc           printf("RS: %s completed restart\n", srv_to_string(rp));
465*433d6423SLionel Sambuc   }
466*433d6423SLionel Sambuc 
467*433d6423SLionel Sambuc   /* If we must keep a replica of this system service, create it now. */
468*433d6423SLionel Sambuc   if(rpub->sys_flags & SF_USE_REPL) {
469*433d6423SLionel Sambuc       if ((r = clone_service(rp, RST_SYS_PROC)) != OK) {
470*433d6423SLionel Sambuc           printf("RS: warning: unable to clone %s\n", srv_to_string(rp));
471*433d6423SLionel Sambuc       }
472*433d6423SLionel Sambuc   }
473*433d6423SLionel Sambuc 
474*433d6423SLionel Sambuc   return is_rs ? OK : EDONTREPLY; /* return what the caller expects */
475*433d6423SLionel Sambuc }
476*433d6423SLionel Sambuc 
477*433d6423SLionel Sambuc /*===========================================================================*
478*433d6423SLionel Sambuc  *				do_update				     *
479*433d6423SLionel Sambuc  *===========================================================================*/
480*433d6423SLionel Sambuc int do_update(message *m_ptr)
481*433d6423SLionel Sambuc {
482*433d6423SLionel Sambuc   struct rproc *rp;
483*433d6423SLionel Sambuc   struct rproc *new_rp;
484*433d6423SLionel Sambuc   struct rprocpub *rpub;
485*433d6423SLionel Sambuc   struct rs_start rs_start;
486*433d6423SLionel Sambuc   int noblock, do_self_update;
487*433d6423SLionel Sambuc   int s;
488*433d6423SLionel Sambuc   char label[RS_MAX_LABEL_LEN];
489*433d6423SLionel Sambuc   int lu_state;
490*433d6423SLionel Sambuc   int prepare_maxtime;
491*433d6423SLionel Sambuc 
492*433d6423SLionel Sambuc   /* Copy the request structure. */
493*433d6423SLionel Sambuc   s = copy_rs_start(m_ptr->m_source, m_ptr->m_rs_req.addr, &rs_start);
494*433d6423SLionel Sambuc   if (s != OK) {
495*433d6423SLionel Sambuc       return s;
496*433d6423SLionel Sambuc   }
497*433d6423SLionel Sambuc   noblock = (rs_start.rss_flags & RSS_NOBLOCK);
498*433d6423SLionel Sambuc   do_self_update = (rs_start.rss_flags & RSS_SELF_LU);
499*433d6423SLionel Sambuc   s = check_request(&rs_start);
500*433d6423SLionel Sambuc   if (s != OK) {
501*433d6423SLionel Sambuc       return s;
502*433d6423SLionel Sambuc   }
503*433d6423SLionel Sambuc 
504*433d6423SLionel Sambuc   /* Copy label. */
505*433d6423SLionel Sambuc   s = copy_label(m_ptr->m_source, rs_start.rss_label.l_addr,
506*433d6423SLionel Sambuc       rs_start.rss_label.l_len, label, sizeof(label));
507*433d6423SLionel Sambuc   if(s != OK) {
508*433d6423SLionel Sambuc       return s;
509*433d6423SLionel Sambuc   }
510*433d6423SLionel Sambuc 
511*433d6423SLionel Sambuc   /* Lookup slot by label. */
512*433d6423SLionel Sambuc   rp = lookup_slot_by_label(label);
513*433d6423SLionel Sambuc   if(!rp) {
514*433d6423SLionel Sambuc       if(rs_verbose)
515*433d6423SLionel Sambuc           printf("RS: do_update: service '%s' not found\n", label);
516*433d6423SLionel Sambuc       return ESRCH;
517*433d6423SLionel Sambuc   }
518*433d6423SLionel Sambuc   rpub = rp->r_pub;
519*433d6423SLionel Sambuc 
520*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
521*433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, RS_UPDATE, rp)) != OK)
522*433d6423SLionel Sambuc       return s;
523*433d6423SLionel Sambuc 
524*433d6423SLionel Sambuc   /* Retrieve live update state. */
525*433d6423SLionel Sambuc   lu_state = m_ptr->m_rs_update.state;
526*433d6423SLionel Sambuc   if(lu_state == SEF_LU_STATE_NULL) {
527*433d6423SLionel Sambuc       return(EINVAL);
528*433d6423SLionel Sambuc   }
529*433d6423SLionel Sambuc 
530*433d6423SLionel Sambuc   /* Retrieve prepare max time. */
531*433d6423SLionel Sambuc   prepare_maxtime = m_ptr->m_rs_update.prepare_maxtime;
532*433d6423SLionel Sambuc   if(prepare_maxtime) {
533*433d6423SLionel Sambuc       if(prepare_maxtime < 0 || prepare_maxtime > RS_MAX_PREPARE_MAXTIME) {
534*433d6423SLionel Sambuc           return(EINVAL);
535*433d6423SLionel Sambuc       }
536*433d6423SLionel Sambuc   }
537*433d6423SLionel Sambuc   else {
538*433d6423SLionel Sambuc       prepare_maxtime = RS_DEFAULT_PREPARE_MAXTIME;
539*433d6423SLionel Sambuc   }
540*433d6423SLionel Sambuc 
541*433d6423SLionel Sambuc   /* Make sure we are not already updating. */
542*433d6423SLionel Sambuc   if(rupdate.flags & RS_UPDATING) {
543*433d6423SLionel Sambuc       if(rs_verbose)
544*433d6423SLionel Sambuc 	  printf("RS: do_update: an update is already in progress\n");
545*433d6423SLionel Sambuc       return EBUSY;
546*433d6423SLionel Sambuc   }
547*433d6423SLionel Sambuc 
548*433d6423SLionel Sambuc   /* A self update live updates a service instance into a replica, a regular
549*433d6423SLionel Sambuc    * update live updates a service instance into a new version, as specified
550*433d6423SLionel Sambuc    * by the given binary.
551*433d6423SLionel Sambuc    */
552*433d6423SLionel Sambuc   if(do_self_update) {
553*433d6423SLionel Sambuc       if(rs_verbose)
554*433d6423SLionel Sambuc           printf("RS: %s performs self update\n", srv_to_string(rp));
555*433d6423SLionel Sambuc 
556*433d6423SLionel Sambuc       /* Clone the system service and use the replica as the new version. */
557*433d6423SLionel Sambuc       s = clone_service(rp, LU_SYS_PROC);
558*433d6423SLionel Sambuc       if(s != OK) {
559*433d6423SLionel Sambuc           printf("RS: do_update: unable to clone service: %d\n", s);
560*433d6423SLionel Sambuc           return s;
561*433d6423SLionel Sambuc       }
562*433d6423SLionel Sambuc   }
563*433d6423SLionel Sambuc   else {
564*433d6423SLionel Sambuc       if(rs_verbose)
565*433d6423SLionel Sambuc           printf("RS: %s performs regular update\n", srv_to_string(rp));
566*433d6423SLionel Sambuc 
567*433d6423SLionel Sambuc       /* Allocate a system service slot for the new version. */
568*433d6423SLionel Sambuc       s = alloc_slot(&new_rp);
569*433d6423SLionel Sambuc       if(s != OK) {
570*433d6423SLionel Sambuc           printf("RS: do_update: unable to allocate a new slot: %d\n", s);
571*433d6423SLionel Sambuc           return s;
572*433d6423SLionel Sambuc       }
573*433d6423SLionel Sambuc 
574*433d6423SLionel Sambuc       /* Initialize the slot as requested. */
575*433d6423SLionel Sambuc       s = init_slot(new_rp, &rs_start, m_ptr->m_source);
576*433d6423SLionel Sambuc       if(s != OK) {
577*433d6423SLionel Sambuc           printf("RS: do_update: unable to init the new slot: %d\n", s);
578*433d6423SLionel Sambuc           return s;
579*433d6423SLionel Sambuc       }
580*433d6423SLionel Sambuc 
581*433d6423SLionel Sambuc       /* Let the new version inherit defaults from the old one. */
582*433d6423SLionel Sambuc       inherit_service_defaults(rp, new_rp);
583*433d6423SLionel Sambuc 
584*433d6423SLionel Sambuc       /* Link the two versions. */
585*433d6423SLionel Sambuc       rp->r_new_rp = new_rp;
586*433d6423SLionel Sambuc       new_rp->r_old_rp = rp;
587*433d6423SLionel Sambuc 
588*433d6423SLionel Sambuc       /* Create new version of the service but don't let it run. */
589*433d6423SLionel Sambuc       new_rp->r_priv.s_flags |= LU_SYS_PROC;
590*433d6423SLionel Sambuc       s = create_service(new_rp);
591*433d6423SLionel Sambuc       if(s != OK) {
592*433d6423SLionel Sambuc           printf("RS: do_update: unable to create a new service: %d\n", s);
593*433d6423SLionel Sambuc           return s;
594*433d6423SLionel Sambuc       }
595*433d6423SLionel Sambuc   }
596*433d6423SLionel Sambuc 
597*433d6423SLionel Sambuc   /* Mark both versions as updating. */
598*433d6423SLionel Sambuc   rp->r_flags |= RS_UPDATING;
599*433d6423SLionel Sambuc   rp->r_new_rp->r_flags |= RS_UPDATING;
600*433d6423SLionel Sambuc   rupdate.flags |= RS_UPDATING;
601*433d6423SLionel Sambuc   getticks(&rupdate.prepare_tm);
602*433d6423SLionel Sambuc   rupdate.prepare_maxtime = prepare_maxtime;
603*433d6423SLionel Sambuc   rupdate.rp = rp;
604*433d6423SLionel Sambuc 
605*433d6423SLionel Sambuc   if(rs_verbose)
606*433d6423SLionel Sambuc     printf("RS: %s updating\n", srv_to_string(rp));
607*433d6423SLionel Sambuc 
608*433d6423SLionel Sambuc   /* If RS is updating, set up signal managers for the new instance.
609*433d6423SLionel Sambuc    * The current RS instance must be made the backup signal manager to
610*433d6423SLionel Sambuc    * support rollback in case of a crash during initialization.
611*433d6423SLionel Sambuc    */
612*433d6423SLionel Sambuc   if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
613*433d6423SLionel Sambuc       new_rp = rp->r_new_rp;
614*433d6423SLionel Sambuc 
615*433d6423SLionel Sambuc       s = update_sig_mgrs(new_rp, SELF, new_rp->r_pub->endpoint);
616*433d6423SLionel Sambuc       if(s != OK) {
617*433d6423SLionel Sambuc           cleanup_service(new_rp);
618*433d6423SLionel Sambuc           return s;
619*433d6423SLionel Sambuc       }
620*433d6423SLionel Sambuc   }
621*433d6423SLionel Sambuc 
622*433d6423SLionel Sambuc   if(noblock) {
623*433d6423SLionel Sambuc       /* Unblock the caller immediately if requested. */
624*433d6423SLionel Sambuc       m_ptr->m_type = OK;
625*433d6423SLionel Sambuc       reply(m_ptr->m_source, NULL, m_ptr);
626*433d6423SLionel Sambuc   }
627*433d6423SLionel Sambuc   else {
628*433d6423SLionel Sambuc       /* Send a reply when the new version completes initialization. */
629*433d6423SLionel Sambuc       rp->r_flags |= RS_LATEREPLY;
630*433d6423SLionel Sambuc       rp->r_caller = m_ptr->m_source;
631*433d6423SLionel Sambuc       rp->r_caller_request = RS_UPDATE;
632*433d6423SLionel Sambuc   }
633*433d6423SLionel Sambuc 
634*433d6423SLionel Sambuc   /* Request to update. */
635*433d6423SLionel Sambuc   m_ptr->m_type = RS_LU_PREPARE;
636*433d6423SLionel Sambuc   if(rpub->endpoint == RS_PROC_NR) {
637*433d6423SLionel Sambuc       /* RS can process the request directly. */
638*433d6423SLionel Sambuc       do_sef_lu_request(m_ptr);
639*433d6423SLionel Sambuc   }
640*433d6423SLionel Sambuc   else {
641*433d6423SLionel Sambuc       /* Send request message to the system service. */
642*433d6423SLionel Sambuc       asynsend3(rpub->endpoint, m_ptr, AMF_NOREPLY);
643*433d6423SLionel Sambuc   }
644*433d6423SLionel Sambuc 
645*433d6423SLionel Sambuc   return EDONTREPLY;
646*433d6423SLionel Sambuc }
647*433d6423SLionel Sambuc 
648*433d6423SLionel Sambuc /*===========================================================================*
649*433d6423SLionel Sambuc  *				do_upd_ready				     *
650*433d6423SLionel Sambuc  *===========================================================================*/
651*433d6423SLionel Sambuc int do_upd_ready(message *m_ptr)
652*433d6423SLionel Sambuc {
653*433d6423SLionel Sambuc   struct rproc *rp, *old_rp, *new_rp;
654*433d6423SLionel Sambuc   int who_p;
655*433d6423SLionel Sambuc   int result;
656*433d6423SLionel Sambuc   int is_rs;
657*433d6423SLionel Sambuc   int r;
658*433d6423SLionel Sambuc 
659*433d6423SLionel Sambuc   who_p = _ENDPOINT_P(m_ptr->m_source);
660*433d6423SLionel Sambuc   rp = rproc_ptr[who_p];
661*433d6423SLionel Sambuc   result = m_ptr->m_rs_update.result;
662*433d6423SLionel Sambuc   is_rs = (m_ptr->m_source == RS_PROC_NR);
663*433d6423SLionel Sambuc 
664*433d6423SLionel Sambuc   /* Make sure the originating service was requested to prepare for update. */
665*433d6423SLionel Sambuc   if(rp != rupdate.rp) {
666*433d6423SLionel Sambuc       if(rs_verbose)
667*433d6423SLionel Sambuc           printf("RS: do_upd_ready: got unexpected update ready msg from %d\n",
668*433d6423SLionel Sambuc               m_ptr->m_source);
669*433d6423SLionel Sambuc       return EINVAL;
670*433d6423SLionel Sambuc   }
671*433d6423SLionel Sambuc 
672*433d6423SLionel Sambuc   /* Check if something went wrong and the service failed to prepare
673*433d6423SLionel Sambuc    * for the update. In that case, end the update process. The old version will
674*433d6423SLionel Sambuc    * be replied to and continue executing.
675*433d6423SLionel Sambuc    */
676*433d6423SLionel Sambuc   if(result != OK) {
677*433d6423SLionel Sambuc       end_update(result, RS_REPLY);
678*433d6423SLionel Sambuc 
679*433d6423SLionel Sambuc       printf("RS: update failed: %s\n", lu_strerror(result));
680*433d6423SLionel Sambuc       return is_rs ? result : EDONTREPLY; /* return what the caller expects */
681*433d6423SLionel Sambuc   }
682*433d6423SLionel Sambuc 
683*433d6423SLionel Sambuc   old_rp = rp;
684*433d6423SLionel Sambuc   new_rp = rp->r_new_rp;
685*433d6423SLionel Sambuc 
686*433d6423SLionel Sambuc   /* If RS itself is updating, yield control to the new version immediately. */
687*433d6423SLionel Sambuc   if(is_rs) {
688*433d6423SLionel Sambuc       r = init_service(new_rp, SEF_INIT_LU);
689*433d6423SLionel Sambuc       if(r != OK) {
690*433d6423SLionel Sambuc           panic("unable to initialize the new RS instance: %d", r);
691*433d6423SLionel Sambuc       }
692*433d6423SLionel Sambuc       r = sys_privctl(new_rp->r_pub->endpoint, SYS_PRIV_YIELD, NULL);
693*433d6423SLionel Sambuc       if(r != OK) {
694*433d6423SLionel Sambuc           panic("unable to yield control to the new RS instance: %d", r);
695*433d6423SLionel Sambuc       }
696*433d6423SLionel Sambuc       /* If we get this far, the new version failed to initialize. Rollback. */
697*433d6423SLionel Sambuc       r = srv_update(RS_PROC_NR, new_rp->r_pub->endpoint);
698*433d6423SLionel Sambuc       assert(r == OK); /* can't fail */
699*433d6423SLionel Sambuc       end_update(ERESTART, RS_REPLY);
700*433d6423SLionel Sambuc       return ERESTART;
701*433d6423SLionel Sambuc   }
702*433d6423SLionel Sambuc 
703*433d6423SLionel Sambuc   /* Perform the update. */
704*433d6423SLionel Sambuc   r = update_service(&old_rp, &new_rp, RS_SWAP);
705*433d6423SLionel Sambuc   if(r != OK) {
706*433d6423SLionel Sambuc       end_update(r, RS_REPLY);
707*433d6423SLionel Sambuc       printf("RS: update failed: error %d\n", r);
708*433d6423SLionel Sambuc       return EDONTREPLY;
709*433d6423SLionel Sambuc   }
710*433d6423SLionel Sambuc 
711*433d6423SLionel Sambuc   /* Let the new version run. */
712*433d6423SLionel Sambuc   r = run_service(new_rp, SEF_INIT_LU);
713*433d6423SLionel Sambuc   if(r != OK) {
714*433d6423SLionel Sambuc       /* Something went wrong. Rollback. */
715*433d6423SLionel Sambuc       r = update_service(&new_rp, &old_rp, RS_SWAP);
716*433d6423SLionel Sambuc       assert(r == OK); /* can't fail */
717*433d6423SLionel Sambuc       end_update(r, RS_REPLY);
718*433d6423SLionel Sambuc       printf("RS: update failed: error %d\n", r);
719*433d6423SLionel Sambuc       return EDONTREPLY;
720*433d6423SLionel Sambuc   }
721*433d6423SLionel Sambuc 
722*433d6423SLionel Sambuc   return EDONTREPLY;
723*433d6423SLionel Sambuc }
724*433d6423SLionel Sambuc 
725*433d6423SLionel Sambuc /*===========================================================================*
726*433d6423SLionel Sambuc  *				do_period				     *
727*433d6423SLionel Sambuc  *===========================================================================*/
728*433d6423SLionel Sambuc void do_period(m_ptr)
729*433d6423SLionel Sambuc message *m_ptr;
730*433d6423SLionel Sambuc {
731*433d6423SLionel Sambuc   register struct rproc *rp;
732*433d6423SLionel Sambuc   register struct rprocpub *rpub;
733*433d6423SLionel Sambuc   clock_t now = m_ptr->m_notify.timestamp;
734*433d6423SLionel Sambuc   int s;
735*433d6423SLionel Sambuc   long period;
736*433d6423SLionel Sambuc 
737*433d6423SLionel Sambuc   /* If an update is in progress, check its status. */
738*433d6423SLionel Sambuc   if(rupdate.flags & RS_UPDATING) {
739*433d6423SLionel Sambuc       update_period(m_ptr);
740*433d6423SLionel Sambuc   }
741*433d6423SLionel Sambuc 
742*433d6423SLionel Sambuc   /* Search system services table. Only check slots that are in use and not
743*433d6423SLionel Sambuc    * updating.
744*433d6423SLionel Sambuc    */
745*433d6423SLionel Sambuc   for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
746*433d6423SLionel Sambuc       rpub = rp->r_pub;
747*433d6423SLionel Sambuc       if ((rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_UPDATING)) {
748*433d6423SLionel Sambuc 
749*433d6423SLionel Sambuc           /* Compute period. */
750*433d6423SLionel Sambuc           period = rp->r_period;
751*433d6423SLionel Sambuc           if(rp->r_flags & RS_INITIALIZING) {
752*433d6423SLionel Sambuc               period = RS_INIT_T;
753*433d6423SLionel Sambuc           }
754*433d6423SLionel Sambuc 
755*433d6423SLionel Sambuc           /* If the service is to be revived (because it repeatedly exited,
756*433d6423SLionel Sambuc 	   * and was not directly restarted), the binary backoff field is
757*433d6423SLionel Sambuc 	   * greater than zero.
758*433d6423SLionel Sambuc 	   */
759*433d6423SLionel Sambuc 	  if (rp->r_backoff > 0) {
760*433d6423SLionel Sambuc               rp->r_backoff -= 1;
761*433d6423SLionel Sambuc 	      if (rp->r_backoff == 0) {
762*433d6423SLionel Sambuc 		  restart_service(rp);
763*433d6423SLionel Sambuc 	      }
764*433d6423SLionel Sambuc 	  }
765*433d6423SLionel Sambuc 
766*433d6423SLionel Sambuc 	  /* If the service was signaled with a SIGTERM and fails to respond,
767*433d6423SLionel Sambuc 	   * kill the system service with a SIGKILL signal.
768*433d6423SLionel Sambuc 	   */
769*433d6423SLionel Sambuc 	  else if (rp->r_stop_tm > 0 && now - rp->r_stop_tm > 2*RS_DELTA_T
770*433d6423SLionel Sambuc 	   && rp->r_pid > 0) {
771*433d6423SLionel Sambuc               rp->r_stop_tm = 0;
772*433d6423SLionel Sambuc               crash_service(rp); /* simulate crash */
773*433d6423SLionel Sambuc 	  }
774*433d6423SLionel Sambuc 
775*433d6423SLionel Sambuc 	  /* There seems to be no special conditions. If the service has a
776*433d6423SLionel Sambuc 	   * period assigned check its status.
777*433d6423SLionel Sambuc 	   */
778*433d6423SLionel Sambuc 	  else if (period > 0) {
779*433d6423SLionel Sambuc 
780*433d6423SLionel Sambuc 	      /* Check if an answer to a status request is still pending. If
781*433d6423SLionel Sambuc 	       * the service didn't respond within time, kill it to simulate
782*433d6423SLionel Sambuc 	       * a crash. The failure will be detected and the service will
783*433d6423SLionel Sambuc 	       * be restarted automatically. Give the service a free pass if
784*433d6423SLionel Sambuc 	       * somebody is initializing. There may be some weird dependencies
785*433d6423SLionel Sambuc 	       * if another service is, for example, restarting at the same
786*433d6423SLionel Sambuc 	       * time.
787*433d6423SLionel Sambuc 	       */
788*433d6423SLionel Sambuc               if (rp->r_alive_tm < rp->r_check_tm) {
789*433d6423SLionel Sambuc 	          if (now - rp->r_alive_tm > 2*period &&
790*433d6423SLionel Sambuc 		      rp->r_pid > 0 && !(rp->r_flags & RS_NOPINGREPLY)) {
791*433d6423SLionel Sambuc 		      if(rs_verbose)
792*433d6423SLionel Sambuc                            printf("RS: %s reported late\n", srv_to_string(rp));
793*433d6423SLionel Sambuc 		      if(lookup_slot_by_flags(RS_INITIALIZING)) {
794*433d6423SLionel Sambuc                            /* Skip for now. */
795*433d6423SLionel Sambuc                            if(rs_verbose)
796*433d6423SLionel Sambuc                                printf("RS: %s gets a free pass\n",
797*433d6423SLionel Sambuc                                    srv_to_string(rp));
798*433d6423SLionel Sambuc                            rp->r_alive_tm = now;
799*433d6423SLionel Sambuc                            rp->r_check_tm = now+1;
800*433d6423SLionel Sambuc                            continue;
801*433d6423SLionel Sambuc 		      }
802*433d6423SLionel Sambuc 		      rp->r_flags |= RS_NOPINGREPLY;
803*433d6423SLionel Sambuc                       crash_service(rp); /* simulate crash */
804*433d6423SLionel Sambuc 		  }
805*433d6423SLionel Sambuc 	      }
806*433d6423SLionel Sambuc 
807*433d6423SLionel Sambuc 	      /* No answer pending. Check if a period expired since the last
808*433d6423SLionel Sambuc 	       * check and, if so request the system service's status.
809*433d6423SLionel Sambuc 	       */
810*433d6423SLionel Sambuc 	      else if (now - rp->r_check_tm > rp->r_period) {
811*433d6423SLionel Sambuc   		  ipc_notify(rpub->endpoint);		/* request status */
812*433d6423SLionel Sambuc 		  rp->r_check_tm = now;			/* mark time */
813*433d6423SLionel Sambuc               }
814*433d6423SLionel Sambuc           }
815*433d6423SLionel Sambuc       }
816*433d6423SLionel Sambuc   }
817*433d6423SLionel Sambuc 
818*433d6423SLionel Sambuc   /* Reschedule a synchronous alarm for the next period. */
819*433d6423SLionel Sambuc   if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
820*433d6423SLionel Sambuc       panic("couldn't set alarm: %d", s);
821*433d6423SLionel Sambuc }
822*433d6423SLionel Sambuc 
823*433d6423SLionel Sambuc /*===========================================================================*
824*433d6423SLionel Sambuc  *			          do_sigchld				     *
825*433d6423SLionel Sambuc  *===========================================================================*/
826*433d6423SLionel Sambuc void do_sigchld()
827*433d6423SLionel Sambuc {
828*433d6423SLionel Sambuc /* PM informed us that there are dead children to cleanup. Go get them. */
829*433d6423SLionel Sambuc   pid_t pid;
830*433d6423SLionel Sambuc   int status;
831*433d6423SLionel Sambuc   struct rproc *rp;
832*433d6423SLionel Sambuc   struct rproc **rps;
833*433d6423SLionel Sambuc   int i, nr_rps;
834*433d6423SLionel Sambuc 
835*433d6423SLionel Sambuc   if(rs_verbose)
836*433d6423SLionel Sambuc      printf("RS: got SIGCHLD signal, cleaning up dead children\n");
837*433d6423SLionel Sambuc 
838*433d6423SLionel Sambuc   while ( (pid = waitpid(-1, &status, WNOHANG)) != 0 ) {
839*433d6423SLionel Sambuc       rp = lookup_slot_by_pid(pid);
840*433d6423SLionel Sambuc       if(rp != NULL) {
841*433d6423SLionel Sambuc 
842*433d6423SLionel Sambuc           if(rs_verbose)
843*433d6423SLionel Sambuc               printf("RS: %s exited via another signal manager\n",
844*433d6423SLionel Sambuc                   srv_to_string(rp));
845*433d6423SLionel Sambuc 
846*433d6423SLionel Sambuc           /* The slot is still there. This means RS is not the signal
847*433d6423SLionel Sambuc            * manager assigned to the process. Ignore the event but
848*433d6423SLionel Sambuc            * free slots for all the service instances and send a late
849*433d6423SLionel Sambuc            * reply if necessary.
850*433d6423SLionel Sambuc            */
851*433d6423SLionel Sambuc           get_service_instances(rp, &rps, &nr_rps);
852*433d6423SLionel Sambuc           for(i=0;i<nr_rps;i++) {
853*433d6423SLionel Sambuc               if(rupdate.flags & RS_UPDATING) {
854*433d6423SLionel Sambuc                   rupdate.flags &= ~RS_UPDATING;
855*433d6423SLionel Sambuc               }
856*433d6423SLionel Sambuc               free_slot(rps[i]);
857*433d6423SLionel Sambuc           }
858*433d6423SLionel Sambuc       }
859*433d6423SLionel Sambuc   }
860*433d6423SLionel Sambuc }
861*433d6423SLionel Sambuc 
862*433d6423SLionel Sambuc /*===========================================================================*
863*433d6423SLionel Sambuc  *				do_getsysinfo				     *
864*433d6423SLionel Sambuc  *===========================================================================*/
865*433d6423SLionel Sambuc int do_getsysinfo(m_ptr)
866*433d6423SLionel Sambuc message *m_ptr;
867*433d6423SLionel Sambuc {
868*433d6423SLionel Sambuc   vir_bytes src_addr, dst_addr;
869*433d6423SLionel Sambuc   int dst_proc;
870*433d6423SLionel Sambuc   size_t len;
871*433d6423SLionel Sambuc   int s;
872*433d6423SLionel Sambuc 
873*433d6423SLionel Sambuc   /* Check if the call can be allowed. */
874*433d6423SLionel Sambuc   if((s = check_call_permission(m_ptr->m_source, 0, NULL)) != OK)
875*433d6423SLionel Sambuc       return s;
876*433d6423SLionel Sambuc 
877*433d6423SLionel Sambuc   switch(m_ptr->m_lsys_getsysinfo.what) {
878*433d6423SLionel Sambuc   case SI_PROC_TAB:
879*433d6423SLionel Sambuc   	src_addr = (vir_bytes) rproc;
880*433d6423SLionel Sambuc   	len = sizeof(struct rproc) * NR_SYS_PROCS;
881*433d6423SLionel Sambuc   	break;
882*433d6423SLionel Sambuc   case SI_PROCPUB_TAB:
883*433d6423SLionel Sambuc   	src_addr = (vir_bytes) rprocpub;
884*433d6423SLionel Sambuc   	len = sizeof(struct rprocpub) * NR_SYS_PROCS;
885*433d6423SLionel Sambuc   	break;
886*433d6423SLionel Sambuc   default:
887*433d6423SLionel Sambuc   	return(EINVAL);
888*433d6423SLionel Sambuc   }
889*433d6423SLionel Sambuc 
890*433d6423SLionel Sambuc   if (len != m_ptr->m_lsys_getsysinfo.size)
891*433d6423SLionel Sambuc 	return(EINVAL);
892*433d6423SLionel Sambuc 
893*433d6423SLionel Sambuc   dst_proc = m_ptr->m_source;
894*433d6423SLionel Sambuc   dst_addr = m_ptr->m_lsys_getsysinfo.where;
895*433d6423SLionel Sambuc   return sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len);
896*433d6423SLionel Sambuc }
897*433d6423SLionel Sambuc 
898*433d6423SLionel Sambuc /*===========================================================================*
899*433d6423SLionel Sambuc  *				do_lookup				     *
900*433d6423SLionel Sambuc  *===========================================================================*/
901*433d6423SLionel Sambuc int do_lookup(m_ptr)
902*433d6423SLionel Sambuc message *m_ptr;
903*433d6423SLionel Sambuc {
904*433d6423SLionel Sambuc 	static char namebuf[100];
905*433d6423SLionel Sambuc 	int len, r;
906*433d6423SLionel Sambuc 	struct rproc *rrp;
907*433d6423SLionel Sambuc 	struct rprocpub *rrpub;
908*433d6423SLionel Sambuc 
909*433d6423SLionel Sambuc 	len = m_ptr->m_rs_req.name_len;
910*433d6423SLionel Sambuc 
911*433d6423SLionel Sambuc 	if(len < 2 || len >= sizeof(namebuf)) {
912*433d6423SLionel Sambuc 		printf("RS: len too weird (%d)\n", len);
913*433d6423SLionel Sambuc 		return EINVAL;
914*433d6423SLionel Sambuc 	}
915*433d6423SLionel Sambuc 
916*433d6423SLionel Sambuc 	if((r=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->m_rs_req.name,
917*433d6423SLionel Sambuc 		SELF, (vir_bytes) namebuf, len)) != OK) {
918*433d6423SLionel Sambuc 		printf("RS: name copy failed\n");
919*433d6423SLionel Sambuc 		return r;
920*433d6423SLionel Sambuc 
921*433d6423SLionel Sambuc 	}
922*433d6423SLionel Sambuc 
923*433d6423SLionel Sambuc 	namebuf[len] = '\0';
924*433d6423SLionel Sambuc 
925*433d6423SLionel Sambuc 	rrp = lookup_slot_by_label(namebuf);
926*433d6423SLionel Sambuc 	if(!rrp) {
927*433d6423SLionel Sambuc 		return ESRCH;
928*433d6423SLionel Sambuc 	}
929*433d6423SLionel Sambuc 	rrpub = rrp->r_pub;
930*433d6423SLionel Sambuc 	m_ptr->m_rs_req.endpoint = rrpub->endpoint;
931*433d6423SLionel Sambuc 
932*433d6423SLionel Sambuc 	return OK;
933*433d6423SLionel Sambuc }
934*433d6423SLionel Sambuc 
935*433d6423SLionel Sambuc /*===========================================================================*
936*433d6423SLionel Sambuc  *				   check_request			     *
937*433d6423SLionel Sambuc  *===========================================================================*/
938*433d6423SLionel Sambuc static int check_request(struct rs_start *rs_start)
939*433d6423SLionel Sambuc {
940*433d6423SLionel Sambuc   /* Verify scheduling parameters */
941*433d6423SLionel Sambuc   if (rs_start->rss_scheduler != KERNEL &&
942*433d6423SLionel Sambuc 	(rs_start->rss_scheduler < 0 ||
943*433d6423SLionel Sambuc 	rs_start->rss_scheduler > LAST_SPECIAL_PROC_NR)) {
944*433d6423SLionel Sambuc 	printf("RS: check_request: invalid scheduler %d\n",
945*433d6423SLionel Sambuc 		rs_start->rss_scheduler);
946*433d6423SLionel Sambuc 	return EINVAL;
947*433d6423SLionel Sambuc   }
948*433d6423SLionel Sambuc   if (rs_start->rss_priority >= NR_SCHED_QUEUES) {
949*433d6423SLionel Sambuc 	printf("RS: check_request: priority %u out of range\n",
950*433d6423SLionel Sambuc 		rs_start->rss_priority);
951*433d6423SLionel Sambuc 	return EINVAL;
952*433d6423SLionel Sambuc   }
953*433d6423SLionel Sambuc   if (rs_start->rss_quantum <= 0) {
954*433d6423SLionel Sambuc 	printf("RS: check_request: quantum %u out of range\n",
955*433d6423SLionel Sambuc 		rs_start->rss_quantum);
956*433d6423SLionel Sambuc 	return EINVAL;
957*433d6423SLionel Sambuc   }
958*433d6423SLionel Sambuc 
959*433d6423SLionel Sambuc   if (rs_start->rss_cpu == RS_CPU_BSP)
960*433d6423SLionel Sambuc 	  rs_start->rss_cpu = machine.bsp_id;
961*433d6423SLionel Sambuc   else if (rs_start->rss_cpu == RS_CPU_DEFAULT) {
962*433d6423SLionel Sambuc 	  /* keep the default value */
963*433d6423SLionel Sambuc   } else if (rs_start->rss_cpu < 0)
964*433d6423SLionel Sambuc 	  return EINVAL;
965*433d6423SLionel Sambuc   else if (rs_start->rss_cpu > machine.processors_count) {
966*433d6423SLionel Sambuc 	  printf("RS: cpu number %d out of range 0-%d, using BSP\n",
967*433d6423SLionel Sambuc 			  rs_start->rss_cpu, machine.processors_count);
968*433d6423SLionel Sambuc 	  rs_start->rss_cpu = machine.bsp_id;
969*433d6423SLionel Sambuc   }
970*433d6423SLionel Sambuc 
971*433d6423SLionel Sambuc   /* Verify signal manager. */
972*433d6423SLionel Sambuc   if (rs_start->rss_sigmgr != SELF &&
973*433d6423SLionel Sambuc 	(rs_start->rss_sigmgr < 0 ||
974*433d6423SLionel Sambuc 	rs_start->rss_sigmgr > LAST_SPECIAL_PROC_NR)) {
975*433d6423SLionel Sambuc 	printf("RS: check_request: invalid signal manager %d\n",
976*433d6423SLionel Sambuc 		rs_start->rss_sigmgr);
977*433d6423SLionel Sambuc 	return EINVAL;
978*433d6423SLionel Sambuc   }
979*433d6423SLionel Sambuc 
980*433d6423SLionel Sambuc   return OK;
981*433d6423SLionel Sambuc }
982*433d6423SLionel Sambuc 
983