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