xref: /minix3/minix/servers/rs/manager.c (revision 37f29f557ab17227a82345b4118d57de4d9ea8e9)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Changes:
3433d6423SLionel Sambuc  *   Nov 22, 2009:	added basic live update support  (Cristiano Giuffrida)
4433d6423SLionel Sambuc  *   Mar 02, 2009:	Extended isolation policies  (Jorrit N. Herder)
5433d6423SLionel Sambuc  *   Jul 22, 2005:	Created  (Jorrit N. Herder)
6433d6423SLionel Sambuc  */
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #include <paths.h>
9433d6423SLionel Sambuc 
10*37f29f55SLionel Sambuc #include <sys/exec_elf.h>
11*37f29f55SLionel Sambuc 
12433d6423SLionel Sambuc #include "inc.h"
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #include "kernel/proc.h"
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc /*===========================================================================*
17433d6423SLionel Sambuc  *				caller_is_root				     *
18433d6423SLionel Sambuc  *===========================================================================*/
19433d6423SLionel Sambuc static int caller_is_root(endpoint)
20433d6423SLionel Sambuc endpoint_t endpoint;				/* caller endpoint */
21433d6423SLionel Sambuc {
22433d6423SLionel Sambuc   uid_t euid;
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc   /* Check if caller has root user ID. */
25433d6423SLionel Sambuc   euid = getnuid(endpoint);
26433d6423SLionel Sambuc   if (rs_verbose && euid != 0)
27433d6423SLionel Sambuc   {
28433d6423SLionel Sambuc 	printf("RS: got unauthorized request from endpoint %d\n", endpoint);
29433d6423SLionel Sambuc   }
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc   return euid == 0;
32433d6423SLionel Sambuc }
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc /*===========================================================================*
35433d6423SLionel Sambuc  *				caller_can_control			     *
36433d6423SLionel Sambuc  *===========================================================================*/
37433d6423SLionel Sambuc static int caller_can_control(endpoint, target_rp)
38433d6423SLionel Sambuc endpoint_t endpoint;
39433d6423SLionel Sambuc struct rproc *target_rp;
40433d6423SLionel Sambuc {
41433d6423SLionel Sambuc   int control_allowed = 0;
42433d6423SLionel Sambuc   register struct rproc *rp;
43433d6423SLionel Sambuc   register struct rprocpub *rpub;
44433d6423SLionel Sambuc   char *proc_name;
45433d6423SLionel Sambuc   int c;
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc   proc_name = target_rp->r_pub->proc_name;
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc   /* Check if label is listed in caller's isolation policy. */
50433d6423SLionel Sambuc   for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
51433d6423SLionel Sambuc 	if (!(rp->r_flags & RS_IN_USE))
52433d6423SLionel Sambuc 		continue;
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc 	rpub = rp->r_pub;
55433d6423SLionel Sambuc 	if (rpub->endpoint == endpoint) {
56433d6423SLionel Sambuc 		break;
57433d6423SLionel Sambuc 	}
58433d6423SLionel Sambuc   }
59433d6423SLionel Sambuc   if (rp == END_RPROC_ADDR) return 0;
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc   for (c = 0; c < rp->r_nr_control; c++) {
62433d6423SLionel Sambuc 	if (strcmp(rp->r_control[c], proc_name) == 0) {
63433d6423SLionel Sambuc 		control_allowed = 1;
64433d6423SLionel Sambuc 		break;
65433d6423SLionel Sambuc 	}
66433d6423SLionel Sambuc   }
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   if (rs_verbose)
69433d6423SLionel Sambuc 	printf("RS: allowing %u control over %s via policy: %s\n",
70433d6423SLionel Sambuc 		endpoint, target_rp->r_pub->label,
71433d6423SLionel Sambuc 		control_allowed ? "yes" : "no");
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc   return control_allowed;
74433d6423SLionel Sambuc }
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc /*===========================================================================*
77433d6423SLionel Sambuc  *			     check_call_permission			     *
78433d6423SLionel Sambuc  *===========================================================================*/
79433d6423SLionel Sambuc int check_call_permission(caller, call, rp)
80433d6423SLionel Sambuc endpoint_t caller;
81433d6423SLionel Sambuc int call;
82433d6423SLionel Sambuc struct rproc *rp;
83433d6423SLionel Sambuc {
84433d6423SLionel Sambuc /* Check if the caller has permission to execute a particular call. */
85433d6423SLionel Sambuc   struct rprocpub *rpub;
86433d6423SLionel Sambuc   int call_allowed;
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc   /* Caller should be either root or have control privileges. */
89433d6423SLionel Sambuc   call_allowed = caller_is_root(caller);
90433d6423SLionel Sambuc   if(rp) {
91433d6423SLionel Sambuc       call_allowed |= caller_can_control(caller, rp);
92433d6423SLionel Sambuc   }
93433d6423SLionel Sambuc   if(!call_allowed) {
94433d6423SLionel Sambuc       return EPERM;
95433d6423SLionel Sambuc   }
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc   if(rp) {
98433d6423SLionel Sambuc       rpub = rp->r_pub;
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc       /* Only allow RS_EDIT if the target is a user process. */
101433d6423SLionel Sambuc       if(!(rp->r_priv.s_flags & SYS_PROC)) {
102433d6423SLionel Sambuc           if(call != RS_EDIT) return EPERM;
103433d6423SLionel Sambuc       }
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc       /* Disallow the call if another call is in progress for the service. */
106433d6423SLionel Sambuc       if((rp->r_flags & RS_LATEREPLY)
107433d6423SLionel Sambuc           || (rp->r_flags & RS_INITIALIZING) || (rp->r_flags & RS_UPDATING)) {
108433d6423SLionel Sambuc           return EBUSY;
109433d6423SLionel Sambuc       }
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc       /* Only allow RS_DOWN and RS_RESTART if the service has terminated. */
112433d6423SLionel Sambuc       if(rp->r_flags & RS_TERMINATED) {
113433d6423SLionel Sambuc           if(call != RS_DOWN && call != RS_RESTART) return EPERM;
114433d6423SLionel Sambuc       }
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc       /* Disallow RS_DOWN for core system services. */
117433d6423SLionel Sambuc       if (rpub->sys_flags & SF_CORE_SRV) {
118433d6423SLionel Sambuc           if(call == RS_DOWN) return EPERM;
119433d6423SLionel Sambuc       }
120433d6423SLionel Sambuc   }
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc   return OK;
123433d6423SLionel Sambuc }
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc /*===========================================================================*
126433d6423SLionel Sambuc  *				copy_rs_start				     *
127433d6423SLionel Sambuc  *===========================================================================*/
128433d6423SLionel Sambuc int copy_rs_start(src_e, src_rs_start, dst_rs_start)
129433d6423SLionel Sambuc endpoint_t src_e;
130433d6423SLionel Sambuc char *src_rs_start;
131433d6423SLionel Sambuc struct rs_start *dst_rs_start;
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc   int r;
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc   r = sys_datacopy(src_e, (vir_bytes) src_rs_start,
136433d6423SLionel Sambuc   	SELF, (vir_bytes) dst_rs_start, sizeof(struct rs_start));
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc   return r;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc /*===========================================================================*
142433d6423SLionel Sambuc  *				copy_label				     *
143433d6423SLionel Sambuc  *===========================================================================*/
144433d6423SLionel Sambuc int copy_label(src_e, src_label, src_len, dst_label, dst_len)
145433d6423SLionel Sambuc endpoint_t src_e;
146433d6423SLionel Sambuc char *src_label;
147433d6423SLionel Sambuc size_t src_len;
148433d6423SLionel Sambuc char *dst_label;
149433d6423SLionel Sambuc size_t dst_len;
150433d6423SLionel Sambuc {
151433d6423SLionel Sambuc   int s, len;
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc   len = MIN(dst_len-1, src_len);
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc   s = sys_datacopy(src_e, (vir_bytes) src_label,
156433d6423SLionel Sambuc 	SELF, (vir_bytes) dst_label, len);
157433d6423SLionel Sambuc   if (s != OK) return s;
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc   dst_label[len] = 0;
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc   return OK;
162433d6423SLionel Sambuc }
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc /*===========================================================================*
165433d6423SLionel Sambuc  *			        build_cmd_dep				     *
166433d6423SLionel Sambuc  *===========================================================================*/
167433d6423SLionel Sambuc void build_cmd_dep(struct rproc *rp)
168433d6423SLionel Sambuc {
169433d6423SLionel Sambuc   struct rprocpub *rpub;
170433d6423SLionel Sambuc   int arg_count;
171433d6423SLionel Sambuc   int len;
172433d6423SLionel Sambuc   char *cmd_ptr;
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc   rpub = rp->r_pub;
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc   /* Build argument vector to be passed to execute call. The format of the
177433d6423SLionel Sambuc    * arguments vector is: path, arguments, NULL.
178433d6423SLionel Sambuc    */
179433d6423SLionel Sambuc   strcpy(rp->r_args, rp->r_cmd);		/* copy raw command */
180433d6423SLionel Sambuc   arg_count = 0;				/* initialize arg count */
181433d6423SLionel Sambuc   rp->r_argv[arg_count++] = rp->r_args;		/* start with path */
182433d6423SLionel Sambuc   cmd_ptr = rp->r_args;				/* do some parsing */
183433d6423SLionel Sambuc   while(*cmd_ptr != '\0') {			/* stop at end of string */
184433d6423SLionel Sambuc       if (*cmd_ptr == ' ') {			/* next argument */
185433d6423SLionel Sambuc           *cmd_ptr = '\0';			/* terminate previous */
186433d6423SLionel Sambuc 	  while (*++cmd_ptr == ' ') ; 		/* skip spaces */
187433d6423SLionel Sambuc 	  if (*cmd_ptr == '\0') break;		/* no arg following */
188433d6423SLionel Sambuc 	  /* There are ARGV_ELEMENTS elements; must leave one for null */
189433d6423SLionel Sambuc 	  if (arg_count>=ARGV_ELEMENTS-1) {	/* arg vector full */
190433d6423SLionel Sambuc 		printf("RS: build_cmd_dep: too many args\n");
191433d6423SLionel Sambuc 	  	break;
192433d6423SLionel Sambuc 	  }
193433d6423SLionel Sambuc 	  assert(arg_count < ARGV_ELEMENTS);
194433d6423SLionel Sambuc           rp->r_argv[arg_count++] = cmd_ptr;	/* add to arg vector */
195433d6423SLionel Sambuc       }
196433d6423SLionel Sambuc       cmd_ptr ++;				/* continue parsing */
197433d6423SLionel Sambuc   }
198433d6423SLionel Sambuc   assert(arg_count < ARGV_ELEMENTS);
199433d6423SLionel Sambuc   rp->r_argv[arg_count] = NULL;			/* end with NULL pointer */
200433d6423SLionel Sambuc   rp->r_argc = arg_count;
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc   /* Build process name. */
203433d6423SLionel Sambuc   cmd_ptr = strrchr(rp->r_argv[0], '/');
204433d6423SLionel Sambuc   if (cmd_ptr)
205433d6423SLionel Sambuc   	cmd_ptr++;
206433d6423SLionel Sambuc   else
207433d6423SLionel Sambuc   	cmd_ptr= rp->r_argv[0];
208433d6423SLionel Sambuc   len= strlen(cmd_ptr);
209433d6423SLionel Sambuc   if (len > RS_MAX_LABEL_LEN-1)
210433d6423SLionel Sambuc   	len= RS_MAX_LABEL_LEN-1;	/* truncate name */
211433d6423SLionel Sambuc   memcpy(rpub->proc_name, cmd_ptr, len);
212433d6423SLionel Sambuc   rpub->proc_name[len]= '\0';
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc /*===========================================================================*
216433d6423SLionel Sambuc  *				 srv_update				     *
217433d6423SLionel Sambuc  *===========================================================================*/
218433d6423SLionel Sambuc int srv_update(endpoint_t src_e, endpoint_t dst_e)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc   int r;
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc   /* Ask VM to swap the slots of the two processes and tell the kernel to
223433d6423SLionel Sambuc    * do the same. If VM is the service being updated, only perform the kernel
224433d6423SLionel Sambuc    * part of the call. The new instance of VM will do the rest at
225433d6423SLionel Sambuc    * initialization time.
226433d6423SLionel Sambuc    */
227433d6423SLionel Sambuc   if(src_e != VM_PROC_NR) {
228433d6423SLionel Sambuc       r = vm_update(src_e, dst_e);
229433d6423SLionel Sambuc   }
230433d6423SLionel Sambuc   else {
231433d6423SLionel Sambuc       r = sys_update(src_e, dst_e);
232433d6423SLionel Sambuc   }
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc   return r;
235433d6423SLionel Sambuc }
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc /*===========================================================================*
238433d6423SLionel Sambuc  *				update_period				     *
239433d6423SLionel Sambuc  *===========================================================================*/
240433d6423SLionel Sambuc void update_period(message *m_ptr)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc   clock_t now = m_ptr->m_notify.timestamp;
243433d6423SLionel Sambuc   short has_update_timed_out;
244433d6423SLionel Sambuc   message m;
245433d6423SLionel Sambuc   struct rprocpub *rpub;
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc   rpub = rupdate.rp->r_pub;
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc   /* See if a timeout has occurred. */
250433d6423SLionel Sambuc   has_update_timed_out = (now - rupdate.prepare_tm > rupdate.prepare_maxtime);
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc   /* If an update timed out, end the update process and notify
253433d6423SLionel Sambuc    * the old version that the update has been canceled. From now on, the old
254433d6423SLionel Sambuc    * version will continue executing.
255433d6423SLionel Sambuc    */
256433d6423SLionel Sambuc   if(has_update_timed_out) {
257433d6423SLionel Sambuc       printf("RS: update failed: maximum prepare time reached\n");
258433d6423SLionel Sambuc       end_update(EINTR, RS_DONTREPLY);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc       /* Prepare cancel request. */
261433d6423SLionel Sambuc       m.m_type = RS_LU_PREPARE;
262433d6423SLionel Sambuc       m.m_rs_update.state = SEF_LU_STATE_NULL;
263433d6423SLionel Sambuc       if(rpub->endpoint == RS_PROC_NR) {
264433d6423SLionel Sambuc           /* RS can process the request directly. */
265433d6423SLionel Sambuc           do_sef_lu_request(&m);
266433d6423SLionel Sambuc       }
267433d6423SLionel Sambuc       else {
268433d6423SLionel Sambuc           /* Send request message to the system service. */
269433d6423SLionel Sambuc           asynsend(rpub->endpoint, &m);
270433d6423SLionel Sambuc       }
271433d6423SLionel Sambuc   }
272433d6423SLionel Sambuc }
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc /*===========================================================================*
275433d6423SLionel Sambuc  *				end_update				     *
276433d6423SLionel Sambuc  *===========================================================================*/
277433d6423SLionel Sambuc void end_update(int result, int reply_flag)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc /* End the update process. There are two possibilities:
280433d6423SLionel Sambuc  * 1) the update succeeded. In that case, cleanup the old version and mark the
281433d6423SLionel Sambuc  *    new version as no longer under update.
282433d6423SLionel Sambuc  * 2) the update failed. In that case, cleanup the new version and mark the old
283433d6423SLionel Sambuc  *    version as no longer under update. Eventual late ready to update
284433d6423SLionel Sambuc  *    messages (if any) will simply be ignored and the service can
285433d6423SLionel Sambuc  *    continue executing. In addition, reset the check timestamp, so that if the
286433d6423SLionel Sambuc  *    service has a period, a status request will be forced in the next period.
287433d6423SLionel Sambuc  */
288433d6423SLionel Sambuc   struct rproc *old_rp, *new_rp, *exiting_rp, *surviving_rp;
289433d6423SLionel Sambuc   struct rproc **rps;
290433d6423SLionel Sambuc   int nr_rps, i;
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc   old_rp = rupdate.rp;
293433d6423SLionel Sambuc   new_rp = old_rp->r_new_rp;
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc   if(rs_verbose)
296433d6423SLionel Sambuc       printf("RS: ending update from %s to %s with result: %d\n",
297433d6423SLionel Sambuc           srv_to_string(old_rp), srv_to_string(new_rp), result);
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc   /* Decide which version has to die out and which version has to survive. */
300433d6423SLionel Sambuc   surviving_rp = (result == OK ? new_rp : old_rp);
301433d6423SLionel Sambuc   exiting_rp =   (result == OK ? old_rp : new_rp);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc   /* End update. */
304433d6423SLionel Sambuc   rupdate.flags &= ~RS_UPDATING;
305433d6423SLionel Sambuc   rupdate.rp = NULL;
306433d6423SLionel Sambuc   old_rp->r_new_rp = NULL;
307433d6423SLionel Sambuc   new_rp->r_old_rp = NULL;
308433d6423SLionel Sambuc   old_rp->r_check_tm = 0;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc   /* Send a late reply if necessary. */
311433d6423SLionel Sambuc   late_reply(old_rp, result);
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc   /* Mark the version that has to survive as no longer updating and
314433d6423SLionel Sambuc    * reply when asked to.
315433d6423SLionel Sambuc    */
316433d6423SLionel Sambuc   surviving_rp->r_flags &= ~RS_UPDATING;
317433d6423SLionel Sambuc   if(reply_flag == RS_REPLY) {
318433d6423SLionel Sambuc       message m;
319433d6423SLionel Sambuc       m.m_type = result;
320433d6423SLionel Sambuc       reply(surviving_rp->r_pub->endpoint, surviving_rp, &m);
321433d6423SLionel Sambuc   }
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc   /* Cleanup the version that has to die out. */
324433d6423SLionel Sambuc   get_service_instances(exiting_rp, &rps, &nr_rps);
325433d6423SLionel Sambuc   for(i=0;i<nr_rps;i++) {
326433d6423SLionel Sambuc       cleanup_service(rps[i]);
327433d6423SLionel Sambuc   }
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc   if(rs_verbose)
330433d6423SLionel Sambuc       printf("RS: %s ended the update\n", srv_to_string(surviving_rp));
331433d6423SLionel Sambuc }
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc /*===========================================================================*
334433d6423SLionel Sambuc  *			     kill_service_debug				     *
335433d6423SLionel Sambuc  *===========================================================================*/
336433d6423SLionel Sambuc int kill_service_debug(file, line, rp, errstr, err)
337433d6423SLionel Sambuc char *file;
338433d6423SLionel Sambuc int line;
339433d6423SLionel Sambuc struct rproc *rp;
340433d6423SLionel Sambuc char *errstr;
341433d6423SLionel Sambuc int err;
342433d6423SLionel Sambuc {
343433d6423SLionel Sambuc /* Crash a system service and don't let it restart. */
344433d6423SLionel Sambuc   if(errstr && !shutting_down) {
345433d6423SLionel Sambuc       printf("RS: %s (error %d)\n", errstr, err);
346433d6423SLionel Sambuc   }
347433d6423SLionel Sambuc   rp->r_flags |= RS_EXITING;				/* expect exit */
348433d6423SLionel Sambuc   crash_service_debug(file, line, rp);			/* simulate crash */
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc   return err;
351433d6423SLionel Sambuc }
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc /*===========================================================================*
354433d6423SLionel Sambuc  *			    crash_service_debug				     *
355433d6423SLionel Sambuc  *===========================================================================*/
356433d6423SLionel Sambuc int crash_service_debug(file, line, rp)
357433d6423SLionel Sambuc char *file;
358433d6423SLionel Sambuc int line;
359433d6423SLionel Sambuc struct rproc *rp;
360433d6423SLionel Sambuc {
361433d6423SLionel Sambuc /* Simluate a crash in a system service. */
362433d6423SLionel Sambuc   struct rprocpub *rpub;
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc   rpub = rp->r_pub;
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc   if(rs_verbose)
367433d6423SLionel Sambuc       printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp),
368433d6423SLionel Sambuc           rp->r_flags & RS_EXITING ? "lethally " : "", file, line);
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc   /* RS should simply exit() directly. */
371433d6423SLionel Sambuc   if(rpub->endpoint == RS_PROC_NR) {
372433d6423SLionel Sambuc       exit(1);
373433d6423SLionel Sambuc   }
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc   return sys_kill(rpub->endpoint, SIGKILL);
376433d6423SLionel Sambuc }
377433d6423SLionel Sambuc 
378433d6423SLionel Sambuc /*===========================================================================*
379433d6423SLionel Sambuc  *			  cleanup_service_debug				     *
380433d6423SLionel Sambuc  *===========================================================================*/
381433d6423SLionel Sambuc void cleanup_service_debug(file, line, rp)
382433d6423SLionel Sambuc char *file;
383433d6423SLionel Sambuc int line;
384433d6423SLionel Sambuc struct rproc *rp;
385433d6423SLionel Sambuc {
386433d6423SLionel Sambuc   struct rprocpub *rpub;
387433d6423SLionel Sambuc   int s;
388433d6423SLionel Sambuc 
389433d6423SLionel Sambuc   rpub = rp->r_pub;
390433d6423SLionel Sambuc 
391433d6423SLionel Sambuc   if(rs_verbose)
392433d6423SLionel Sambuc       printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp),
393433d6423SLionel Sambuc           file, line);
394433d6423SLionel Sambuc 
395433d6423SLionel Sambuc   /* Tell scheduler this process is finished */
396433d6423SLionel Sambuc   if ((s = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
397433d6423SLionel Sambuc 	printf("RS: warning: scheduler won't give up process: %d\n", s);
398433d6423SLionel Sambuc   }
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc   /* Ask PM to exit the service */
401433d6423SLionel Sambuc   if(rp->r_pid == -1) {
402433d6423SLionel Sambuc       printf("RS: warning: attempt to kill pid -1!\n");
403433d6423SLionel Sambuc   }
404433d6423SLionel Sambuc   else {
405433d6423SLionel Sambuc       srv_kill(rp->r_pid, SIGKILL);
406433d6423SLionel Sambuc   }
407433d6423SLionel Sambuc 
408433d6423SLionel Sambuc   /* Free slot, unless we're about to reuse it */
409433d6423SLionel Sambuc   if (!(rp->r_flags & RS_REINCARNATE))
410433d6423SLionel Sambuc       free_slot(rp);
411433d6423SLionel Sambuc }
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc /*===========================================================================*
414433d6423SLionel Sambuc  *				create_service				     *
415433d6423SLionel Sambuc  *===========================================================================*/
416433d6423SLionel Sambuc int create_service(rp)
417433d6423SLionel Sambuc struct rproc *rp;
418433d6423SLionel Sambuc {
419433d6423SLionel Sambuc /* Create the given system service. */
420433d6423SLionel Sambuc   int child_proc_nr_e, child_proc_nr_n;		/* child process slot */
421433d6423SLionel Sambuc   pid_t child_pid;				/* child's process id */
422433d6423SLionel Sambuc   int s, use_copy, has_replica;
423433d6423SLionel Sambuc   extern char **environ;
424433d6423SLionel Sambuc   struct rprocpub *rpub;
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc   rpub = rp->r_pub;
427433d6423SLionel Sambuc   use_copy= (rpub->sys_flags & SF_USE_COPY);
428433d6423SLionel Sambuc   has_replica= (rp->r_old_rp
429433d6423SLionel Sambuc       || (rp->r_prev_rp && !(rp->r_prev_rp->r_flags & RS_TERMINATED)));
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc   /* Do we need an existing replica to create the service? */
432433d6423SLionel Sambuc   if(!has_replica && (rpub->sys_flags & SF_NEED_REPL)) {
433433d6423SLionel Sambuc       printf("RS: unable to create service '%s' without a replica\n",
434433d6423SLionel Sambuc           rpub->label);
435433d6423SLionel Sambuc       free_slot(rp);
436433d6423SLionel Sambuc       return(EPERM);
437433d6423SLionel Sambuc   }
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc   /* Do we need an in-memory copy to create the service? */
440433d6423SLionel Sambuc   if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) {
441433d6423SLionel Sambuc       printf("RS: unable to create service '%s' without an in-memory copy\n",
442433d6423SLionel Sambuc           rpub->label);
443433d6423SLionel Sambuc       free_slot(rp);
444433d6423SLionel Sambuc       return(EPERM);
445433d6423SLionel Sambuc   }
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc   /* Do we have a copy or a command to create the service? */
448433d6423SLionel Sambuc   if(!use_copy && !strcmp(rp->r_cmd, "")) {
449433d6423SLionel Sambuc       printf("RS: unable to create service '%s' without a copy or command\n",
450433d6423SLionel Sambuc           rpub->label);
451433d6423SLionel Sambuc       free_slot(rp);
452433d6423SLionel Sambuc       return(EPERM);
453433d6423SLionel Sambuc   }
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc   /* Now fork and branch for parent and child process (and check for error).
456433d6423SLionel Sambuc    * After fork()ing, we need to pin RS memory again or pagefaults will occur
457433d6423SLionel Sambuc    * on future writes.
458433d6423SLionel Sambuc    */
459433d6423SLionel Sambuc   if(rs_verbose)
460433d6423SLionel Sambuc       printf("RS: forking child with srv_fork()...\n");
461433d6423SLionel Sambuc   child_pid= srv_fork(rp->r_uid, 0);	/* Force group to operator for now */
462433d6423SLionel Sambuc   if(child_pid < 0) {
463433d6423SLionel Sambuc       printf("RS: srv_fork() failed (error %d)\n", child_pid);
464433d6423SLionel Sambuc       free_slot(rp);
465433d6423SLionel Sambuc       return(child_pid);
466433d6423SLionel Sambuc   }
467433d6423SLionel Sambuc 
468433d6423SLionel Sambuc   /* Get endpoint of the child. */
469433d6423SLionel Sambuc   if ((s = getprocnr(child_pid, &child_proc_nr_e)) != 0)
470433d6423SLionel Sambuc 	panic("unable to get child endpoint: %d", s);
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc   /* There is now a child process. Update the system process table. */
473433d6423SLionel Sambuc   child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
474433d6423SLionel Sambuc   rp->r_flags = RS_IN_USE;			/* mark slot in use */
475433d6423SLionel Sambuc   rpub->endpoint = child_proc_nr_e;		/* set child endpoint */
476433d6423SLionel Sambuc   rp->r_pid = child_pid;			/* set child pid */
477433d6423SLionel Sambuc   rp->r_check_tm = 0;				/* not checked yet */
478433d6423SLionel Sambuc   getticks(&rp->r_alive_tm); 			/* currently alive */
479433d6423SLionel Sambuc   rp->r_stop_tm = 0;				/* not exiting yet */
480433d6423SLionel Sambuc   rp->r_backoff = 0;				/* not to be restarted */
481433d6423SLionel Sambuc   rproc_ptr[child_proc_nr_n] = rp;		/* mapping for fast access */
482433d6423SLionel Sambuc   rpub->in_use = TRUE;				/* public entry is now in use */
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc   /* Set and synch the privilege structure for the new service. */
485433d6423SLionel Sambuc   if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_SET_SYS, &rp->r_priv)) != OK
486433d6423SLionel Sambuc 	|| (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) {
487433d6423SLionel Sambuc 	printf("RS: unable to set privilege structure: %d\n", s);
488433d6423SLionel Sambuc 	cleanup_service(rp);
489433d6423SLionel Sambuc 	vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN);
490433d6423SLionel Sambuc 	return ENOMEM;
491433d6423SLionel Sambuc   }
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc   /* Set the scheduler for this process */
494433d6423SLionel Sambuc   if ((s = sched_init_proc(rp)) != OK) {
495433d6423SLionel Sambuc 	printf("RS: unable to start scheduling: %d\n", s);
496433d6423SLionel Sambuc 	cleanup_service(rp);
497433d6423SLionel Sambuc 	vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN);
498433d6423SLionel Sambuc 	return s;
499433d6423SLionel Sambuc   }
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc   /* Copy the executable image into the child process. If no copy exists,
502433d6423SLionel Sambuc    * allocate one and free it right after exec completes.
503433d6423SLionel Sambuc    */
504433d6423SLionel Sambuc   if(use_copy) {
505433d6423SLionel Sambuc       if(rs_verbose)
506433d6423SLionel Sambuc           printf("RS: %s uses an in-memory copy\n",
507433d6423SLionel Sambuc               srv_to_string(rp));
508433d6423SLionel Sambuc   }
509433d6423SLionel Sambuc   else {
510433d6423SLionel Sambuc       if ((s = read_exec(rp)) != OK) {
511433d6423SLionel Sambuc           printf("RS: read_exec failed: %d\n", s);
512433d6423SLionel Sambuc           cleanup_service(rp);
513433d6423SLionel Sambuc           vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN);
514433d6423SLionel Sambuc           return s;
515433d6423SLionel Sambuc       }
516433d6423SLionel Sambuc   }
517433d6423SLionel Sambuc   if(rs_verbose)
518433d6423SLionel Sambuc         printf("RS: execing child with srv_execve()...\n");
519433d6423SLionel Sambuc   s = srv_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rp->r_argv,
520433d6423SLionel Sambuc         environ);
521433d6423SLionel Sambuc   vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN);
522433d6423SLionel Sambuc   if (s != OK) {
523433d6423SLionel Sambuc         printf("RS: srv_execve failed: %d\n", s);
524433d6423SLionel Sambuc         cleanup_service(rp);
525433d6423SLionel Sambuc         return s;
526433d6423SLionel Sambuc   }
527433d6423SLionel Sambuc   if(!use_copy) {
528433d6423SLionel Sambuc         free_exec(rp);
529433d6423SLionel Sambuc   }
530433d6423SLionel Sambuc 
531433d6423SLionel Sambuc   /* If this is a VM instance, let VM know now. */
532433d6423SLionel Sambuc   if(rp->r_priv.s_flags & VM_SYS_PROC) {
533433d6423SLionel Sambuc       if(rs_verbose)
534433d6423SLionel Sambuc           printf("RS: informing VM of instance %s\n", srv_to_string(rp));
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc       s = vm_memctl(rpub->endpoint, VM_RS_MEM_MAKE_VM);
537433d6423SLionel Sambuc       if(s != OK) {
538433d6423SLionel Sambuc           printf("vm_memctl failed: %d\n", s);
539433d6423SLionel Sambuc           cleanup_service(rp);
540433d6423SLionel Sambuc           return s;
541433d6423SLionel Sambuc       }
542433d6423SLionel Sambuc   }
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc   /* Tell VM about allowed calls. */
545433d6423SLionel Sambuc   if ((s = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0], TRUE)) != OK) {
546433d6423SLionel Sambuc       printf("RS: vm_set_priv failed: %d\n", s);
547433d6423SLionel Sambuc       cleanup_service(rp);
548433d6423SLionel Sambuc       return s;
549433d6423SLionel Sambuc   }
550433d6423SLionel Sambuc 
551433d6423SLionel Sambuc   if(rs_verbose)
552433d6423SLionel Sambuc       printf("RS: %s created\n", srv_to_string(rp));
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc   return OK;
555433d6423SLionel Sambuc }
556433d6423SLionel Sambuc 
557433d6423SLionel Sambuc /*===========================================================================*
558433d6423SLionel Sambuc  *				clone_service				     *
559433d6423SLionel Sambuc  *===========================================================================*/
560433d6423SLionel Sambuc int clone_service(rp, instance_flag)
561433d6423SLionel Sambuc struct rproc *rp;
562433d6423SLionel Sambuc int instance_flag;
563433d6423SLionel Sambuc {
564433d6423SLionel Sambuc /* Clone the given system service instance. */
565433d6423SLionel Sambuc   struct rproc *replica_rp;
566433d6423SLionel Sambuc   struct rprocpub *replica_rpub;
567433d6423SLionel Sambuc   struct rproc **rp_link;
568433d6423SLionel Sambuc   struct rproc **replica_link;
569433d6423SLionel Sambuc   struct rproc *rs_rp;
570433d6423SLionel Sambuc   int rs_flags;
571433d6423SLionel Sambuc   int r;
572433d6423SLionel Sambuc 
573433d6423SLionel Sambuc   if(rs_verbose)
574433d6423SLionel Sambuc       printf("RS: creating a replica for %s\n", srv_to_string(rp));
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc   /* Clone slot. */
577433d6423SLionel Sambuc   if((r = clone_slot(rp, &replica_rp)) != OK) {
578433d6423SLionel Sambuc       return r;
579433d6423SLionel Sambuc   }
580433d6423SLionel Sambuc   replica_rpub = replica_rp->r_pub;
581433d6423SLionel Sambuc 
582433d6423SLionel Sambuc   /* Clone is a live updated or restarted service instance? */
583433d6423SLionel Sambuc   if(instance_flag == LU_SYS_PROC) {
584433d6423SLionel Sambuc       rp_link = &rp->r_new_rp;
585433d6423SLionel Sambuc       replica_link = &replica_rp->r_old_rp;
586433d6423SLionel Sambuc   }
587433d6423SLionel Sambuc   else {
588433d6423SLionel Sambuc       rp_link = &rp->r_next_rp;
589433d6423SLionel Sambuc       replica_link = &replica_rp->r_prev_rp;
590433d6423SLionel Sambuc   }
591433d6423SLionel Sambuc   replica_rp->r_priv.s_flags |= instance_flag;
592433d6423SLionel Sambuc 
593433d6423SLionel Sambuc   /* Link the two slots. */
594433d6423SLionel Sambuc   *rp_link = replica_rp;
595433d6423SLionel Sambuc   *replica_link = rp;
596433d6423SLionel Sambuc 
597433d6423SLionel Sambuc   /* Create a new replica of the service. */
598433d6423SLionel Sambuc   r = create_service(replica_rp);
599433d6423SLionel Sambuc   if(r != OK) {
600433d6423SLionel Sambuc       *rp_link = NULL;
601433d6423SLionel Sambuc       return r;
602433d6423SLionel Sambuc   }
603433d6423SLionel Sambuc 
604433d6423SLionel Sambuc   /* If this instance is for restarting RS, set up a backup signal manager. */
605433d6423SLionel Sambuc   rs_flags = (ROOT_SYS_PROC | RST_SYS_PROC);
606433d6423SLionel Sambuc   if((replica_rp->r_priv.s_flags & rs_flags) == rs_flags) {
607433d6423SLionel Sambuc       rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
608433d6423SLionel Sambuc 
609433d6423SLionel Sambuc       /* Update signal managers. */
610433d6423SLionel Sambuc       r = update_sig_mgrs(rs_rp, SELF, replica_rpub->endpoint);
611433d6423SLionel Sambuc       if(r == OK) {
612433d6423SLionel Sambuc           r = update_sig_mgrs(replica_rp, SELF, NONE);
613433d6423SLionel Sambuc       }
614433d6423SLionel Sambuc       if(r != OK) {
615433d6423SLionel Sambuc           *rp_link = NULL;
616433d6423SLionel Sambuc           return kill_service(replica_rp, "update_sig_mgrs failed", r);
617433d6423SLionel Sambuc       }
618433d6423SLionel Sambuc   }
619433d6423SLionel Sambuc 
620433d6423SLionel Sambuc   return OK;
621433d6423SLionel Sambuc }
622433d6423SLionel Sambuc 
623433d6423SLionel Sambuc /*===========================================================================*
624433d6423SLionel Sambuc  *				publish_service				     *
625433d6423SLionel Sambuc  *===========================================================================*/
626433d6423SLionel Sambuc int publish_service(rp)
627433d6423SLionel Sambuc struct rproc *rp;				/* pointer to service slot */
628433d6423SLionel Sambuc {
629433d6423SLionel Sambuc /* Publish a service. */
630433d6423SLionel Sambuc   int r;
631433d6423SLionel Sambuc   struct rprocpub *rpub;
632433d6423SLionel Sambuc   struct rs_pci pci_acl;
633433d6423SLionel Sambuc   message m;
634433d6423SLionel Sambuc   endpoint_t ep;
635433d6423SLionel Sambuc 
636433d6423SLionel Sambuc   rpub = rp->r_pub;
637433d6423SLionel Sambuc 
638433d6423SLionel Sambuc   /* Register label with DS. */
639433d6423SLionel Sambuc   r = ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
640433d6423SLionel Sambuc   if (r != OK) {
641433d6423SLionel Sambuc       return kill_service(rp, "ds_publish_label call failed", r);
642433d6423SLionel Sambuc   }
643433d6423SLionel Sambuc 
644433d6423SLionel Sambuc   /* If the service is a driver, map it. */
645433d6423SLionel Sambuc   if (rpub->dev_nr > 0) {
646433d6423SLionel Sambuc       /* The purpose of non-blocking forks is to avoid involving VFS in the
647433d6423SLionel Sambuc        * forking process, because VFS may be blocked on a ipc_sendrec() to a MFS
648433d6423SLionel Sambuc        * that is waiting for a endpoint update for a dead driver. We have just
649433d6423SLionel Sambuc        * published that update, but VFS may still be blocked. As a result, VFS
650433d6423SLionel Sambuc        * may not yet have received PM's fork message. Hence, if we call
651433d6423SLionel Sambuc        * mapdriver() immediately, VFS may not know about the process and thus
652433d6423SLionel Sambuc        * refuse to add the driver entry. The following temporary hack works
653433d6423SLionel Sambuc        * around this by forcing blocking communication from PM to VFS. Once VFS
654433d6423SLionel Sambuc        * has been made non-blocking towards MFS instances, this hack and the
655433d6423SLionel Sambuc        * big part of srv_fork() can go.
656433d6423SLionel Sambuc        */
657433d6423SLionel Sambuc       setuid(0);
658433d6423SLionel Sambuc 
659433d6423SLionel Sambuc       if ((r = mapdriver(rpub->label, rpub->dev_nr)) != OK) {
660433d6423SLionel Sambuc           return kill_service(rp, "couldn't map driver", r);
661433d6423SLionel Sambuc       }
662433d6423SLionel Sambuc   }
663433d6423SLionel Sambuc 
664433d6423SLionel Sambuc #if USE_PCI
665433d6423SLionel Sambuc   /* If PCI properties are set, inform the PCI driver about the new service. */
666433d6423SLionel Sambuc   if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
667433d6423SLionel Sambuc       pci_acl = rpub->pci_acl;
668433d6423SLionel Sambuc       strcpy(pci_acl.rsp_label, rpub->label);
669433d6423SLionel Sambuc       pci_acl.rsp_endpoint= rpub->endpoint;
670433d6423SLionel Sambuc 
671433d6423SLionel Sambuc       r = pci_set_acl(&pci_acl);
672433d6423SLionel Sambuc       if (r != OK) {
673433d6423SLionel Sambuc           return kill_service(rp, "pci_set_acl call failed", r);
674433d6423SLionel Sambuc       }
675433d6423SLionel Sambuc   }
676433d6423SLionel Sambuc #endif /* USE_PCI */
677433d6423SLionel Sambuc 
678433d6423SLionel Sambuc   if (rpub->devman_id != 0) {
679433d6423SLionel Sambuc 	  r = ds_retrieve_label_endpt("devman",&ep);
680433d6423SLionel Sambuc 
681433d6423SLionel Sambuc 	  if (r != OK) {
682433d6423SLionel Sambuc 		return kill_service(rp, "devman not running?", r);
683433d6423SLionel Sambuc 	  }
684433d6423SLionel Sambuc 	  m.m_type = DEVMAN_BIND;
685433d6423SLionel Sambuc 	  m.DEVMAN_ENDPOINT  = rpub->endpoint;
686433d6423SLionel Sambuc 	  m.DEVMAN_DEVICE_ID = rpub->devman_id;
687433d6423SLionel Sambuc 	  r = ipc_sendrec(ep, &m);
688433d6423SLionel Sambuc 	  if (r != OK || m.DEVMAN_RESULT != OK) {
689433d6423SLionel Sambuc 		 return kill_service(rp, "devman bind device failed", r);
690433d6423SLionel Sambuc 	  }
691433d6423SLionel Sambuc   }
692433d6423SLionel Sambuc 
693433d6423SLionel Sambuc   if(rs_verbose)
694433d6423SLionel Sambuc       printf("RS: %s published\n", srv_to_string(rp));
695433d6423SLionel Sambuc 
696433d6423SLionel Sambuc   return OK;
697433d6423SLionel Sambuc }
698433d6423SLionel Sambuc 
699433d6423SLionel Sambuc /*===========================================================================*
700433d6423SLionel Sambuc  *			      unpublish_service				     *
701433d6423SLionel Sambuc  *===========================================================================*/
702433d6423SLionel Sambuc int unpublish_service(rp)
703433d6423SLionel Sambuc struct rproc *rp;				/* pointer to service slot */
704433d6423SLionel Sambuc {
705433d6423SLionel Sambuc /* Unpublish a service. */
706433d6423SLionel Sambuc   struct rprocpub *rpub;
707433d6423SLionel Sambuc   int r, result;
708433d6423SLionel Sambuc   message m;
709433d6423SLionel Sambuc   endpoint_t ep;
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc 
712433d6423SLionel Sambuc   rpub = rp->r_pub;
713433d6423SLionel Sambuc   result = OK;
714433d6423SLionel Sambuc 
715433d6423SLionel Sambuc   /* Unregister label with DS. */
716433d6423SLionel Sambuc   r = ds_delete_label(rpub->label);
717433d6423SLionel Sambuc   if (r != OK && !shutting_down) {
718433d6423SLionel Sambuc      printf("RS: ds_delete_label call failed (error %d)\n", r);
719433d6423SLionel Sambuc      result = r;
720433d6423SLionel Sambuc   }
721433d6423SLionel Sambuc 
722433d6423SLionel Sambuc   /* No need to inform VFS and VM, cleanup is done on exit automatically. */
723433d6423SLionel Sambuc 
724433d6423SLionel Sambuc #if USE_PCI
725433d6423SLionel Sambuc   /* If PCI properties are set, inform the PCI driver. */
726433d6423SLionel Sambuc   if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
727433d6423SLionel Sambuc       r = pci_del_acl(rpub->endpoint);
728433d6423SLionel Sambuc       if (r != OK && !shutting_down) {
729433d6423SLionel Sambuc           printf("RS: pci_del_acl call failed (error %d)\n", r);
730433d6423SLionel Sambuc           result = r;
731433d6423SLionel Sambuc       }
732433d6423SLionel Sambuc   }
733433d6423SLionel Sambuc #endif /* USE_PCI */
734433d6423SLionel Sambuc 
735433d6423SLionel Sambuc   if (rpub->devman_id != 0) {
736433d6423SLionel Sambuc 	  r = ds_retrieve_label_endpt("devman",&ep);
737433d6423SLionel Sambuc 
738433d6423SLionel Sambuc 	  if (r != OK) {
739433d6423SLionel Sambuc 		printf("RS: devman not running?");
740433d6423SLionel Sambuc 	  } else {
741433d6423SLionel Sambuc 		m.m_type = DEVMAN_UNBIND;
742433d6423SLionel Sambuc 		m.DEVMAN_ENDPOINT  = rpub->endpoint;
743433d6423SLionel Sambuc 		m.DEVMAN_DEVICE_ID = rpub->devman_id;
744433d6423SLionel Sambuc 		r = ipc_sendrec(ep, &m);
745433d6423SLionel Sambuc 
746433d6423SLionel Sambuc 		if (r != OK || m.DEVMAN_RESULT != OK) {
747433d6423SLionel Sambuc 			 printf("RS: devman unbind device failed");
748433d6423SLionel Sambuc 		}
749433d6423SLionel Sambuc 	  }
750433d6423SLionel Sambuc   }
751433d6423SLionel Sambuc 
752433d6423SLionel Sambuc   if(rs_verbose)
753433d6423SLionel Sambuc       printf("RS: %s unpublished\n", srv_to_string(rp));
754433d6423SLionel Sambuc 
755433d6423SLionel Sambuc   return result;
756433d6423SLionel Sambuc }
757433d6423SLionel Sambuc 
758433d6423SLionel Sambuc /*===========================================================================*
759433d6423SLionel Sambuc  *				run_service				     *
760433d6423SLionel Sambuc  *===========================================================================*/
761433d6423SLionel Sambuc int run_service(rp, init_type)
762433d6423SLionel Sambuc struct rproc *rp;
763433d6423SLionel Sambuc int init_type;
764433d6423SLionel Sambuc {
765433d6423SLionel Sambuc /* Let a newly created service run. */
766433d6423SLionel Sambuc   struct rprocpub *rpub;
767433d6423SLionel Sambuc   int s;
768433d6423SLionel Sambuc 
769433d6423SLionel Sambuc   rpub = rp->r_pub;
770433d6423SLionel Sambuc 
771433d6423SLionel Sambuc   /* Allow the service to run. */
772433d6423SLionel Sambuc   if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
773433d6423SLionel Sambuc       return kill_service(rp, "unable to allow the service to run",s);
774433d6423SLionel Sambuc   }
775433d6423SLionel Sambuc 
776433d6423SLionel Sambuc   /* Initialize service. */
777433d6423SLionel Sambuc   if((s = init_service(rp, init_type)) != OK) {
778433d6423SLionel Sambuc       return kill_service(rp, "unable to initialize service", s);
779433d6423SLionel Sambuc   }
780433d6423SLionel Sambuc 
781433d6423SLionel Sambuc   if(rs_verbose)
782433d6423SLionel Sambuc       printf("RS: %s allowed to run\n", srv_to_string(rp));
783433d6423SLionel Sambuc 
784433d6423SLionel Sambuc   return OK;
785433d6423SLionel Sambuc }
786433d6423SLionel Sambuc 
787433d6423SLionel Sambuc /*===========================================================================*
788433d6423SLionel Sambuc  *				start_service				     *
789433d6423SLionel Sambuc  *===========================================================================*/
790433d6423SLionel Sambuc int start_service(rp)
791433d6423SLionel Sambuc struct rproc *rp;
792433d6423SLionel Sambuc {
793433d6423SLionel Sambuc /* Start a system service. */
794433d6423SLionel Sambuc   int r, init_type;
795433d6423SLionel Sambuc   struct rprocpub *rpub;
796433d6423SLionel Sambuc 
797433d6423SLionel Sambuc   rpub = rp->r_pub;
798433d6423SLionel Sambuc 
799433d6423SLionel Sambuc   /* Create and make active. */
800433d6423SLionel Sambuc   r = create_service(rp);
801433d6423SLionel Sambuc   if(r != OK) {
802433d6423SLionel Sambuc       return r;
803433d6423SLionel Sambuc   }
804433d6423SLionel Sambuc   activate_service(rp, NULL);
805433d6423SLionel Sambuc 
806433d6423SLionel Sambuc   /* Publish service properties. */
807433d6423SLionel Sambuc   r = publish_service(rp);
808433d6423SLionel Sambuc   if (r != OK) {
809433d6423SLionel Sambuc       return r;
810433d6423SLionel Sambuc   }
811433d6423SLionel Sambuc 
812433d6423SLionel Sambuc   /* Run. */
813433d6423SLionel Sambuc   init_type = SEF_INIT_FRESH;
814433d6423SLionel Sambuc   r = run_service(rp, init_type);
815433d6423SLionel Sambuc   if(r != OK) {
816433d6423SLionel Sambuc       return r;
817433d6423SLionel Sambuc   }
818433d6423SLionel Sambuc 
819433d6423SLionel Sambuc   if(rs_verbose)
820433d6423SLionel Sambuc       printf("RS: %s started with major %d\n", srv_to_string(rp),
821433d6423SLionel Sambuc           rpub->dev_nr);
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc   return OK;
824433d6423SLionel Sambuc }
825433d6423SLionel Sambuc 
826433d6423SLionel Sambuc /*===========================================================================*
827433d6423SLionel Sambuc  *				stop_service				     *
828433d6423SLionel Sambuc  *===========================================================================*/
829433d6423SLionel Sambuc void stop_service(struct rproc *rp,int how)
830433d6423SLionel Sambuc {
831433d6423SLionel Sambuc   struct rprocpub *rpub;
832433d6423SLionel Sambuc   int signo;
833433d6423SLionel Sambuc 
834433d6423SLionel Sambuc   rpub = rp->r_pub;
835433d6423SLionel Sambuc 
836433d6423SLionel Sambuc   /* Try to stop the system service. First send a SIGTERM signal to ask the
837433d6423SLionel Sambuc    * system service to terminate. If the service didn't install a signal
838433d6423SLionel Sambuc    * handler, it will be killed. If it did and ignores the signal, we'll
839433d6423SLionel Sambuc    * find out because we record the time here and send a SIGKILL.
840433d6423SLionel Sambuc    */
841433d6423SLionel Sambuc   if(rs_verbose)
842433d6423SLionel Sambuc       printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp));
843433d6423SLionel Sambuc 
844433d6423SLionel Sambuc   signo = rpub->endpoint != RS_PROC_NR ? SIGTERM : SIGHUP; /* SIGHUP for RS. */
845433d6423SLionel Sambuc 
846433d6423SLionel Sambuc   rp->r_flags |= how;				/* what to on exit? */
847433d6423SLionel Sambuc   sys_kill(rpub->endpoint, signo);		/* first try friendly */
848433d6423SLionel Sambuc   getticks(&rp->r_stop_tm); 			/* record current time */
849433d6423SLionel Sambuc }
850433d6423SLionel Sambuc 
851433d6423SLionel Sambuc /*===========================================================================*
852433d6423SLionel Sambuc  *				update_service				     *
853433d6423SLionel Sambuc  *===========================================================================*/
854433d6423SLionel Sambuc int update_service(src_rpp, dst_rpp, swap_flag)
855433d6423SLionel Sambuc struct rproc **src_rpp;
856433d6423SLionel Sambuc struct rproc **dst_rpp;
857433d6423SLionel Sambuc int swap_flag;
858433d6423SLionel Sambuc {
859433d6423SLionel Sambuc /* Update an existing service. */
860433d6423SLionel Sambuc   int r;
861433d6423SLionel Sambuc   struct rproc *src_rp;
862433d6423SLionel Sambuc   struct rproc *dst_rp;
863433d6423SLionel Sambuc   struct rprocpub *src_rpub;
864433d6423SLionel Sambuc   struct rprocpub *dst_rpub;
865433d6423SLionel Sambuc   int pid;
866433d6423SLionel Sambuc   endpoint_t endpoint;
867433d6423SLionel Sambuc 
868433d6423SLionel Sambuc   src_rp = *src_rpp;
869433d6423SLionel Sambuc   dst_rp = *dst_rpp;
870433d6423SLionel Sambuc   src_rpub = src_rp->r_pub;
871433d6423SLionel Sambuc   dst_rpub = dst_rp->r_pub;
872433d6423SLionel Sambuc 
873433d6423SLionel Sambuc   if(rs_verbose)
874433d6423SLionel Sambuc       printf("RS: %s updating into %s\n",
875433d6423SLionel Sambuc           srv_to_string(src_rp), srv_to_string(dst_rp));
876433d6423SLionel Sambuc 
877433d6423SLionel Sambuc   /* Swap the slots of the two processes when asked to. */
878433d6423SLionel Sambuc   if(swap_flag == RS_SWAP) {
879433d6423SLionel Sambuc       if((r = srv_update(src_rpub->endpoint, dst_rpub->endpoint)) != OK) {
880433d6423SLionel Sambuc           return r;
881433d6423SLionel Sambuc       }
882433d6423SLionel Sambuc   }
883433d6423SLionel Sambuc 
884433d6423SLionel Sambuc   /* Swap slots here as well. */
885433d6423SLionel Sambuc   pid = src_rp->r_pid;
886433d6423SLionel Sambuc   endpoint = src_rpub->endpoint;
887433d6423SLionel Sambuc   swap_slot(&src_rp, &dst_rp);
888433d6423SLionel Sambuc 
889433d6423SLionel Sambuc   /* Reassign pids and endpoints. */
890433d6423SLionel Sambuc   src_rp->r_pid = dst_rp->r_pid;
891433d6423SLionel Sambuc   src_rp->r_pub->endpoint = dst_rp->r_pub->endpoint;
892433d6423SLionel Sambuc   rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)] = src_rp;
893433d6423SLionel Sambuc   dst_rp->r_pid = pid;
894433d6423SLionel Sambuc   dst_rp->r_pub->endpoint = endpoint;
895433d6423SLionel Sambuc   rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)] = dst_rp;
896433d6423SLionel Sambuc 
897433d6423SLionel Sambuc   /* Adjust input pointers. */
898433d6423SLionel Sambuc   *src_rpp = src_rp;
899433d6423SLionel Sambuc   *dst_rpp = dst_rp;
900433d6423SLionel Sambuc 
901433d6423SLionel Sambuc   /* Make the new version active. */
902433d6423SLionel Sambuc   activate_service(dst_rp, src_rp);
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc   if(rs_verbose)
905433d6423SLionel Sambuc       printf("RS: %s updated into %s\n",
906433d6423SLionel Sambuc           srv_to_string(src_rp), srv_to_string(dst_rp));
907433d6423SLionel Sambuc 
908433d6423SLionel Sambuc   return OK;
909433d6423SLionel Sambuc }
910433d6423SLionel Sambuc 
911433d6423SLionel Sambuc /*===========================================================================*
912433d6423SLionel Sambuc  *			      activate_service				     *
913433d6423SLionel Sambuc  *===========================================================================*/
914433d6423SLionel Sambuc void activate_service(struct rproc *rp, struct rproc *ex_rp)
915433d6423SLionel Sambuc {
916433d6423SLionel Sambuc /* Activate a service instance and deactivate another one if requested. */
917433d6423SLionel Sambuc 
918433d6423SLionel Sambuc   if(ex_rp && (ex_rp->r_flags & RS_ACTIVE) ) {
919433d6423SLionel Sambuc       ex_rp->r_flags &= ~RS_ACTIVE;
920433d6423SLionel Sambuc       if(rs_verbose)
921433d6423SLionel Sambuc           printf("RS: %s becomes inactive\n", srv_to_string(ex_rp));
922433d6423SLionel Sambuc   }
923433d6423SLionel Sambuc 
924433d6423SLionel Sambuc   if(! (rp->r_flags & RS_ACTIVE) ) {
925433d6423SLionel Sambuc       rp->r_flags |= RS_ACTIVE;
926433d6423SLionel Sambuc       if(rs_verbose)
927433d6423SLionel Sambuc           printf("RS: %s becomes active\n", srv_to_string(rp));
928433d6423SLionel Sambuc   }
929433d6423SLionel Sambuc }
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc /*===========================================================================*
932433d6423SLionel Sambuc  *			      reincarnate_service			     *
933433d6423SLionel Sambuc  *===========================================================================*/
934433d6423SLionel Sambuc void reincarnate_service(struct rproc *rp)
935433d6423SLionel Sambuc {
936433d6423SLionel Sambuc /* Restart a service as if it were never started before. */
937433d6423SLionel Sambuc   struct rprocpub *rpub;
938433d6423SLionel Sambuc   int i;
939433d6423SLionel Sambuc 
940433d6423SLionel Sambuc   rpub = rp->r_pub;
941433d6423SLionel Sambuc 
942433d6423SLionel Sambuc   rp->r_flags &= RS_IN_USE;
943433d6423SLionel Sambuc   rp->r_pid = -1;
944433d6423SLionel Sambuc   rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL;
945433d6423SLionel Sambuc 
946433d6423SLionel Sambuc   /* Restore original IRQ and I/O range tables in the priv struct. This is the
947433d6423SLionel Sambuc    * only part of the privilege structure that can be modified by processes
948433d6423SLionel Sambuc    * other than RS itself.
949433d6423SLionel Sambuc    */
950433d6423SLionel Sambuc   rp->r_priv.s_nr_irq = rp->r_nr_irq;
951433d6423SLionel Sambuc   for (i = 0; i < rp->r_nr_irq; i++)
952433d6423SLionel Sambuc       rp->r_priv.s_irq_tab[i] = rp->r_irq_tab[i];
953433d6423SLionel Sambuc   rp->r_priv.s_nr_io_range = rp->r_nr_io_range;
954433d6423SLionel Sambuc   for (i = 0; i < rp->r_nr_io_range; i++)
955433d6423SLionel Sambuc       rp->r_priv.s_io_tab[i] = rp->r_io_tab[i];
956433d6423SLionel Sambuc 
957433d6423SLionel Sambuc   rp->r_old_rp = NULL;
958433d6423SLionel Sambuc   rp->r_new_rp = NULL;
959433d6423SLionel Sambuc   rp->r_prev_rp = NULL;
960433d6423SLionel Sambuc   rp->r_next_rp = NULL;
961433d6423SLionel Sambuc 
962433d6423SLionel Sambuc   start_service(rp);
963433d6423SLionel Sambuc }
964433d6423SLionel Sambuc 
965433d6423SLionel Sambuc /*===========================================================================*
966433d6423SLionel Sambuc  *			      terminate_service				     *
967433d6423SLionel Sambuc  *===========================================================================*/
968433d6423SLionel Sambuc void terminate_service(struct rproc *rp)
969433d6423SLionel Sambuc {
970433d6423SLionel Sambuc /* Handle a termination event for a system service. */
971433d6423SLionel Sambuc   struct rproc **rps;
972433d6423SLionel Sambuc   struct rprocpub *rpub;
973433d6423SLionel Sambuc   int nr_rps;
974433d6423SLionel Sambuc   int i, r;
975433d6423SLionel Sambuc 
976433d6423SLionel Sambuc   rpub = rp->r_pub;
977433d6423SLionel Sambuc 
978433d6423SLionel Sambuc   if(rs_verbose)
979433d6423SLionel Sambuc      printf("RS: %s terminated\n", srv_to_string(rp));
980433d6423SLionel Sambuc 
981433d6423SLionel Sambuc   /* Deal with failures during initialization. */
982433d6423SLionel Sambuc   if(rp->r_flags & RS_INITIALIZING) {
983433d6423SLionel Sambuc       if (rpub->sys_flags & SF_NO_BIN_EXP) {
984433d6423SLionel Sambuc           /* If service was deliberately started with binary exponential offset
985433d6423SLionel Sambuc 	   * disabled, we're going to assume we want to refresh a service upon
986433d6423SLionel Sambuc 	   * failure.
987433d6423SLionel Sambuc 	   */
988433d6423SLionel Sambuc           if(rs_verbose)
989433d6423SLionel Sambuc               printf("RS: service '%s' exited during initialization; "
990433d6423SLionel Sambuc 		     "refreshing\n", rpub->label);
991433d6423SLionel Sambuc           rp->r_flags |= RS_REFRESHING; /* restart initialization. */
992433d6423SLionel Sambuc       } else {
993433d6423SLionel Sambuc           if(rs_verbose)
994433d6423SLionel Sambuc               printf("RS: service '%s' exited during initialization; "
995433d6423SLionel Sambuc                      "not restarting\n", rpub->label);
996433d6423SLionel Sambuc           rp->r_flags |= RS_EXITING; /* don't restart. */
997433d6423SLionel Sambuc       }
998433d6423SLionel Sambuc 
999433d6423SLionel Sambuc       /* If updating, rollback. */
1000433d6423SLionel Sambuc       if(rp->r_flags & RS_UPDATING) {
1001433d6423SLionel Sambuc           struct rproc *old_rp, *new_rp;
1002433d6423SLionel Sambuc           printf("RS: update failed: state transfer failed. Rolling back...\n");
1003433d6423SLionel Sambuc           new_rp = rp;
1004433d6423SLionel Sambuc           old_rp = new_rp->r_old_rp;
1005433d6423SLionel Sambuc           new_rp->r_flags &= ~RS_INITIALIZING;
1006433d6423SLionel Sambuc           r = update_service(&new_rp, &old_rp, RS_SWAP);
1007433d6423SLionel Sambuc           assert(r == OK); /* can't fail */
1008433d6423SLionel Sambuc           end_update(ERESTART, RS_REPLY);
1009433d6423SLionel Sambuc           return;
1010433d6423SLionel Sambuc       }
1011433d6423SLionel Sambuc   }
1012433d6423SLionel Sambuc 
1013433d6423SLionel Sambuc   if (rp->r_flags & RS_EXITING) {
1014433d6423SLionel Sambuc       /* If a core system service is exiting, we are in trouble. */
1015433d6423SLionel Sambuc       if (rp->r_pub->sys_flags & SF_CORE_SRV && !shutting_down) {
1016433d6423SLionel Sambuc           printf("core system service died: %s\n", srv_to_string(rp));
1017433d6423SLionel Sambuc 	  _exit(1);
1018433d6423SLionel Sambuc       }
1019433d6423SLionel Sambuc 
1020433d6423SLionel Sambuc       /* See if a late reply has to be sent. */
1021433d6423SLionel Sambuc       r = (rp->r_caller_request == RS_DOWN ? OK : EDEADEPT);
1022433d6423SLionel Sambuc       late_reply(rp, r);
1023433d6423SLionel Sambuc 
1024433d6423SLionel Sambuc       /* Unpublish the service. */
1025433d6423SLionel Sambuc       unpublish_service(rp);
1026433d6423SLionel Sambuc 
1027433d6423SLionel Sambuc       /* Cleanup all the instances of the service. */
1028433d6423SLionel Sambuc       get_service_instances(rp, &rps, &nr_rps);
1029433d6423SLionel Sambuc       for(i=0;i<nr_rps;i++) {
1030433d6423SLionel Sambuc           cleanup_service(rps[i]);
1031433d6423SLionel Sambuc       }
1032433d6423SLionel Sambuc 
1033433d6423SLionel Sambuc       /* If the service is reincarnating, its slot has not been cleaned up.
1034433d6423SLionel Sambuc        * Check for this flag now, and attempt to start the service again.
1035433d6423SLionel Sambuc        * If this fails, start_service() itself will perform cleanup.
1036433d6423SLionel Sambuc        */
1037433d6423SLionel Sambuc       if (rp->r_flags & RS_REINCARNATE) {
1038433d6423SLionel Sambuc           reincarnate_service(rp);
1039433d6423SLionel Sambuc       }
1040433d6423SLionel Sambuc   }
1041433d6423SLionel Sambuc   else if(rp->r_flags & RS_REFRESHING) {
1042433d6423SLionel Sambuc       /* Restart service. */
1043433d6423SLionel Sambuc       restart_service(rp);
1044433d6423SLionel Sambuc   }
1045433d6423SLionel Sambuc   else {
1046433d6423SLionel Sambuc       /* If an update is in progress, end it. The old version
1047433d6423SLionel Sambuc        * that just exited will continue executing.
1048433d6423SLionel Sambuc        */
1049433d6423SLionel Sambuc       if(rp->r_flags & RS_UPDATING) {
1050433d6423SLionel Sambuc           end_update(ERESTART, RS_DONTREPLY);
1051433d6423SLionel Sambuc       }
1052433d6423SLionel Sambuc 
1053433d6423SLionel Sambuc       /* Determine what to do. If this is the first unexpected
1054433d6423SLionel Sambuc        * exit, immediately restart this service. Otherwise use
1055433d6423SLionel Sambuc        * a binary exponential backoff.
1056433d6423SLionel Sambuc        */
1057433d6423SLionel Sambuc       if (rp->r_restarts > 0) {
1058433d6423SLionel Sambuc           if (!(rpub->sys_flags & SF_NO_BIN_EXP)) {
1059433d6423SLionel Sambuc               rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
1060433d6423SLionel Sambuc               rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
1061433d6423SLionel Sambuc               if ((rpub->sys_flags & SF_USE_COPY) && rp->r_backoff > 1)
1062433d6423SLionel Sambuc                   rp->r_backoff= 1;
1063433d6423SLionel Sambuc 	  }
1064433d6423SLionel Sambuc 	  else {
1065433d6423SLionel Sambuc               rp->r_backoff = 1;
1066433d6423SLionel Sambuc 	  }
1067433d6423SLionel Sambuc           return;
1068433d6423SLionel Sambuc       }
1069433d6423SLionel Sambuc 
1070433d6423SLionel Sambuc       /* Restart service. */
1071433d6423SLionel Sambuc       restart_service(rp);
1072433d6423SLionel Sambuc   }
1073433d6423SLionel Sambuc }
1074433d6423SLionel Sambuc 
1075433d6423SLionel Sambuc /*===========================================================================*
1076433d6423SLionel Sambuc  *				run_script				     *
1077433d6423SLionel Sambuc  *===========================================================================*/
1078433d6423SLionel Sambuc static int run_script(struct rproc *rp)
1079433d6423SLionel Sambuc {
1080433d6423SLionel Sambuc 	int r, endpoint;
1081433d6423SLionel Sambuc 	pid_t pid;
1082433d6423SLionel Sambuc 	char *reason;
1083433d6423SLionel Sambuc 	char incarnation_str[20];	/* Enough for a counter? */
1084433d6423SLionel Sambuc 	char *envp[1] = { NULL };
1085433d6423SLionel Sambuc 	struct rprocpub *rpub;
1086433d6423SLionel Sambuc 
1087433d6423SLionel Sambuc 	rpub = rp->r_pub;
1088433d6423SLionel Sambuc 	if (rp->r_flags & RS_REFRESHING)
1089433d6423SLionel Sambuc 		reason= "restart";
1090433d6423SLionel Sambuc 	else if (rp->r_flags & RS_NOPINGREPLY)
1091433d6423SLionel Sambuc 		reason= "no-heartbeat";
1092433d6423SLionel Sambuc 	else reason= "terminated";
1093433d6423SLionel Sambuc 	sprintf(incarnation_str, "%d", rp->r_restarts);
1094433d6423SLionel Sambuc 
1095433d6423SLionel Sambuc  	if(rs_verbose) {
1096433d6423SLionel Sambuc 		printf("RS: %s:\n", srv_to_string(rp));
1097433d6423SLionel Sambuc 		printf("RS:     calling script '%s'\n", rp->r_script);
1098433d6423SLionel Sambuc 		printf("RS:     reason: '%s'\n", reason);
1099433d6423SLionel Sambuc 		printf("RS:     incarnation: '%s'\n", incarnation_str);
1100433d6423SLionel Sambuc 	}
1101433d6423SLionel Sambuc 
1102433d6423SLionel Sambuc 	pid= fork();
1103433d6423SLionel Sambuc 	switch(pid)
1104433d6423SLionel Sambuc 	{
1105433d6423SLionel Sambuc 	case -1:
1106433d6423SLionel Sambuc 		return kill_service(rp, "unable to fork script", errno);
1107433d6423SLionel Sambuc 	case 0:
1108433d6423SLionel Sambuc 		execle(_PATH_BSHELL, "sh", rp->r_script, rpub->label, reason,
1109433d6423SLionel Sambuc 			incarnation_str, (char*) NULL, envp);
1110433d6423SLionel Sambuc 		printf("RS: run_script: execl '%s' failed: %s\n",
1111433d6423SLionel Sambuc 			rp->r_script, strerror(errno));
1112433d6423SLionel Sambuc 		exit(1);
1113433d6423SLionel Sambuc 	default:
1114433d6423SLionel Sambuc 		/* Set the privilege structure for the child process. */
1115433d6423SLionel Sambuc 		if ((r = getprocnr(pid, &endpoint)) != 0)
1116433d6423SLionel Sambuc 			panic("unable to get child endpoint: %d", r);
1117433d6423SLionel Sambuc 		if ((r = sys_privctl(endpoint, SYS_PRIV_SET_USER, NULL))
1118433d6423SLionel Sambuc 			!= OK) {
1119433d6423SLionel Sambuc 			return kill_service(rp,"can't set script privileges",r);
1120433d6423SLionel Sambuc 		}
1121433d6423SLionel Sambuc 		/* Set the script's privileges on other servers. */
1122433d6423SLionel Sambuc 		vm_set_priv(endpoint, NULL, FALSE);
1123433d6423SLionel Sambuc 		if ((r = vm_set_priv(endpoint, NULL, FALSE)) != OK) {
1124433d6423SLionel Sambuc 			return kill_service(rp,"can't set script VM privs",r);
1125433d6423SLionel Sambuc 		}
1126433d6423SLionel Sambuc 		/* Allow the script to run. */
1127433d6423SLionel Sambuc 		if ((r = sys_privctl(endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
1128433d6423SLionel Sambuc 			return kill_service(rp,"can't let the script run",r);
1129433d6423SLionel Sambuc 		}
1130433d6423SLionel Sambuc 		/* Pin RS memory again after fork()ing. */
1131433d6423SLionel Sambuc 		vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN);
1132433d6423SLionel Sambuc 	}
1133433d6423SLionel Sambuc 	return OK;
1134433d6423SLionel Sambuc }
1135433d6423SLionel Sambuc 
1136433d6423SLionel Sambuc /*===========================================================================*
1137433d6423SLionel Sambuc  *			      restart_service				     *
1138433d6423SLionel Sambuc  *===========================================================================*/
1139433d6423SLionel Sambuc void restart_service(struct rproc *rp)
1140433d6423SLionel Sambuc {
1141433d6423SLionel Sambuc /* Restart service via a recovery script or directly. */
1142433d6423SLionel Sambuc   struct rproc *replica_rp;
1143433d6423SLionel Sambuc   int r;
1144433d6423SLionel Sambuc 
1145433d6423SLionel Sambuc   /* See if a late reply has to be sent. */
1146433d6423SLionel Sambuc   late_reply(rp, OK);
1147433d6423SLionel Sambuc 
1148433d6423SLionel Sambuc   /* This hack disables restarting of file servers, which at the moment always
1149433d6423SLionel Sambuc    * cause VFS to hang indefinitely. As soon as VFS no longer blocks on calls
1150433d6423SLionel Sambuc    * to file servers, this exception can be removed again.
1151433d6423SLionel Sambuc    */
1152433d6423SLionel Sambuc   if (!strncmp(rp->r_pub->label, "fs_", 3)) {
1153433d6423SLionel Sambuc       kill_service(rp, "file servers cannot be restarted yet", ENOSYS);
1154433d6423SLionel Sambuc       return;
1155433d6423SLionel Sambuc   }
1156433d6423SLionel Sambuc 
1157433d6423SLionel Sambuc   /* Run a recovery script if available. */
1158433d6423SLionel Sambuc   if (rp->r_script[0] != '\0') {
1159433d6423SLionel Sambuc       run_script(rp);
1160433d6423SLionel Sambuc       return;
1161433d6423SLionel Sambuc   }
1162433d6423SLionel Sambuc 
1163433d6423SLionel Sambuc   /* Restart directly. We need a replica if not already available. */
1164433d6423SLionel Sambuc   if(rp->r_next_rp == NULL) {
1165433d6423SLionel Sambuc       /* Create the replica. */
1166433d6423SLionel Sambuc       r = clone_service(rp, RST_SYS_PROC);
1167433d6423SLionel Sambuc       if(r != OK) {
1168433d6423SLionel Sambuc           kill_service(rp, "unable to clone service", r);
1169433d6423SLionel Sambuc           return;
1170433d6423SLionel Sambuc       }
1171433d6423SLionel Sambuc   }
1172433d6423SLionel Sambuc   replica_rp = rp->r_next_rp;
1173433d6423SLionel Sambuc 
1174433d6423SLionel Sambuc   /* Update the service into the replica. */
1175433d6423SLionel Sambuc   r = update_service(&rp, &replica_rp, RS_SWAP);
1176433d6423SLionel Sambuc   if(r != OK) {
1177433d6423SLionel Sambuc       kill_service(rp, "unable to update into new replica", r);
1178433d6423SLionel Sambuc       return;
1179433d6423SLionel Sambuc   }
1180433d6423SLionel Sambuc 
1181433d6423SLionel Sambuc   /* Let the new replica run. */
1182433d6423SLionel Sambuc   r = run_service(replica_rp, SEF_INIT_RESTART);
1183433d6423SLionel Sambuc   if(r != OK) {
1184433d6423SLionel Sambuc       kill_service(rp, "unable to let the replica run", r);
1185433d6423SLionel Sambuc       return;
1186433d6423SLionel Sambuc   }
1187433d6423SLionel Sambuc 
1188433d6423SLionel Sambuc   if(rs_verbose)
1189433d6423SLionel Sambuc       printf("RS: %s restarted into %s\n",
1190433d6423SLionel Sambuc           srv_to_string(rp), srv_to_string(replica_rp));
1191433d6423SLionel Sambuc }
1192433d6423SLionel Sambuc 
1193433d6423SLionel Sambuc /*===========================================================================*
1194433d6423SLionel Sambuc  *		         inherit_service_defaults			     *
1195433d6423SLionel Sambuc  *===========================================================================*/
1196433d6423SLionel Sambuc void inherit_service_defaults(def_rp, rp)
1197433d6423SLionel Sambuc struct rproc *def_rp;
1198433d6423SLionel Sambuc struct rproc *rp;
1199433d6423SLionel Sambuc {
1200433d6423SLionel Sambuc   struct rprocpub *def_rpub;
1201433d6423SLionel Sambuc   struct rprocpub *rpub;
1202433d6423SLionel Sambuc 
1203433d6423SLionel Sambuc   def_rpub = def_rp->r_pub;
1204433d6423SLionel Sambuc   rpub = rp->r_pub;
1205433d6423SLionel Sambuc 
1206433d6423SLionel Sambuc   /* Device and PCI settings. These properties cannot change. */
1207433d6423SLionel Sambuc   rpub->dev_nr = def_rpub->dev_nr;
1208433d6423SLionel Sambuc   rpub->pci_acl = def_rpub->pci_acl;
1209433d6423SLionel Sambuc 
1210433d6423SLionel Sambuc   /* Immutable system and privilege flags. */
1211433d6423SLionel Sambuc   rpub->sys_flags &= ~IMM_SF;
1212433d6423SLionel Sambuc   rpub->sys_flags |= (def_rpub->sys_flags & IMM_SF);
1213433d6423SLionel Sambuc   rp->r_priv.s_flags &= ~IMM_F;
1214433d6423SLionel Sambuc   rp->r_priv.s_flags |= (def_rp->r_priv.s_flags & IMM_F);
1215433d6423SLionel Sambuc 
1216433d6423SLionel Sambuc   /* Allowed traps. They cannot change. */
1217433d6423SLionel Sambuc   rp->r_priv.s_trap_mask = def_rp->r_priv.s_trap_mask;
1218433d6423SLionel Sambuc }
1219433d6423SLionel Sambuc 
1220433d6423SLionel Sambuc /*===========================================================================*
1221433d6423SLionel Sambuc  *		           get_service_instances			     *
1222433d6423SLionel Sambuc  *===========================================================================*/
1223433d6423SLionel Sambuc void get_service_instances(rp, rps, length)
1224433d6423SLionel Sambuc struct rproc *rp;
1225433d6423SLionel Sambuc struct rproc ***rps;
1226433d6423SLionel Sambuc int *length;
1227433d6423SLionel Sambuc {
1228433d6423SLionel Sambuc /* Retrieve all the service instances of a given service. */
1229433d6423SLionel Sambuc   static struct rproc *instances[5];
1230433d6423SLionel Sambuc   int nr_instances;
1231433d6423SLionel Sambuc 
1232433d6423SLionel Sambuc   nr_instances = 0;
1233433d6423SLionel Sambuc   instances[nr_instances++] = rp;
1234433d6423SLionel Sambuc   if(rp->r_prev_rp) instances[nr_instances++] = rp->r_prev_rp;
1235433d6423SLionel Sambuc   if(rp->r_next_rp) instances[nr_instances++] = rp->r_next_rp;
1236433d6423SLionel Sambuc   if(rp->r_old_rp) instances[nr_instances++] = rp->r_old_rp;
1237433d6423SLionel Sambuc   if(rp->r_new_rp) instances[nr_instances++] = rp->r_new_rp;
1238433d6423SLionel Sambuc 
1239433d6423SLionel Sambuc   *rps = instances;
1240433d6423SLionel Sambuc   *length = nr_instances;
1241433d6423SLionel Sambuc }
1242433d6423SLionel Sambuc 
1243433d6423SLionel Sambuc /*===========================================================================*
1244433d6423SLionel Sambuc  *				share_exec				     *
1245433d6423SLionel Sambuc  *===========================================================================*/
1246433d6423SLionel Sambuc void share_exec(rp_dst, rp_src)
1247433d6423SLionel Sambuc struct rproc *rp_dst, *rp_src;
1248433d6423SLionel Sambuc {
1249433d6423SLionel Sambuc   if(rs_verbose)
1250433d6423SLionel Sambuc       printf("RS: %s shares exec image with %s\n",
1251433d6423SLionel Sambuc           srv_to_string(rp_dst), srv_to_string(rp_src));
1252433d6423SLionel Sambuc 
1253433d6423SLionel Sambuc   /* Share exec image from rp_src to rp_dst. */
1254433d6423SLionel Sambuc   rp_dst->r_exec_len = rp_src->r_exec_len;
1255433d6423SLionel Sambuc   rp_dst->r_exec = rp_src->r_exec;
1256433d6423SLionel Sambuc }
1257433d6423SLionel Sambuc 
1258433d6423SLionel Sambuc /*===========================================================================*
1259433d6423SLionel Sambuc  *				read_exec				     *
1260433d6423SLionel Sambuc  *===========================================================================*/
1261433d6423SLionel Sambuc int read_exec(rp)
1262433d6423SLionel Sambuc struct rproc *rp;
1263433d6423SLionel Sambuc {
1264433d6423SLionel Sambuc   int e, r, fd;
1265433d6423SLionel Sambuc   char *e_name;
1266433d6423SLionel Sambuc   struct stat sb;
1267433d6423SLionel Sambuc 
1268433d6423SLionel Sambuc   e_name= rp->r_argv[0];
1269433d6423SLionel Sambuc   if(rs_verbose)
1270433d6423SLionel Sambuc       printf("RS: service '%s' reads exec image from: %s\n", rp->r_pub->label,
1271433d6423SLionel Sambuc           e_name);
1272433d6423SLionel Sambuc 
1273433d6423SLionel Sambuc   r= stat(e_name, &sb);
1274433d6423SLionel Sambuc   if (r != 0)
1275433d6423SLionel Sambuc       return -errno;
1276433d6423SLionel Sambuc 
1277*37f29f55SLionel Sambuc   if (sb.st_size < sizeof(Elf_Ehdr))
1278*37f29f55SLionel Sambuc       return ENOEXEC;
1279*37f29f55SLionel Sambuc 
1280433d6423SLionel Sambuc   fd= open(e_name, O_RDONLY);
1281433d6423SLionel Sambuc   if (fd == -1)
1282433d6423SLionel Sambuc       return -errno;
1283433d6423SLionel Sambuc 
1284433d6423SLionel Sambuc   rp->r_exec_len= sb.st_size;
1285433d6423SLionel Sambuc   rp->r_exec= malloc(rp->r_exec_len);
1286433d6423SLionel Sambuc   if (rp->r_exec == NULL)
1287433d6423SLionel Sambuc   {
1288433d6423SLionel Sambuc       printf("RS: read_exec: unable to allocate %d bytes\n",
1289433d6423SLionel Sambuc           rp->r_exec_len);
1290433d6423SLionel Sambuc       close(fd);
1291433d6423SLionel Sambuc       return ENOMEM;
1292433d6423SLionel Sambuc   }
1293433d6423SLionel Sambuc 
1294433d6423SLionel Sambuc   r= read(fd, rp->r_exec, rp->r_exec_len);
1295433d6423SLionel Sambuc   e= errno;
1296433d6423SLionel Sambuc   close(fd);
1297433d6423SLionel Sambuc   if (r == rp->r_exec_len)
1298433d6423SLionel Sambuc       return OK;
1299433d6423SLionel Sambuc 
1300433d6423SLionel Sambuc   printf("RS: read_exec: read failed %d, errno %d\n", r, e);
1301433d6423SLionel Sambuc 
1302433d6423SLionel Sambuc   free_exec(rp);
1303433d6423SLionel Sambuc 
1304433d6423SLionel Sambuc   if (r >= 0)
1305433d6423SLionel Sambuc       return EIO;
1306433d6423SLionel Sambuc   else
1307433d6423SLionel Sambuc       return -e;
1308433d6423SLionel Sambuc }
1309433d6423SLionel Sambuc 
1310433d6423SLionel Sambuc /*===========================================================================*
1311433d6423SLionel Sambuc  *				free_exec				     *
1312433d6423SLionel Sambuc  *===========================================================================*/
1313433d6423SLionel Sambuc void free_exec(rp)
1314433d6423SLionel Sambuc struct rproc *rp;
1315433d6423SLionel Sambuc {
1316433d6423SLionel Sambuc /* Free an exec image. */
1317433d6423SLionel Sambuc   int slot_nr, has_shared_exec;
1318433d6423SLionel Sambuc   struct rproc *other_rp;
1319433d6423SLionel Sambuc 
1320433d6423SLionel Sambuc   /* Search for some other slot sharing the same exec image. */
1321433d6423SLionel Sambuc   has_shared_exec = FALSE;
1322433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1323433d6423SLionel Sambuc       other_rp = &rproc[slot_nr];		/* get pointer to slot */
1324433d6423SLionel Sambuc       if (other_rp->r_flags & RS_IN_USE && other_rp != rp
1325433d6423SLionel Sambuc           && other_rp->r_exec == rp->r_exec) {  /* found! */
1326433d6423SLionel Sambuc           has_shared_exec = TRUE;
1327433d6423SLionel Sambuc           break;
1328433d6423SLionel Sambuc       }
1329433d6423SLionel Sambuc   }
1330433d6423SLionel Sambuc 
1331433d6423SLionel Sambuc   /* If nobody uses our copy of the exec image, we can try to get rid of it. */
1332433d6423SLionel Sambuc   if(!has_shared_exec) {
1333433d6423SLionel Sambuc       if(rs_verbose)
1334433d6423SLionel Sambuc           printf("RS: %s frees exec image\n", srv_to_string(rp));
1335433d6423SLionel Sambuc       free(rp->r_exec);
1336433d6423SLionel Sambuc   }
1337433d6423SLionel Sambuc   else {
1338433d6423SLionel Sambuc       if(rs_verbose)
1339433d6423SLionel Sambuc           printf("RS: %s no longer sharing exec image with %s\n",
1340433d6423SLionel Sambuc               srv_to_string(rp), srv_to_string(other_rp));
1341433d6423SLionel Sambuc   }
1342433d6423SLionel Sambuc   rp->r_exec = NULL;
1343433d6423SLionel Sambuc   rp->r_exec_len = 0;
1344433d6423SLionel Sambuc }
1345433d6423SLionel Sambuc 
1346433d6423SLionel Sambuc /*===========================================================================*
1347433d6423SLionel Sambuc  *				 edit_slot				     *
1348433d6423SLionel Sambuc  *===========================================================================*/
1349433d6423SLionel Sambuc int edit_slot(rp, rs_start, source)
1350433d6423SLionel Sambuc struct rproc *rp;
1351433d6423SLionel Sambuc struct rs_start *rs_start;
1352433d6423SLionel Sambuc endpoint_t source;
1353433d6423SLionel Sambuc {
1354433d6423SLionel Sambuc /* Edit a given slot to override existing settings. */
1355433d6423SLionel Sambuc   struct rprocpub *rpub;
1356433d6423SLionel Sambuc   char *label;
1357433d6423SLionel Sambuc   int len;
1358433d6423SLionel Sambuc   int s, i;
1359433d6423SLionel Sambuc   int basic_kc[] =  { SYS_BASIC_CALLS, NULL_C };
1360433d6423SLionel Sambuc   int basic_vmc[] =  { VM_BASIC_CALLS, NULL_C };
1361433d6423SLionel Sambuc 
1362433d6423SLionel Sambuc   rpub = rp->r_pub;
1363433d6423SLionel Sambuc 
1364433d6423SLionel Sambuc   /* Update IPC target list. */
1365433d6423SLionel Sambuc   if (rs_start->rss_ipclen==0 || rs_start->rss_ipclen+1>sizeof(rp->r_ipc_list)){
1366433d6423SLionel Sambuc       printf("RS: edit_slot: ipc list empty or long for '%s'\n", rpub->label);
1367433d6423SLionel Sambuc       return EINVAL;
1368433d6423SLionel Sambuc   }
1369433d6423SLionel Sambuc   s=sys_datacopy(source, (vir_bytes) rs_start->rss_ipc,
1370433d6423SLionel Sambuc       SELF, (vir_bytes) rp->r_ipc_list, rs_start->rss_ipclen);
1371433d6423SLionel Sambuc   if (s != OK) return(s);
1372433d6423SLionel Sambuc   rp->r_ipc_list[rs_start->rss_ipclen]= '\0';
1373433d6423SLionel Sambuc 
1374433d6423SLionel Sambuc   /* Update IRQs. */
1375433d6423SLionel Sambuc   if(rs_start->rss_nr_irq == RSS_IRQ_ALL) {
1376433d6423SLionel Sambuc       rs_start->rss_nr_irq = 0;
1377433d6423SLionel Sambuc   }
1378433d6423SLionel Sambuc   else {
1379433d6423SLionel Sambuc       rp->r_priv.s_flags |= CHECK_IRQ;
1380433d6423SLionel Sambuc   }
1381433d6423SLionel Sambuc   if (rs_start->rss_nr_irq > NR_IRQ) {
1382433d6423SLionel Sambuc       printf("RS: edit_slot: too many IRQs requested\n");
1383433d6423SLionel Sambuc       return EINVAL;
1384433d6423SLionel Sambuc   }
1385433d6423SLionel Sambuc   rp->r_nr_irq= rp->r_priv.s_nr_irq= rs_start->rss_nr_irq;
1386433d6423SLionel Sambuc   for (i= 0; i<rp->r_priv.s_nr_irq; i++) {
1387433d6423SLionel Sambuc       rp->r_irq_tab[i]= rp->r_priv.s_irq_tab[i]= rs_start->rss_irq[i];
1388433d6423SLionel Sambuc       if(rs_verbose)
1389433d6423SLionel Sambuc           printf("RS: edit_slot: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
1390433d6423SLionel Sambuc   }
1391433d6423SLionel Sambuc 
1392433d6423SLionel Sambuc   /* Update I/O ranges. */
1393433d6423SLionel Sambuc   if(rs_start->rss_nr_io == RSS_IO_ALL) {
1394433d6423SLionel Sambuc       rs_start->rss_nr_io = 0;
1395433d6423SLionel Sambuc   }
1396433d6423SLionel Sambuc   else {
1397433d6423SLionel Sambuc       rp->r_priv.s_flags |= CHECK_IO_PORT;
1398433d6423SLionel Sambuc   }
1399433d6423SLionel Sambuc   if (rs_start->rss_nr_io > NR_IO_RANGE) {
1400433d6423SLionel Sambuc       printf("RS: edit_slot: too many I/O ranges requested\n");
1401433d6423SLionel Sambuc       return EINVAL;
1402433d6423SLionel Sambuc   }
1403433d6423SLionel Sambuc   rp->r_nr_io_range= rp->r_priv.s_nr_io_range= rs_start->rss_nr_io;
1404433d6423SLionel Sambuc   for (i= 0; i<rp->r_priv.s_nr_io_range; i++) {
1405433d6423SLionel Sambuc       rp->r_priv.s_io_tab[i].ior_base= rs_start->rss_io[i].base;
1406433d6423SLionel Sambuc       rp->r_priv.s_io_tab[i].ior_limit=
1407433d6423SLionel Sambuc           rs_start->rss_io[i].base+rs_start->rss_io[i].len-1;
1408433d6423SLionel Sambuc       rp->r_io_tab[i] = rp->r_priv.s_io_tab[i];
1409433d6423SLionel Sambuc       if(rs_verbose)
1410433d6423SLionel Sambuc           printf("RS: edit_slot: I/O [%x..%x]\n",
1411433d6423SLionel Sambuc               rp->r_priv.s_io_tab[i].ior_base,
1412433d6423SLionel Sambuc               rp->r_priv.s_io_tab[i].ior_limit);
1413433d6423SLionel Sambuc   }
1414433d6423SLionel Sambuc 
1415433d6423SLionel Sambuc   /* Update kernel call mask. Inherit basic kernel calls when asked to. */
1416433d6423SLionel Sambuc   memcpy(rp->r_priv.s_k_call_mask, rs_start->rss_system,
1417433d6423SLionel Sambuc       sizeof(rp->r_priv.s_k_call_mask));
1418433d6423SLionel Sambuc   if(rs_start->rss_flags & RSS_SYS_BASIC_CALLS) {
1419433d6423SLionel Sambuc       fill_call_mask(basic_kc, NR_SYS_CALLS,
1420433d6423SLionel Sambuc           rp->r_priv.s_k_call_mask, KERNEL_CALL, FALSE);
1421433d6423SLionel Sambuc   }
1422433d6423SLionel Sambuc 
1423433d6423SLionel Sambuc   /* Update VM call mask. Inherit basic VM calls. */
1424433d6423SLionel Sambuc   memcpy(rpub->vm_call_mask, rs_start->rss_vm,
1425433d6423SLionel Sambuc       sizeof(rpub->vm_call_mask));
1426433d6423SLionel Sambuc   if(rs_start->rss_flags & RSS_VM_BASIC_CALLS) {
1427433d6423SLionel Sambuc       fill_call_mask(basic_vmc, NR_VM_CALLS,
1428433d6423SLionel Sambuc           rpub->vm_call_mask, VM_RQ_BASE, FALSE);
1429433d6423SLionel Sambuc   }
1430433d6423SLionel Sambuc 
1431433d6423SLionel Sambuc   /* Update control labels. */
1432433d6423SLionel Sambuc   if(rs_start->rss_nr_control > 0) {
1433433d6423SLionel Sambuc       int i, s;
1434433d6423SLionel Sambuc       if (rs_start->rss_nr_control > RS_NR_CONTROL) {
1435433d6423SLionel Sambuc           printf("RS: edit_slot: too many control labels\n");
1436433d6423SLionel Sambuc           return EINVAL;
1437433d6423SLionel Sambuc       }
1438433d6423SLionel Sambuc       for (i=0; i<rs_start->rss_nr_control; i++) {
1439433d6423SLionel Sambuc           s = copy_label(source, rs_start->rss_control[i].l_addr,
1440433d6423SLionel Sambuc               rs_start->rss_control[i].l_len, rp->r_control[i],
1441433d6423SLionel Sambuc               sizeof(rp->r_control[i]));
1442433d6423SLionel Sambuc           if(s != OK)
1443433d6423SLionel Sambuc               return s;
1444433d6423SLionel Sambuc       }
1445433d6423SLionel Sambuc       rp->r_nr_control = rs_start->rss_nr_control;
1446433d6423SLionel Sambuc 
1447433d6423SLionel Sambuc       if (rs_verbose) {
1448433d6423SLionel Sambuc           printf("RS: edit_slot: control labels:");
1449433d6423SLionel Sambuc           for (i=0; i<rp->r_nr_control; i++)
1450433d6423SLionel Sambuc               printf(" %s", rp->r_control[i]);
1451433d6423SLionel Sambuc           printf("\n");
1452433d6423SLionel Sambuc       }
1453433d6423SLionel Sambuc   }
1454433d6423SLionel Sambuc 
1455433d6423SLionel Sambuc   /* Update signal manager. */
1456433d6423SLionel Sambuc   rp->r_priv.s_sig_mgr = rs_start->rss_sigmgr;
1457433d6423SLionel Sambuc 
1458433d6423SLionel Sambuc   /* Update scheduling properties if possible. */
1459433d6423SLionel Sambuc   if(rp->r_scheduler != NONE) {
1460433d6423SLionel Sambuc       rp->r_scheduler = rs_start->rss_scheduler;
1461433d6423SLionel Sambuc       rp->r_priority = rs_start->rss_priority;
1462433d6423SLionel Sambuc       rp->r_quantum = rs_start->rss_quantum;
1463433d6423SLionel Sambuc       rp->r_cpu = rs_start->rss_cpu;
1464433d6423SLionel Sambuc   }
1465433d6423SLionel Sambuc 
1466433d6423SLionel Sambuc   /* Update command and arguments. */
1467433d6423SLionel Sambuc   if (rs_start->rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG);
1468433d6423SLionel Sambuc   s=sys_datacopy(source, (vir_bytes) rs_start->rss_cmd,
1469433d6423SLionel Sambuc       SELF, (vir_bytes) rp->r_cmd, rs_start->rss_cmdlen);
1470433d6423SLionel Sambuc   if (s != OK) return(s);
1471433d6423SLionel Sambuc   rp->r_cmd[rs_start->rss_cmdlen] = '\0';	/* ensure it is terminated */
1472433d6423SLionel Sambuc   if (rp->r_cmd[0] != '/') return(EINVAL);	/* insist on absolute path */
1473433d6423SLionel Sambuc 
1474433d6423SLionel Sambuc   /* Build cmd dependencies: argv and program name. */
1475433d6423SLionel Sambuc   build_cmd_dep(rp);
1476433d6423SLionel Sambuc 
1477433d6423SLionel Sambuc   /* Update label if not already set. */
1478433d6423SLionel Sambuc   if(!strcmp(rpub->label, "")) {
1479433d6423SLionel Sambuc       if(rs_start->rss_label.l_len > 0) {
1480433d6423SLionel Sambuc           /* RS_UP caller has supplied a custom label for this service. */
1481433d6423SLionel Sambuc           int s = copy_label(source, rs_start->rss_label.l_addr,
1482433d6423SLionel Sambuc               rs_start->rss_label.l_len, rpub->label, sizeof(rpub->label));
1483433d6423SLionel Sambuc           if(s != OK)
1484433d6423SLionel Sambuc               return s;
1485433d6423SLionel Sambuc           if(rs_verbose)
1486433d6423SLionel Sambuc               printf("RS: edit_slot: using label (custom) '%s'\n", rpub->label);
1487433d6423SLionel Sambuc       } else {
1488433d6423SLionel Sambuc           /* Default label for the service. */
1489433d6423SLionel Sambuc           label = rpub->proc_name;
1490433d6423SLionel Sambuc           len= strlen(label);
1491433d6423SLionel Sambuc           memcpy(rpub->label, label, len);
1492433d6423SLionel Sambuc           rpub->label[len]= '\0';
1493433d6423SLionel Sambuc           if(rs_verbose)
1494433d6423SLionel Sambuc               printf("RS: edit_slot: using label (from proc_name) '%s'\n",
1495433d6423SLionel Sambuc                   rpub->label);
1496433d6423SLionel Sambuc       }
1497433d6423SLionel Sambuc   }
1498433d6423SLionel Sambuc 
1499433d6423SLionel Sambuc   /* Update recovery script. */
1500433d6423SLionel Sambuc   if (rs_start->rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
1501433d6423SLionel Sambuc   if (rs_start->rss_script != NULL && !(rpub->sys_flags & SF_CORE_SRV)) {
1502433d6423SLionel Sambuc       s=sys_datacopy(source, (vir_bytes) rs_start->rss_script,
1503433d6423SLionel Sambuc           SELF, (vir_bytes) rp->r_script, rs_start->rss_scriptlen);
1504433d6423SLionel Sambuc       if (s != OK) return(s);
1505433d6423SLionel Sambuc       rp->r_script[rs_start->rss_scriptlen] = '\0';
1506433d6423SLionel Sambuc   }
1507433d6423SLionel Sambuc 
1508433d6423SLionel Sambuc   /* Update system flags and in-memory copy. */
1509433d6423SLionel Sambuc   if ((rs_start->rss_flags & RSS_COPY) && !(rpub->sys_flags & SF_USE_COPY)) {
1510433d6423SLionel Sambuc       int exst_cpy;
1511433d6423SLionel Sambuc       struct rproc *rp2;
1512433d6423SLionel Sambuc       struct rprocpub *rpub2;
1513433d6423SLionel Sambuc       exst_cpy = 0;
1514433d6423SLionel Sambuc 
1515433d6423SLionel Sambuc       if(rs_start->rss_flags & RSS_REUSE) {
1516433d6423SLionel Sambuc           int i;
1517433d6423SLionel Sambuc 
1518433d6423SLionel Sambuc           for(i = 0; i < NR_SYS_PROCS; i++) {
1519433d6423SLionel Sambuc               rp2 = &rproc[i];
1520433d6423SLionel Sambuc               if (!(rp2->r_flags & RS_IN_USE)) {
1521433d6423SLionel Sambuc               	  continue;
1522433d6423SLionel Sambuc               }
1523433d6423SLionel Sambuc               rpub2 = rproc[i].r_pub;
1524433d6423SLionel Sambuc               if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
1525433d6423SLionel Sambuc                   (rpub2->sys_flags & SF_USE_COPY)) {
1526433d6423SLionel Sambuc                   /* We have found the same binary that's
1527433d6423SLionel Sambuc                    * already been copied */
1528433d6423SLionel Sambuc                   exst_cpy = 1;
1529433d6423SLionel Sambuc                   break;
1530433d6423SLionel Sambuc               }
1531433d6423SLionel Sambuc           }
1532433d6423SLionel Sambuc       }
1533433d6423SLionel Sambuc 
1534433d6423SLionel Sambuc       s = OK;
1535433d6423SLionel Sambuc       if(!exst_cpy)
1536433d6423SLionel Sambuc           s = read_exec(rp);
1537433d6423SLionel Sambuc       else
1538433d6423SLionel Sambuc           share_exec(rp, rp2);
1539433d6423SLionel Sambuc 
1540433d6423SLionel Sambuc       if (s != OK)
1541433d6423SLionel Sambuc           return s;
1542433d6423SLionel Sambuc 
1543433d6423SLionel Sambuc       rpub->sys_flags |= SF_USE_COPY;
1544433d6423SLionel Sambuc   }
1545433d6423SLionel Sambuc   if (rs_start->rss_flags & RSS_REPLICA) {
1546433d6423SLionel Sambuc       rpub->sys_flags |= SF_USE_REPL;
1547433d6423SLionel Sambuc   }
1548433d6423SLionel Sambuc   if (rs_start->rss_flags & RSS_NO_BIN_EXP) {
1549433d6423SLionel Sambuc       rpub->sys_flags |= SF_NO_BIN_EXP;
1550433d6423SLionel Sambuc   }
1551433d6423SLionel Sambuc 
1552433d6423SLionel Sambuc   /* Update period. */
1553433d6423SLionel Sambuc   if(rpub->endpoint != RS_PROC_NR) {
1554433d6423SLionel Sambuc       rp->r_period = rs_start->rss_period;
1555433d6423SLionel Sambuc   }
1556433d6423SLionel Sambuc 
1557433d6423SLionel Sambuc   /* (Re)initialize privilege settings. */
1558433d6423SLionel Sambuc   init_privs(rp, &rp->r_priv);
1559433d6423SLionel Sambuc 
1560433d6423SLionel Sambuc   return OK;
1561433d6423SLionel Sambuc }
1562433d6423SLionel Sambuc 
1563433d6423SLionel Sambuc /*===========================================================================*
1564433d6423SLionel Sambuc  *				 init_slot				     *
1565433d6423SLionel Sambuc  *===========================================================================*/
1566433d6423SLionel Sambuc int init_slot(rp, rs_start, source)
1567433d6423SLionel Sambuc struct rproc *rp;
1568433d6423SLionel Sambuc struct rs_start *rs_start;
1569433d6423SLionel Sambuc endpoint_t source;
1570433d6423SLionel Sambuc {
1571433d6423SLionel Sambuc /* Initialize a slot as requested by the client. */
1572433d6423SLionel Sambuc   struct rprocpub *rpub;
1573433d6423SLionel Sambuc   int i;
1574433d6423SLionel Sambuc 
1575433d6423SLionel Sambuc   rpub = rp->r_pub;
1576433d6423SLionel Sambuc 
1577433d6423SLionel Sambuc   /* All dynamically created services get the same sys and privilege flags, and
1578433d6423SLionel Sambuc    * allowed traps. Other privilege settings can be specified at runtime. The
1579433d6423SLionel Sambuc    * privilege id is dynamically allocated by the kernel.
1580433d6423SLionel Sambuc    */
1581433d6423SLionel Sambuc   rpub->sys_flags = DSRV_SF;             /* system flags */
1582433d6423SLionel Sambuc   rp->r_priv.s_flags = DSRV_F;           /* privilege flags */
1583433d6423SLionel Sambuc   rp->r_priv.s_trap_mask = DSRV_T;       /* allowed traps */
1584433d6423SLionel Sambuc   rp->r_priv.s_bak_sig_mgr = NONE;       /* backup signal manager */
1585433d6423SLionel Sambuc 
1586433d6423SLionel Sambuc   /* Initialize uid. */
1587433d6423SLionel Sambuc   rp->r_uid= rs_start->rss_uid;
1588433d6423SLionel Sambuc 
1589433d6423SLionel Sambuc   /* Initialize device driver settings. */
1590433d6423SLionel Sambuc   rpub->dev_nr = rs_start->rss_major;
1591433d6423SLionel Sambuc   rpub->devman_id = rs_start->devman_id;
1592433d6423SLionel Sambuc 
1593433d6423SLionel Sambuc   /* Initialize pci settings. */
1594433d6423SLionel Sambuc   if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE) {
1595433d6423SLionel Sambuc       printf("RS: init_slot: too many PCI device IDs\n");
1596433d6423SLionel Sambuc       return EINVAL;
1597433d6423SLionel Sambuc   }
1598433d6423SLionel Sambuc   rpub->pci_acl.rsp_nr_device = rs_start->rss_nr_pci_id;
1599433d6423SLionel Sambuc   for (i= 0; i<rpub->pci_acl.rsp_nr_device; i++) {
1600433d6423SLionel Sambuc       rpub->pci_acl.rsp_device[i].vid= rs_start->rss_pci_id[i].vid;
1601433d6423SLionel Sambuc       rpub->pci_acl.rsp_device[i].did= rs_start->rss_pci_id[i].did;
1602433d6423SLionel Sambuc       rpub->pci_acl.rsp_device[i].sub_vid= rs_start->rss_pci_id[i].sub_vid;
1603433d6423SLionel Sambuc       rpub->pci_acl.rsp_device[i].sub_did= rs_start->rss_pci_id[i].sub_did;
1604433d6423SLionel Sambuc       if(rs_verbose)
1605433d6423SLionel Sambuc           printf("RS: init_slot: PCI %04x/%04x (sub %04x:%04x)\n",
1606433d6423SLionel Sambuc               rpub->pci_acl.rsp_device[i].vid,
1607433d6423SLionel Sambuc               rpub->pci_acl.rsp_device[i].did,
1608433d6423SLionel Sambuc               rpub->pci_acl.rsp_device[i].sub_vid,
1609433d6423SLionel Sambuc               rpub->pci_acl.rsp_device[i].sub_did);
1610433d6423SLionel Sambuc   }
1611433d6423SLionel Sambuc   if (rs_start->rss_nr_pci_class > RS_NR_PCI_CLASS) {
1612433d6423SLionel Sambuc       printf("RS: init_slot: too many PCI class IDs\n");
1613433d6423SLionel Sambuc       return EINVAL;
1614433d6423SLionel Sambuc   }
1615433d6423SLionel Sambuc   rpub->pci_acl.rsp_nr_class= rs_start->rss_nr_pci_class;
1616433d6423SLionel Sambuc   for (i= 0; i<rpub->pci_acl.rsp_nr_class; i++) {
1617433d6423SLionel Sambuc       rpub->pci_acl.rsp_class[i].pciclass=rs_start->rss_pci_class[i].pciclass;
1618433d6423SLionel Sambuc       rpub->pci_acl.rsp_class[i].mask= rs_start->rss_pci_class[i].mask;
1619433d6423SLionel Sambuc       if(rs_verbose)
1620433d6423SLionel Sambuc           printf("RS: init_slot: PCI class %06x mask %06x\n",
1621433d6423SLionel Sambuc               (unsigned int) rpub->pci_acl.rsp_class[i].pciclass,
1622433d6423SLionel Sambuc               (unsigned int) rpub->pci_acl.rsp_class[i].mask);
1623433d6423SLionel Sambuc   }
1624433d6423SLionel Sambuc 
1625433d6423SLionel Sambuc   /* Initialize some fields. */
1626433d6423SLionel Sambuc   rp->r_restarts = 0; 				/* no restarts yet */
1627433d6423SLionel Sambuc   rp->r_old_rp = NULL;			        /* no old version yet */
1628433d6423SLionel Sambuc   rp->r_new_rp = NULL;			        /* no new version yet */
1629433d6423SLionel Sambuc   rp->r_prev_rp = NULL;			        /* no prev replica yet */
1630433d6423SLionel Sambuc   rp->r_next_rp = NULL;			        /* no next replica yet */
1631433d6423SLionel Sambuc   rp->r_exec = NULL;                            /* no in-memory copy yet */
1632433d6423SLionel Sambuc   rp->r_exec_len = 0;
1633433d6423SLionel Sambuc   rp->r_script[0]= '\0';                        /* no recovery script yet */
1634433d6423SLionel Sambuc   rpub->label[0]= '\0';                         /* no label yet */
1635433d6423SLionel Sambuc   rp->r_scheduler = -1;                         /* no scheduler yet */
1636433d6423SLionel Sambuc   rp->r_priv.s_sig_mgr = -1;                    /* no signal manager yet */
1637433d6423SLionel Sambuc 
1638433d6423SLionel Sambuc   /* Initialize editable slot settings. */
1639433d6423SLionel Sambuc   return edit_slot(rp, rs_start, source);
1640433d6423SLionel Sambuc }
1641433d6423SLionel Sambuc 
1642433d6423SLionel Sambuc /*===========================================================================*
1643433d6423SLionel Sambuc  *				clone_slot				     *
1644433d6423SLionel Sambuc  *===========================================================================*/
1645433d6423SLionel Sambuc int clone_slot(rp, clone_rpp)
1646433d6423SLionel Sambuc struct rproc *rp;
1647433d6423SLionel Sambuc struct rproc **clone_rpp;
1648433d6423SLionel Sambuc {
1649433d6423SLionel Sambuc   int r;
1650433d6423SLionel Sambuc   struct rproc *clone_rp;
1651433d6423SLionel Sambuc   struct rprocpub *rpub, *clone_rpub;
1652433d6423SLionel Sambuc 
1653433d6423SLionel Sambuc   /* Allocate a system service slot for the clone. */
1654433d6423SLionel Sambuc   r = alloc_slot(&clone_rp);
1655433d6423SLionel Sambuc   if(r != OK) {
1656433d6423SLionel Sambuc       printf("RS: clone_slot: unable to allocate a new slot: %d\n", r);
1657433d6423SLionel Sambuc       return r;
1658433d6423SLionel Sambuc   }
1659433d6423SLionel Sambuc 
1660433d6423SLionel Sambuc   rpub = rp->r_pub;
1661433d6423SLionel Sambuc   clone_rpub = clone_rp->r_pub;
1662433d6423SLionel Sambuc 
1663433d6423SLionel Sambuc   /* Synch the privilege structure of the source with the kernel. */
1664433d6423SLionel Sambuc   if ((r = sys_getpriv(&(rp->r_priv), rpub->endpoint)) != OK) {
1665433d6423SLionel Sambuc       panic("unable to synch privilege structure: %d", r);
1666433d6423SLionel Sambuc   }
1667433d6423SLionel Sambuc 
1668433d6423SLionel Sambuc   /* Shallow copy. */
1669433d6423SLionel Sambuc   *clone_rp = *rp;
1670433d6423SLionel Sambuc   *clone_rpub = *rpub;
1671433d6423SLionel Sambuc 
1672433d6423SLionel Sambuc   /* Deep copy. */
1673433d6423SLionel Sambuc   clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
1674433d6423SLionel Sambuc   clone_rp->r_pid = -1;            /* no pid yet */
1675433d6423SLionel Sambuc   clone_rpub->endpoint = -1;       /* no endpoint yet */
1676433d6423SLionel Sambuc   clone_rp->r_pub = clone_rpub;    /* restore pointer to public entry */
1677433d6423SLionel Sambuc   build_cmd_dep(clone_rp);         /* rebuild cmd dependencies */
1678433d6423SLionel Sambuc   if(clone_rpub->sys_flags & SF_USE_COPY) {
1679433d6423SLionel Sambuc       share_exec(clone_rp, rp);        /* share exec image */
1680433d6423SLionel Sambuc   }
1681433d6423SLionel Sambuc   clone_rp->r_old_rp = NULL;	   /* no old version yet */
1682433d6423SLionel Sambuc   clone_rp->r_new_rp = NULL;	   /* no new version yet */
1683433d6423SLionel Sambuc   clone_rp->r_prev_rp = NULL;	   /* no prev replica yet */
1684433d6423SLionel Sambuc   clone_rp->r_next_rp = NULL;	   /* no next replica yet */
1685433d6423SLionel Sambuc 
1686433d6423SLionel Sambuc   /* Force dynamic privilege id. */
1687433d6423SLionel Sambuc   clone_rp->r_priv.s_flags |= DYN_PRIV_ID;
1688433d6423SLionel Sambuc 
1689433d6423SLionel Sambuc   /* Clear instance flags. */
1690433d6423SLionel Sambuc   clone_rp->r_priv.s_flags &= ~(LU_SYS_PROC | RST_SYS_PROC);
1691433d6423SLionel Sambuc 
1692433d6423SLionel Sambuc   *clone_rpp = clone_rp;
1693433d6423SLionel Sambuc   return OK;
1694433d6423SLionel Sambuc }
1695433d6423SLionel Sambuc 
1696433d6423SLionel Sambuc /*===========================================================================*
1697433d6423SLionel Sambuc  *			    swap_slot_pointer				     *
1698433d6423SLionel Sambuc  *===========================================================================*/
1699433d6423SLionel Sambuc static void swap_slot_pointer(struct rproc **rpp, struct rproc *src_rp,
1700433d6423SLionel Sambuc     struct rproc *dst_rp)
1701433d6423SLionel Sambuc {
1702433d6423SLionel Sambuc   if(*rpp == src_rp) {
1703433d6423SLionel Sambuc       *rpp = dst_rp;
1704433d6423SLionel Sambuc   }
1705433d6423SLionel Sambuc   else if(*rpp == dst_rp) {
1706433d6423SLionel Sambuc       *rpp = src_rp;
1707433d6423SLionel Sambuc   }
1708433d6423SLionel Sambuc }
1709433d6423SLionel Sambuc 
1710433d6423SLionel Sambuc /*===========================================================================*
1711433d6423SLionel Sambuc  *				swap_slot				     *
1712433d6423SLionel Sambuc  *===========================================================================*/
1713433d6423SLionel Sambuc void swap_slot(src_rpp, dst_rpp)
1714433d6423SLionel Sambuc struct rproc **src_rpp;
1715433d6423SLionel Sambuc struct rproc **dst_rpp;
1716433d6423SLionel Sambuc {
1717433d6423SLionel Sambuc /* Swap two service slots. */
1718433d6423SLionel Sambuc   struct rproc *src_rp;
1719433d6423SLionel Sambuc   struct rproc *dst_rp;
1720433d6423SLionel Sambuc   struct rprocpub *src_rpub;
1721433d6423SLionel Sambuc   struct rprocpub *dst_rpub;
1722433d6423SLionel Sambuc   struct rproc orig_src_rproc, orig_dst_rproc;
1723433d6423SLionel Sambuc   struct rprocpub orig_src_rprocpub, orig_dst_rprocpub;
1724433d6423SLionel Sambuc 
1725433d6423SLionel Sambuc   src_rp = *src_rpp;
1726433d6423SLionel Sambuc   dst_rp = *dst_rpp;
1727433d6423SLionel Sambuc   src_rpub = src_rp->r_pub;
1728433d6423SLionel Sambuc   dst_rpub = dst_rp->r_pub;
1729433d6423SLionel Sambuc 
1730433d6423SLionel Sambuc   /* Save existing data first. */
1731433d6423SLionel Sambuc   orig_src_rproc = *src_rp;
1732433d6423SLionel Sambuc   orig_src_rprocpub = *src_rpub;
1733433d6423SLionel Sambuc   orig_dst_rproc = *dst_rp;
1734433d6423SLionel Sambuc   orig_dst_rprocpub = *dst_rpub;
1735433d6423SLionel Sambuc 
1736433d6423SLionel Sambuc   /* Swap slots. */
1737433d6423SLionel Sambuc   *src_rp = orig_dst_rproc;
1738433d6423SLionel Sambuc   *src_rpub = orig_dst_rprocpub;
1739433d6423SLionel Sambuc   *dst_rp = orig_src_rproc;
1740433d6423SLionel Sambuc   *dst_rpub = orig_src_rprocpub;
1741433d6423SLionel Sambuc 
1742433d6423SLionel Sambuc   /* Restore public entries. */
1743433d6423SLionel Sambuc   src_rp->r_pub = orig_src_rproc.r_pub;
1744433d6423SLionel Sambuc   dst_rp->r_pub = orig_dst_rproc.r_pub;
1745433d6423SLionel Sambuc 
1746433d6423SLionel Sambuc   /* Rebuild command dependencies. */
1747433d6423SLionel Sambuc   build_cmd_dep(src_rp);
1748433d6423SLionel Sambuc   build_cmd_dep(dst_rp);
1749433d6423SLionel Sambuc 
1750433d6423SLionel Sambuc   /* Swap local slot pointers. */
1751433d6423SLionel Sambuc   swap_slot_pointer(&src_rp->r_prev_rp, src_rp, dst_rp);
1752433d6423SLionel Sambuc   swap_slot_pointer(&src_rp->r_next_rp, src_rp, dst_rp);
1753433d6423SLionel Sambuc   swap_slot_pointer(&src_rp->r_old_rp, src_rp, dst_rp);
1754433d6423SLionel Sambuc   swap_slot_pointer(&src_rp->r_new_rp, src_rp, dst_rp);
1755433d6423SLionel Sambuc   swap_slot_pointer(&dst_rp->r_prev_rp, src_rp, dst_rp);
1756433d6423SLionel Sambuc   swap_slot_pointer(&dst_rp->r_next_rp, src_rp, dst_rp);
1757433d6423SLionel Sambuc   swap_slot_pointer(&dst_rp->r_old_rp, src_rp, dst_rp);
1758433d6423SLionel Sambuc   swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp);
1759433d6423SLionel Sambuc 
1760433d6423SLionel Sambuc   /* Swap global slot pointers. */
1761433d6423SLionel Sambuc   swap_slot_pointer(&rupdate.rp, src_rp, dst_rp);
1762433d6423SLionel Sambuc   swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)],
1763433d6423SLionel Sambuc       src_rp, dst_rp);
1764433d6423SLionel Sambuc   swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)],
1765433d6423SLionel Sambuc       src_rp, dst_rp);
1766433d6423SLionel Sambuc 
1767433d6423SLionel Sambuc   /* Adjust input pointers. */
1768433d6423SLionel Sambuc   *src_rpp = dst_rp;
1769433d6423SLionel Sambuc   *dst_rpp = src_rp;
1770433d6423SLionel Sambuc }
1771433d6423SLionel Sambuc 
1772433d6423SLionel Sambuc /*===========================================================================*
1773433d6423SLionel Sambuc  *			   lookup_slot_by_label				     *
1774433d6423SLionel Sambuc  *===========================================================================*/
1775433d6423SLionel Sambuc struct rproc* lookup_slot_by_label(char *label)
1776433d6423SLionel Sambuc {
1777433d6423SLionel Sambuc /* Lookup a service slot matching the given label. */
1778433d6423SLionel Sambuc   int slot_nr;
1779433d6423SLionel Sambuc   struct rproc *rp;
1780433d6423SLionel Sambuc   struct rprocpub *rpub;
1781433d6423SLionel Sambuc 
1782433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1783433d6423SLionel Sambuc       rp = &rproc[slot_nr];
1784433d6423SLionel Sambuc       if (!(rp->r_flags & RS_ACTIVE)) {
1785433d6423SLionel Sambuc           continue;
1786433d6423SLionel Sambuc       }
1787433d6423SLionel Sambuc       rpub = rp->r_pub;
1788433d6423SLionel Sambuc       if (strcmp(rpub->label, label) == 0) {
1789433d6423SLionel Sambuc           return rp;
1790433d6423SLionel Sambuc       }
1791433d6423SLionel Sambuc   }
1792433d6423SLionel Sambuc 
1793433d6423SLionel Sambuc   return NULL;
1794433d6423SLionel Sambuc }
1795433d6423SLionel Sambuc 
1796433d6423SLionel Sambuc /*===========================================================================*
1797433d6423SLionel Sambuc  *			   lookup_slot_by_pid				     *
1798433d6423SLionel Sambuc  *===========================================================================*/
1799433d6423SLionel Sambuc struct rproc* lookup_slot_by_pid(pid_t pid)
1800433d6423SLionel Sambuc {
1801433d6423SLionel Sambuc /* Lookup a service slot matching the given pid. */
1802433d6423SLionel Sambuc   int slot_nr;
1803433d6423SLionel Sambuc   struct rproc *rp;
1804433d6423SLionel Sambuc 
1805433d6423SLionel Sambuc   if(pid < 0) {
1806433d6423SLionel Sambuc       return NULL;
1807433d6423SLionel Sambuc   }
1808433d6423SLionel Sambuc 
1809433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1810433d6423SLionel Sambuc       rp = &rproc[slot_nr];
1811433d6423SLionel Sambuc       if (!(rp->r_flags & RS_IN_USE)) {
1812433d6423SLionel Sambuc           continue;
1813433d6423SLionel Sambuc       }
1814433d6423SLionel Sambuc       if (rp->r_pid == pid) {
1815433d6423SLionel Sambuc           return rp;
1816433d6423SLionel Sambuc       }
1817433d6423SLionel Sambuc   }
1818433d6423SLionel Sambuc 
1819433d6423SLionel Sambuc   return NULL;
1820433d6423SLionel Sambuc }
1821433d6423SLionel Sambuc 
1822433d6423SLionel Sambuc /*===========================================================================*
1823433d6423SLionel Sambuc  *			   lookup_slot_by_dev_nr			     *
1824433d6423SLionel Sambuc  *===========================================================================*/
1825433d6423SLionel Sambuc struct rproc* lookup_slot_by_dev_nr(dev_t dev_nr)
1826433d6423SLionel Sambuc {
1827433d6423SLionel Sambuc /* Lookup a service slot matching the given device number. */
1828433d6423SLionel Sambuc   int slot_nr;
1829433d6423SLionel Sambuc   struct rproc *rp;
1830433d6423SLionel Sambuc   struct rprocpub *rpub;
1831433d6423SLionel Sambuc 
1832433d6423SLionel Sambuc   if(dev_nr <= 0) {
1833433d6423SLionel Sambuc       return NULL;
1834433d6423SLionel Sambuc   }
1835433d6423SLionel Sambuc 
1836433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1837433d6423SLionel Sambuc       rp = &rproc[slot_nr];
1838433d6423SLionel Sambuc       rpub = rp->r_pub;
1839433d6423SLionel Sambuc       if (!(rp->r_flags & RS_IN_USE)) {
1840433d6423SLionel Sambuc           continue;
1841433d6423SLionel Sambuc       }
1842433d6423SLionel Sambuc       if (rpub->dev_nr == dev_nr) {
1843433d6423SLionel Sambuc           return rp;
1844433d6423SLionel Sambuc       }
1845433d6423SLionel Sambuc   }
1846433d6423SLionel Sambuc 
1847433d6423SLionel Sambuc   return NULL;
1848433d6423SLionel Sambuc }
1849433d6423SLionel Sambuc 
1850433d6423SLionel Sambuc /*===========================================================================*
1851433d6423SLionel Sambuc  *			   lookup_slot_by_flags				     *
1852433d6423SLionel Sambuc  *===========================================================================*/
1853433d6423SLionel Sambuc struct rproc* lookup_slot_by_flags(int flags)
1854433d6423SLionel Sambuc {
1855433d6423SLionel Sambuc /* Lookup a service slot matching the given flags. */
1856433d6423SLionel Sambuc   int slot_nr;
1857433d6423SLionel Sambuc   struct rproc *rp;
1858433d6423SLionel Sambuc 
1859433d6423SLionel Sambuc   if(!flags) {
1860433d6423SLionel Sambuc       return NULL;
1861433d6423SLionel Sambuc   }
1862433d6423SLionel Sambuc 
1863433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1864433d6423SLionel Sambuc       rp = &rproc[slot_nr];
1865433d6423SLionel Sambuc       if (!(rp->r_flags & RS_IN_USE)) {
1866433d6423SLionel Sambuc           continue;
1867433d6423SLionel Sambuc       }
1868433d6423SLionel Sambuc       if (rp->r_flags & flags) {
1869433d6423SLionel Sambuc           return rp;
1870433d6423SLionel Sambuc       }
1871433d6423SLionel Sambuc   }
1872433d6423SLionel Sambuc 
1873433d6423SLionel Sambuc   return NULL;
1874433d6423SLionel Sambuc }
1875433d6423SLionel Sambuc 
1876433d6423SLionel Sambuc /*===========================================================================*
1877433d6423SLionel Sambuc  *				alloc_slot				     *
1878433d6423SLionel Sambuc  *===========================================================================*/
1879433d6423SLionel Sambuc int alloc_slot(rpp)
1880433d6423SLionel Sambuc struct rproc **rpp;
1881433d6423SLionel Sambuc {
1882433d6423SLionel Sambuc /* Alloc a new system service slot. */
1883433d6423SLionel Sambuc   int slot_nr;
1884433d6423SLionel Sambuc 
1885433d6423SLionel Sambuc   for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1886433d6423SLionel Sambuc       *rpp = &rproc[slot_nr];			/* get pointer to slot */
1887433d6423SLionel Sambuc       if (!((*rpp)->r_flags & RS_IN_USE)) 	/* check if available */
1888433d6423SLionel Sambuc 	  break;
1889433d6423SLionel Sambuc   }
1890433d6423SLionel Sambuc   if (slot_nr >= NR_SYS_PROCS) {
1891433d6423SLionel Sambuc 	return ENOMEM;
1892433d6423SLionel Sambuc   }
1893433d6423SLionel Sambuc 
1894433d6423SLionel Sambuc   return OK;
1895433d6423SLionel Sambuc }
1896433d6423SLionel Sambuc 
1897433d6423SLionel Sambuc /*===========================================================================*
1898433d6423SLionel Sambuc  *				free_slot				     *
1899433d6423SLionel Sambuc  *===========================================================================*/
1900433d6423SLionel Sambuc void free_slot(rp)
1901433d6423SLionel Sambuc struct rproc *rp;
1902433d6423SLionel Sambuc {
1903433d6423SLionel Sambuc /* Free a system service slot. */
1904433d6423SLionel Sambuc   struct rprocpub *rpub;
1905433d6423SLionel Sambuc 
1906433d6423SLionel Sambuc   rpub = rp->r_pub;
1907433d6423SLionel Sambuc 
1908433d6423SLionel Sambuc   /* Send a late reply if there is any pending. */
1909433d6423SLionel Sambuc   late_reply(rp, OK);
1910433d6423SLionel Sambuc 
1911433d6423SLionel Sambuc   /* Free memory if necessary. */
1912433d6423SLionel Sambuc   if(rpub->sys_flags & SF_USE_COPY) {
1913433d6423SLionel Sambuc       free_exec(rp);
1914433d6423SLionel Sambuc   }
1915433d6423SLionel Sambuc 
1916433d6423SLionel Sambuc   /* Mark slot as no longer in use.. */
1917433d6423SLionel Sambuc   rp->r_flags = 0;
1918433d6423SLionel Sambuc   rp->r_pid = -1;
1919433d6423SLionel Sambuc   rpub->in_use = FALSE;
1920433d6423SLionel Sambuc   rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL;
1921433d6423SLionel Sambuc }
1922433d6423SLionel Sambuc 
1923433d6423SLionel Sambuc 
1924433d6423SLionel Sambuc /*===========================================================================*
1925433d6423SLionel Sambuc  *				get_next_name				     *
1926433d6423SLionel Sambuc  *===========================================================================*/
1927433d6423SLionel Sambuc static char *get_next_name(ptr, name, caller_label)
1928433d6423SLionel Sambuc char *ptr;
1929433d6423SLionel Sambuc char *name;
1930433d6423SLionel Sambuc char *caller_label;
1931433d6423SLionel Sambuc {
1932433d6423SLionel Sambuc 	/* Get the next name from the list of (IPC) program names.
1933433d6423SLionel Sambuc 	 */
1934433d6423SLionel Sambuc 	char *p, *q;
1935433d6423SLionel Sambuc 	size_t len;
1936433d6423SLionel Sambuc 
1937433d6423SLionel Sambuc 	for (p= ptr; p[0] != '\0'; p= q)
1938433d6423SLionel Sambuc 	{
1939433d6423SLionel Sambuc 		/* Skip leading space */
1940433d6423SLionel Sambuc 		while (p[0] != '\0' && isspace((unsigned char)p[0]))
1941433d6423SLionel Sambuc 			p++;
1942433d6423SLionel Sambuc 
1943433d6423SLionel Sambuc 		/* Find start of next word */
1944433d6423SLionel Sambuc 		q= p;
1945433d6423SLionel Sambuc 		while (q[0] != '\0' && !isspace((unsigned char)q[0]))
1946433d6423SLionel Sambuc 			q++;
1947433d6423SLionel Sambuc 		if (q == p)
1948433d6423SLionel Sambuc 			continue;
1949433d6423SLionel Sambuc 		len= q-p;
1950433d6423SLionel Sambuc 		if (len > RS_MAX_LABEL_LEN)
1951433d6423SLionel Sambuc 		{
1952433d6423SLionel Sambuc 			printf(
1953433d6423SLionel Sambuc 	"rs:get_next_name: bad ipc list entry '%.*s' for %s: too long\n",
1954433d6423SLionel Sambuc 				len, p, caller_label);
1955433d6423SLionel Sambuc 			continue;
1956433d6423SLionel Sambuc 		}
1957433d6423SLionel Sambuc 		memcpy(name, p, len);
1958433d6423SLionel Sambuc 		name[len]= '\0';
1959433d6423SLionel Sambuc 
1960433d6423SLionel Sambuc 		return q; /* found another */
1961433d6423SLionel Sambuc 	}
1962433d6423SLionel Sambuc 
1963433d6423SLionel Sambuc 	return NULL; /* done */
1964433d6423SLionel Sambuc }
1965433d6423SLionel Sambuc 
1966433d6423SLionel Sambuc /*===========================================================================*
1967433d6423SLionel Sambuc  *				add_forward_ipc				     *
1968433d6423SLionel Sambuc  *===========================================================================*/
1969433d6423SLionel Sambuc void add_forward_ipc(rp, privp)
1970433d6423SLionel Sambuc struct rproc *rp;
1971433d6423SLionel Sambuc struct priv *privp;
1972433d6423SLionel Sambuc {
1973433d6423SLionel Sambuc 	/* Add IPC send permissions to a process based on that process's IPC
1974433d6423SLionel Sambuc 	 * list.
1975433d6423SLionel Sambuc 	 */
1976433d6423SLionel Sambuc 	char name[RS_MAX_LABEL_LEN+1], *p;
1977433d6423SLionel Sambuc 	struct rproc *rrp;
1978433d6423SLionel Sambuc 	endpoint_t endpoint;
1979433d6423SLionel Sambuc 	int r;
1980433d6423SLionel Sambuc 	int priv_id;
1981433d6423SLionel Sambuc 	struct priv priv;
1982433d6423SLionel Sambuc 	struct rprocpub *rpub;
1983433d6423SLionel Sambuc 
1984433d6423SLionel Sambuc 	rpub = rp->r_pub;
1985433d6423SLionel Sambuc 	p = rp->r_ipc_list;
1986433d6423SLionel Sambuc 
1987433d6423SLionel Sambuc 	while ((p = get_next_name(p, name, rpub->label)) != NULL) {
1988433d6423SLionel Sambuc 
1989433d6423SLionel Sambuc 		if (strcmp(name, "SYSTEM") == 0)
1990433d6423SLionel Sambuc 			endpoint= SYSTEM;
1991433d6423SLionel Sambuc 		else if (strcmp(name, "USER") == 0)
1992433d6423SLionel Sambuc 			endpoint= INIT_PROC_NR; /* all user procs */
1993433d6423SLionel Sambuc 		else
1994433d6423SLionel Sambuc 		{
1995433d6423SLionel Sambuc 			/* Set a privilege bit for every process matching the
1996433d6423SLionel Sambuc 			 * given process name. It is perfectly fine if this
1997433d6423SLionel Sambuc 			 * loop does not find any matches, as the target
1998433d6423SLionel Sambuc 			 * process(es) may not have been started yet. See
1999433d6423SLionel Sambuc 			 * add_backward_ipc() below.
2000433d6423SLionel Sambuc 			 */
2001433d6423SLionel Sambuc 			for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
2002433d6423SLionel Sambuc 				if (!(rrp->r_flags & RS_IN_USE))
2003433d6423SLionel Sambuc 					continue;
2004433d6423SLionel Sambuc 
2005433d6423SLionel Sambuc 				if (!strcmp(rrp->r_pub->proc_name, name)) {
2006433d6423SLionel Sambuc #if PRIV_DEBUG
2007433d6423SLionel Sambuc 					printf("  RS: add_forward_ipc: setting"
2008433d6423SLionel Sambuc 						" sendto bit for %d...\n",
2009433d6423SLionel Sambuc 						rrp->r_pub->endpoint);
2010433d6423SLionel Sambuc #endif
2011433d6423SLionel Sambuc 
2012433d6423SLionel Sambuc 					priv_id= rrp->r_priv.s_id;
2013433d6423SLionel Sambuc 					set_sys_bit(privp->s_ipc_to, priv_id);
2014433d6423SLionel Sambuc 				}
2015433d6423SLionel Sambuc 			}
2016433d6423SLionel Sambuc 
2017433d6423SLionel Sambuc 			continue;
2018433d6423SLionel Sambuc 		}
2019433d6423SLionel Sambuc 
2020433d6423SLionel Sambuc 		/* This code only applies to the exception cases. */
2021433d6423SLionel Sambuc 		if ((r = sys_getpriv(&priv, endpoint)) < 0)
2022433d6423SLionel Sambuc 		{
2023433d6423SLionel Sambuc 			printf(
2024433d6423SLionel Sambuc 		"add_forward_ipc: unable to get priv_id for '%s': %d\n",
2025433d6423SLionel Sambuc 				name, r);
2026433d6423SLionel Sambuc 			continue;
2027433d6423SLionel Sambuc 		}
2028433d6423SLionel Sambuc 
2029433d6423SLionel Sambuc #if PRIV_DEBUG
2030433d6423SLionel Sambuc 		printf("  RS: add_forward_ipc: setting sendto bit for %d...\n",
2031433d6423SLionel Sambuc 			endpoint);
2032433d6423SLionel Sambuc #endif
2033433d6423SLionel Sambuc 		priv_id= priv.s_id;
2034433d6423SLionel Sambuc 		set_sys_bit(privp->s_ipc_to, priv_id);
2035433d6423SLionel Sambuc 	}
2036433d6423SLionel Sambuc }
2037433d6423SLionel Sambuc 
2038433d6423SLionel Sambuc 
2039433d6423SLionel Sambuc /*===========================================================================*
2040433d6423SLionel Sambuc  *				add_backward_ipc			     *
2041433d6423SLionel Sambuc  *===========================================================================*/
2042433d6423SLionel Sambuc void add_backward_ipc(rp, privp)
2043433d6423SLionel Sambuc struct rproc *rp;
2044433d6423SLionel Sambuc struct priv *privp;
2045433d6423SLionel Sambuc {
2046433d6423SLionel Sambuc 	/* Add IPC send permissions to a process based on other processes' IPC
2047433d6423SLionel Sambuc 	 * lists. This is enough to allow each such two processes to talk to
2048433d6423SLionel Sambuc 	 * each other, as the kernel guarantees send mask symmetry. We need to
2049433d6423SLionel Sambuc 	 * add these permissions now because the current process may not yet
2050433d6423SLionel Sambuc 	 * have existed at the time that the other process was initialized.
2051433d6423SLionel Sambuc 	 */
2052433d6423SLionel Sambuc 	char name[RS_MAX_LABEL_LEN+1], *p;
2053433d6423SLionel Sambuc 	struct rproc *rrp;
2054433d6423SLionel Sambuc 	struct rprocpub *rrpub;
2055433d6423SLionel Sambuc 	char *proc_name;
2056433d6423SLionel Sambuc 	int priv_id, is_ipc_all, is_ipc_all_sys;
2057433d6423SLionel Sambuc 
2058433d6423SLionel Sambuc 	proc_name = rp->r_pub->proc_name;
2059433d6423SLionel Sambuc 
2060433d6423SLionel Sambuc 	for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
2061433d6423SLionel Sambuc 		if (!(rrp->r_flags & RS_IN_USE))
2062433d6423SLionel Sambuc 			continue;
2063433d6423SLionel Sambuc 
2064433d6423SLionel Sambuc 		if (!rrp->r_ipc_list[0])
2065433d6423SLionel Sambuc 			continue;
2066433d6423SLionel Sambuc 
2067433d6423SLionel Sambuc 		/* If the process being checked is set to allow IPC to all
2068433d6423SLionel Sambuc 		 * other processes, or for all other system processes and the
2069433d6423SLionel Sambuc 		 * target process is a system process, add a permission bit.
2070433d6423SLionel Sambuc 		 */
2071433d6423SLionel Sambuc 		rrpub = rrp->r_pub;
2072433d6423SLionel Sambuc 
2073433d6423SLionel Sambuc 		is_ipc_all = !strcmp(rrp->r_ipc_list, RSS_IPC_ALL);
2074433d6423SLionel Sambuc 		is_ipc_all_sys = !strcmp(rrp->r_ipc_list, RSS_IPC_ALL_SYS);
2075433d6423SLionel Sambuc 
2076433d6423SLionel Sambuc 		if (is_ipc_all ||
2077433d6423SLionel Sambuc 			(is_ipc_all_sys && (privp->s_flags & SYS_PROC))) {
2078433d6423SLionel Sambuc #if PRIV_DEBUG
2079433d6423SLionel Sambuc 			printf("  RS: add_backward_ipc: setting sendto bit "
2080433d6423SLionel Sambuc 				"for %d...\n", rrpub->endpoint);
2081433d6423SLionel Sambuc #endif
2082433d6423SLionel Sambuc 			priv_id= rrp->r_priv.s_id;
2083433d6423SLionel Sambuc 			set_sys_bit(privp->s_ipc_to, priv_id);
2084433d6423SLionel Sambuc 
2085433d6423SLionel Sambuc 			continue;
2086433d6423SLionel Sambuc 		}
2087433d6423SLionel Sambuc 
2088433d6423SLionel Sambuc 		/* An IPC target list was provided for the process being
2089433d6423SLionel Sambuc 		 * checked here. Make sure that the name of the new process
2090433d6423SLionel Sambuc 		 * is in that process's list. There may be multiple matches.
2091433d6423SLionel Sambuc 		 */
2092433d6423SLionel Sambuc 		p = rrp->r_ipc_list;
2093433d6423SLionel Sambuc 
2094433d6423SLionel Sambuc 		while ((p = get_next_name(p, name, rrpub->label)) != NULL) {
2095433d6423SLionel Sambuc 			if (!strcmp(proc_name, name)) {
2096433d6423SLionel Sambuc #if PRIV_DEBUG
2097433d6423SLionel Sambuc 				printf("  RS: add_backward_ipc: setting sendto"
2098433d6423SLionel Sambuc 					" bit for %d...\n",
2099433d6423SLionel Sambuc 					rrpub->endpoint);
2100433d6423SLionel Sambuc #endif
2101433d6423SLionel Sambuc 				priv_id= rrp->r_priv.s_id;
2102433d6423SLionel Sambuc 				set_sys_bit(privp->s_ipc_to, priv_id);
2103433d6423SLionel Sambuc 			}
2104433d6423SLionel Sambuc 		}
2105433d6423SLionel Sambuc 	}
2106433d6423SLionel Sambuc }
2107433d6423SLionel Sambuc 
2108433d6423SLionel Sambuc 
2109433d6423SLionel Sambuc /*===========================================================================*
2110433d6423SLionel Sambuc  *				init_privs				     *
2111433d6423SLionel Sambuc  *===========================================================================*/
2112433d6423SLionel Sambuc void init_privs(rp, privp)
2113433d6423SLionel Sambuc struct rproc *rp;
2114433d6423SLionel Sambuc struct priv *privp;
2115433d6423SLionel Sambuc {
2116433d6423SLionel Sambuc 	int i;
2117433d6423SLionel Sambuc 	int is_ipc_all, is_ipc_all_sys;
2118433d6423SLionel Sambuc 
2119433d6423SLionel Sambuc 	/* Clear s_ipc_to */
2120433d6423SLionel Sambuc 	fill_send_mask(&privp->s_ipc_to, FALSE);
2121433d6423SLionel Sambuc 
2122433d6423SLionel Sambuc 	is_ipc_all = !strcmp(rp->r_ipc_list, RSS_IPC_ALL);
2123433d6423SLionel Sambuc 	is_ipc_all_sys = !strcmp(rp->r_ipc_list, RSS_IPC_ALL_SYS);
2124433d6423SLionel Sambuc 
2125433d6423SLionel Sambuc #if PRIV_DEBUG
2126433d6423SLionel Sambuc 	printf("  RS: init_privs: ipc list is '%s'...\n", rp->r_ipc_list);
2127433d6423SLionel Sambuc #endif
2128433d6423SLionel Sambuc 
2129433d6423SLionel Sambuc 	if (!is_ipc_all && !is_ipc_all_sys)
2130433d6423SLionel Sambuc 	{
2131433d6423SLionel Sambuc 		add_forward_ipc(rp, privp);
2132433d6423SLionel Sambuc 		add_backward_ipc(rp, privp);
2133433d6423SLionel Sambuc 
2134433d6423SLionel Sambuc 	}
2135433d6423SLionel Sambuc 	else
2136433d6423SLionel Sambuc 	{
2137433d6423SLionel Sambuc 		for (i= 0; i<NR_SYS_PROCS; i++)
2138433d6423SLionel Sambuc 		{
2139433d6423SLionel Sambuc 			if (is_ipc_all || i != USER_PRIV_ID)
2140433d6423SLionel Sambuc 				set_sys_bit(privp->s_ipc_to, i);
2141433d6423SLionel Sambuc 		}
2142433d6423SLionel Sambuc 	}
2143433d6423SLionel Sambuc }
2144433d6423SLionel Sambuc 
2145