/*===========================================================================* * do_shmdt * *===========================================================================*/ PUBLIC int do_shmdt(message *m) { vir_bytes addr; phys_bytes paddr; int i; addr = m->SHMDT_ADDR; if ((paddr = vm_getphys(who_e, (void *) addr)) == 0) return EINVAL; for (i = 0; i < shm_list_nr; i++) { if (shm_list[i].phys == paddr) { struct shm_struct *shm = &shm_list[i]; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattch is updated lazily */ vm_unmap(who_e, (void *) addr); break; } } if (i == shm_list_nr) fprintf(stderr, "IPC: do_shmdt impossible error!\n"); update_refcount_and_destroy(); return OK; }
/*===========================================================================* * do_shmdt * *===========================================================================*/ int do_shmdt(message *m) { vir_bytes addr; phys_bytes vm_id; int i; addr = (vir_bytes) m->m_lc_ipc_shmdt.addr; if ((vm_id = vm_getphys(who_e, (void *) addr)) == 0) return EINVAL; for (i = 0; i < shm_list_nr; i++) { if (shm_list[i].vm_id == vm_id) { struct shm_struct *shm = &shm_list[i]; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattch is updated lazily */ vm_unmap(who_e, (void *) addr); break; } } if (i == shm_list_nr) printf("IPC: do_shmdt impossible error! could not find id %lu to unmap\n", vm_id); update_refcount_and_destroy(); return OK; }
/*===========================================================================* * init_server * *===========================================================================*/ PRIVATE void init_server(void) { /* Initialize the reincarnation server. */ struct sigaction sa; struct boot_image *ip; int s,t; /* Install signal handlers. Ask PM to transform signal into message. */ sa.sa_handler = SIG_MESS; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno); if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno); /* Initialize the system process table. Use the boot image from the kernel * and the device map from the FS to gather all needed information. */ if ((s = sys_getimage(image)) != OK) panic("RS","warning: couldn't get copy of image table", s); if ((s = getsysinfo(FS_PROC_NR, SI_DMAP_TAB, dmap)) < 0) panic("RS","warning: couldn't get copy of dmap table", errno); /* Now initialize the table with the processes in the system image. * Prepend /sbin/ to the binaries so that we can actually find them. */ for (s=0; s< NR_BOOT_PROCS; s++) { ip = &image[s]; if (ip->proc_nr >= 0) { nr_in_use ++; rproc[s].r_flags = RS_IN_USE; rproc[s].r_proc_nr_e = ip->endpoint; rproc[s].r_pid = getnpid(ip->proc_nr); for(t=0; t< NR_DEVICES; t++) if (dmap[t].dmap_driver == ip->proc_nr) rproc[s].r_dev_nr = t; strcpy(rproc[s].r_cmd, "/sbin/"); strcpy(rproc[s].r_cmd+6, ip->proc_name); rproc[s].r_argc = 1; rproc[s].r_argv[0] = rproc[s].r_cmd; rproc[s].r_argv[1] = NULL; } } /* Set alarm to periodically check driver status. */ if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) panic("RS", "couldn't set alarm", s); }
/*===========================================================================* * do_shmat * *===========================================================================*/ PUBLIC int do_shmat(message *m) { int id, flag; vir_bytes addr; void *ret; struct shm_struct *shm; id = m->SHMAT_ID; addr = (vir_bytes) m->SHMAT_ADDR; flag = m->SHMAT_FLAG; if (addr && (addr % I386_PAGE_SIZE)) { if (flag & SHM_RND) addr -= (addr % I386_PAGE_SIZE); else return EINVAL; } if (!(shm = shm_find_id(id))) return EINVAL; if (flag & SHM_RDONLY) flag = 0444; else flag = 0666; if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; ret = vm_remap(who_e, SELF_E, (void *)addr, (void *)shm->page, shm->shmid_ds.shm_segsz); if (ret == MAP_FAILED) return ENOMEM; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattach is updated lazily */ m->SHMAT_RETADDR = (long) ret; return OK; }
/*===========================================================================* * do_shmat * *===========================================================================*/ int do_shmat(message *m) { int id, flag; vir_bytes addr; void *ret; struct shm_struct *shm; id = m->m_lc_ipc_shmat.id; addr = (vir_bytes) m->m_lc_ipc_shmat.addr; flag = m->m_lc_ipc_shmat.flag; if (addr && (addr % PAGE_SIZE)) { if (flag & SHM_RND) addr -= (addr % PAGE_SIZE); else return EINVAL; } if (!(shm = shm_find_id(id))) return EINVAL; if (flag & SHM_RDONLY) flag = 0444; else flag = 0666; if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page, shm->shmid_ds.shm_segsz); if (ret == MAP_FAILED) return ENOMEM; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattach is updated lazily */ m->m_lc_ipc_shmat.retaddr = ret; return OK; }
/*===========================================================================* * sef_cb_init_fresh * *===========================================================================*/ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) { /* Initialize the reincarnation server. */ struct boot_image *ip; int s,i; int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs; struct rproc *rp; struct rproc *replica_rp; struct rprocpub *rpub; struct boot_image image[NR_BOOT_PROCS]; struct boot_image_priv *boot_image_priv; struct boot_image_sys *boot_image_sys; struct boot_image_dev *boot_image_dev; int pid, replica_pid; endpoint_t replica_endpoint; int ipc_to; int *calls; int all_c[] = { ALL_C, NULL_C }; int no_c[] = { NULL_C }; /* See if we run in verbose mode. */ env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1); if ((s = sys_getinfo(GET_HZ, &system_hz, sizeof(system_hz), 0, 0)) != OK) panic("Cannot get system timer frequency\n"); /* Initialize the global init descriptor. */ rinit.rproctab_gid = cpf_grant_direct(ANY, (vir_bytes) rprocpub, sizeof(rprocpub), CPF_READ); if(!GRANT_VALID(rinit.rproctab_gid)) { panic("unable to create rprocpub table grant: %d", rinit.rproctab_gid); } /* Initialize some global variables. */ rupdate.flags = 0; shutting_down = FALSE; /* Get a copy of the boot image table. */ if ((s = sys_getimage(image)) != OK) { panic("unable to get copy of boot image table: %d", s); } /* Determine the number of system services in the boot image table. */ nr_image_srvs = 0; for(i=0;i<NR_BOOT_PROCS;i++) { ip = &image[i]; /* System services only. */ if(iskerneln(_ENDPOINT_P(ip->endpoint))) { continue; } nr_image_srvs++; } /* Determine the number of entries in the boot image priv table and make sure * it matches the number of system services in the boot image table. */ nr_image_priv_srvs = 0; for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { boot_image_priv = &boot_image_priv_table[i]; /* System services only. */ if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) { continue; } nr_image_priv_srvs++; } if(nr_image_srvs != nr_image_priv_srvs) { panic("boot image table and boot image priv table mismatch"); } /* Reset the system process table. */ for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) { rp->r_flags = 0; rp->r_pub = &rprocpub[rp - rproc]; rp->r_pub->in_use = FALSE; } /* Initialize the system process table in 4 steps, each of them following * the appearance of system services in the boot image priv table. * - Step 1: set priviliges, sys properties, and dev properties (if any) * for every system service. */ for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { boot_image_priv = &boot_image_priv_table[i]; /* System services only. */ if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) { continue; } /* Lookup the corresponding entries in other tables. */ boot_image_info_lookup(boot_image_priv->endpoint, image, &ip, NULL, &boot_image_sys, &boot_image_dev); rp = &rproc[boot_image_priv - boot_image_priv_table]; rpub = rp->r_pub; /* * Set privileges. */ /* Get label. */ strcpy(rpub->label, boot_image_priv->label); /* Force a static priv id for system services in the boot image. */ rp->r_priv.s_id = static_priv_id( _ENDPOINT_P(boot_image_priv->endpoint)); /* Initialize privilege bitmaps and signal manager. */ rp->r_priv.s_flags = boot_image_priv->flags; /* priv flags */ rp->r_priv.s_trap_mask= SRV_OR_USR(rp, SRV_T, USR_T); /* traps */ ipc_to = SRV_OR_USR(rp, SRV_M, USR_M); /* targets */ fill_send_mask(&rp->r_priv.s_ipc_to, ipc_to == ALL_M); rp->r_priv.s_sig_mgr= SRV_OR_USR(rp, SRV_SM, USR_SM); /* sig mgr */ rp->r_priv.s_bak_sig_mgr = NONE; /* backup sig mgr */ /* Initialize kernel call mask bitmap. */ calls = SRV_OR_USR(rp, SRV_KC, USR_KC) == ALL_C ? all_c : no_c; fill_call_mask(calls, NR_SYS_CALLS, rp->r_priv.s_k_call_mask, KERNEL_CALL, TRUE); /* Set the privilege structure. */ if(boot_image_priv->endpoint != RS_PROC_NR) { if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv))) != OK) { panic("unable to set privilege structure: %d", s); } } /* Synch the privilege structure with the kernel. */ if ((s = sys_getpriv(&(rp->r_priv), ip->endpoint)) != OK) { panic("unable to synch privilege structure: %d", s); } /* * Set sys properties. */ rpub->sys_flags = boot_image_sys->flags; /* sys flags */ /* * Set dev properties. */ rpub->dev_flags = boot_image_dev->flags; /* device flags */ rpub->dev_nr = boot_image_dev->dev_nr; /* major device number */ rpub->dev_style = boot_image_dev->dev_style; /* device style */ rpub->dev_style2 = boot_image_dev->dev_style2; /* device style 2 */ /* Get process name. */ strcpy(rpub->proc_name, ip->proc_name); /* Build command settings. */ rp->r_cmd[0]= '\0'; rp->r_script[0]= '\0'; build_cmd_dep(rp); /* Initialize vm call mask bitmap. */ calls = SRV_OR_USR(rp, SRV_VC, USR_VC) == ALL_C ? all_c : no_c; fill_call_mask(calls, NR_VM_CALLS, rpub->vm_call_mask, VM_RQ_BASE, TRUE); /* Scheduling parameters. */ rp->r_scheduler = SRV_OR_USR(rp, SRV_SCH, USR_SCH); rp->r_priority = SRV_OR_USR(rp, SRV_Q, USR_Q); rp->r_quantum = SRV_OR_USR(rp, SRV_QT, USR_QT); /* Get some settings from the boot image table. */ rpub->endpoint = ip->endpoint; /* Set some defaults. */ rp->r_old_rp = NULL; /* no old version yet */ rp->r_new_rp = NULL; /* no new version yet */ rp->r_prev_rp = NULL; /* no prev replica yet */ rp->r_next_rp = NULL; /* no next replica yet */ rp->r_uid = 0; /* root */ rp->r_check_tm = 0; /* not checked yet */ getuptime(&rp->r_alive_tm); /* currently alive */ rp->r_stop_tm = 0; /* not exiting yet */ rp->r_restarts = 0; /* no restarts so far */ rp->r_period = 0; /* no period yet */ rp->r_exec = NULL; /* no in-memory copy yet */ rp->r_exec_len = 0; /* Mark as in use and active. */ rp->r_flags = RS_IN_USE | RS_ACTIVE; rproc_ptr[_ENDPOINT_P(rpub->endpoint)]= rp; rpub->in_use = TRUE; } /* - Step 2: allow every system service in the boot image to run. */ nr_uncaught_init_srvs = 0; for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { boot_image_priv = &boot_image_priv_table[i]; /* System services only. */ if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) { continue; } /* Lookup the corresponding slot in the system process table. */ rp = &rproc[boot_image_priv - boot_image_priv_table]; rpub = rp->r_pub; /* RS is already running as we speak. */ if(boot_image_priv->endpoint == RS_PROC_NR) { if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) { panic("unable to initialize RS: %d", s); } continue; } /* Allow the service to run. */ if ((s = sched_init_proc(rp)) != OK) { panic("unable to initialize scheduling: %d", s); } if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) { panic("unable to initialize privileges: %d", s); } /* Initialize service. We assume every service will always get * back to us here at boot time. */ if(boot_image_priv->flags & SYS_PROC) { if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) { panic("unable to initialize service: %d", s); } if(rpub->sys_flags & SF_SYNCH_BOOT) { /* Catch init ready message now to synchronize. */ catch_boot_init_ready(rpub->endpoint); } else { /* Catch init ready message later. */ nr_uncaught_init_srvs++; } } } /* - Step 3: let every system service complete initialization by * catching all the init ready messages left. */ while(nr_uncaught_init_srvs) { catch_boot_init_ready(ANY); nr_uncaught_init_srvs--; } /* - Step 4: all the system services in the boot image are now running. * Complete the initialization of the system process table in collaboration * with other system services. */ for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) { boot_image_priv = &boot_image_priv_table[i]; /* System services only. */ if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) { continue; } /* Lookup the corresponding slot in the system process table. */ rp = &rproc[boot_image_priv - boot_image_priv_table]; rpub = rp->r_pub; /* Get pid from PM. */ rp->r_pid = getnpid(rpub->endpoint); if(rp->r_pid == -1) { panic("unable to get pid"); } } /* Set alarm to periodically check service status. */ if (OK != (s=sys_setalarm(RS_DELTA_T, 0))) panic("couldn't set alarm: %d", s); /* Now create a new RS instance with a private page table and let the current * instance live update into the replica. Clone RS' own slot first. */ rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)]; if((s = clone_slot(rp, &replica_rp)) != OK) { panic("unable to clone current RS instance: %d", s); } /* Fork a new RS instance. */ pid = srv_fork(); if(pid == -1) { panic("unable to fork a new RS instance"); } replica_pid = pid ? pid : getpid(); replica_endpoint = getnprocnr(replica_pid); replica_rp->r_pid = replica_pid; replica_rp->r_pub->endpoint = replica_endpoint; if(pid == 0) { /* New RS instance running. */ /* Live update the old instance into the new one. */ s = update_service(&rp, &replica_rp, RS_SWAP); if(s != OK) { panic("unable to live update RS: %d", s); } cpf_reload(); /* Clean up the old RS instance, the new instance will take over. */ cleanup_service(rp); /* Map out our own text and data. */ unmap_ok = 1; _minix_unmapzero(); /* Ask VM to pin memory for the new RS instance. */ if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN)) != OK) { panic("unable to pin memory for the new RS instance: %d", s); } } else { /* Old RS instance running. */ /* Set up privileges for the new instance and let it run. */ s = sys_privctl(replica_endpoint, SYS_PRIV_SET_SYS, &(replica_rp->r_priv)); if(s != OK) { panic("unable to set privileges for the new RS instance: %d", s); } if ((s = sched_init_proc(replica_rp)) != OK) { panic("unable to initialize RS replica scheduling: %d", s); } s = sys_privctl(replica_endpoint, SYS_PRIV_YIELD, NULL); if(s != OK) { panic("unable to yield control to the new RS instance: %d", s); } NOT_REACHABLE; } return(OK); }
/*===========================================================================* * do_shmget * *===========================================================================*/ PUBLIC int do_shmget(message *m) { struct shm_struct *shm; long key, size, old_size; int flag; int id; key = m->SHMGET_KEY; old_size = size = m->SHMGET_SIZE; flag = m->SHMGET_FLAG; if ((shm = shm_find_key(key))) { if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; if ((flag & IPC_CREAT) && (flag & IPC_EXCL)) return EEXIST; if (size && shm->shmid_ds.shm_segsz < size) return EINVAL; id = shm->id; } else { /* no key found */ if (!(flag & IPC_CREAT)) return ENOENT; if (size <= 0) return EINVAL; /* round up to a multiple of PAGE_SIZE */ if (size % I386_PAGE_SIZE) size += I386_PAGE_SIZE - size % I386_PAGE_SIZE; if (size <= 0) return EINVAL; if (shm_list_nr == MAX_SHM_NR) return ENOMEM; /* TODO: shmmni should be changed... */ if (identifier == SHMMNI) return ENOSPC; shm = &shm_list[shm_list_nr]; memset(shm, 0, sizeof(struct shm_struct)); shm->page = (vir_bytes) mmap(0, size, PROT_READ|PROT_WRITE, MAP_CONTIG|MAP_PREALLOC|MAP_ANON|MAP_SHARED, -1, 0); if (shm->page == (vir_bytes) MAP_FAILED) return ENOMEM; shm->phys = vm_getphys(SELF_E, (void *) shm->page); memset((void *)shm->page, 0, size); shm->shmid_ds.shm_perm.cuid = shm->shmid_ds.shm_perm.uid = getnuid(who_e); shm->shmid_ds.shm_perm.cgid = shm->shmid_ds.shm_perm.gid = getngid(who_e); shm->shmid_ds.shm_perm.mode = flag & 0777; shm->shmid_ds.shm_segsz = old_size; shm->shmid_ds.shm_atime = 0; shm->shmid_ds.shm_dtime = 0; shm->shmid_ds.shm_ctime = time(NULL); shm->shmid_ds.shm_cpid = getnpid(who_e); shm->shmid_ds.shm_lpid = 0; shm->shmid_ds.shm_nattch = 0; shm->id = id = identifier++; shm->key = key; shm_list_nr++; } m->SHMGET_RETID = id; return OK; }
/*===========================================================================* * do_semop * *===========================================================================*/ PUBLIC int do_semop(message *m) { int id, i, j, r; struct sembuf *sops; unsigned int nsops; struct sem_struct *sem; int no_reply = 0; id = m->SEMOP_ID; nsops = (unsigned int) m->SEMOP_SIZE; r = EINVAL; if (!(sem = sem_find_id(id))) goto out; if (nsops <= 0) goto out; r = E2BIG; if (nsops > SEMOPM) goto out; /* check for read permission */ r = EACCES; if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444)) goto out; /* get the array from user application */ r = ENOMEM; sops = malloc(sizeof(struct sembuf) * nsops); if (!sops) goto out_free; r = sys_datacopy(who_e, (vir_bytes) m->SEMOP_OPS, SELF_E, (vir_bytes) sops, sizeof(struct sembuf) * nsops); if (r != OK) { r = EINVAL; goto out_free; } #ifdef DEBUG_SEM for (i = 0; i < nsops; i++) printf("SEMOP: num:%d op:%d flg:%d\n", sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg); #endif /* check for value range */ r = EFBIG; for (i = 0; i < nsops; i++) if (sops[i].sem_num < 0 || sops[i].sem_num >= sem->semid_ds.sem_nsems) goto out_free; /* check for duplicate number */ r = EINVAL; for (i = 0; i < nsops; i++) for (j = i + 1; j < nsops; j++) if (sops[i].sem_num == sops[j].sem_num) goto out_free; /* check for EAGAIN error */ r = EAGAIN; for (i = 0; i < nsops; i++) { int op_n, val; op_n = sops[i].sem_op; val = sem->sems[sops[i].sem_num].semval; if ((sops[i].sem_flg & IPC_NOWAIT) && ((!op_n && val) || (op_n < 0 && -op_n > val))) goto out_free; } /* there will be no errors left, so we can go ahead */ for (i = 0; i < nsops; i++) { struct semaphore *s; int op_n; s = &sem->sems[sops[i].sem_num]; op_n = sops[i].sem_op; s->sempid = getnpid(who_e); if (op_n > 0) { /* check for alter permission */ r = EACCES; if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222)) goto out_free; s->semval += sops[i].sem_op; } else if (!op_n) { if (s->semval) { /* put the process asleep */ s->semzcnt++; s->zlist = realloc(s->zlist, sizeof(struct waiting) * s->semzcnt); if (!s->zlist) { printf("IPC: zero waiting list lost...\n"); break; } s->zlist[s->semzcnt-1].who = who_e; s->zlist[s->semzcnt-1].val = op_n; #ifdef DEBUG_SEM printf("SEMOP: Put into sleep... %d\n", who_e); #endif no_reply++; } } else { /* check for alter permission */ r = EACCES; if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222)) goto out_free; if (s->semval >= -op_n) s->semval += op_n; else { /* put the process asleep */ s->semncnt++; s->nlist = realloc(s->nlist, sizeof(struct waiting) * s->semncnt); if (!s->nlist) { printf("IPC: increase waiting list lost...\n"); break; } s->nlist[s->semncnt-1].who = who_e; s->nlist[s->semncnt-1].val = -op_n; no_reply++; } } } r = OK; out_free: free(sops); out: /* if we reach here by errors * or with no errors but we should reply back. */ if (r != OK || !no_reply) { m->m_type = r; sendnb(who_e, m); } /* awaken process if possible */ update_semaphores(); return 0; }