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
1037f29f55SLionel Sambuc #include <sys/exec_elf.h>
1137f29f55SLionel Sambuc
12433d6423SLionel Sambuc #include "inc.h"
13433d6423SLionel Sambuc
14433d6423SLionel Sambuc #include "kernel/proc.h"
15433d6423SLionel Sambuc
16fb6bd596SCristiano Giuffrida static int run_script(struct rproc *rp);
17fb6bd596SCristiano Giuffrida
18433d6423SLionel Sambuc /*===========================================================================*
19433d6423SLionel Sambuc * caller_is_root *
20433d6423SLionel Sambuc *===========================================================================*/
caller_is_root(endpoint)21433d6423SLionel Sambuc static int caller_is_root(endpoint)
22433d6423SLionel Sambuc endpoint_t endpoint; /* caller endpoint */
23433d6423SLionel Sambuc {
24433d6423SLionel Sambuc uid_t euid;
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc /* Check if caller has root user ID. */
27433d6423SLionel Sambuc euid = getnuid(endpoint);
28433d6423SLionel Sambuc if (rs_verbose && euid != 0)
29433d6423SLionel Sambuc {
30433d6423SLionel Sambuc printf("RS: got unauthorized request from endpoint %d\n", endpoint);
31433d6423SLionel Sambuc }
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc return euid == 0;
34433d6423SLionel Sambuc }
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc /*===========================================================================*
37433d6423SLionel Sambuc * caller_can_control *
38433d6423SLionel Sambuc *===========================================================================*/
caller_can_control(endpoint,target_rp)39433d6423SLionel Sambuc static int caller_can_control(endpoint, target_rp)
40433d6423SLionel Sambuc endpoint_t endpoint;
41433d6423SLionel Sambuc struct rproc *target_rp;
42433d6423SLionel Sambuc {
43433d6423SLionel Sambuc int control_allowed = 0;
44433d6423SLionel Sambuc register struct rproc *rp;
45433d6423SLionel Sambuc register struct rprocpub *rpub;
46433d6423SLionel Sambuc char *proc_name;
47433d6423SLionel Sambuc int c;
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc proc_name = target_rp->r_pub->proc_name;
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc /* Check if label is listed in caller's isolation policy. */
52433d6423SLionel Sambuc for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
53433d6423SLionel Sambuc if (!(rp->r_flags & RS_IN_USE))
54433d6423SLionel Sambuc continue;
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc rpub = rp->r_pub;
57433d6423SLionel Sambuc if (rpub->endpoint == endpoint) {
58433d6423SLionel Sambuc break;
59433d6423SLionel Sambuc }
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc if (rp == END_RPROC_ADDR) return 0;
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc for (c = 0; c < rp->r_nr_control; c++) {
64433d6423SLionel Sambuc if (strcmp(rp->r_control[c], proc_name) == 0) {
65433d6423SLionel Sambuc control_allowed = 1;
66433d6423SLionel Sambuc break;
67433d6423SLionel Sambuc }
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc if (rs_verbose)
71433d6423SLionel Sambuc printf("RS: allowing %u control over %s via policy: %s\n",
72433d6423SLionel Sambuc endpoint, target_rp->r_pub->label,
73433d6423SLionel Sambuc control_allowed ? "yes" : "no");
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc return control_allowed;
76433d6423SLionel Sambuc }
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc /*===========================================================================*
79433d6423SLionel Sambuc * check_call_permission *
80433d6423SLionel Sambuc *===========================================================================*/
check_call_permission(caller,call,rp)81433d6423SLionel Sambuc int check_call_permission(caller, call, rp)
82433d6423SLionel Sambuc endpoint_t caller;
83433d6423SLionel Sambuc int call;
84433d6423SLionel Sambuc struct rproc *rp;
85433d6423SLionel Sambuc {
86433d6423SLionel Sambuc /* Check if the caller has permission to execute a particular call. */
87433d6423SLionel Sambuc struct rprocpub *rpub;
88433d6423SLionel Sambuc int call_allowed;
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc /* Caller should be either root or have control privileges. */
91433d6423SLionel Sambuc call_allowed = caller_is_root(caller);
92433d6423SLionel Sambuc if(rp) {
93433d6423SLionel Sambuc call_allowed |= caller_can_control(caller, rp);
94433d6423SLionel Sambuc }
95433d6423SLionel Sambuc if(!call_allowed) {
96433d6423SLionel Sambuc return EPERM;
97433d6423SLionel Sambuc }
98433d6423SLionel Sambuc
99433d6423SLionel Sambuc if(rp) {
100433d6423SLionel Sambuc rpub = rp->r_pub;
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc /* Only allow RS_EDIT if the target is a user process. */
103433d6423SLionel Sambuc if(!(rp->r_priv.s_flags & SYS_PROC)) {
104433d6423SLionel Sambuc if(call != RS_EDIT) return EPERM;
105433d6423SLionel Sambuc }
106433d6423SLionel Sambuc
107fb6bd596SCristiano Giuffrida /* Disallow the call if an update is in progress. */
108fb6bd596SCristiano Giuffrida if(RUPDATE_IS_UPDATING()) {
109fb6bd596SCristiano Giuffrida return EBUSY;
110fb6bd596SCristiano Giuffrida }
111fb6bd596SCristiano Giuffrida
112433d6423SLionel Sambuc /* Disallow the call if another call is in progress for the service. */
113433d6423SLionel Sambuc if((rp->r_flags & RS_LATEREPLY)
114fb6bd596SCristiano Giuffrida || (rp->r_flags & RS_INITIALIZING)) {
115433d6423SLionel Sambuc return EBUSY;
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc /* Only allow RS_DOWN and RS_RESTART if the service has terminated. */
119433d6423SLionel Sambuc if(rp->r_flags & RS_TERMINATED) {
120433d6423SLionel Sambuc if(call != RS_DOWN && call != RS_RESTART) return EPERM;
121433d6423SLionel Sambuc }
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /* Disallow RS_DOWN for core system services. */
124433d6423SLionel Sambuc if (rpub->sys_flags & SF_CORE_SRV) {
125433d6423SLionel Sambuc if(call == RS_DOWN) return EPERM;
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc }
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc return OK;
130433d6423SLionel Sambuc }
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc /*===========================================================================*
133433d6423SLionel Sambuc * copy_rs_start *
134433d6423SLionel Sambuc *===========================================================================*/
copy_rs_start(src_e,src_rs_start,dst_rs_start)135433d6423SLionel Sambuc int copy_rs_start(src_e, src_rs_start, dst_rs_start)
136433d6423SLionel Sambuc endpoint_t src_e;
137433d6423SLionel Sambuc char *src_rs_start;
138433d6423SLionel Sambuc struct rs_start *dst_rs_start;
139433d6423SLionel Sambuc {
140433d6423SLionel Sambuc int r;
141433d6423SLionel Sambuc
142433d6423SLionel Sambuc r = sys_datacopy(src_e, (vir_bytes) src_rs_start,
143433d6423SLionel Sambuc SELF, (vir_bytes) dst_rs_start, sizeof(struct rs_start));
144433d6423SLionel Sambuc
145433d6423SLionel Sambuc return r;
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc /*===========================================================================*
149433d6423SLionel Sambuc * copy_label *
150433d6423SLionel Sambuc *===========================================================================*/
copy_label(src_e,src_label,src_len,dst_label,dst_len)151433d6423SLionel Sambuc int copy_label(src_e, src_label, src_len, dst_label, dst_len)
152433d6423SLionel Sambuc endpoint_t src_e;
153433d6423SLionel Sambuc char *src_label;
154433d6423SLionel Sambuc size_t src_len;
155433d6423SLionel Sambuc char *dst_label;
156433d6423SLionel Sambuc size_t dst_len;
157433d6423SLionel Sambuc {
158433d6423SLionel Sambuc int s, len;
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc len = MIN(dst_len-1, src_len);
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc s = sys_datacopy(src_e, (vir_bytes) src_label,
163433d6423SLionel Sambuc SELF, (vir_bytes) dst_label, len);
164433d6423SLionel Sambuc if (s != OK) return s;
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc dst_label[len] = 0;
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc return OK;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc
171433d6423SLionel Sambuc /*===========================================================================*
172fb6bd596SCristiano Giuffrida * init_state_data *
173fb6bd596SCristiano Giuffrida *===========================================================================*/
init_state_data(endpoint_t src_e,int prepare_state,struct rs_state_data * src_rs_state_data,struct rs_state_data * dst_rs_state_data)174fb6bd596SCristiano Giuffrida int init_state_data(endpoint_t src_e, int prepare_state,
175fb6bd596SCristiano Giuffrida struct rs_state_data *src_rs_state_data,
176fb6bd596SCristiano Giuffrida struct rs_state_data *dst_rs_state_data)
177fb6bd596SCristiano Giuffrida {
178fb6bd596SCristiano Giuffrida int s, i, j, num_ipc_filters = 0;
179fb6bd596SCristiano Giuffrida struct rs_ipc_filter_el (*rs_ipc_filter_els)[IPCF_MAX_ELEMENTS];
180fb6bd596SCristiano Giuffrida struct rs_ipc_filter_el rs_ipc_filter[IPCF_MAX_ELEMENTS];
181fb6bd596SCristiano Giuffrida size_t rs_ipc_filter_size = sizeof(rs_ipc_filter);
182fb6bd596SCristiano Giuffrida ipc_filter_el_t (*ipcf_els_buff)[IPCF_MAX_ELEMENTS];
183fb6bd596SCristiano Giuffrida size_t ipcf_els_buff_size;
184fb6bd596SCristiano Giuffrida
185fb6bd596SCristiano Giuffrida dst_rs_state_data->size = 0;
186fb6bd596SCristiano Giuffrida dst_rs_state_data->eval_addr = NULL;
187fb6bd596SCristiano Giuffrida dst_rs_state_data->eval_len = 0;
188fb6bd596SCristiano Giuffrida dst_rs_state_data->ipcf_els = NULL;
189fb6bd596SCristiano Giuffrida dst_rs_state_data->ipcf_els_size = 0;
190fb6bd596SCristiano Giuffrida if(src_rs_state_data->size != sizeof(struct rs_state_data)) {
191fb6bd596SCristiano Giuffrida return E2BIG;
192fb6bd596SCristiano Giuffrida }
193fb6bd596SCristiano Giuffrida
194fb6bd596SCristiano Giuffrida /* Initialize eval expression. */
195fb6bd596SCristiano Giuffrida if(prepare_state == SEF_LU_STATE_EVAL) {
196fb6bd596SCristiano Giuffrida if(src_rs_state_data->eval_len == 0 || !src_rs_state_data->eval_addr) {
197fb6bd596SCristiano Giuffrida return EINVAL;
198fb6bd596SCristiano Giuffrida }
199fb6bd596SCristiano Giuffrida dst_rs_state_data->eval_addr = malloc(src_rs_state_data->eval_len+1);
200fb6bd596SCristiano Giuffrida dst_rs_state_data->eval_len = src_rs_state_data->eval_len;
201fb6bd596SCristiano Giuffrida if(!dst_rs_state_data->eval_addr) {
202fb6bd596SCristiano Giuffrida return ENOMEM;
203fb6bd596SCristiano Giuffrida }
204fb6bd596SCristiano Giuffrida s = sys_datacopy(src_e, (vir_bytes) src_rs_state_data->eval_addr,
205fb6bd596SCristiano Giuffrida SELF, (vir_bytes) dst_rs_state_data->eval_addr,
206fb6bd596SCristiano Giuffrida dst_rs_state_data->eval_len);
207fb6bd596SCristiano Giuffrida if(s != OK) {
208fb6bd596SCristiano Giuffrida return s;
209fb6bd596SCristiano Giuffrida }
210fb6bd596SCristiano Giuffrida *((char*)dst_rs_state_data->eval_addr + dst_rs_state_data->eval_len) = '\0';
211fb6bd596SCristiano Giuffrida dst_rs_state_data->size = src_rs_state_data->size;
212fb6bd596SCristiano Giuffrida }
213fb6bd596SCristiano Giuffrida
214fb6bd596SCristiano Giuffrida /* Initialize ipc filters. */
215fb6bd596SCristiano Giuffrida if(src_rs_state_data->ipcf_els_size % rs_ipc_filter_size) {
216fb6bd596SCristiano Giuffrida return E2BIG;
217fb6bd596SCristiano Giuffrida }
218fb6bd596SCristiano Giuffrida rs_ipc_filter_els = src_rs_state_data->ipcf_els;
219fb6bd596SCristiano Giuffrida num_ipc_filters = src_rs_state_data->ipcf_els_size / rs_ipc_filter_size;
220fb6bd596SCristiano Giuffrida if(!rs_ipc_filter_els) {
221fb6bd596SCristiano Giuffrida return OK;
222fb6bd596SCristiano Giuffrida }
223fb6bd596SCristiano Giuffrida
224fb6bd596SCristiano Giuffrida ipcf_els_buff_size = sizeof(ipc_filter_el_t)*IPCF_MAX_ELEMENTS*num_ipc_filters;
225fb6bd596SCristiano Giuffrida if(src_e == VM_PROC_NR) {
226fb6bd596SCristiano Giuffrida ipcf_els_buff_size += sizeof(ipc_filter_el_t)*IPCF_MAX_ELEMENTS;
227fb6bd596SCristiano Giuffrida }
228fb6bd596SCristiano Giuffrida ipcf_els_buff = malloc(ipcf_els_buff_size);
229fb6bd596SCristiano Giuffrida if(!ipcf_els_buff) {
230fb6bd596SCristiano Giuffrida return ENOMEM;
231fb6bd596SCristiano Giuffrida }
232fb6bd596SCristiano Giuffrida memset(ipcf_els_buff, 0, ipcf_els_buff_size);
233fb6bd596SCristiano Giuffrida for(i=0;i<num_ipc_filters;i++) {
234fb6bd596SCristiano Giuffrida s = sys_datacopy(src_e, (vir_bytes) rs_ipc_filter_els[i],
235fb6bd596SCristiano Giuffrida SELF, (vir_bytes) rs_ipc_filter, rs_ipc_filter_size);
236fb6bd596SCristiano Giuffrida if(s != OK) {
237fb6bd596SCristiano Giuffrida return s;
238fb6bd596SCristiano Giuffrida }
239fb6bd596SCristiano Giuffrida for(j=0;j<IPCF_MAX_ELEMENTS && rs_ipc_filter[j].flags;j++) {
240fb6bd596SCristiano Giuffrida endpoint_t m_source = 0;
241fb6bd596SCristiano Giuffrida int m_type = 0;
242fb6bd596SCristiano Giuffrida int flags = rs_ipc_filter[j].flags;
243fb6bd596SCristiano Giuffrida if(flags & IPCF_MATCH_M_TYPE) {
244fb6bd596SCristiano Giuffrida m_type = rs_ipc_filter[j].m_type;
245fb6bd596SCristiano Giuffrida }
246fb6bd596SCristiano Giuffrida if(flags & IPCF_MATCH_M_SOURCE) {
247fb6bd596SCristiano Giuffrida if(ds_retrieve_label_endpt(rs_ipc_filter[j].m_label,&m_source) != OK) {
248fb6bd596SCristiano Giuffrida /* try to see if an endpoint was provided as label */
249fb6bd596SCristiano Giuffrida char *buff;
250fb6bd596SCristiano Giuffrida if(!strcmp("ANY_USR", rs_ipc_filter[j].m_label)) {
251fb6bd596SCristiano Giuffrida m_source = ANY_USR;
252fb6bd596SCristiano Giuffrida }
253fb6bd596SCristiano Giuffrida else if(!strcmp("ANY_SYS", rs_ipc_filter[j].m_label)) {
254fb6bd596SCristiano Giuffrida m_source = ANY_SYS;
255fb6bd596SCristiano Giuffrida }
256fb6bd596SCristiano Giuffrida else if(!strcmp("ANY_TSK", rs_ipc_filter[j].m_label)) {
257fb6bd596SCristiano Giuffrida m_source = ANY_TSK;
258fb6bd596SCristiano Giuffrida }
259fb6bd596SCristiano Giuffrida else {
260fb6bd596SCristiano Giuffrida errno=0;
261fb6bd596SCristiano Giuffrida m_source = strtol(rs_ipc_filter[j].m_label, &buff, 10);
262fb6bd596SCristiano Giuffrida if(errno || strcmp(buff, "")) {
263fb6bd596SCristiano Giuffrida return ESRCH;
264fb6bd596SCristiano Giuffrida }
265fb6bd596SCristiano Giuffrida }
266fb6bd596SCristiano Giuffrida }
267fb6bd596SCristiano Giuffrida }
268fb6bd596SCristiano Giuffrida ipcf_els_buff[i][j].flags = flags;
269fb6bd596SCristiano Giuffrida ipcf_els_buff[i][j].m_source = m_source;
270fb6bd596SCristiano Giuffrida ipcf_els_buff[i][j].m_type = m_type;
271fb6bd596SCristiano Giuffrida }
272fb6bd596SCristiano Giuffrida }
273fb6bd596SCristiano Giuffrida if(src_e == VM_PROC_NR) {
274fb6bd596SCristiano Giuffrida /* Make sure VM can still talk to us at update time. */
275fb6bd596SCristiano Giuffrida ipcf_els_buff[i][0].flags = (IPCF_EL_WHITELIST|IPCF_MATCH_M_SOURCE|IPCF_MATCH_M_TYPE);
276fb6bd596SCristiano Giuffrida ipcf_els_buff[i][0].m_source = RS_PROC_NR;
277fb6bd596SCristiano Giuffrida ipcf_els_buff[i][0].m_type = VM_RS_UPDATE;
278fb6bd596SCristiano Giuffrida }
279fb6bd596SCristiano Giuffrida dst_rs_state_data->size = src_rs_state_data->size;
280fb6bd596SCristiano Giuffrida dst_rs_state_data->ipcf_els = ipcf_els_buff;
281fb6bd596SCristiano Giuffrida dst_rs_state_data->ipcf_els_size = ipcf_els_buff_size;
282fb6bd596SCristiano Giuffrida
283fb6bd596SCristiano Giuffrida return OK;
284fb6bd596SCristiano Giuffrida }
285fb6bd596SCristiano Giuffrida
286fb6bd596SCristiano Giuffrida /*===========================================================================*
287433d6423SLionel Sambuc * build_cmd_dep *
288433d6423SLionel Sambuc *===========================================================================*/
build_cmd_dep(struct rproc * rp)289433d6423SLionel Sambuc void build_cmd_dep(struct rproc *rp)
290433d6423SLionel Sambuc {
291433d6423SLionel Sambuc struct rprocpub *rpub;
292433d6423SLionel Sambuc int arg_count;
293433d6423SLionel Sambuc int len;
294433d6423SLionel Sambuc char *cmd_ptr;
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc rpub = rp->r_pub;
297433d6423SLionel Sambuc
298433d6423SLionel Sambuc /* Build argument vector to be passed to execute call. The format of the
299433d6423SLionel Sambuc * arguments vector is: path, arguments, NULL.
300433d6423SLionel Sambuc */
301433d6423SLionel Sambuc strcpy(rp->r_args, rp->r_cmd); /* copy raw command */
302433d6423SLionel Sambuc arg_count = 0; /* initialize arg count */
303433d6423SLionel Sambuc rp->r_argv[arg_count++] = rp->r_args; /* start with path */
304433d6423SLionel Sambuc cmd_ptr = rp->r_args; /* do some parsing */
305433d6423SLionel Sambuc while(*cmd_ptr != '\0') { /* stop at end of string */
306433d6423SLionel Sambuc if (*cmd_ptr == ' ') { /* next argument */
307433d6423SLionel Sambuc *cmd_ptr = '\0'; /* terminate previous */
308433d6423SLionel Sambuc while (*++cmd_ptr == ' ') ; /* skip spaces */
309433d6423SLionel Sambuc if (*cmd_ptr == '\0') break; /* no arg following */
310433d6423SLionel Sambuc /* There are ARGV_ELEMENTS elements; must leave one for null */
311433d6423SLionel Sambuc if (arg_count>=ARGV_ELEMENTS-1) { /* arg vector full */
312433d6423SLionel Sambuc printf("RS: build_cmd_dep: too many args\n");
313433d6423SLionel Sambuc break;
314433d6423SLionel Sambuc }
315433d6423SLionel Sambuc assert(arg_count < ARGV_ELEMENTS);
316433d6423SLionel Sambuc rp->r_argv[arg_count++] = cmd_ptr; /* add to arg vector */
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc cmd_ptr ++; /* continue parsing */
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc assert(arg_count < ARGV_ELEMENTS);
321433d6423SLionel Sambuc rp->r_argv[arg_count] = NULL; /* end with NULL pointer */
322433d6423SLionel Sambuc rp->r_argc = arg_count;
323433d6423SLionel Sambuc }
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc /*===========================================================================*
326fb6bd596SCristiano Giuffrida * end_srv_init *
327433d6423SLionel Sambuc *===========================================================================*/
end_srv_init(struct rproc * rp)328fb6bd596SCristiano Giuffrida void end_srv_init(struct rproc *rp)
329433d6423SLionel Sambuc {
330433d6423SLionel Sambuc struct rprocpub *rpub;
331fb6bd596SCristiano Giuffrida int r;
332433d6423SLionel Sambuc
333fb6bd596SCristiano Giuffrida rpub = rp->r_pub;
334433d6423SLionel Sambuc
335fb6bd596SCristiano Giuffrida /* See if a late reply has to be sent. */
336fb6bd596SCristiano Giuffrida late_reply(rp, OK);
337433d6423SLionel Sambuc
338fb6bd596SCristiano Giuffrida /* If the service has completed initialization after a crash
339fb6bd596SCristiano Giuffrida * make the new instance active and cleanup the old replica.
340fb6bd596SCristiano Giuffrida * If the service was part of a scheduled update, schedule the new
341fb6bd596SCristiano Giuffrida * replica for the same update.
342433d6423SLionel Sambuc */
343fb6bd596SCristiano Giuffrida if(rp->r_prev_rp) {
344fb6bd596SCristiano Giuffrida if(SRV_IS_UPD_SCHEDULED(rp->r_prev_rp)) {
345fb6bd596SCristiano Giuffrida rupdate_upd_move(rp->r_prev_rp, rp);
346433d6423SLionel Sambuc }
347fb6bd596SCristiano Giuffrida cleanup_service(rp->r_prev_rp);
348fb6bd596SCristiano Giuffrida rp->r_prev_rp = NULL;
349fb6bd596SCristiano Giuffrida rp->r_restarts += 1;
350433d6423SLionel Sambuc
351433d6423SLionel Sambuc if(rs_verbose)
352fb6bd596SCristiano Giuffrida printf("RS: %s completed restart\n", srv_to_string(rp));
353433d6423SLionel Sambuc }
354fb6bd596SCristiano Giuffrida rp->r_next_rp = NULL;
355433d6423SLionel Sambuc }
356433d6423SLionel Sambuc
357433d6423SLionel Sambuc /*===========================================================================*
358433d6423SLionel Sambuc * kill_service_debug *
359433d6423SLionel Sambuc *===========================================================================*/
kill_service_debug(file,line,rp,errstr,err)360433d6423SLionel Sambuc int kill_service_debug(file, line, rp, errstr, err)
361433d6423SLionel Sambuc char *file;
362433d6423SLionel Sambuc int line;
363433d6423SLionel Sambuc struct rproc *rp;
364433d6423SLionel Sambuc char *errstr;
365433d6423SLionel Sambuc int err;
366433d6423SLionel Sambuc {
367433d6423SLionel Sambuc /* Crash a system service and don't let it restart. */
368433d6423SLionel Sambuc if(errstr && !shutting_down) {
369433d6423SLionel Sambuc printf("RS: %s (error %d)\n", errstr, err);
370433d6423SLionel Sambuc }
371433d6423SLionel Sambuc rp->r_flags |= RS_EXITING; /* expect exit */
372433d6423SLionel Sambuc crash_service_debug(file, line, rp); /* simulate crash */
373433d6423SLionel Sambuc
374433d6423SLionel Sambuc return err;
375433d6423SLionel Sambuc }
376433d6423SLionel Sambuc
377433d6423SLionel Sambuc /*===========================================================================*
378433d6423SLionel Sambuc * crash_service_debug *
379433d6423SLionel Sambuc *===========================================================================*/
crash_service_debug(file,line,rp)380433d6423SLionel Sambuc int crash_service_debug(file, line, rp)
381433d6423SLionel Sambuc char *file;
382433d6423SLionel Sambuc int line;
383433d6423SLionel Sambuc struct rproc *rp;
384433d6423SLionel Sambuc {
385433d6423SLionel Sambuc /* Simluate a crash in a system service. */
386433d6423SLionel Sambuc struct rprocpub *rpub;
387433d6423SLionel Sambuc
388433d6423SLionel Sambuc rpub = rp->r_pub;
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc if(rs_verbose)
391433d6423SLionel Sambuc printf("RS: %s %skilled at %s:%d\n", srv_to_string(rp),
392433d6423SLionel Sambuc rp->r_flags & RS_EXITING ? "lethally " : "", file, line);
393433d6423SLionel Sambuc
394433d6423SLionel Sambuc /* RS should simply exit() directly. */
395433d6423SLionel Sambuc if(rpub->endpoint == RS_PROC_NR) {
396433d6423SLionel Sambuc exit(1);
397433d6423SLionel Sambuc }
398433d6423SLionel Sambuc
399433d6423SLionel Sambuc return sys_kill(rpub->endpoint, SIGKILL);
400433d6423SLionel Sambuc }
401433d6423SLionel Sambuc
402433d6423SLionel Sambuc /*===========================================================================*
403433d6423SLionel Sambuc * cleanup_service_debug *
404433d6423SLionel Sambuc *===========================================================================*/
cleanup_service_debug(file,line,rp)405433d6423SLionel Sambuc void cleanup_service_debug(file, line, rp)
406433d6423SLionel Sambuc char *file;
407433d6423SLionel Sambuc int line;
408433d6423SLionel Sambuc struct rproc *rp;
409433d6423SLionel Sambuc {
410433d6423SLionel Sambuc struct rprocpub *rpub;
411fb6bd596SCristiano Giuffrida int detach, cleanup_script;
412433d6423SLionel Sambuc int s;
413433d6423SLionel Sambuc
414433d6423SLionel Sambuc rpub = rp->r_pub;
415433d6423SLionel Sambuc
416fb6bd596SCristiano Giuffrida if(!(rp->r_flags & RS_DEAD)) {
417fb6bd596SCristiano Giuffrida if(rs_verbose)
418fb6bd596SCristiano Giuffrida printf("RS: %s marked for cleanup at %s:%d\n", srv_to_string(rp),
419fb6bd596SCristiano Giuffrida file, line);
420fb6bd596SCristiano Giuffrida
421fb6bd596SCristiano Giuffrida /* Unlink service the first time. */
422fb6bd596SCristiano Giuffrida if(rp->r_next_rp) {
423fb6bd596SCristiano Giuffrida rp->r_next_rp->r_prev_rp = NULL;
424fb6bd596SCristiano Giuffrida rp->r_next_rp = NULL;
425fb6bd596SCristiano Giuffrida }
426fb6bd596SCristiano Giuffrida if(rp->r_prev_rp) {
427fb6bd596SCristiano Giuffrida rp->r_prev_rp->r_next_rp = NULL;
428fb6bd596SCristiano Giuffrida rp->r_prev_rp = NULL;
429fb6bd596SCristiano Giuffrida }
430fb6bd596SCristiano Giuffrida if(rp->r_new_rp) {
431fb6bd596SCristiano Giuffrida rp->r_new_rp->r_old_rp = NULL;
432fb6bd596SCristiano Giuffrida rp->r_new_rp = NULL;
433fb6bd596SCristiano Giuffrida }
434fb6bd596SCristiano Giuffrida if(rp->r_old_rp) {
435fb6bd596SCristiano Giuffrida rp->r_old_rp->r_new_rp = NULL;
436fb6bd596SCristiano Giuffrida rp->r_old_rp = NULL;
437fb6bd596SCristiano Giuffrida }
438fb6bd596SCristiano Giuffrida rp->r_flags |= RS_DEAD;
439fb6bd596SCristiano Giuffrida
440fb6bd596SCristiano Giuffrida /* Make sure the service can no longer run and unblock IPC callers. */
441fb6bd596SCristiano Giuffrida sys_privctl(rpub->endpoint, SYS_PRIV_DISALLOW, NULL);
442fb6bd596SCristiano Giuffrida sys_privctl(rpub->endpoint, SYS_PRIV_CLEAR_IPC_REFS, NULL);
443fb6bd596SCristiano Giuffrida rp->r_flags &= ~RS_ACTIVE;
444fb6bd596SCristiano Giuffrida
445fb6bd596SCristiano Giuffrida /* Send a late reply if there is any pending. */
446fb6bd596SCristiano Giuffrida late_reply(rp, OK);
447fb6bd596SCristiano Giuffrida
448fb6bd596SCristiano Giuffrida return;
449fb6bd596SCristiano Giuffrida }
450fb6bd596SCristiano Giuffrida
451fb6bd596SCristiano Giuffrida cleanup_script = rp->r_flags & RS_CLEANUP_SCRIPT;
452fb6bd596SCristiano Giuffrida detach = rp->r_flags & RS_CLEANUP_DETACH;
453fb6bd596SCristiano Giuffrida
454fb6bd596SCristiano Giuffrida /* Cleanup the service when not detaching. */
455fb6bd596SCristiano Giuffrida if(!detach) {
456433d6423SLionel Sambuc if(rs_verbose)
457433d6423SLionel Sambuc printf("RS: %s cleaned up at %s:%d\n", srv_to_string(rp),
458433d6423SLionel Sambuc file, line);
459433d6423SLionel Sambuc
460433d6423SLionel Sambuc /* Tell scheduler this process is finished */
461433d6423SLionel Sambuc if ((s = sched_stop(rp->r_scheduler, rpub->endpoint)) != OK) {
462433d6423SLionel Sambuc printf("RS: warning: scheduler won't give up process: %d\n", s);
463433d6423SLionel Sambuc }
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc /* Ask PM to exit the service */
466433d6423SLionel Sambuc if(rp->r_pid == -1) {
467433d6423SLionel Sambuc printf("RS: warning: attempt to kill pid -1!\n");
468433d6423SLionel Sambuc }
469433d6423SLionel Sambuc else {
470433d6423SLionel Sambuc srv_kill(rp->r_pid, SIGKILL);
471433d6423SLionel Sambuc }
472fb6bd596SCristiano Giuffrida }
473433d6423SLionel Sambuc
474fb6bd596SCristiano Giuffrida /* See if we need to run a script now. */
475fb6bd596SCristiano Giuffrida if(cleanup_script) {
476fb6bd596SCristiano Giuffrida rp->r_flags &= ~RS_CLEANUP_SCRIPT;
477fb6bd596SCristiano Giuffrida s = run_script(rp);
478fb6bd596SCristiano Giuffrida if(s != OK) {
479fb6bd596SCristiano Giuffrida printf("RS: warning: cannot run cleanup script: %d\n", s);
480fb6bd596SCristiano Giuffrida }
481fb6bd596SCristiano Giuffrida }
482fb6bd596SCristiano Giuffrida
483fb6bd596SCristiano Giuffrida if(detach) {
484fb6bd596SCristiano Giuffrida /* Detach service when asked to. */
485fb6bd596SCristiano Giuffrida detach_service(rp);
486fb6bd596SCristiano Giuffrida }
487fb6bd596SCristiano Giuffrida else {
488fb6bd596SCristiano Giuffrida /* Free slot otherwise, unless we're about to reuse it */
489433d6423SLionel Sambuc if (!(rp->r_flags & RS_REINCARNATE))
490433d6423SLionel Sambuc free_slot(rp);
491433d6423SLionel Sambuc }
492fb6bd596SCristiano Giuffrida }
493fb6bd596SCristiano Giuffrida
494fb6bd596SCristiano Giuffrida /*===========================================================================*
495fb6bd596SCristiano Giuffrida * detach_service_debug *
496fb6bd596SCristiano Giuffrida *===========================================================================*/
detach_service_debug(file,line,rp)497fb6bd596SCristiano Giuffrida void detach_service_debug(file, line, rp)
498fb6bd596SCristiano Giuffrida char *file;
499fb6bd596SCristiano Giuffrida int line;
500fb6bd596SCristiano Giuffrida struct rproc *rp;
501fb6bd596SCristiano Giuffrida {
502fb6bd596SCristiano Giuffrida /* Detach the given system service. */
503fb6bd596SCristiano Giuffrida static unsigned long detach_counter = 0;
504fb6bd596SCristiano Giuffrida char label[RS_MAX_LABEL_LEN];
505fb6bd596SCristiano Giuffrida struct rprocpub *rpub;
506fb6bd596SCristiano Giuffrida
507fb6bd596SCristiano Giuffrida rpub = rp->r_pub;
508fb6bd596SCristiano Giuffrida
509fb6bd596SCristiano Giuffrida /* Publish a new unique label for the system service. */
510fb6bd596SCristiano Giuffrida rpub->label[RS_MAX_LABEL_LEN-1] = '\0';
511fb6bd596SCristiano Giuffrida strcpy(label, rpub->label);
512fb6bd596SCristiano Giuffrida snprintf(rpub->label, RS_MAX_LABEL_LEN, "%lu.%s", ++detach_counter, label);
513fb6bd596SCristiano Giuffrida ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
514fb6bd596SCristiano Giuffrida
515fb6bd596SCristiano Giuffrida if(rs_verbose)
516fb6bd596SCristiano Giuffrida printf("RS: %s detached at %s:%d\n", srv_to_string(rp),
517fb6bd596SCristiano Giuffrida file, line);
518fb6bd596SCristiano Giuffrida
519fb6bd596SCristiano Giuffrida /* Allow the service to run. */
520fb6bd596SCristiano Giuffrida rp->r_flags = RS_IN_USE | RS_ACTIVE;
521fb6bd596SCristiano Giuffrida rpub->sys_flags &= ~(SF_CORE_SRV|SF_DET_RESTART);
522fb6bd596SCristiano Giuffrida rp->r_period = 0;
523fb6bd596SCristiano Giuffrida rpub->dev_nr = 0;
524*181fb1b2SDavid van Moolenbroek rpub->nr_domain = 0;
525fb6bd596SCristiano Giuffrida sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL);
526fb6bd596SCristiano Giuffrida }
527433d6423SLionel Sambuc
528433d6423SLionel Sambuc /*===========================================================================*
529433d6423SLionel Sambuc * create_service *
530433d6423SLionel Sambuc *===========================================================================*/
create_service(rp)531433d6423SLionel Sambuc int create_service(rp)
532433d6423SLionel Sambuc struct rproc *rp;
533433d6423SLionel Sambuc {
534433d6423SLionel Sambuc /* Create the given system service. */
535433d6423SLionel Sambuc int child_proc_nr_e, child_proc_nr_n; /* child process slot */
536433d6423SLionel Sambuc pid_t child_pid; /* child's process id */
537433d6423SLionel Sambuc int s, use_copy, has_replica;
538433d6423SLionel Sambuc extern char **environ;
539433d6423SLionel Sambuc struct rprocpub *rpub;
540433d6423SLionel Sambuc
541433d6423SLionel Sambuc rpub = rp->r_pub;
542433d6423SLionel Sambuc use_copy= (rpub->sys_flags & SF_USE_COPY);
543433d6423SLionel Sambuc has_replica= (rp->r_old_rp
544433d6423SLionel Sambuc || (rp->r_prev_rp && !(rp->r_prev_rp->r_flags & RS_TERMINATED)));
545433d6423SLionel Sambuc
546433d6423SLionel Sambuc /* Do we need an existing replica to create the service? */
547433d6423SLionel Sambuc if(!has_replica && (rpub->sys_flags & SF_NEED_REPL)) {
548433d6423SLionel Sambuc printf("RS: unable to create service '%s' without a replica\n",
549433d6423SLionel Sambuc rpub->label);
550433d6423SLionel Sambuc free_slot(rp);
551433d6423SLionel Sambuc return(EPERM);
552433d6423SLionel Sambuc }
553433d6423SLionel Sambuc
554433d6423SLionel Sambuc /* Do we need an in-memory copy to create the service? */
555433d6423SLionel Sambuc if(!use_copy && (rpub->sys_flags & SF_NEED_COPY)) {
556433d6423SLionel Sambuc printf("RS: unable to create service '%s' without an in-memory copy\n",
557433d6423SLionel Sambuc rpub->label);
558433d6423SLionel Sambuc free_slot(rp);
559433d6423SLionel Sambuc return(EPERM);
560433d6423SLionel Sambuc }
561433d6423SLionel Sambuc
562433d6423SLionel Sambuc /* Do we have a copy or a command to create the service? */
563433d6423SLionel Sambuc if(!use_copy && !strcmp(rp->r_cmd, "")) {
564433d6423SLionel Sambuc printf("RS: unable to create service '%s' without a copy or command\n",
565433d6423SLionel Sambuc rpub->label);
566433d6423SLionel Sambuc free_slot(rp);
567433d6423SLionel Sambuc return(EPERM);
568433d6423SLionel Sambuc }
569433d6423SLionel Sambuc
570433d6423SLionel Sambuc /* Now fork and branch for parent and child process (and check for error).
571433d6423SLionel Sambuc * After fork()ing, we need to pin RS memory again or pagefaults will occur
572433d6423SLionel Sambuc * on future writes.
573433d6423SLionel Sambuc */
574433d6423SLionel Sambuc if(rs_verbose)
575433d6423SLionel Sambuc printf("RS: forking child with srv_fork()...\n");
57677e79d33SDavid van Moolenbroek child_pid= srv_fork(rp->r_uid, 0); /* Force group to wheel for now */
577433d6423SLionel Sambuc if(child_pid < 0) {
578433d6423SLionel Sambuc printf("RS: srv_fork() failed (error %d)\n", child_pid);
579433d6423SLionel Sambuc free_slot(rp);
580433d6423SLionel Sambuc return(child_pid);
581433d6423SLionel Sambuc }
582433d6423SLionel Sambuc
583433d6423SLionel Sambuc /* Get endpoint of the child. */
584433d6423SLionel Sambuc if ((s = getprocnr(child_pid, &child_proc_nr_e)) != 0)
585433d6423SLionel Sambuc panic("unable to get child endpoint: %d", s);
586433d6423SLionel Sambuc
587433d6423SLionel Sambuc /* There is now a child process. Update the system process table. */
588433d6423SLionel Sambuc child_proc_nr_n = _ENDPOINT_P(child_proc_nr_e);
589433d6423SLionel Sambuc rp->r_flags = RS_IN_USE; /* mark slot in use */
590433d6423SLionel Sambuc rpub->endpoint = child_proc_nr_e; /* set child endpoint */
591433d6423SLionel Sambuc rp->r_pid = child_pid; /* set child pid */
592433d6423SLionel Sambuc rp->r_check_tm = 0; /* not checked yet */
593d91f738bSDavid van Moolenbroek rp->r_alive_tm = getticks(); /* currently alive */
594433d6423SLionel Sambuc rp->r_stop_tm = 0; /* not exiting yet */
595433d6423SLionel Sambuc rp->r_backoff = 0; /* not to be restarted */
596433d6423SLionel Sambuc rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
597433d6423SLionel Sambuc rpub->in_use = TRUE; /* public entry is now in use */
598433d6423SLionel Sambuc
599433d6423SLionel Sambuc /* Set and synch the privilege structure for the new service. */
600433d6423SLionel Sambuc if ((s = sys_privctl(child_proc_nr_e, SYS_PRIV_SET_SYS, &rp->r_priv)) != OK
601433d6423SLionel Sambuc || (s = sys_getpriv(&rp->r_priv, child_proc_nr_e)) != OK) {
602433d6423SLionel Sambuc printf("RS: unable to set privilege structure: %d\n", s);
603433d6423SLionel Sambuc cleanup_service(rp);
60448f446ecSCristiano Giuffrida vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
605433d6423SLionel Sambuc return ENOMEM;
606433d6423SLionel Sambuc }
607433d6423SLionel Sambuc
608433d6423SLionel Sambuc /* Set the scheduler for this process */
609433d6423SLionel Sambuc if ((s = sched_init_proc(rp)) != OK) {
610433d6423SLionel Sambuc printf("RS: unable to start scheduling: %d\n", s);
611433d6423SLionel Sambuc cleanup_service(rp);
61248f446ecSCristiano Giuffrida vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
613433d6423SLionel Sambuc return s;
614433d6423SLionel Sambuc }
615433d6423SLionel Sambuc
616433d6423SLionel Sambuc /* Copy the executable image into the child process. If no copy exists,
617433d6423SLionel Sambuc * allocate one and free it right after exec completes.
618433d6423SLionel Sambuc */
619433d6423SLionel Sambuc if(use_copy) {
620433d6423SLionel Sambuc if(rs_verbose)
621433d6423SLionel Sambuc printf("RS: %s uses an in-memory copy\n",
622433d6423SLionel Sambuc srv_to_string(rp));
623433d6423SLionel Sambuc }
624433d6423SLionel Sambuc else {
625433d6423SLionel Sambuc if ((s = read_exec(rp)) != OK) {
626433d6423SLionel Sambuc printf("RS: read_exec failed: %d\n", s);
627433d6423SLionel Sambuc cleanup_service(rp);
62848f446ecSCristiano Giuffrida vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
629433d6423SLionel Sambuc return s;
630433d6423SLionel Sambuc }
631433d6423SLionel Sambuc }
632433d6423SLionel Sambuc if(rs_verbose)
633433d6423SLionel Sambuc printf("RS: execing child with srv_execve()...\n");
63423199f62SDavid van Moolenbroek s = srv_execve(child_proc_nr_e, rp->r_exec, rp->r_exec_len, rpub->proc_name,
63523199f62SDavid van Moolenbroek rp->r_argv, environ);
63648f446ecSCristiano Giuffrida vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
637433d6423SLionel Sambuc if (s != OK) {
638433d6423SLionel Sambuc printf("RS: srv_execve failed: %d\n", s);
639433d6423SLionel Sambuc cleanup_service(rp);
640433d6423SLionel Sambuc return s;
641433d6423SLionel Sambuc }
642433d6423SLionel Sambuc if(!use_copy) {
643433d6423SLionel Sambuc free_exec(rp);
644433d6423SLionel Sambuc }
645433d6423SLionel Sambuc
646fb6bd596SCristiano Giuffrida /* The purpose of non-blocking forks is to avoid involving VFS in the forking
647fb6bd596SCristiano Giuffrida * process, because VFS may be blocked on a sendrec() to a MFS that is
648fb6bd596SCristiano Giuffrida * waiting for a endpoint update for a dead driver. We have just published
649fb6bd596SCristiano Giuffrida * that update, but VFS may still be blocked. As a result, VFS may not yet
650fb6bd596SCristiano Giuffrida * have received PM's fork message. Hence, if we call mapdriver()
651fb6bd596SCristiano Giuffrida * immediately, VFS may not know about the process and thus refuse to add the
652fb6bd596SCristiano Giuffrida * driver entry. The following temporary hack works around this by forcing
653fb6bd596SCristiano Giuffrida * blocking communication from PM to VFS. Once VFS has been made non-blocking
654fb6bd596SCristiano Giuffrida * towards MFS instances, this hack and the big part of srv_fork() can go.
655fb6bd596SCristiano Giuffrida */
656fb6bd596SCristiano Giuffrida setuid(0);
657fb6bd596SCristiano Giuffrida
658fb6bd596SCristiano Giuffrida /* If this is a RS instance, pin memory. */
659fb6bd596SCristiano Giuffrida if(rp->r_priv.s_flags & ROOT_SYS_PROC) {
660fb6bd596SCristiano Giuffrida if(rs_verbose)
661fb6bd596SCristiano Giuffrida printf("RS: pinning memory of RS instance %s\n", srv_to_string(rp));
662fb6bd596SCristiano Giuffrida
663fb6bd596SCristiano Giuffrida s = vm_memctl(rpub->endpoint, VM_RS_MEM_PIN, 0, 0);
664fb6bd596SCristiano Giuffrida if(s != OK) {
665fb6bd596SCristiano Giuffrida printf("vm_memctl failed: %d\n", s);
666fb6bd596SCristiano Giuffrida cleanup_service(rp);
667fb6bd596SCristiano Giuffrida return s;
668fb6bd596SCristiano Giuffrida }
669fb6bd596SCristiano Giuffrida }
670fb6bd596SCristiano Giuffrida
671433d6423SLionel Sambuc /* If this is a VM instance, let VM know now. */
672433d6423SLionel Sambuc if(rp->r_priv.s_flags & VM_SYS_PROC) {
673fb6bd596SCristiano Giuffrida struct rproc *rs_rp;
674fb6bd596SCristiano Giuffrida struct rproc **rs_rps;
675fb6bd596SCristiano Giuffrida int i, nr_rs_rps;
676fb6bd596SCristiano Giuffrida
677433d6423SLionel Sambuc if(rs_verbose)
678433d6423SLionel Sambuc printf("RS: informing VM of instance %s\n", srv_to_string(rp));
679433d6423SLionel Sambuc
68048f446ecSCristiano Giuffrida s = vm_memctl(rpub->endpoint, VM_RS_MEM_MAKE_VM, 0, 0);
681433d6423SLionel Sambuc if(s != OK) {
682433d6423SLionel Sambuc printf("vm_memctl failed: %d\n", s);
683433d6423SLionel Sambuc cleanup_service(rp);
684433d6423SLionel Sambuc return s;
685433d6423SLionel Sambuc }
686fb6bd596SCristiano Giuffrida
687fb6bd596SCristiano Giuffrida /* VM may start actually pinning memory for us only now.
688fb6bd596SCristiano Giuffrida * Ask again for all our instances.
689fb6bd596SCristiano Giuffrida */
690fb6bd596SCristiano Giuffrida rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
691fb6bd596SCristiano Giuffrida get_service_instances(rs_rp, &rs_rps, &nr_rs_rps);
692fb6bd596SCristiano Giuffrida for(i=0;i<nr_rs_rps;i++) {
693fb6bd596SCristiano Giuffrida vm_memctl(rs_rps[i]->r_pub->endpoint, VM_RS_MEM_PIN, 0, 0);
694fb6bd596SCristiano Giuffrida }
695433d6423SLionel Sambuc }
696433d6423SLionel Sambuc
697433d6423SLionel Sambuc /* Tell VM about allowed calls. */
698433d6423SLionel Sambuc if ((s = vm_set_priv(rpub->endpoint, &rpub->vm_call_mask[0], TRUE)) != OK) {
699433d6423SLionel Sambuc printf("RS: vm_set_priv failed: %d\n", s);
700433d6423SLionel Sambuc cleanup_service(rp);
701433d6423SLionel Sambuc return s;
702433d6423SLionel Sambuc }
703433d6423SLionel Sambuc
704433d6423SLionel Sambuc if(rs_verbose)
705433d6423SLionel Sambuc printf("RS: %s created\n", srv_to_string(rp));
706433d6423SLionel Sambuc
707433d6423SLionel Sambuc return OK;
708433d6423SLionel Sambuc }
709433d6423SLionel Sambuc
710433d6423SLionel Sambuc /*===========================================================================*
711433d6423SLionel Sambuc * clone_service *
712433d6423SLionel Sambuc *===========================================================================*/
clone_service(struct rproc * rp,int instance_flag,int init_flags)713fb6bd596SCristiano Giuffrida int clone_service(struct rproc *rp, int instance_flag, int init_flags)
714433d6423SLionel Sambuc {
715433d6423SLionel Sambuc /* Clone the given system service instance. */
716433d6423SLionel Sambuc struct rproc *replica_rp;
717433d6423SLionel Sambuc struct rprocpub *replica_rpub;
718433d6423SLionel Sambuc struct rproc **rp_link;
719433d6423SLionel Sambuc struct rproc **replica_link;
720433d6423SLionel Sambuc struct rproc *rs_rp;
721433d6423SLionel Sambuc int rs_flags;
722433d6423SLionel Sambuc int r;
723433d6423SLionel Sambuc
724433d6423SLionel Sambuc if(rs_verbose)
725fb6bd596SCristiano Giuffrida printf("RS: %s creating a replica\n", srv_to_string(rp));
726fb6bd596SCristiano Giuffrida
727fb6bd596SCristiano Giuffrida /* VM can only reliably support one replica at the time for now.
728fb6bd596SCristiano Giuffrida * XXX TO-DO: Fix VM's rs_memctl_make_vm_instance to allow multiple replicas.
729fb6bd596SCristiano Giuffrida */
730fb6bd596SCristiano Giuffrida if(rp->r_pub->endpoint == VM_PROC_NR && instance_flag == LU_SYS_PROC
731fb6bd596SCristiano Giuffrida && rp->r_next_rp) {
732fb6bd596SCristiano Giuffrida cleanup_service_now(rp->r_next_rp);
733fb6bd596SCristiano Giuffrida rp->r_next_rp = NULL;
734fb6bd596SCristiano Giuffrida }
735433d6423SLionel Sambuc
736433d6423SLionel Sambuc /* Clone slot. */
737433d6423SLionel Sambuc if((r = clone_slot(rp, &replica_rp)) != OK) {
738433d6423SLionel Sambuc return r;
739433d6423SLionel Sambuc }
740433d6423SLionel Sambuc replica_rpub = replica_rp->r_pub;
741433d6423SLionel Sambuc
742433d6423SLionel Sambuc /* Clone is a live updated or restarted service instance? */
743433d6423SLionel Sambuc if(instance_flag == LU_SYS_PROC) {
744433d6423SLionel Sambuc rp_link = &rp->r_new_rp;
745433d6423SLionel Sambuc replica_link = &replica_rp->r_old_rp;
746433d6423SLionel Sambuc }
747433d6423SLionel Sambuc else {
748433d6423SLionel Sambuc rp_link = &rp->r_next_rp;
749433d6423SLionel Sambuc replica_link = &replica_rp->r_prev_rp;
750433d6423SLionel Sambuc }
751433d6423SLionel Sambuc replica_rp->r_priv.s_flags |= instance_flag;
752fb6bd596SCristiano Giuffrida replica_rp->r_priv.s_init_flags |= init_flags;
753433d6423SLionel Sambuc
754433d6423SLionel Sambuc /* Link the two slots. */
755433d6423SLionel Sambuc *rp_link = replica_rp;
756433d6423SLionel Sambuc *replica_link = rp;
757433d6423SLionel Sambuc
758433d6423SLionel Sambuc /* Create a new replica of the service. */
759433d6423SLionel Sambuc r = create_service(replica_rp);
760433d6423SLionel Sambuc if(r != OK) {
761433d6423SLionel Sambuc *rp_link = NULL;
762433d6423SLionel Sambuc return r;
763433d6423SLionel Sambuc }
764433d6423SLionel Sambuc
765433d6423SLionel Sambuc /* If this instance is for restarting RS, set up a backup signal manager. */
766433d6423SLionel Sambuc rs_flags = (ROOT_SYS_PROC | RST_SYS_PROC);
767433d6423SLionel Sambuc if((replica_rp->r_priv.s_flags & rs_flags) == rs_flags) {
768433d6423SLionel Sambuc rs_rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
769433d6423SLionel Sambuc
770433d6423SLionel Sambuc /* Update signal managers. */
771433d6423SLionel Sambuc r = update_sig_mgrs(rs_rp, SELF, replica_rpub->endpoint);
772433d6423SLionel Sambuc if(r == OK) {
773433d6423SLionel Sambuc r = update_sig_mgrs(replica_rp, SELF, NONE);
774433d6423SLionel Sambuc }
775433d6423SLionel Sambuc if(r != OK) {
776433d6423SLionel Sambuc *rp_link = NULL;
777433d6423SLionel Sambuc return kill_service(replica_rp, "update_sig_mgrs failed", r);
778433d6423SLionel Sambuc }
779433d6423SLionel Sambuc }
780433d6423SLionel Sambuc
781433d6423SLionel Sambuc return OK;
782433d6423SLionel Sambuc }
783433d6423SLionel Sambuc
784433d6423SLionel Sambuc /*===========================================================================*
785433d6423SLionel Sambuc * publish_service *
786433d6423SLionel Sambuc *===========================================================================*/
publish_service(rp)787433d6423SLionel Sambuc int publish_service(rp)
788433d6423SLionel Sambuc struct rproc *rp; /* pointer to service slot */
789433d6423SLionel Sambuc {
790433d6423SLionel Sambuc /* Publish a service. */
791433d6423SLionel Sambuc int r;
792433d6423SLionel Sambuc struct rprocpub *rpub;
793433d6423SLionel Sambuc struct rs_pci pci_acl;
794433d6423SLionel Sambuc message m;
795433d6423SLionel Sambuc endpoint_t ep;
796433d6423SLionel Sambuc
797433d6423SLionel Sambuc rpub = rp->r_pub;
798433d6423SLionel Sambuc
799433d6423SLionel Sambuc /* Register label with DS. */
800433d6423SLionel Sambuc r = ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
801433d6423SLionel Sambuc if (r != OK) {
802433d6423SLionel Sambuc return kill_service(rp, "ds_publish_label call failed", r);
803433d6423SLionel Sambuc }
804433d6423SLionel Sambuc
805433d6423SLionel Sambuc /* If the service is a driver, map it. */
806*181fb1b2SDavid van Moolenbroek if (rpub->dev_nr > 0 || rpub->nr_domain > 0) {
807433d6423SLionel Sambuc /* The purpose of non-blocking forks is to avoid involving VFS in the
808433d6423SLionel Sambuc * forking process, because VFS may be blocked on a ipc_sendrec() to a MFS
809433d6423SLionel Sambuc * that is waiting for a endpoint update for a dead driver. We have just
810433d6423SLionel Sambuc * published that update, but VFS may still be blocked. As a result, VFS
811433d6423SLionel Sambuc * may not yet have received PM's fork message. Hence, if we call
812433d6423SLionel Sambuc * mapdriver() immediately, VFS may not know about the process and thus
813433d6423SLionel Sambuc * refuse to add the driver entry. The following temporary hack works
814433d6423SLionel Sambuc * around this by forcing blocking communication from PM to VFS. Once VFS
815433d6423SLionel Sambuc * has been made non-blocking towards MFS instances, this hack and the
816433d6423SLionel Sambuc * big part of srv_fork() can go.
817433d6423SLionel Sambuc */
818433d6423SLionel Sambuc setuid(0);
819433d6423SLionel Sambuc
820*181fb1b2SDavid van Moolenbroek if ((r = mapdriver(rpub->label, rpub->dev_nr, rpub->domain,
821*181fb1b2SDavid van Moolenbroek rpub->nr_domain)) != OK) {
822433d6423SLionel Sambuc return kill_service(rp, "couldn't map driver", r);
823433d6423SLionel Sambuc }
824433d6423SLionel Sambuc }
825433d6423SLionel Sambuc
826433d6423SLionel Sambuc #if USE_PCI
827433d6423SLionel Sambuc /* If PCI properties are set, inform the PCI driver about the new service. */
828433d6423SLionel Sambuc if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
829433d6423SLionel Sambuc pci_acl = rpub->pci_acl;
830433d6423SLionel Sambuc strcpy(pci_acl.rsp_label, rpub->label);
831433d6423SLionel Sambuc pci_acl.rsp_endpoint= rpub->endpoint;
832433d6423SLionel Sambuc
833433d6423SLionel Sambuc r = pci_set_acl(&pci_acl);
834433d6423SLionel Sambuc if (r != OK) {
835433d6423SLionel Sambuc return kill_service(rp, "pci_set_acl call failed", r);
836433d6423SLionel Sambuc }
837433d6423SLionel Sambuc }
838433d6423SLionel Sambuc #endif /* USE_PCI */
839433d6423SLionel Sambuc
840433d6423SLionel Sambuc if (rpub->devman_id != 0) {
841433d6423SLionel Sambuc r = ds_retrieve_label_endpt("devman",&ep);
842433d6423SLionel Sambuc
843433d6423SLionel Sambuc if (r != OK) {
844433d6423SLionel Sambuc return kill_service(rp, "devman not running?", r);
845433d6423SLionel Sambuc }
846433d6423SLionel Sambuc m.m_type = DEVMAN_BIND;
847433d6423SLionel Sambuc m.DEVMAN_ENDPOINT = rpub->endpoint;
848433d6423SLionel Sambuc m.DEVMAN_DEVICE_ID = rpub->devman_id;
849433d6423SLionel Sambuc r = ipc_sendrec(ep, &m);
850433d6423SLionel Sambuc if (r != OK || m.DEVMAN_RESULT != OK) {
851433d6423SLionel Sambuc return kill_service(rp, "devman bind device failed", r);
852433d6423SLionel Sambuc }
853433d6423SLionel Sambuc }
854433d6423SLionel Sambuc
855433d6423SLionel Sambuc if(rs_verbose)
856433d6423SLionel Sambuc printf("RS: %s published\n", srv_to_string(rp));
857433d6423SLionel Sambuc
858433d6423SLionel Sambuc return OK;
859433d6423SLionel Sambuc }
860433d6423SLionel Sambuc
861433d6423SLionel Sambuc /*===========================================================================*
862433d6423SLionel Sambuc * unpublish_service *
863433d6423SLionel Sambuc *===========================================================================*/
unpublish_service(rp)864433d6423SLionel Sambuc int unpublish_service(rp)
865433d6423SLionel Sambuc struct rproc *rp; /* pointer to service slot */
866433d6423SLionel Sambuc {
867433d6423SLionel Sambuc /* Unpublish a service. */
868433d6423SLionel Sambuc struct rprocpub *rpub;
869433d6423SLionel Sambuc int r, result;
870433d6423SLionel Sambuc message m;
871433d6423SLionel Sambuc endpoint_t ep;
872433d6423SLionel Sambuc
873433d6423SLionel Sambuc
874433d6423SLionel Sambuc rpub = rp->r_pub;
875433d6423SLionel Sambuc result = OK;
876433d6423SLionel Sambuc
877433d6423SLionel Sambuc /* Unregister label with DS. */
878433d6423SLionel Sambuc r = ds_delete_label(rpub->label);
879433d6423SLionel Sambuc if (r != OK && !shutting_down) {
880433d6423SLionel Sambuc printf("RS: ds_delete_label call failed (error %d)\n", r);
881433d6423SLionel Sambuc result = r;
882433d6423SLionel Sambuc }
883433d6423SLionel Sambuc
884433d6423SLionel Sambuc /* No need to inform VFS and VM, cleanup is done on exit automatically. */
885433d6423SLionel Sambuc
886433d6423SLionel Sambuc #if USE_PCI
887433d6423SLionel Sambuc /* If PCI properties are set, inform the PCI driver. */
888433d6423SLionel Sambuc if(rpub->pci_acl.rsp_nr_device || rpub->pci_acl.rsp_nr_class) {
889433d6423SLionel Sambuc r = pci_del_acl(rpub->endpoint);
890433d6423SLionel Sambuc if (r != OK && !shutting_down) {
891433d6423SLionel Sambuc printf("RS: pci_del_acl call failed (error %d)\n", r);
892433d6423SLionel Sambuc result = r;
893433d6423SLionel Sambuc }
894433d6423SLionel Sambuc }
895433d6423SLionel Sambuc #endif /* USE_PCI */
896433d6423SLionel Sambuc
897433d6423SLionel Sambuc if (rpub->devman_id != 0) {
898433d6423SLionel Sambuc r = ds_retrieve_label_endpt("devman",&ep);
899433d6423SLionel Sambuc
900433d6423SLionel Sambuc if (r != OK) {
901433d6423SLionel Sambuc printf("RS: devman not running?");
902433d6423SLionel Sambuc } else {
903433d6423SLionel Sambuc m.m_type = DEVMAN_UNBIND;
904433d6423SLionel Sambuc m.DEVMAN_ENDPOINT = rpub->endpoint;
905433d6423SLionel Sambuc m.DEVMAN_DEVICE_ID = rpub->devman_id;
906433d6423SLionel Sambuc r = ipc_sendrec(ep, &m);
907433d6423SLionel Sambuc
908433d6423SLionel Sambuc if (r != OK || m.DEVMAN_RESULT != OK) {
909433d6423SLionel Sambuc printf("RS: devman unbind device failed");
910433d6423SLionel Sambuc }
911433d6423SLionel Sambuc }
912433d6423SLionel Sambuc }
913433d6423SLionel Sambuc
914433d6423SLionel Sambuc if(rs_verbose)
915433d6423SLionel Sambuc printf("RS: %s unpublished\n", srv_to_string(rp));
916433d6423SLionel Sambuc
917433d6423SLionel Sambuc return result;
918433d6423SLionel Sambuc }
919433d6423SLionel Sambuc
920433d6423SLionel Sambuc /*===========================================================================*
921433d6423SLionel Sambuc * run_service *
922433d6423SLionel Sambuc *===========================================================================*/
run_service(struct rproc * rp,int init_type,int init_flags)923fb6bd596SCristiano Giuffrida int run_service(struct rproc *rp, int init_type, int init_flags)
924433d6423SLionel Sambuc {
925433d6423SLionel Sambuc /* Let a newly created service run. */
926433d6423SLionel Sambuc struct rprocpub *rpub;
927433d6423SLionel Sambuc int s;
928433d6423SLionel Sambuc
929433d6423SLionel Sambuc rpub = rp->r_pub;
930433d6423SLionel Sambuc
931433d6423SLionel Sambuc /* Allow the service to run. */
932433d6423SLionel Sambuc if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
933433d6423SLionel Sambuc return kill_service(rp, "unable to allow the service to run",s);
934433d6423SLionel Sambuc }
935433d6423SLionel Sambuc
936433d6423SLionel Sambuc /* Initialize service. */
937fb6bd596SCristiano Giuffrida if((s = init_service(rp, init_type, init_flags)) != OK) {
938433d6423SLionel Sambuc return kill_service(rp, "unable to initialize service", s);
939433d6423SLionel Sambuc }
940433d6423SLionel Sambuc
941433d6423SLionel Sambuc if(rs_verbose)
942433d6423SLionel Sambuc printf("RS: %s allowed to run\n", srv_to_string(rp));
943433d6423SLionel Sambuc
944433d6423SLionel Sambuc return OK;
945433d6423SLionel Sambuc }
946433d6423SLionel Sambuc
947433d6423SLionel Sambuc /*===========================================================================*
948433d6423SLionel Sambuc * start_service *
949433d6423SLionel Sambuc *===========================================================================*/
start_service(struct rproc * rp,int init_flags)950fb6bd596SCristiano Giuffrida int start_service(struct rproc *rp, int init_flags)
951433d6423SLionel Sambuc {
952433d6423SLionel Sambuc /* Start a system service. */
953fb6bd596SCristiano Giuffrida int r;
954433d6423SLionel Sambuc struct rprocpub *rpub;
955433d6423SLionel Sambuc
956433d6423SLionel Sambuc rpub = rp->r_pub;
957433d6423SLionel Sambuc
958433d6423SLionel Sambuc /* Create and make active. */
959fb6bd596SCristiano Giuffrida rp->r_priv.s_init_flags |= init_flags;
960433d6423SLionel Sambuc r = create_service(rp);
961433d6423SLionel Sambuc if(r != OK) {
962433d6423SLionel Sambuc return r;
963433d6423SLionel Sambuc }
964433d6423SLionel Sambuc activate_service(rp, NULL);
965433d6423SLionel Sambuc
966433d6423SLionel Sambuc /* Publish service properties. */
967433d6423SLionel Sambuc r = publish_service(rp);
968433d6423SLionel Sambuc if (r != OK) {
969433d6423SLionel Sambuc return r;
970433d6423SLionel Sambuc }
971433d6423SLionel Sambuc
972433d6423SLionel Sambuc /* Run. */
973fb6bd596SCristiano Giuffrida r = run_service(rp, SEF_INIT_FRESH, init_flags);
974433d6423SLionel Sambuc if(r != OK) {
975433d6423SLionel Sambuc return r;
976433d6423SLionel Sambuc }
977433d6423SLionel Sambuc
978433d6423SLionel Sambuc if(rs_verbose)
979433d6423SLionel Sambuc printf("RS: %s started with major %d\n", srv_to_string(rp),
980433d6423SLionel Sambuc rpub->dev_nr);
981433d6423SLionel Sambuc
982433d6423SLionel Sambuc return OK;
983433d6423SLionel Sambuc }
984433d6423SLionel Sambuc
985433d6423SLionel Sambuc /*===========================================================================*
986433d6423SLionel Sambuc * stop_service *
987433d6423SLionel Sambuc *===========================================================================*/
stop_service(struct rproc * rp,int how)988433d6423SLionel Sambuc void stop_service(struct rproc *rp,int how)
989433d6423SLionel Sambuc {
990433d6423SLionel Sambuc struct rprocpub *rpub;
991433d6423SLionel Sambuc int signo;
992433d6423SLionel Sambuc
993433d6423SLionel Sambuc rpub = rp->r_pub;
994433d6423SLionel Sambuc
995433d6423SLionel Sambuc /* Try to stop the system service. First send a SIGTERM signal to ask the
996433d6423SLionel Sambuc * system service to terminate. If the service didn't install a signal
997433d6423SLionel Sambuc * handler, it will be killed. If it did and ignores the signal, we'll
998433d6423SLionel Sambuc * find out because we record the time here and send a SIGKILL.
999433d6423SLionel Sambuc */
1000433d6423SLionel Sambuc if(rs_verbose)
1001433d6423SLionel Sambuc printf("RS: %s signaled with SIGTERM\n", srv_to_string(rp));
1002433d6423SLionel Sambuc
1003433d6423SLionel Sambuc signo = rpub->endpoint != RS_PROC_NR ? SIGTERM : SIGHUP; /* SIGHUP for RS. */
1004433d6423SLionel Sambuc
1005433d6423SLionel Sambuc rp->r_flags |= how; /* what to on exit? */
1006433d6423SLionel Sambuc sys_kill(rpub->endpoint, signo); /* first try friendly */
1007d91f738bSDavid van Moolenbroek rp->r_stop_tm = getticks(); /* record current time */
1008433d6423SLionel Sambuc }
1009433d6423SLionel Sambuc
1010433d6423SLionel Sambuc /*===========================================================================*
1011433d6423SLionel Sambuc * activate_service *
1012433d6423SLionel Sambuc *===========================================================================*/
activate_service(struct rproc * rp,struct rproc * ex_rp)1013433d6423SLionel Sambuc void activate_service(struct rproc *rp, struct rproc *ex_rp)
1014433d6423SLionel Sambuc {
1015433d6423SLionel Sambuc /* Activate a service instance and deactivate another one if requested. */
1016433d6423SLionel Sambuc
1017433d6423SLionel Sambuc if(ex_rp && (ex_rp->r_flags & RS_ACTIVE) ) {
1018433d6423SLionel Sambuc ex_rp->r_flags &= ~RS_ACTIVE;
1019433d6423SLionel Sambuc if(rs_verbose)
1020433d6423SLionel Sambuc printf("RS: %s becomes inactive\n", srv_to_string(ex_rp));
1021433d6423SLionel Sambuc }
1022433d6423SLionel Sambuc
1023433d6423SLionel Sambuc if(! (rp->r_flags & RS_ACTIVE) ) {
1024433d6423SLionel Sambuc rp->r_flags |= RS_ACTIVE;
1025433d6423SLionel Sambuc if(rs_verbose)
1026433d6423SLionel Sambuc printf("RS: %s becomes active\n", srv_to_string(rp));
1027433d6423SLionel Sambuc }
1028433d6423SLionel Sambuc }
1029433d6423SLionel Sambuc
1030433d6423SLionel Sambuc /*===========================================================================*
1031433d6423SLionel Sambuc * reincarnate_service *
1032433d6423SLionel Sambuc *===========================================================================*/
reincarnate_service(struct rproc * old_rp)1033fb6bd596SCristiano Giuffrida void reincarnate_service(struct rproc *old_rp)
1034433d6423SLionel Sambuc {
1035433d6423SLionel Sambuc /* Restart a service as if it were never started before. */
1036fb6bd596SCristiano Giuffrida struct rproc *rp;
1037fb6bd596SCristiano Giuffrida int r, restarts;
1038433d6423SLionel Sambuc
1039fb6bd596SCristiano Giuffrida if ((r = clone_slot(old_rp, &rp)) != OK) {
1040fb6bd596SCristiano Giuffrida printf("RS: Failed to clone the slot: %d\n", r);
1041fb6bd596SCristiano Giuffrida return;
1042fb6bd596SCristiano Giuffrida }
1043433d6423SLionel Sambuc
1044fb6bd596SCristiano Giuffrida rp->r_flags = RS_IN_USE;
1045fb6bd596SCristiano Giuffrida rproc_ptr[_ENDPOINT_P(rp->r_pub->endpoint)] = NULL;
1046433d6423SLionel Sambuc
1047fb6bd596SCristiano Giuffrida restarts = rp->r_restarts;
1048fb6bd596SCristiano Giuffrida start_service(rp, SEF_INIT_FRESH);
1049fb6bd596SCristiano Giuffrida rp->r_restarts = restarts + 1;
1050433d6423SLionel Sambuc }
1051433d6423SLionel Sambuc
1052433d6423SLionel Sambuc /*===========================================================================*
1053433d6423SLionel Sambuc * terminate_service *
1054433d6423SLionel Sambuc *===========================================================================*/
terminate_service(struct rproc * rp)1055433d6423SLionel Sambuc void terminate_service(struct rproc *rp)
1056433d6423SLionel Sambuc {
1057433d6423SLionel Sambuc /* Handle a termination event for a system service. */
1058433d6423SLionel Sambuc struct rproc **rps;
1059433d6423SLionel Sambuc struct rprocpub *rpub;
1060fb6bd596SCristiano Giuffrida int nr_rps, norestart;
1061433d6423SLionel Sambuc int i, r;
1062433d6423SLionel Sambuc
1063433d6423SLionel Sambuc rpub = rp->r_pub;
1064433d6423SLionel Sambuc
1065433d6423SLionel Sambuc if(rs_verbose)
1066433d6423SLionel Sambuc printf("RS: %s terminated\n", srv_to_string(rp));
1067433d6423SLionel Sambuc
1068433d6423SLionel Sambuc /* Deal with failures during initialization. */
1069433d6423SLionel Sambuc if(rp->r_flags & RS_INITIALIZING) {
1070fb6bd596SCristiano Giuffrida /* If updating, rollback. */
1071fb6bd596SCristiano Giuffrida if(SRV_IS_UPDATING(rp)) {
1072fb6bd596SCristiano Giuffrida printf("RS: update failed: state transfer failed. Rolling back...\n");
1073fb6bd596SCristiano Giuffrida end_update(rp->r_init_err, RS_REPLY);
1074fb6bd596SCristiano Giuffrida rp->r_init_err = ERESTART;
1075fb6bd596SCristiano Giuffrida return;
1076fb6bd596SCristiano Giuffrida }
1077fb6bd596SCristiano Giuffrida
1078433d6423SLionel Sambuc if (rpub->sys_flags & SF_NO_BIN_EXP) {
1079433d6423SLionel Sambuc /* If service was deliberately started with binary exponential offset
1080433d6423SLionel Sambuc * disabled, we're going to assume we want to refresh a service upon
1081433d6423SLionel Sambuc * failure.
1082433d6423SLionel Sambuc */
1083433d6423SLionel Sambuc if(rs_verbose)
1084433d6423SLionel Sambuc printf("RS: service '%s' exited during initialization; "
1085433d6423SLionel Sambuc "refreshing\n", rpub->label);
1086433d6423SLionel Sambuc rp->r_flags |= RS_REFRESHING; /* restart initialization. */
1087433d6423SLionel Sambuc } else {
1088433d6423SLionel Sambuc if(rs_verbose)
1089433d6423SLionel Sambuc printf("RS: service '%s' exited during initialization; "
1090fb6bd596SCristiano Giuffrida "exiting\n", rpub->label);
1091433d6423SLionel Sambuc rp->r_flags |= RS_EXITING; /* don't restart. */
1092433d6423SLionel Sambuc }
1093fb6bd596SCristiano Giuffrida }
1094433d6423SLionel Sambuc
1095fb6bd596SCristiano Giuffrida /* If an update process is in progress, end it before doing anything else.
1096fb6bd596SCristiano Giuffrida * This is to be on the safe side, since there may be some weird dependencies
1097fb6bd596SCristiano Giuffrida * with services under update, while we perform recovery actions.
1098fb6bd596SCristiano Giuffrida */
1099fb6bd596SCristiano Giuffrida if(RUPDATE_IS_UPDATING()) {
1100fb6bd596SCristiano Giuffrida printf("RS: aborting the update after a crash...\n");
1101fb6bd596SCristiano Giuffrida abort_update_proc(ERESTART);
1102fb6bd596SCristiano Giuffrida }
1103fb6bd596SCristiano Giuffrida
1104fb6bd596SCristiano Giuffrida /* Force exit when no restart is requested. */
1105fb6bd596SCristiano Giuffrida norestart = !(rp->r_flags & RS_EXITING) && (rp->r_pub->sys_flags & SF_NORESTART);
1106fb6bd596SCristiano Giuffrida if(norestart) {
1107fb6bd596SCristiano Giuffrida rp->r_flags |= RS_EXITING;
1108fb6bd596SCristiano Giuffrida if((rp->r_pub->sys_flags & SF_DET_RESTART)
1109fb6bd596SCristiano Giuffrida && (rp->r_restarts < MAX_DET_RESTART)) {
1110fb6bd596SCristiano Giuffrida /* Detach at cleanup time. */
1111fb6bd596SCristiano Giuffrida rp->r_flags |= RS_CLEANUP_DETACH;
1112fb6bd596SCristiano Giuffrida }
1113fb6bd596SCristiano Giuffrida if(rp->r_script[0] != '\0') {
1114fb6bd596SCristiano Giuffrida /* Run script at cleanup time. */
1115fb6bd596SCristiano Giuffrida rp->r_flags |= RS_CLEANUP_SCRIPT;
1116433d6423SLionel Sambuc }
1117433d6423SLionel Sambuc }
1118433d6423SLionel Sambuc
1119433d6423SLionel Sambuc if (rp->r_flags & RS_EXITING) {
1120433d6423SLionel Sambuc /* If a core system service is exiting, we are in trouble. */
1121fb6bd596SCristiano Giuffrida if ((rp->r_pub->sys_flags & SF_CORE_SRV) && !shutting_down) {
1122433d6423SLionel Sambuc printf("core system service died: %s\n", srv_to_string(rp));
1123433d6423SLionel Sambuc _exit(1);
1124433d6423SLionel Sambuc }
1125433d6423SLionel Sambuc
1126fb6bd596SCristiano Giuffrida /* If this service was scheduled for the update, abort the update now. */
1127fb6bd596SCristiano Giuffrida if(SRV_IS_UPD_SCHEDULED(rp)) {
1128fb6bd596SCristiano Giuffrida printf("RS: aborting the scheduled update, one of the services part of it is exiting...\n");
1129fb6bd596SCristiano Giuffrida abort_update_proc(EDEADSRCDST);
1130fb6bd596SCristiano Giuffrida }
1131fb6bd596SCristiano Giuffrida
1132433d6423SLionel Sambuc /* See if a late reply has to be sent. */
1133fb6bd596SCristiano Giuffrida r = (rp->r_caller_request == RS_DOWN
1134fb6bd596SCristiano Giuffrida || (rp->r_caller_request == RS_REFRESH && norestart) ? OK : EDEADEPT);
1135433d6423SLionel Sambuc late_reply(rp, r);
1136433d6423SLionel Sambuc
1137433d6423SLionel Sambuc /* Unpublish the service. */
1138433d6423SLionel Sambuc unpublish_service(rp);
1139433d6423SLionel Sambuc
1140433d6423SLionel Sambuc /* Cleanup all the instances of the service. */
1141433d6423SLionel Sambuc get_service_instances(rp, &rps, &nr_rps);
1142433d6423SLionel Sambuc for(i=0;i<nr_rps;i++) {
1143433d6423SLionel Sambuc cleanup_service(rps[i]);
1144433d6423SLionel Sambuc }
1145433d6423SLionel Sambuc
1146433d6423SLionel Sambuc /* If the service is reincarnating, its slot has not been cleaned up.
1147433d6423SLionel Sambuc * Check for this flag now, and attempt to start the service again.
1148433d6423SLionel Sambuc * If this fails, start_service() itself will perform cleanup.
1149433d6423SLionel Sambuc */
1150433d6423SLionel Sambuc if (rp->r_flags & RS_REINCARNATE) {
1151fb6bd596SCristiano Giuffrida rp->r_flags &= ~RS_REINCARNATE;
1152433d6423SLionel Sambuc reincarnate_service(rp);
1153433d6423SLionel Sambuc }
1154433d6423SLionel Sambuc }
1155433d6423SLionel Sambuc else if(rp->r_flags & RS_REFRESHING) {
1156433d6423SLionel Sambuc /* Restart service. */
1157433d6423SLionel Sambuc restart_service(rp);
1158433d6423SLionel Sambuc }
1159433d6423SLionel Sambuc else {
1160433d6423SLionel Sambuc /* Determine what to do. If this is the first unexpected
1161433d6423SLionel Sambuc * exit, immediately restart this service. Otherwise use
1162433d6423SLionel Sambuc * a binary exponential backoff.
1163433d6423SLionel Sambuc */
1164433d6423SLionel Sambuc if (rp->r_restarts > 0) {
1165433d6423SLionel Sambuc if (!(rpub->sys_flags & SF_NO_BIN_EXP)) {
1166433d6423SLionel Sambuc rp->r_backoff = 1 << MIN(rp->r_restarts,(BACKOFF_BITS-2));
1167433d6423SLionel Sambuc rp->r_backoff = MIN(rp->r_backoff,MAX_BACKOFF);
1168433d6423SLionel Sambuc if ((rpub->sys_flags & SF_USE_COPY) && rp->r_backoff > 1)
1169433d6423SLionel Sambuc rp->r_backoff= 1;
1170433d6423SLionel Sambuc }
1171433d6423SLionel Sambuc else {
1172433d6423SLionel Sambuc rp->r_backoff = 1;
1173433d6423SLionel Sambuc }
1174433d6423SLionel Sambuc return;
1175433d6423SLionel Sambuc }
1176433d6423SLionel Sambuc
1177433d6423SLionel Sambuc /* Restart service. */
1178433d6423SLionel Sambuc restart_service(rp);
1179433d6423SLionel Sambuc }
1180433d6423SLionel Sambuc }
1181433d6423SLionel Sambuc
1182433d6423SLionel Sambuc /*===========================================================================*
1183433d6423SLionel Sambuc * run_script *
1184433d6423SLionel Sambuc *===========================================================================*/
run_script(struct rproc * rp)1185433d6423SLionel Sambuc static int run_script(struct rproc *rp)
1186433d6423SLionel Sambuc {
1187433d6423SLionel Sambuc int r, endpoint;
1188433d6423SLionel Sambuc pid_t pid;
1189433d6423SLionel Sambuc char *reason;
1190433d6423SLionel Sambuc char incarnation_str[20]; /* Enough for a counter? */
1191433d6423SLionel Sambuc char *envp[1] = { NULL };
1192433d6423SLionel Sambuc struct rprocpub *rpub;
1193433d6423SLionel Sambuc
1194433d6423SLionel Sambuc rpub = rp->r_pub;
1195433d6423SLionel Sambuc if (rp->r_flags & RS_REFRESHING)
1196433d6423SLionel Sambuc reason= "restart";
1197433d6423SLionel Sambuc else if (rp->r_flags & RS_NOPINGREPLY)
1198433d6423SLionel Sambuc reason= "no-heartbeat";
1199433d6423SLionel Sambuc else reason= "terminated";
12000a6a1f1dSLionel Sambuc snprintf(incarnation_str, sizeof(incarnation_str), "%d", rp->r_restarts);
1201433d6423SLionel Sambuc
1202433d6423SLionel Sambuc if(rs_verbose) {
1203433d6423SLionel Sambuc printf("RS: %s:\n", srv_to_string(rp));
1204433d6423SLionel Sambuc printf("RS: calling script '%s'\n", rp->r_script);
1205433d6423SLionel Sambuc printf("RS: reason: '%s'\n", reason);
1206433d6423SLionel Sambuc printf("RS: incarnation: '%s'\n", incarnation_str);
1207433d6423SLionel Sambuc }
1208433d6423SLionel Sambuc
1209433d6423SLionel Sambuc pid= fork();
1210433d6423SLionel Sambuc switch(pid)
1211433d6423SLionel Sambuc {
1212433d6423SLionel Sambuc case -1:
1213fb6bd596SCristiano Giuffrida return errno;
1214433d6423SLionel Sambuc case 0:
1215433d6423SLionel Sambuc execle(_PATH_BSHELL, "sh", rp->r_script, rpub->label, reason,
1216433d6423SLionel Sambuc incarnation_str, (char*) NULL, envp);
1217433d6423SLionel Sambuc printf("RS: run_script: execl '%s' failed: %s\n",
1218433d6423SLionel Sambuc rp->r_script, strerror(errno));
1219433d6423SLionel Sambuc exit(1);
1220433d6423SLionel Sambuc default:
1221433d6423SLionel Sambuc /* Set the privilege structure for the child process. */
1222433d6423SLionel Sambuc if ((r = getprocnr(pid, &endpoint)) != 0)
1223433d6423SLionel Sambuc panic("unable to get child endpoint: %d", r);
1224433d6423SLionel Sambuc if ((r = sys_privctl(endpoint, SYS_PRIV_SET_USER, NULL))
1225433d6423SLionel Sambuc != OK) {
1226433d6423SLionel Sambuc return kill_service(rp,"can't set script privileges",r);
1227433d6423SLionel Sambuc }
1228433d6423SLionel Sambuc /* Set the script's privileges on other servers. */
1229433d6423SLionel Sambuc vm_set_priv(endpoint, NULL, FALSE);
1230433d6423SLionel Sambuc if ((r = vm_set_priv(endpoint, NULL, FALSE)) != OK) {
1231433d6423SLionel Sambuc return kill_service(rp,"can't set script VM privs",r);
1232433d6423SLionel Sambuc }
1233433d6423SLionel Sambuc /* Allow the script to run. */
1234433d6423SLionel Sambuc if ((r = sys_privctl(endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
1235433d6423SLionel Sambuc return kill_service(rp,"can't let the script run",r);
1236433d6423SLionel Sambuc }
1237433d6423SLionel Sambuc /* Pin RS memory again after fork()ing. */
123848f446ecSCristiano Giuffrida vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN, 0, 0);
1239433d6423SLionel Sambuc }
1240433d6423SLionel Sambuc return OK;
1241433d6423SLionel Sambuc }
1242433d6423SLionel Sambuc
1243433d6423SLionel Sambuc /*===========================================================================*
1244433d6423SLionel Sambuc * restart_service *
1245433d6423SLionel Sambuc *===========================================================================*/
restart_service(struct rproc * rp)1246433d6423SLionel Sambuc void restart_service(struct rproc *rp)
1247433d6423SLionel Sambuc {
1248433d6423SLionel Sambuc /* Restart service via a recovery script or directly. */
1249433d6423SLionel Sambuc struct rproc *replica_rp;
1250433d6423SLionel Sambuc int r;
1251433d6423SLionel Sambuc
1252433d6423SLionel Sambuc /* See if a late reply has to be sent. */
1253433d6423SLionel Sambuc late_reply(rp, OK);
1254433d6423SLionel Sambuc
1255433d6423SLionel Sambuc /* Run a recovery script if available. */
1256433d6423SLionel Sambuc if (rp->r_script[0] != '\0') {
1257fb6bd596SCristiano Giuffrida r = run_script(rp);
1258fb6bd596SCristiano Giuffrida if(r != OK) {
1259fb6bd596SCristiano Giuffrida kill_service(rp, "unable to run script", errno);
1260fb6bd596SCristiano Giuffrida }
1261433d6423SLionel Sambuc return;
1262433d6423SLionel Sambuc }
1263433d6423SLionel Sambuc
1264433d6423SLionel Sambuc /* Restart directly. We need a replica if not already available. */
1265433d6423SLionel Sambuc if(rp->r_next_rp == NULL) {
1266433d6423SLionel Sambuc /* Create the replica. */
1267fb6bd596SCristiano Giuffrida r = clone_service(rp, RST_SYS_PROC, 0);
1268433d6423SLionel Sambuc if(r != OK) {
1269433d6423SLionel Sambuc kill_service(rp, "unable to clone service", r);
1270433d6423SLionel Sambuc return;
1271433d6423SLionel Sambuc }
1272433d6423SLionel Sambuc }
1273433d6423SLionel Sambuc replica_rp = rp->r_next_rp;
1274433d6423SLionel Sambuc
1275433d6423SLionel Sambuc /* Update the service into the replica. */
1276fb6bd596SCristiano Giuffrida r = update_service(&rp, &replica_rp, RS_SWAP, 0);
1277433d6423SLionel Sambuc if(r != OK) {
1278433d6423SLionel Sambuc kill_service(rp, "unable to update into new replica", r);
1279433d6423SLionel Sambuc return;
1280433d6423SLionel Sambuc }
1281433d6423SLionel Sambuc
1282433d6423SLionel Sambuc /* Let the new replica run. */
1283fb6bd596SCristiano Giuffrida r = run_service(replica_rp, SEF_INIT_RESTART, 0);
1284433d6423SLionel Sambuc if(r != OK) {
1285433d6423SLionel Sambuc kill_service(rp, "unable to let the replica run", r);
1286433d6423SLionel Sambuc return;
1287433d6423SLionel Sambuc }
1288433d6423SLionel Sambuc
1289fb6bd596SCristiano Giuffrida /* See if the old version needs to be detached. */
1290fb6bd596SCristiano Giuffrida if((rp->r_pub->sys_flags & SF_DET_RESTART)
1291fb6bd596SCristiano Giuffrida && (rp->r_restarts < MAX_DET_RESTART)) {
1292fb6bd596SCristiano Giuffrida rp->r_flags |= RS_CLEANUP_DETACH;
1293fb6bd596SCristiano Giuffrida }
1294fb6bd596SCristiano Giuffrida
1295433d6423SLionel Sambuc if(rs_verbose)
1296433d6423SLionel Sambuc printf("RS: %s restarted into %s\n",
1297433d6423SLionel Sambuc srv_to_string(rp), srv_to_string(replica_rp));
1298433d6423SLionel Sambuc }
1299433d6423SLionel Sambuc
1300433d6423SLionel Sambuc /*===========================================================================*
1301433d6423SLionel Sambuc * inherit_service_defaults *
1302433d6423SLionel Sambuc *===========================================================================*/
inherit_service_defaults(def_rp,rp)1303433d6423SLionel Sambuc void inherit_service_defaults(def_rp, rp)
1304433d6423SLionel Sambuc struct rproc *def_rp;
1305433d6423SLionel Sambuc struct rproc *rp;
1306433d6423SLionel Sambuc {
1307433d6423SLionel Sambuc struct rprocpub *def_rpub;
1308433d6423SLionel Sambuc struct rprocpub *rpub;
1309*181fb1b2SDavid van Moolenbroek int i;
1310433d6423SLionel Sambuc
1311433d6423SLionel Sambuc def_rpub = def_rp->r_pub;
1312433d6423SLionel Sambuc rpub = rp->r_pub;
1313433d6423SLionel Sambuc
1314*181fb1b2SDavid van Moolenbroek /* Device, domain, and PCI settings. These properties cannot change. */
1315433d6423SLionel Sambuc rpub->dev_nr = def_rpub->dev_nr;
1316*181fb1b2SDavid van Moolenbroek rpub->nr_domain = def_rpub->nr_domain;
1317*181fb1b2SDavid van Moolenbroek for (i = 0; i < def_rpub->nr_domain; i++)
1318*181fb1b2SDavid van Moolenbroek rpub->domain[i] = def_rpub->domain[i];
1319433d6423SLionel Sambuc rpub->pci_acl = def_rpub->pci_acl;
1320433d6423SLionel Sambuc
1321433d6423SLionel Sambuc /* Immutable system and privilege flags. */
1322433d6423SLionel Sambuc rpub->sys_flags &= ~IMM_SF;
1323433d6423SLionel Sambuc rpub->sys_flags |= (def_rpub->sys_flags & IMM_SF);
1324433d6423SLionel Sambuc rp->r_priv.s_flags &= ~IMM_F;
1325433d6423SLionel Sambuc rp->r_priv.s_flags |= (def_rp->r_priv.s_flags & IMM_F);
1326433d6423SLionel Sambuc
1327433d6423SLionel Sambuc /* Allowed traps. They cannot change. */
1328433d6423SLionel Sambuc rp->r_priv.s_trap_mask = def_rp->r_priv.s_trap_mask;
1329433d6423SLionel Sambuc }
1330433d6423SLionel Sambuc
1331433d6423SLionel Sambuc /*===========================================================================*
1332433d6423SLionel Sambuc * get_service_instances *
1333433d6423SLionel Sambuc *===========================================================================*/
get_service_instances(rp,rps,length)1334433d6423SLionel Sambuc void get_service_instances(rp, rps, length)
1335433d6423SLionel Sambuc struct rproc *rp;
1336433d6423SLionel Sambuc struct rproc ***rps;
1337433d6423SLionel Sambuc int *length;
1338433d6423SLionel Sambuc {
1339433d6423SLionel Sambuc /* Retrieve all the service instances of a given service. */
1340433d6423SLionel Sambuc static struct rproc *instances[5];
1341433d6423SLionel Sambuc int nr_instances;
1342433d6423SLionel Sambuc
1343433d6423SLionel Sambuc nr_instances = 0;
1344433d6423SLionel Sambuc instances[nr_instances++] = rp;
1345433d6423SLionel Sambuc if(rp->r_prev_rp) instances[nr_instances++] = rp->r_prev_rp;
1346433d6423SLionel Sambuc if(rp->r_next_rp) instances[nr_instances++] = rp->r_next_rp;
1347433d6423SLionel Sambuc if(rp->r_old_rp) instances[nr_instances++] = rp->r_old_rp;
1348433d6423SLionel Sambuc if(rp->r_new_rp) instances[nr_instances++] = rp->r_new_rp;
1349433d6423SLionel Sambuc
1350433d6423SLionel Sambuc *rps = instances;
1351433d6423SLionel Sambuc *length = nr_instances;
1352433d6423SLionel Sambuc }
1353433d6423SLionel Sambuc
1354433d6423SLionel Sambuc /*===========================================================================*
1355433d6423SLionel Sambuc * share_exec *
1356433d6423SLionel Sambuc *===========================================================================*/
share_exec(rp_dst,rp_src)1357433d6423SLionel Sambuc void share_exec(rp_dst, rp_src)
1358433d6423SLionel Sambuc struct rproc *rp_dst, *rp_src;
1359433d6423SLionel Sambuc {
1360433d6423SLionel Sambuc if(rs_verbose)
1361433d6423SLionel Sambuc printf("RS: %s shares exec image with %s\n",
1362433d6423SLionel Sambuc srv_to_string(rp_dst), srv_to_string(rp_src));
1363433d6423SLionel Sambuc
1364433d6423SLionel Sambuc /* Share exec image from rp_src to rp_dst. */
1365433d6423SLionel Sambuc rp_dst->r_exec_len = rp_src->r_exec_len;
1366433d6423SLionel Sambuc rp_dst->r_exec = rp_src->r_exec;
1367433d6423SLionel Sambuc }
1368433d6423SLionel Sambuc
1369433d6423SLionel Sambuc /*===========================================================================*
1370433d6423SLionel Sambuc * read_exec *
1371433d6423SLionel Sambuc *===========================================================================*/
read_exec(rp)1372433d6423SLionel Sambuc int read_exec(rp)
1373433d6423SLionel Sambuc struct rproc *rp;
1374433d6423SLionel Sambuc {
1375433d6423SLionel Sambuc int e, r, fd;
1376433d6423SLionel Sambuc char *e_name;
1377433d6423SLionel Sambuc struct stat sb;
1378433d6423SLionel Sambuc
1379433d6423SLionel Sambuc e_name= rp->r_argv[0];
1380433d6423SLionel Sambuc if(rs_verbose)
1381433d6423SLionel Sambuc printf("RS: service '%s' reads exec image from: %s\n", rp->r_pub->label,
1382433d6423SLionel Sambuc e_name);
1383433d6423SLionel Sambuc
1384433d6423SLionel Sambuc r= stat(e_name, &sb);
1385433d6423SLionel Sambuc if (r != 0)
1386433d6423SLionel Sambuc return -errno;
1387433d6423SLionel Sambuc
138837f29f55SLionel Sambuc if (sb.st_size < sizeof(Elf_Ehdr))
138937f29f55SLionel Sambuc return ENOEXEC;
139037f29f55SLionel Sambuc
1391433d6423SLionel Sambuc fd= open(e_name, O_RDONLY);
1392433d6423SLionel Sambuc if (fd == -1)
1393433d6423SLionel Sambuc return -errno;
1394433d6423SLionel Sambuc
1395433d6423SLionel Sambuc rp->r_exec_len= sb.st_size;
1396433d6423SLionel Sambuc rp->r_exec= malloc(rp->r_exec_len);
1397433d6423SLionel Sambuc if (rp->r_exec == NULL)
1398433d6423SLionel Sambuc {
13993c8950ccSBen Gras printf("RS: read_exec: unable to allocate %zu bytes\n",
1400433d6423SLionel Sambuc rp->r_exec_len);
1401433d6423SLionel Sambuc close(fd);
1402433d6423SLionel Sambuc return ENOMEM;
1403433d6423SLionel Sambuc }
1404433d6423SLionel Sambuc
1405433d6423SLionel Sambuc r= read(fd, rp->r_exec, rp->r_exec_len);
1406433d6423SLionel Sambuc e= errno;
1407433d6423SLionel Sambuc close(fd);
1408433d6423SLionel Sambuc if (r == rp->r_exec_len)
1409433d6423SLionel Sambuc return OK;
1410433d6423SLionel Sambuc
1411433d6423SLionel Sambuc printf("RS: read_exec: read failed %d, errno %d\n", r, e);
1412433d6423SLionel Sambuc
1413433d6423SLionel Sambuc free_exec(rp);
1414433d6423SLionel Sambuc
1415433d6423SLionel Sambuc if (r >= 0)
1416433d6423SLionel Sambuc return EIO;
1417433d6423SLionel Sambuc else
1418433d6423SLionel Sambuc return -e;
1419433d6423SLionel Sambuc }
1420433d6423SLionel Sambuc
1421433d6423SLionel Sambuc /*===========================================================================*
1422433d6423SLionel Sambuc * free_exec *
1423433d6423SLionel Sambuc *===========================================================================*/
free_exec(rp)1424433d6423SLionel Sambuc void free_exec(rp)
1425433d6423SLionel Sambuc struct rproc *rp;
1426433d6423SLionel Sambuc {
1427433d6423SLionel Sambuc /* Free an exec image. */
1428433d6423SLionel Sambuc int slot_nr, has_shared_exec;
1429433d6423SLionel Sambuc struct rproc *other_rp;
1430433d6423SLionel Sambuc
1431433d6423SLionel Sambuc /* Search for some other slot sharing the same exec image. */
1432433d6423SLionel Sambuc has_shared_exec = FALSE;
1433433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1434433d6423SLionel Sambuc other_rp = &rproc[slot_nr]; /* get pointer to slot */
1435433d6423SLionel Sambuc if (other_rp->r_flags & RS_IN_USE && other_rp != rp
1436433d6423SLionel Sambuc && other_rp->r_exec == rp->r_exec) { /* found! */
1437433d6423SLionel Sambuc has_shared_exec = TRUE;
1438433d6423SLionel Sambuc break;
1439433d6423SLionel Sambuc }
1440433d6423SLionel Sambuc }
1441433d6423SLionel Sambuc
1442433d6423SLionel Sambuc /* If nobody uses our copy of the exec image, we can try to get rid of it. */
1443433d6423SLionel Sambuc if(!has_shared_exec) {
1444433d6423SLionel Sambuc if(rs_verbose)
1445433d6423SLionel Sambuc printf("RS: %s frees exec image\n", srv_to_string(rp));
1446433d6423SLionel Sambuc free(rp->r_exec);
1447433d6423SLionel Sambuc }
1448433d6423SLionel Sambuc else {
1449433d6423SLionel Sambuc if(rs_verbose)
1450433d6423SLionel Sambuc printf("RS: %s no longer sharing exec image with %s\n",
1451433d6423SLionel Sambuc srv_to_string(rp), srv_to_string(other_rp));
1452433d6423SLionel Sambuc }
1453433d6423SLionel Sambuc rp->r_exec = NULL;
1454433d6423SLionel Sambuc rp->r_exec_len = 0;
1455433d6423SLionel Sambuc }
1456433d6423SLionel Sambuc
1457433d6423SLionel Sambuc /*===========================================================================*
1458433d6423SLionel Sambuc * edit_slot *
1459433d6423SLionel Sambuc *===========================================================================*/
edit_slot(rp,rs_start,source)1460433d6423SLionel Sambuc int edit_slot(rp, rs_start, source)
1461433d6423SLionel Sambuc struct rproc *rp;
1462433d6423SLionel Sambuc struct rs_start *rs_start;
1463433d6423SLionel Sambuc endpoint_t source;
1464433d6423SLionel Sambuc {
1465433d6423SLionel Sambuc /* Edit a given slot to override existing settings. */
1466433d6423SLionel Sambuc struct rprocpub *rpub;
1467433d6423SLionel Sambuc char *label;
1468433d6423SLionel Sambuc int len;
1469433d6423SLionel Sambuc int s, i;
1470433d6423SLionel Sambuc int basic_kc[] = { SYS_BASIC_CALLS, NULL_C };
1471433d6423SLionel Sambuc int basic_vmc[] = { VM_BASIC_CALLS, NULL_C };
1472433d6423SLionel Sambuc
1473433d6423SLionel Sambuc rpub = rp->r_pub;
1474433d6423SLionel Sambuc
1475433d6423SLionel Sambuc /* Update IPC target list. */
1476433d6423SLionel Sambuc if (rs_start->rss_ipclen==0 || rs_start->rss_ipclen+1>sizeof(rp->r_ipc_list)){
1477433d6423SLionel Sambuc printf("RS: edit_slot: ipc list empty or long for '%s'\n", rpub->label);
1478433d6423SLionel Sambuc return EINVAL;
1479433d6423SLionel Sambuc }
1480433d6423SLionel Sambuc s=sys_datacopy(source, (vir_bytes) rs_start->rss_ipc,
1481433d6423SLionel Sambuc SELF, (vir_bytes) rp->r_ipc_list, rs_start->rss_ipclen);
1482433d6423SLionel Sambuc if (s != OK) return(s);
1483433d6423SLionel Sambuc rp->r_ipc_list[rs_start->rss_ipclen]= '\0';
1484433d6423SLionel Sambuc
1485433d6423SLionel Sambuc /* Update IRQs. */
1486433d6423SLionel Sambuc if(rs_start->rss_nr_irq == RSS_IRQ_ALL) {
1487433d6423SLionel Sambuc rs_start->rss_nr_irq = 0;
1488433d6423SLionel Sambuc }
1489433d6423SLionel Sambuc else {
1490433d6423SLionel Sambuc rp->r_priv.s_flags |= CHECK_IRQ;
1491433d6423SLionel Sambuc }
1492433d6423SLionel Sambuc if (rs_start->rss_nr_irq > NR_IRQ) {
1493433d6423SLionel Sambuc printf("RS: edit_slot: too many IRQs requested\n");
1494433d6423SLionel Sambuc return EINVAL;
1495433d6423SLionel Sambuc }
1496433d6423SLionel Sambuc rp->r_nr_irq= rp->r_priv.s_nr_irq= rs_start->rss_nr_irq;
1497433d6423SLionel Sambuc for (i= 0; i<rp->r_priv.s_nr_irq; i++) {
1498433d6423SLionel Sambuc rp->r_irq_tab[i]= rp->r_priv.s_irq_tab[i]= rs_start->rss_irq[i];
1499433d6423SLionel Sambuc if(rs_verbose)
1500433d6423SLionel Sambuc printf("RS: edit_slot: IRQ %d\n", rp->r_priv.s_irq_tab[i]);
1501433d6423SLionel Sambuc }
1502433d6423SLionel Sambuc
1503433d6423SLionel Sambuc /* Update I/O ranges. */
1504433d6423SLionel Sambuc if(rs_start->rss_nr_io == RSS_IO_ALL) {
1505433d6423SLionel Sambuc rs_start->rss_nr_io = 0;
1506433d6423SLionel Sambuc }
1507433d6423SLionel Sambuc else {
1508433d6423SLionel Sambuc rp->r_priv.s_flags |= CHECK_IO_PORT;
1509433d6423SLionel Sambuc }
1510433d6423SLionel Sambuc if (rs_start->rss_nr_io > NR_IO_RANGE) {
1511433d6423SLionel Sambuc printf("RS: edit_slot: too many I/O ranges requested\n");
1512433d6423SLionel Sambuc return EINVAL;
1513433d6423SLionel Sambuc }
1514433d6423SLionel Sambuc rp->r_nr_io_range= rp->r_priv.s_nr_io_range= rs_start->rss_nr_io;
1515433d6423SLionel Sambuc for (i= 0; i<rp->r_priv.s_nr_io_range; i++) {
1516433d6423SLionel Sambuc rp->r_priv.s_io_tab[i].ior_base= rs_start->rss_io[i].base;
1517433d6423SLionel Sambuc rp->r_priv.s_io_tab[i].ior_limit=
1518433d6423SLionel Sambuc rs_start->rss_io[i].base+rs_start->rss_io[i].len-1;
1519433d6423SLionel Sambuc rp->r_io_tab[i] = rp->r_priv.s_io_tab[i];
1520433d6423SLionel Sambuc if(rs_verbose)
1521433d6423SLionel Sambuc printf("RS: edit_slot: I/O [%x..%x]\n",
1522433d6423SLionel Sambuc rp->r_priv.s_io_tab[i].ior_base,
1523433d6423SLionel Sambuc rp->r_priv.s_io_tab[i].ior_limit);
1524433d6423SLionel Sambuc }
1525433d6423SLionel Sambuc
1526433d6423SLionel Sambuc /* Update kernel call mask. Inherit basic kernel calls when asked to. */
1527433d6423SLionel Sambuc memcpy(rp->r_priv.s_k_call_mask, rs_start->rss_system,
1528433d6423SLionel Sambuc sizeof(rp->r_priv.s_k_call_mask));
1529433d6423SLionel Sambuc if(rs_start->rss_flags & RSS_SYS_BASIC_CALLS) {
1530433d6423SLionel Sambuc fill_call_mask(basic_kc, NR_SYS_CALLS,
1531433d6423SLionel Sambuc rp->r_priv.s_k_call_mask, KERNEL_CALL, FALSE);
1532433d6423SLionel Sambuc }
1533433d6423SLionel Sambuc
1534433d6423SLionel Sambuc /* Update VM call mask. Inherit basic VM calls. */
1535433d6423SLionel Sambuc memcpy(rpub->vm_call_mask, rs_start->rss_vm,
1536433d6423SLionel Sambuc sizeof(rpub->vm_call_mask));
1537433d6423SLionel Sambuc if(rs_start->rss_flags & RSS_VM_BASIC_CALLS) {
1538433d6423SLionel Sambuc fill_call_mask(basic_vmc, NR_VM_CALLS,
1539433d6423SLionel Sambuc rpub->vm_call_mask, VM_RQ_BASE, FALSE);
1540433d6423SLionel Sambuc }
1541433d6423SLionel Sambuc
1542433d6423SLionel Sambuc /* Update control labels. */
1543433d6423SLionel Sambuc if(rs_start->rss_nr_control > 0) {
1544433d6423SLionel Sambuc int i, s;
1545433d6423SLionel Sambuc if (rs_start->rss_nr_control > RS_NR_CONTROL) {
1546433d6423SLionel Sambuc printf("RS: edit_slot: too many control labels\n");
1547433d6423SLionel Sambuc return EINVAL;
1548433d6423SLionel Sambuc }
1549433d6423SLionel Sambuc for (i=0; i<rs_start->rss_nr_control; i++) {
1550433d6423SLionel Sambuc s = copy_label(source, rs_start->rss_control[i].l_addr,
1551433d6423SLionel Sambuc rs_start->rss_control[i].l_len, rp->r_control[i],
1552433d6423SLionel Sambuc sizeof(rp->r_control[i]));
1553433d6423SLionel Sambuc if(s != OK)
1554433d6423SLionel Sambuc return s;
1555433d6423SLionel Sambuc }
1556433d6423SLionel Sambuc rp->r_nr_control = rs_start->rss_nr_control;
1557433d6423SLionel Sambuc
1558433d6423SLionel Sambuc if (rs_verbose) {
1559433d6423SLionel Sambuc printf("RS: edit_slot: control labels:");
1560433d6423SLionel Sambuc for (i=0; i<rp->r_nr_control; i++)
1561433d6423SLionel Sambuc printf(" %s", rp->r_control[i]);
1562433d6423SLionel Sambuc printf("\n");
1563433d6423SLionel Sambuc }
1564433d6423SLionel Sambuc }
1565433d6423SLionel Sambuc
1566433d6423SLionel Sambuc /* Update signal manager. */
1567433d6423SLionel Sambuc rp->r_priv.s_sig_mgr = rs_start->rss_sigmgr;
1568433d6423SLionel Sambuc
1569433d6423SLionel Sambuc /* Update scheduling properties if possible. */
1570433d6423SLionel Sambuc if(rp->r_scheduler != NONE) {
1571433d6423SLionel Sambuc rp->r_scheduler = rs_start->rss_scheduler;
1572433d6423SLionel Sambuc rp->r_priority = rs_start->rss_priority;
1573433d6423SLionel Sambuc rp->r_quantum = rs_start->rss_quantum;
1574433d6423SLionel Sambuc rp->r_cpu = rs_start->rss_cpu;
1575433d6423SLionel Sambuc }
1576433d6423SLionel Sambuc
1577433d6423SLionel Sambuc /* Update command and arguments. */
1578433d6423SLionel Sambuc if (rs_start->rss_cmdlen > MAX_COMMAND_LEN-1) return(E2BIG);
1579433d6423SLionel Sambuc s=sys_datacopy(source, (vir_bytes) rs_start->rss_cmd,
1580433d6423SLionel Sambuc SELF, (vir_bytes) rp->r_cmd, rs_start->rss_cmdlen);
1581433d6423SLionel Sambuc if (s != OK) return(s);
1582433d6423SLionel Sambuc rp->r_cmd[rs_start->rss_cmdlen] = '\0'; /* ensure it is terminated */
1583433d6423SLionel Sambuc if (rp->r_cmd[0] != '/') return(EINVAL); /* insist on absolute path */
1584433d6423SLionel Sambuc
158523199f62SDavid van Moolenbroek /* Build cmd dependencies (argv). */
1586433d6423SLionel Sambuc build_cmd_dep(rp);
1587433d6423SLionel Sambuc
158823199f62SDavid van Moolenbroek /* Copy in the program name. */
158923199f62SDavid van Moolenbroek if (rs_start->rss_prognamelen > sizeof(rpub->proc_name)-1) return(E2BIG);
159023199f62SDavid van Moolenbroek s=sys_datacopy(source, (vir_bytes) rs_start->rss_progname,
159123199f62SDavid van Moolenbroek SELF, (vir_bytes) rpub->proc_name, rs_start->rss_prognamelen);
159223199f62SDavid van Moolenbroek if (s != OK) return(s);
159323199f62SDavid van Moolenbroek rpub->proc_name[rs_start->rss_prognamelen] = '\0';
159423199f62SDavid van Moolenbroek
1595433d6423SLionel Sambuc /* Update label if not already set. */
1596433d6423SLionel Sambuc if(!strcmp(rpub->label, "")) {
1597433d6423SLionel Sambuc if(rs_start->rss_label.l_len > 0) {
1598433d6423SLionel Sambuc /* RS_UP caller has supplied a custom label for this service. */
1599433d6423SLionel Sambuc int s = copy_label(source, rs_start->rss_label.l_addr,
1600433d6423SLionel Sambuc rs_start->rss_label.l_len, rpub->label, sizeof(rpub->label));
1601433d6423SLionel Sambuc if(s != OK)
1602433d6423SLionel Sambuc return s;
1603433d6423SLionel Sambuc if(rs_verbose)
1604433d6423SLionel Sambuc printf("RS: edit_slot: using label (custom) '%s'\n", rpub->label);
1605433d6423SLionel Sambuc } else {
1606433d6423SLionel Sambuc /* Default label for the service. */
1607433d6423SLionel Sambuc label = rpub->proc_name;
1608433d6423SLionel Sambuc len= strlen(label);
1609433d6423SLionel Sambuc memcpy(rpub->label, label, len);
1610433d6423SLionel Sambuc rpub->label[len]= '\0';
1611433d6423SLionel Sambuc if(rs_verbose)
1612433d6423SLionel Sambuc printf("RS: edit_slot: using label (from proc_name) '%s'\n",
1613433d6423SLionel Sambuc rpub->label);
1614433d6423SLionel Sambuc }
1615433d6423SLionel Sambuc }
1616433d6423SLionel Sambuc
1617433d6423SLionel Sambuc /* Update recovery script. */
1618433d6423SLionel Sambuc if (rs_start->rss_scriptlen > MAX_SCRIPT_LEN-1) return(E2BIG);
1619fb6bd596SCristiano Giuffrida if (rs_start->rss_script != NULL && rs_start->rss_scriptlen > 0
1620fb6bd596SCristiano Giuffrida && !(rpub->sys_flags & SF_CORE_SRV)) {
1621433d6423SLionel Sambuc s=sys_datacopy(source, (vir_bytes) rs_start->rss_script,
1622433d6423SLionel Sambuc SELF, (vir_bytes) rp->r_script, rs_start->rss_scriptlen);
1623433d6423SLionel Sambuc if (s != OK) return(s);
1624433d6423SLionel Sambuc rp->r_script[rs_start->rss_scriptlen] = '\0';
1625fb6bd596SCristiano Giuffrida rpub->sys_flags |= SF_USE_SCRIPT;
1626433d6423SLionel Sambuc }
1627433d6423SLionel Sambuc
1628433d6423SLionel Sambuc /* Update system flags and in-memory copy. */
1629433d6423SLionel Sambuc if ((rs_start->rss_flags & RSS_COPY) && !(rpub->sys_flags & SF_USE_COPY)) {
1630433d6423SLionel Sambuc int exst_cpy;
1631433d6423SLionel Sambuc struct rproc *rp2;
1632433d6423SLionel Sambuc struct rprocpub *rpub2;
1633433d6423SLionel Sambuc exst_cpy = 0;
1634433d6423SLionel Sambuc
1635433d6423SLionel Sambuc if(rs_start->rss_flags & RSS_REUSE) {
1636433d6423SLionel Sambuc int i;
1637433d6423SLionel Sambuc
1638433d6423SLionel Sambuc for(i = 0; i < NR_SYS_PROCS; i++) {
1639433d6423SLionel Sambuc rp2 = &rproc[i];
1640433d6423SLionel Sambuc rpub2 = rproc[i].r_pub;
1641433d6423SLionel Sambuc if(strcmp(rpub->proc_name, rpub2->proc_name) == 0 &&
1642433d6423SLionel Sambuc (rpub2->sys_flags & SF_USE_COPY)) {
1643433d6423SLionel Sambuc /* We have found the same binary that's
1644433d6423SLionel Sambuc * already been copied */
1645433d6423SLionel Sambuc exst_cpy = 1;
1646433d6423SLionel Sambuc break;
1647433d6423SLionel Sambuc }
1648433d6423SLionel Sambuc }
1649433d6423SLionel Sambuc }
1650433d6423SLionel Sambuc
1651433d6423SLionel Sambuc s = OK;
1652433d6423SLionel Sambuc if(!exst_cpy)
1653433d6423SLionel Sambuc s = read_exec(rp);
1654433d6423SLionel Sambuc else
1655433d6423SLionel Sambuc share_exec(rp, rp2);
1656433d6423SLionel Sambuc
1657433d6423SLionel Sambuc if (s != OK)
1658433d6423SLionel Sambuc return s;
1659433d6423SLionel Sambuc
1660433d6423SLionel Sambuc rpub->sys_flags |= SF_USE_COPY;
1661433d6423SLionel Sambuc }
1662433d6423SLionel Sambuc if (rs_start->rss_flags & RSS_REPLICA) {
1663433d6423SLionel Sambuc rpub->sys_flags |= SF_USE_REPL;
1664433d6423SLionel Sambuc }
1665433d6423SLionel Sambuc if (rs_start->rss_flags & RSS_NO_BIN_EXP) {
1666433d6423SLionel Sambuc rpub->sys_flags |= SF_NO_BIN_EXP;
1667433d6423SLionel Sambuc }
1668fb6bd596SCristiano Giuffrida if (rs_start->rss_flags & RSS_DETACH) {
1669fb6bd596SCristiano Giuffrida rpub->sys_flags |= SF_DET_RESTART;
1670fb6bd596SCristiano Giuffrida }
1671fb6bd596SCristiano Giuffrida else {
1672fb6bd596SCristiano Giuffrida rpub->sys_flags &= ~SF_DET_RESTART;
1673fb6bd596SCristiano Giuffrida }
1674fb6bd596SCristiano Giuffrida if (rs_start->rss_flags & RSS_NORESTART) {
1675fb6bd596SCristiano Giuffrida if(rpub->sys_flags & SF_CORE_SRV) {
1676fb6bd596SCristiano Giuffrida return EPERM;
1677fb6bd596SCristiano Giuffrida }
1678fb6bd596SCristiano Giuffrida rpub->sys_flags |= SF_NORESTART;
1679fb6bd596SCristiano Giuffrida }
1680fb6bd596SCristiano Giuffrida else {
1681fb6bd596SCristiano Giuffrida rpub->sys_flags &= ~SF_NORESTART;
1682fb6bd596SCristiano Giuffrida }
1683433d6423SLionel Sambuc
1684433d6423SLionel Sambuc /* Update period. */
1685433d6423SLionel Sambuc if(rpub->endpoint != RS_PROC_NR) {
1686433d6423SLionel Sambuc rp->r_period = rs_start->rss_period;
1687433d6423SLionel Sambuc }
1688433d6423SLionel Sambuc
1689fb6bd596SCristiano Giuffrida /* Update restarts. */
1690fb6bd596SCristiano Giuffrida if(rs_start->rss_restarts) {
1691fb6bd596SCristiano Giuffrida rp->r_restarts = rs_start->rss_restarts;
1692fb6bd596SCristiano Giuffrida }
1693fb6bd596SCristiano Giuffrida
1694e4d99eb9SDavid van Moolenbroek /* Update number of ASR live updates. */
1695e4d99eb9SDavid van Moolenbroek if(rs_start->rss_asr_count >= 0) {
1696e4d99eb9SDavid van Moolenbroek rp->r_asr_count = rs_start->rss_asr_count;
1697e4d99eb9SDavid van Moolenbroek }
1698e4d99eb9SDavid van Moolenbroek
1699433d6423SLionel Sambuc /* (Re)initialize privilege settings. */
1700433d6423SLionel Sambuc init_privs(rp, &rp->r_priv);
1701433d6423SLionel Sambuc
1702433d6423SLionel Sambuc return OK;
1703433d6423SLionel Sambuc }
1704433d6423SLionel Sambuc
1705433d6423SLionel Sambuc /*===========================================================================*
1706433d6423SLionel Sambuc * init_slot *
1707433d6423SLionel Sambuc *===========================================================================*/
init_slot(rp,rs_start,source)1708433d6423SLionel Sambuc int init_slot(rp, rs_start, source)
1709433d6423SLionel Sambuc struct rproc *rp;
1710433d6423SLionel Sambuc struct rs_start *rs_start;
1711433d6423SLionel Sambuc endpoint_t source;
1712433d6423SLionel Sambuc {
1713433d6423SLionel Sambuc /* Initialize a slot as requested by the client. */
1714433d6423SLionel Sambuc struct rprocpub *rpub;
1715433d6423SLionel Sambuc int i;
1716433d6423SLionel Sambuc
1717433d6423SLionel Sambuc rpub = rp->r_pub;
1718433d6423SLionel Sambuc
1719433d6423SLionel Sambuc /* All dynamically created services get the same sys and privilege flags, and
1720433d6423SLionel Sambuc * allowed traps. Other privilege settings can be specified at runtime. The
1721433d6423SLionel Sambuc * privilege id is dynamically allocated by the kernel.
1722433d6423SLionel Sambuc */
1723433d6423SLionel Sambuc rpub->sys_flags = DSRV_SF; /* system flags */
1724433d6423SLionel Sambuc rp->r_priv.s_flags = DSRV_F; /* privilege flags */
1725fb6bd596SCristiano Giuffrida rp->r_priv.s_init_flags = DSRV_I; /* init flags */
1726433d6423SLionel Sambuc rp->r_priv.s_trap_mask = DSRV_T; /* allowed traps */
1727433d6423SLionel Sambuc rp->r_priv.s_bak_sig_mgr = NONE; /* backup signal manager */
1728433d6423SLionel Sambuc
1729433d6423SLionel Sambuc /* Initialize uid. */
1730433d6423SLionel Sambuc rp->r_uid= rs_start->rss_uid;
1731433d6423SLionel Sambuc
1732433d6423SLionel Sambuc /* Initialize device driver settings. */
1733*181fb1b2SDavid van Moolenbroek if (rs_start->rss_nr_domain < 0 || rs_start->rss_nr_domain > NR_DOMAIN) {
1734*181fb1b2SDavid van Moolenbroek printf("RS: init_slot: too many domains\n");
1735*181fb1b2SDavid van Moolenbroek return EINVAL;
1736*181fb1b2SDavid van Moolenbroek }
1737*181fb1b2SDavid van Moolenbroek
1738433d6423SLionel Sambuc rpub->dev_nr = rs_start->rss_major;
1739*181fb1b2SDavid van Moolenbroek rpub->nr_domain = rs_start->rss_nr_domain;
1740*181fb1b2SDavid van Moolenbroek for (i = 0; i < rs_start->rss_nr_domain; i++)
1741*181fb1b2SDavid van Moolenbroek rpub->domain[i] = rs_start->rss_domain[i];
1742433d6423SLionel Sambuc rpub->devman_id = rs_start->devman_id;
1743433d6423SLionel Sambuc
1744433d6423SLionel Sambuc /* Initialize pci settings. */
1745433d6423SLionel Sambuc if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE) {
1746433d6423SLionel Sambuc printf("RS: init_slot: too many PCI device IDs\n");
1747433d6423SLionel Sambuc return EINVAL;
1748433d6423SLionel Sambuc }
1749433d6423SLionel Sambuc rpub->pci_acl.rsp_nr_device = rs_start->rss_nr_pci_id;
1750433d6423SLionel Sambuc for (i= 0; i<rpub->pci_acl.rsp_nr_device; i++) {
1751433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].vid= rs_start->rss_pci_id[i].vid;
1752433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].did= rs_start->rss_pci_id[i].did;
1753433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].sub_vid= rs_start->rss_pci_id[i].sub_vid;
1754433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].sub_did= rs_start->rss_pci_id[i].sub_did;
1755433d6423SLionel Sambuc if(rs_verbose)
1756433d6423SLionel Sambuc printf("RS: init_slot: PCI %04x/%04x (sub %04x:%04x)\n",
1757433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].vid,
1758433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].did,
1759433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].sub_vid,
1760433d6423SLionel Sambuc rpub->pci_acl.rsp_device[i].sub_did);
1761433d6423SLionel Sambuc }
1762433d6423SLionel Sambuc if (rs_start->rss_nr_pci_class > RS_NR_PCI_CLASS) {
1763433d6423SLionel Sambuc printf("RS: init_slot: too many PCI class IDs\n");
1764433d6423SLionel Sambuc return EINVAL;
1765433d6423SLionel Sambuc }
1766433d6423SLionel Sambuc rpub->pci_acl.rsp_nr_class= rs_start->rss_nr_pci_class;
1767433d6423SLionel Sambuc for (i= 0; i<rpub->pci_acl.rsp_nr_class; i++) {
1768433d6423SLionel Sambuc rpub->pci_acl.rsp_class[i].pciclass=rs_start->rss_pci_class[i].pciclass;
1769433d6423SLionel Sambuc rpub->pci_acl.rsp_class[i].mask= rs_start->rss_pci_class[i].mask;
1770433d6423SLionel Sambuc if(rs_verbose)
1771433d6423SLionel Sambuc printf("RS: init_slot: PCI class %06x mask %06x\n",
1772433d6423SLionel Sambuc (unsigned int) rpub->pci_acl.rsp_class[i].pciclass,
1773433d6423SLionel Sambuc (unsigned int) rpub->pci_acl.rsp_class[i].mask);
1774433d6423SLionel Sambuc }
1775433d6423SLionel Sambuc
1776433d6423SLionel Sambuc /* Initialize some fields. */
1777e4d99eb9SDavid van Moolenbroek rp->r_asr_count = 0; /* no ASR updates yet */
1778433d6423SLionel Sambuc rp->r_restarts = 0; /* no restarts yet */
1779433d6423SLionel Sambuc rp->r_old_rp = NULL; /* no old version yet */
1780433d6423SLionel Sambuc rp->r_new_rp = NULL; /* no new version yet */
1781433d6423SLionel Sambuc rp->r_prev_rp = NULL; /* no prev replica yet */
1782433d6423SLionel Sambuc rp->r_next_rp = NULL; /* no next replica yet */
1783433d6423SLionel Sambuc rp->r_exec = NULL; /* no in-memory copy yet */
1784433d6423SLionel Sambuc rp->r_exec_len = 0;
1785433d6423SLionel Sambuc rp->r_script[0]= '\0'; /* no recovery script yet */
1786433d6423SLionel Sambuc rpub->label[0]= '\0'; /* no label yet */
1787433d6423SLionel Sambuc rp->r_scheduler = -1; /* no scheduler yet */
1788433d6423SLionel Sambuc rp->r_priv.s_sig_mgr = -1; /* no signal manager yet */
1789fb6bd596SCristiano Giuffrida rp->r_map_prealloc_addr = 0; /* no preallocated memory */
1790fb6bd596SCristiano Giuffrida rp->r_map_prealloc_len = 0;
1791fb6bd596SCristiano Giuffrida rp->r_init_err = ERESTART; /* default init error `*/
1792433d6423SLionel Sambuc
1793433d6423SLionel Sambuc /* Initialize editable slot settings. */
1794433d6423SLionel Sambuc return edit_slot(rp, rs_start, source);
1795433d6423SLionel Sambuc }
1796433d6423SLionel Sambuc
1797433d6423SLionel Sambuc /*===========================================================================*
1798433d6423SLionel Sambuc * clone_slot *
1799433d6423SLionel Sambuc *===========================================================================*/
clone_slot(rp,clone_rpp)1800433d6423SLionel Sambuc int clone_slot(rp, clone_rpp)
1801433d6423SLionel Sambuc struct rproc *rp;
1802433d6423SLionel Sambuc struct rproc **clone_rpp;
1803433d6423SLionel Sambuc {
1804433d6423SLionel Sambuc int r;
1805433d6423SLionel Sambuc struct rproc *clone_rp;
1806433d6423SLionel Sambuc struct rprocpub *rpub, *clone_rpub;
1807433d6423SLionel Sambuc
1808433d6423SLionel Sambuc /* Allocate a system service slot for the clone. */
1809433d6423SLionel Sambuc r = alloc_slot(&clone_rp);
1810433d6423SLionel Sambuc if(r != OK) {
1811433d6423SLionel Sambuc printf("RS: clone_slot: unable to allocate a new slot: %d\n", r);
1812433d6423SLionel Sambuc return r;
1813433d6423SLionel Sambuc }
1814433d6423SLionel Sambuc
1815433d6423SLionel Sambuc rpub = rp->r_pub;
1816433d6423SLionel Sambuc clone_rpub = clone_rp->r_pub;
1817433d6423SLionel Sambuc
1818433d6423SLionel Sambuc /* Synch the privilege structure of the source with the kernel. */
1819433d6423SLionel Sambuc if ((r = sys_getpriv(&(rp->r_priv), rpub->endpoint)) != OK) {
1820433d6423SLionel Sambuc panic("unable to synch privilege structure: %d", r);
1821433d6423SLionel Sambuc }
1822433d6423SLionel Sambuc
1823433d6423SLionel Sambuc /* Shallow copy. */
1824433d6423SLionel Sambuc *clone_rp = *rp;
1825433d6423SLionel Sambuc *clone_rpub = *rpub;
1826433d6423SLionel Sambuc
1827433d6423SLionel Sambuc /* Deep copy. */
1828fb6bd596SCristiano Giuffrida clone_rp->r_init_err = ERESTART; /* default init error */
1829433d6423SLionel Sambuc clone_rp->r_flags &= ~RS_ACTIVE; /* the clone is not active yet */
1830433d6423SLionel Sambuc clone_rp->r_pid = -1; /* no pid yet */
1831433d6423SLionel Sambuc clone_rpub->endpoint = -1; /* no endpoint yet */
1832433d6423SLionel Sambuc clone_rp->r_pub = clone_rpub; /* restore pointer to public entry */
1833433d6423SLionel Sambuc build_cmd_dep(clone_rp); /* rebuild cmd dependencies */
1834433d6423SLionel Sambuc if(clone_rpub->sys_flags & SF_USE_COPY) {
1835433d6423SLionel Sambuc share_exec(clone_rp, rp); /* share exec image */
1836433d6423SLionel Sambuc }
1837433d6423SLionel Sambuc clone_rp->r_old_rp = NULL; /* no old version yet */
1838433d6423SLionel Sambuc clone_rp->r_new_rp = NULL; /* no new version yet */
1839433d6423SLionel Sambuc clone_rp->r_prev_rp = NULL; /* no prev replica yet */
1840433d6423SLionel Sambuc clone_rp->r_next_rp = NULL; /* no next replica yet */
1841433d6423SLionel Sambuc
1842433d6423SLionel Sambuc /* Force dynamic privilege id. */
1843433d6423SLionel Sambuc clone_rp->r_priv.s_flags |= DYN_PRIV_ID;
1844433d6423SLionel Sambuc
1845433d6423SLionel Sambuc /* Clear instance flags. */
1846433d6423SLionel Sambuc clone_rp->r_priv.s_flags &= ~(LU_SYS_PROC | RST_SYS_PROC);
1847fb6bd596SCristiano Giuffrida clone_rp->r_priv.s_init_flags = 0;
1848433d6423SLionel Sambuc
1849433d6423SLionel Sambuc *clone_rpp = clone_rp;
1850433d6423SLionel Sambuc return OK;
1851433d6423SLionel Sambuc }
1852433d6423SLionel Sambuc
1853433d6423SLionel Sambuc /*===========================================================================*
1854433d6423SLionel Sambuc * swap_slot_pointer *
1855433d6423SLionel Sambuc *===========================================================================*/
swap_slot_pointer(struct rproc ** rpp,struct rproc * src_rp,struct rproc * dst_rp)1856433d6423SLionel Sambuc static void swap_slot_pointer(struct rproc **rpp, struct rproc *src_rp,
1857433d6423SLionel Sambuc struct rproc *dst_rp)
1858433d6423SLionel Sambuc {
1859433d6423SLionel Sambuc if(*rpp == src_rp) {
1860433d6423SLionel Sambuc *rpp = dst_rp;
1861433d6423SLionel Sambuc }
1862433d6423SLionel Sambuc else if(*rpp == dst_rp) {
1863433d6423SLionel Sambuc *rpp = src_rp;
1864433d6423SLionel Sambuc }
1865433d6423SLionel Sambuc }
1866433d6423SLionel Sambuc
1867433d6423SLionel Sambuc /*===========================================================================*
1868433d6423SLionel Sambuc * swap_slot *
1869433d6423SLionel Sambuc *===========================================================================*/
swap_slot(src_rpp,dst_rpp)1870433d6423SLionel Sambuc void swap_slot(src_rpp, dst_rpp)
1871433d6423SLionel Sambuc struct rproc **src_rpp;
1872433d6423SLionel Sambuc struct rproc **dst_rpp;
1873433d6423SLionel Sambuc {
1874433d6423SLionel Sambuc /* Swap two service slots. */
1875fb6bd596SCristiano Giuffrida struct rproc *src_rp, *dst_rp;
1876fb6bd596SCristiano Giuffrida struct rprocpub *src_rpub, *dst_rpub;
1877433d6423SLionel Sambuc struct rproc orig_src_rproc, orig_dst_rproc;
1878433d6423SLionel Sambuc struct rprocpub orig_src_rprocpub, orig_dst_rprocpub;
1879fb6bd596SCristiano Giuffrida struct rprocupd *prev_rpupd, *rpupd;
1880433d6423SLionel Sambuc
1881433d6423SLionel Sambuc src_rp = *src_rpp;
1882433d6423SLionel Sambuc dst_rp = *dst_rpp;
1883433d6423SLionel Sambuc src_rpub = src_rp->r_pub;
1884433d6423SLionel Sambuc dst_rpub = dst_rp->r_pub;
1885433d6423SLionel Sambuc
1886433d6423SLionel Sambuc /* Save existing data first. */
1887433d6423SLionel Sambuc orig_src_rproc = *src_rp;
1888433d6423SLionel Sambuc orig_src_rprocpub = *src_rpub;
1889433d6423SLionel Sambuc orig_dst_rproc = *dst_rp;
1890433d6423SLionel Sambuc orig_dst_rprocpub = *dst_rpub;
1891433d6423SLionel Sambuc
1892433d6423SLionel Sambuc /* Swap slots. */
1893433d6423SLionel Sambuc *src_rp = orig_dst_rproc;
1894433d6423SLionel Sambuc *src_rpub = orig_dst_rprocpub;
1895433d6423SLionel Sambuc *dst_rp = orig_src_rproc;
1896433d6423SLionel Sambuc *dst_rpub = orig_src_rprocpub;
1897433d6423SLionel Sambuc
1898fb6bd596SCristiano Giuffrida /* Restore public entries and update descriptors. */
1899433d6423SLionel Sambuc src_rp->r_pub = orig_src_rproc.r_pub;
1900433d6423SLionel Sambuc dst_rp->r_pub = orig_dst_rproc.r_pub;
1901fb6bd596SCristiano Giuffrida src_rp->r_upd = orig_src_rproc.r_upd;
1902fb6bd596SCristiano Giuffrida dst_rp->r_upd = orig_dst_rproc.r_upd;
1903433d6423SLionel Sambuc
1904433d6423SLionel Sambuc /* Rebuild command dependencies. */
1905433d6423SLionel Sambuc build_cmd_dep(src_rp);
1906433d6423SLionel Sambuc build_cmd_dep(dst_rp);
1907433d6423SLionel Sambuc
1908433d6423SLionel Sambuc /* Swap local slot pointers. */
1909433d6423SLionel Sambuc swap_slot_pointer(&src_rp->r_prev_rp, src_rp, dst_rp);
1910433d6423SLionel Sambuc swap_slot_pointer(&src_rp->r_next_rp, src_rp, dst_rp);
1911433d6423SLionel Sambuc swap_slot_pointer(&src_rp->r_old_rp, src_rp, dst_rp);
1912433d6423SLionel Sambuc swap_slot_pointer(&src_rp->r_new_rp, src_rp, dst_rp);
1913433d6423SLionel Sambuc swap_slot_pointer(&dst_rp->r_prev_rp, src_rp, dst_rp);
1914433d6423SLionel Sambuc swap_slot_pointer(&dst_rp->r_next_rp, src_rp, dst_rp);
1915433d6423SLionel Sambuc swap_slot_pointer(&dst_rp->r_old_rp, src_rp, dst_rp);
1916433d6423SLionel Sambuc swap_slot_pointer(&dst_rp->r_new_rp, src_rp, dst_rp);
1917433d6423SLionel Sambuc
1918433d6423SLionel Sambuc /* Swap global slot pointers. */
1919fb6bd596SCristiano Giuffrida RUPDATE_ITER(rupdate.first_rpupd, prev_rpupd, rpupd,
1920fb6bd596SCristiano Giuffrida swap_slot_pointer(&rpupd->rp, src_rp, dst_rp);
1921fb6bd596SCristiano Giuffrida );
1922433d6423SLionel Sambuc swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(src_rp->r_pub->endpoint)],
1923433d6423SLionel Sambuc src_rp, dst_rp);
1924433d6423SLionel Sambuc swap_slot_pointer(&rproc_ptr[_ENDPOINT_P(dst_rp->r_pub->endpoint)],
1925433d6423SLionel Sambuc src_rp, dst_rp);
1926433d6423SLionel Sambuc
1927433d6423SLionel Sambuc /* Adjust input pointers. */
1928433d6423SLionel Sambuc *src_rpp = dst_rp;
1929433d6423SLionel Sambuc *dst_rpp = src_rp;
1930433d6423SLionel Sambuc }
1931433d6423SLionel Sambuc
1932433d6423SLionel Sambuc /*===========================================================================*
1933433d6423SLionel Sambuc * lookup_slot_by_label *
1934433d6423SLionel Sambuc *===========================================================================*/
lookup_slot_by_label(char * label)1935433d6423SLionel Sambuc struct rproc* lookup_slot_by_label(char *label)
1936433d6423SLionel Sambuc {
1937433d6423SLionel Sambuc /* Lookup a service slot matching the given label. */
1938433d6423SLionel Sambuc int slot_nr;
1939433d6423SLionel Sambuc struct rproc *rp;
1940433d6423SLionel Sambuc struct rprocpub *rpub;
1941433d6423SLionel Sambuc
1942433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1943433d6423SLionel Sambuc rp = &rproc[slot_nr];
1944433d6423SLionel Sambuc if (!(rp->r_flags & RS_ACTIVE)) {
1945433d6423SLionel Sambuc continue;
1946433d6423SLionel Sambuc }
1947433d6423SLionel Sambuc rpub = rp->r_pub;
1948433d6423SLionel Sambuc if (strcmp(rpub->label, label) == 0) {
1949433d6423SLionel Sambuc return rp;
1950433d6423SLionel Sambuc }
1951433d6423SLionel Sambuc }
1952433d6423SLionel Sambuc
1953433d6423SLionel Sambuc return NULL;
1954433d6423SLionel Sambuc }
1955433d6423SLionel Sambuc
1956433d6423SLionel Sambuc /*===========================================================================*
1957433d6423SLionel Sambuc * lookup_slot_by_pid *
1958433d6423SLionel Sambuc *===========================================================================*/
lookup_slot_by_pid(pid_t pid)1959433d6423SLionel Sambuc struct rproc* lookup_slot_by_pid(pid_t pid)
1960433d6423SLionel Sambuc {
1961433d6423SLionel Sambuc /* Lookup a service slot matching the given pid. */
1962433d6423SLionel Sambuc int slot_nr;
1963433d6423SLionel Sambuc struct rproc *rp;
1964433d6423SLionel Sambuc
1965433d6423SLionel Sambuc if(pid < 0) {
1966433d6423SLionel Sambuc return NULL;
1967433d6423SLionel Sambuc }
1968433d6423SLionel Sambuc
1969433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1970433d6423SLionel Sambuc rp = &rproc[slot_nr];
1971433d6423SLionel Sambuc if (!(rp->r_flags & RS_IN_USE)) {
1972433d6423SLionel Sambuc continue;
1973433d6423SLionel Sambuc }
1974433d6423SLionel Sambuc if (rp->r_pid == pid) {
1975433d6423SLionel Sambuc return rp;
1976433d6423SLionel Sambuc }
1977433d6423SLionel Sambuc }
1978433d6423SLionel Sambuc
1979433d6423SLionel Sambuc return NULL;
1980433d6423SLionel Sambuc }
1981433d6423SLionel Sambuc
1982433d6423SLionel Sambuc /*===========================================================================*
1983433d6423SLionel Sambuc * lookup_slot_by_dev_nr *
1984433d6423SLionel Sambuc *===========================================================================*/
lookup_slot_by_dev_nr(dev_t dev_nr)1985433d6423SLionel Sambuc struct rproc* lookup_slot_by_dev_nr(dev_t dev_nr)
1986433d6423SLionel Sambuc {
1987433d6423SLionel Sambuc /* Lookup a service slot matching the given device number. */
1988433d6423SLionel Sambuc int slot_nr;
1989433d6423SLionel Sambuc struct rproc *rp;
1990433d6423SLionel Sambuc struct rprocpub *rpub;
1991433d6423SLionel Sambuc
1992433d6423SLionel Sambuc if(dev_nr <= 0) {
1993433d6423SLionel Sambuc return NULL;
1994433d6423SLionel Sambuc }
1995433d6423SLionel Sambuc
1996433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
1997433d6423SLionel Sambuc rp = &rproc[slot_nr];
1998433d6423SLionel Sambuc rpub = rp->r_pub;
1999433d6423SLionel Sambuc if (!(rp->r_flags & RS_IN_USE)) {
2000433d6423SLionel Sambuc continue;
2001433d6423SLionel Sambuc }
2002433d6423SLionel Sambuc if (rpub->dev_nr == dev_nr) {
2003433d6423SLionel Sambuc return rp;
2004433d6423SLionel Sambuc }
2005433d6423SLionel Sambuc }
2006433d6423SLionel Sambuc
2007433d6423SLionel Sambuc return NULL;
2008433d6423SLionel Sambuc }
2009433d6423SLionel Sambuc
2010433d6423SLionel Sambuc /*===========================================================================*
2011*181fb1b2SDavid van Moolenbroek * lookup_slot_by_domain *
2012*181fb1b2SDavid van Moolenbroek *===========================================================================*/
lookup_slot_by_domain(int domain)2013*181fb1b2SDavid van Moolenbroek struct rproc* lookup_slot_by_domain(int domain)
2014*181fb1b2SDavid van Moolenbroek {
2015*181fb1b2SDavid van Moolenbroek /* Lookup a service slot matching the given protocol family. */
2016*181fb1b2SDavid van Moolenbroek int i, slot_nr;
2017*181fb1b2SDavid van Moolenbroek struct rproc *rp;
2018*181fb1b2SDavid van Moolenbroek struct rprocpub *rpub;
2019*181fb1b2SDavid van Moolenbroek
2020*181fb1b2SDavid van Moolenbroek if (domain <= 0) {
2021*181fb1b2SDavid van Moolenbroek return NULL;
2022*181fb1b2SDavid van Moolenbroek }
2023*181fb1b2SDavid van Moolenbroek
2024*181fb1b2SDavid van Moolenbroek for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
2025*181fb1b2SDavid van Moolenbroek rp = &rproc[slot_nr];
2026*181fb1b2SDavid van Moolenbroek rpub = rp->r_pub;
2027*181fb1b2SDavid van Moolenbroek if (!(rp->r_flags & RS_IN_USE)) {
2028*181fb1b2SDavid van Moolenbroek continue;
2029*181fb1b2SDavid van Moolenbroek }
2030*181fb1b2SDavid van Moolenbroek for (i = 0; i < rpub->nr_domain; i++)
2031*181fb1b2SDavid van Moolenbroek if (rpub->domain[i] == domain)
2032*181fb1b2SDavid van Moolenbroek return rp;
2033*181fb1b2SDavid van Moolenbroek }
2034*181fb1b2SDavid van Moolenbroek
2035*181fb1b2SDavid van Moolenbroek return NULL;
2036*181fb1b2SDavid van Moolenbroek }
2037*181fb1b2SDavid van Moolenbroek
2038*181fb1b2SDavid van Moolenbroek /*===========================================================================*
2039433d6423SLionel Sambuc * lookup_slot_by_flags *
2040433d6423SLionel Sambuc *===========================================================================*/
lookup_slot_by_flags(int flags)2041433d6423SLionel Sambuc struct rproc* lookup_slot_by_flags(int flags)
2042433d6423SLionel Sambuc {
2043433d6423SLionel Sambuc /* Lookup a service slot matching the given flags. */
2044433d6423SLionel Sambuc int slot_nr;
2045433d6423SLionel Sambuc struct rproc *rp;
2046433d6423SLionel Sambuc
2047433d6423SLionel Sambuc if(!flags) {
2048433d6423SLionel Sambuc return NULL;
2049433d6423SLionel Sambuc }
2050433d6423SLionel Sambuc
2051433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
2052433d6423SLionel Sambuc rp = &rproc[slot_nr];
2053433d6423SLionel Sambuc if (!(rp->r_flags & RS_IN_USE)) {
2054433d6423SLionel Sambuc continue;
2055433d6423SLionel Sambuc }
2056433d6423SLionel Sambuc if (rp->r_flags & flags) {
2057433d6423SLionel Sambuc return rp;
2058433d6423SLionel Sambuc }
2059433d6423SLionel Sambuc }
2060433d6423SLionel Sambuc
2061433d6423SLionel Sambuc return NULL;
2062433d6423SLionel Sambuc }
2063433d6423SLionel Sambuc
2064433d6423SLionel Sambuc /*===========================================================================*
2065433d6423SLionel Sambuc * alloc_slot *
2066433d6423SLionel Sambuc *===========================================================================*/
alloc_slot(rpp)2067433d6423SLionel Sambuc int alloc_slot(rpp)
2068433d6423SLionel Sambuc struct rproc **rpp;
2069433d6423SLionel Sambuc {
2070433d6423SLionel Sambuc /* Alloc a new system service slot. */
2071433d6423SLionel Sambuc int slot_nr;
2072433d6423SLionel Sambuc
2073433d6423SLionel Sambuc for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
2074433d6423SLionel Sambuc *rpp = &rproc[slot_nr]; /* get pointer to slot */
2075433d6423SLionel Sambuc if (!((*rpp)->r_flags & RS_IN_USE)) /* check if available */
2076433d6423SLionel Sambuc break;
2077433d6423SLionel Sambuc }
2078433d6423SLionel Sambuc if (slot_nr >= NR_SYS_PROCS) {
2079433d6423SLionel Sambuc return ENOMEM;
2080433d6423SLionel Sambuc }
2081433d6423SLionel Sambuc
2082433d6423SLionel Sambuc return OK;
2083433d6423SLionel Sambuc }
2084433d6423SLionel Sambuc
2085433d6423SLionel Sambuc /*===========================================================================*
2086433d6423SLionel Sambuc * free_slot *
2087433d6423SLionel Sambuc *===========================================================================*/
free_slot(rp)2088433d6423SLionel Sambuc void free_slot(rp)
2089433d6423SLionel Sambuc struct rproc *rp;
2090433d6423SLionel Sambuc {
2091433d6423SLionel Sambuc /* Free a system service slot. */
2092433d6423SLionel Sambuc struct rprocpub *rpub;
2093433d6423SLionel Sambuc
2094433d6423SLionel Sambuc rpub = rp->r_pub;
2095433d6423SLionel Sambuc
2096433d6423SLionel Sambuc /* Send a late reply if there is any pending. */
2097433d6423SLionel Sambuc late_reply(rp, OK);
2098433d6423SLionel Sambuc
2099433d6423SLionel Sambuc /* Free memory if necessary. */
2100433d6423SLionel Sambuc if(rpub->sys_flags & SF_USE_COPY) {
2101433d6423SLionel Sambuc free_exec(rp);
2102433d6423SLionel Sambuc }
2103433d6423SLionel Sambuc
2104433d6423SLionel Sambuc /* Mark slot as no longer in use.. */
2105433d6423SLionel Sambuc rp->r_flags = 0;
2106433d6423SLionel Sambuc rp->r_pid = -1;
2107433d6423SLionel Sambuc rpub->in_use = FALSE;
2108433d6423SLionel Sambuc rproc_ptr[_ENDPOINT_P(rpub->endpoint)] = NULL;
2109433d6423SLionel Sambuc }
2110433d6423SLionel Sambuc
2111433d6423SLionel Sambuc
2112433d6423SLionel Sambuc /*===========================================================================*
2113433d6423SLionel Sambuc * get_next_name *
2114433d6423SLionel Sambuc *===========================================================================*/
get_next_name(ptr,name,caller_label)2115433d6423SLionel Sambuc static char *get_next_name(ptr, name, caller_label)
2116433d6423SLionel Sambuc char *ptr;
2117433d6423SLionel Sambuc char *name;
2118433d6423SLionel Sambuc char *caller_label;
2119433d6423SLionel Sambuc {
2120433d6423SLionel Sambuc /* Get the next name from the list of (IPC) program names.
2121433d6423SLionel Sambuc */
2122433d6423SLionel Sambuc char *p, *q;
2123433d6423SLionel Sambuc size_t len;
2124433d6423SLionel Sambuc
2125433d6423SLionel Sambuc for (p= ptr; p[0] != '\0'; p= q)
2126433d6423SLionel Sambuc {
2127433d6423SLionel Sambuc /* Skip leading space */
2128433d6423SLionel Sambuc while (p[0] != '\0' && isspace((unsigned char)p[0]))
2129433d6423SLionel Sambuc p++;
2130433d6423SLionel Sambuc
2131433d6423SLionel Sambuc /* Find start of next word */
2132433d6423SLionel Sambuc q= p;
2133433d6423SLionel Sambuc while (q[0] != '\0' && !isspace((unsigned char)q[0]))
2134433d6423SLionel Sambuc q++;
2135433d6423SLionel Sambuc if (q == p)
2136433d6423SLionel Sambuc continue;
2137433d6423SLionel Sambuc len= q-p;
2138433d6423SLionel Sambuc if (len > RS_MAX_LABEL_LEN)
2139433d6423SLionel Sambuc {
2140433d6423SLionel Sambuc printf(
2141433d6423SLionel Sambuc "rs:get_next_name: bad ipc list entry '%.*s' for %s: too long\n",
21423c8950ccSBen Gras (int) len, p, caller_label);
2143433d6423SLionel Sambuc continue;
2144433d6423SLionel Sambuc }
2145433d6423SLionel Sambuc memcpy(name, p, len);
2146433d6423SLionel Sambuc name[len]= '\0';
2147433d6423SLionel Sambuc
2148433d6423SLionel Sambuc return q; /* found another */
2149433d6423SLionel Sambuc }
2150433d6423SLionel Sambuc
2151433d6423SLionel Sambuc return NULL; /* done */
2152433d6423SLionel Sambuc }
2153433d6423SLionel Sambuc
2154433d6423SLionel Sambuc /*===========================================================================*
2155433d6423SLionel Sambuc * add_forward_ipc *
2156433d6423SLionel Sambuc *===========================================================================*/
add_forward_ipc(rp,privp)2157433d6423SLionel Sambuc void add_forward_ipc(rp, privp)
2158433d6423SLionel Sambuc struct rproc *rp;
2159433d6423SLionel Sambuc struct priv *privp;
2160433d6423SLionel Sambuc {
2161433d6423SLionel Sambuc /* Add IPC send permissions to a process based on that process's IPC
2162433d6423SLionel Sambuc * list.
2163433d6423SLionel Sambuc */
2164433d6423SLionel Sambuc char name[RS_MAX_LABEL_LEN+1], *p;
2165433d6423SLionel Sambuc struct rproc *rrp;
2166433d6423SLionel Sambuc endpoint_t endpoint;
2167433d6423SLionel Sambuc int r;
2168433d6423SLionel Sambuc int priv_id;
2169433d6423SLionel Sambuc struct priv priv;
2170433d6423SLionel Sambuc struct rprocpub *rpub;
2171433d6423SLionel Sambuc
2172433d6423SLionel Sambuc rpub = rp->r_pub;
2173433d6423SLionel Sambuc p = rp->r_ipc_list;
2174433d6423SLionel Sambuc
2175433d6423SLionel Sambuc while ((p = get_next_name(p, name, rpub->label)) != NULL) {
2176433d6423SLionel Sambuc
2177433d6423SLionel Sambuc if (strcmp(name, "SYSTEM") == 0)
2178433d6423SLionel Sambuc endpoint= SYSTEM;
2179433d6423SLionel Sambuc else if (strcmp(name, "USER") == 0)
2180433d6423SLionel Sambuc endpoint= INIT_PROC_NR; /* all user procs */
2181433d6423SLionel Sambuc else
2182433d6423SLionel Sambuc {
2183433d6423SLionel Sambuc /* Set a privilege bit for every process matching the
2184433d6423SLionel Sambuc * given process name. It is perfectly fine if this
2185433d6423SLionel Sambuc * loop does not find any matches, as the target
2186433d6423SLionel Sambuc * process(es) may not have been started yet. See
2187433d6423SLionel Sambuc * add_backward_ipc() below.
2188433d6423SLionel Sambuc */
2189433d6423SLionel Sambuc for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
2190433d6423SLionel Sambuc if (!(rrp->r_flags & RS_IN_USE))
2191433d6423SLionel Sambuc continue;
2192433d6423SLionel Sambuc
2193433d6423SLionel Sambuc if (!strcmp(rrp->r_pub->proc_name, name)) {
2194433d6423SLionel Sambuc #if PRIV_DEBUG
2195433d6423SLionel Sambuc printf(" RS: add_forward_ipc: setting"
2196433d6423SLionel Sambuc " sendto bit for %d...\n",
2197433d6423SLionel Sambuc rrp->r_pub->endpoint);
2198433d6423SLionel Sambuc #endif
2199433d6423SLionel Sambuc
2200433d6423SLionel Sambuc priv_id= rrp->r_priv.s_id;
2201433d6423SLionel Sambuc set_sys_bit(privp->s_ipc_to, priv_id);
2202433d6423SLionel Sambuc }
2203433d6423SLionel Sambuc }
2204433d6423SLionel Sambuc
2205433d6423SLionel Sambuc continue;
2206433d6423SLionel Sambuc }
2207433d6423SLionel Sambuc
2208433d6423SLionel Sambuc /* This code only applies to the exception cases. */
2209433d6423SLionel Sambuc if ((r = sys_getpriv(&priv, endpoint)) < 0)
2210433d6423SLionel Sambuc {
2211433d6423SLionel Sambuc printf(
2212433d6423SLionel Sambuc "add_forward_ipc: unable to get priv_id for '%s': %d\n",
2213433d6423SLionel Sambuc name, r);
2214433d6423SLionel Sambuc continue;
2215433d6423SLionel Sambuc }
2216433d6423SLionel Sambuc
2217433d6423SLionel Sambuc #if PRIV_DEBUG
2218433d6423SLionel Sambuc printf(" RS: add_forward_ipc: setting sendto bit for %d...\n",
2219433d6423SLionel Sambuc endpoint);
2220433d6423SLionel Sambuc #endif
2221433d6423SLionel Sambuc priv_id= priv.s_id;
2222433d6423SLionel Sambuc set_sys_bit(privp->s_ipc_to, priv_id);
2223433d6423SLionel Sambuc }
2224433d6423SLionel Sambuc }
2225433d6423SLionel Sambuc
2226433d6423SLionel Sambuc
2227433d6423SLionel Sambuc /*===========================================================================*
2228433d6423SLionel Sambuc * add_backward_ipc *
2229433d6423SLionel Sambuc *===========================================================================*/
add_backward_ipc(rp,privp)2230433d6423SLionel Sambuc void add_backward_ipc(rp, privp)
2231433d6423SLionel Sambuc struct rproc *rp;
2232433d6423SLionel Sambuc struct priv *privp;
2233433d6423SLionel Sambuc {
2234433d6423SLionel Sambuc /* Add IPC send permissions to a process based on other processes' IPC
2235433d6423SLionel Sambuc * lists. This is enough to allow each such two processes to talk to
2236433d6423SLionel Sambuc * each other, as the kernel guarantees send mask symmetry. We need to
2237433d6423SLionel Sambuc * add these permissions now because the current process may not yet
2238433d6423SLionel Sambuc * have existed at the time that the other process was initialized.
2239433d6423SLionel Sambuc */
2240433d6423SLionel Sambuc char name[RS_MAX_LABEL_LEN+1], *p;
2241433d6423SLionel Sambuc struct rproc *rrp;
2242433d6423SLionel Sambuc struct rprocpub *rrpub;
2243433d6423SLionel Sambuc char *proc_name;
2244433d6423SLionel Sambuc int priv_id, is_ipc_all, is_ipc_all_sys;
2245433d6423SLionel Sambuc
2246433d6423SLionel Sambuc proc_name = rp->r_pub->proc_name;
2247433d6423SLionel Sambuc
2248433d6423SLionel Sambuc for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
2249433d6423SLionel Sambuc if (!(rrp->r_flags & RS_IN_USE))
2250433d6423SLionel Sambuc continue;
2251433d6423SLionel Sambuc
2252433d6423SLionel Sambuc if (!rrp->r_ipc_list[0])
2253433d6423SLionel Sambuc continue;
2254433d6423SLionel Sambuc
2255433d6423SLionel Sambuc /* If the process being checked is set to allow IPC to all
2256433d6423SLionel Sambuc * other processes, or for all other system processes and the
2257433d6423SLionel Sambuc * target process is a system process, add a permission bit.
2258433d6423SLionel Sambuc */
2259433d6423SLionel Sambuc rrpub = rrp->r_pub;
2260433d6423SLionel Sambuc
2261433d6423SLionel Sambuc is_ipc_all = !strcmp(rrp->r_ipc_list, RSS_IPC_ALL);
2262433d6423SLionel Sambuc is_ipc_all_sys = !strcmp(rrp->r_ipc_list, RSS_IPC_ALL_SYS);
2263433d6423SLionel Sambuc
2264433d6423SLionel Sambuc if (is_ipc_all ||
2265433d6423SLionel Sambuc (is_ipc_all_sys && (privp->s_flags & SYS_PROC))) {
2266433d6423SLionel Sambuc #if PRIV_DEBUG
2267433d6423SLionel Sambuc printf(" RS: add_backward_ipc: setting sendto bit "
2268433d6423SLionel Sambuc "for %d...\n", rrpub->endpoint);
2269433d6423SLionel Sambuc #endif
2270433d6423SLionel Sambuc priv_id= rrp->r_priv.s_id;
2271433d6423SLionel Sambuc set_sys_bit(privp->s_ipc_to, priv_id);
2272433d6423SLionel Sambuc
2273433d6423SLionel Sambuc continue;
2274433d6423SLionel Sambuc }
2275433d6423SLionel Sambuc
2276433d6423SLionel Sambuc /* An IPC target list was provided for the process being
2277433d6423SLionel Sambuc * checked here. Make sure that the name of the new process
2278433d6423SLionel Sambuc * is in that process's list. There may be multiple matches.
2279433d6423SLionel Sambuc */
2280433d6423SLionel Sambuc p = rrp->r_ipc_list;
2281433d6423SLionel Sambuc
2282433d6423SLionel Sambuc while ((p = get_next_name(p, name, rrpub->label)) != NULL) {
2283433d6423SLionel Sambuc if (!strcmp(proc_name, name)) {
2284433d6423SLionel Sambuc #if PRIV_DEBUG
2285433d6423SLionel Sambuc printf(" RS: add_backward_ipc: setting sendto"
2286433d6423SLionel Sambuc " bit for %d...\n",
2287433d6423SLionel Sambuc rrpub->endpoint);
2288433d6423SLionel Sambuc #endif
2289433d6423SLionel Sambuc priv_id= rrp->r_priv.s_id;
2290433d6423SLionel Sambuc set_sys_bit(privp->s_ipc_to, priv_id);
2291433d6423SLionel Sambuc }
2292433d6423SLionel Sambuc }
2293433d6423SLionel Sambuc }
2294433d6423SLionel Sambuc }
2295433d6423SLionel Sambuc
2296433d6423SLionel Sambuc
2297433d6423SLionel Sambuc /*===========================================================================*
2298433d6423SLionel Sambuc * init_privs *
2299433d6423SLionel Sambuc *===========================================================================*/
init_privs(rp,privp)2300433d6423SLionel Sambuc void init_privs(rp, privp)
2301433d6423SLionel Sambuc struct rproc *rp;
2302433d6423SLionel Sambuc struct priv *privp;
2303433d6423SLionel Sambuc {
2304433d6423SLionel Sambuc int i;
2305433d6423SLionel Sambuc int is_ipc_all, is_ipc_all_sys;
2306433d6423SLionel Sambuc
2307433d6423SLionel Sambuc /* Clear s_ipc_to */
2308433d6423SLionel Sambuc fill_send_mask(&privp->s_ipc_to, FALSE);
2309433d6423SLionel Sambuc
2310433d6423SLionel Sambuc is_ipc_all = !strcmp(rp->r_ipc_list, RSS_IPC_ALL);
2311433d6423SLionel Sambuc is_ipc_all_sys = !strcmp(rp->r_ipc_list, RSS_IPC_ALL_SYS);
2312433d6423SLionel Sambuc
2313433d6423SLionel Sambuc #if PRIV_DEBUG
2314433d6423SLionel Sambuc printf(" RS: init_privs: ipc list is '%s'...\n", rp->r_ipc_list);
2315433d6423SLionel Sambuc #endif
2316433d6423SLionel Sambuc
2317433d6423SLionel Sambuc if (!is_ipc_all && !is_ipc_all_sys)
2318433d6423SLionel Sambuc {
2319433d6423SLionel Sambuc add_forward_ipc(rp, privp);
2320433d6423SLionel Sambuc add_backward_ipc(rp, privp);
2321433d6423SLionel Sambuc
2322433d6423SLionel Sambuc }
2323433d6423SLionel Sambuc else
2324433d6423SLionel Sambuc {
2325433d6423SLionel Sambuc for (i= 0; i<NR_SYS_PROCS; i++)
2326433d6423SLionel Sambuc {
2327433d6423SLionel Sambuc if (is_ipc_all || i != USER_PRIV_ID)
2328433d6423SLionel Sambuc set_sys_bit(privp->s_ipc_to, i);
2329433d6423SLionel Sambuc }
2330433d6423SLionel Sambuc }
2331433d6423SLionel Sambuc }
2332433d6423SLionel Sambuc
2333