/*===========================================================================* * service_pm * *===========================================================================*/ static void service_pm() { int r, slot; switch (job_call_nr) { case PM_SETUID: { endpoint_t proc_e; uid_t euid, ruid; proc_e = job_m_in.PM_PROC; euid = job_m_in.PM_EID; ruid = job_m_in.PM_RID; pm_setuid(proc_e, euid, ruid); m_out.m_type = PM_SETUID_REPLY; m_out.PM_PROC = proc_e; } break; case PM_SETGID: { endpoint_t proc_e; gid_t egid, rgid; proc_e = job_m_in.PM_PROC; egid = job_m_in.PM_EID; rgid = job_m_in.PM_RID; pm_setgid(proc_e, egid, rgid); m_out.m_type = PM_SETGID_REPLY; m_out.PM_PROC = proc_e; } break; case PM_SETSID: { endpoint_t proc_e; proc_e = job_m_in.PM_PROC; pm_setsid(proc_e); m_out.m_type = PM_SETSID_REPLY; m_out.PM_PROC = proc_e; } break; case PM_EXEC: case PM_EXIT: case PM_DUMPCORE: { endpoint_t proc_e = job_m_in.PM_PROC; okendpt(proc_e, &slot); fp = &fproc[slot]; if (fp->fp_flags & FP_PENDING) { /* This process has a request pending, but PM wants it * gone. Forget about the pending request and satisfy * PM's request instead. Note that a pending request * AND an EXEC request are mutually exclusive. Also, PM * should send only one request/process at a time. */ assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR); } /* PM requests on behalf of a proc are handled after the * system call that might be in progress for that proc has * finished. If the proc is not busy, we start a dummy call. */ if (!(fp->fp_flags & FP_PENDING) && mutex_trylock(&fp->fp_lock) == 0) { mutex_unlock(&fp->fp_lock); worker_start(do_dummy); fp->fp_flags |= FP_DROP_WORK; } fp->fp_job.j_m_in = job_m_in; fp->fp_flags |= FP_PM_PENDING; return; } case PM_FORK: case PM_SRV_FORK: { endpoint_t pproc_e, proc_e; pid_t child_pid; uid_t reuid; gid_t regid; pproc_e = job_m_in.PM_PPROC; proc_e = job_m_in.PM_PROC; child_pid = job_m_in.PM_CPID; reuid = job_m_in.PM_REUID; regid = job_m_in.PM_REGID; pm_fork(pproc_e, proc_e, child_pid); m_out.m_type = PM_FORK_REPLY; if (job_call_nr == PM_SRV_FORK) { m_out.m_type = PM_SRV_FORK_REPLY; pm_setuid(proc_e, reuid, reuid); pm_setgid(proc_e, regid, regid); } m_out.PM_PROC = proc_e; } break; case PM_SETGROUPS: { endpoint_t proc_e; int group_no; gid_t *group_addr; proc_e = job_m_in.PM_PROC; group_no = job_m_in.PM_GROUP_NO; group_addr = (gid_t *) job_m_in.PM_GROUP_ADDR; pm_setgroups(proc_e, group_no, group_addr); m_out.m_type = PM_SETGROUPS_REPLY; m_out.PM_PROC = proc_e; } break; case PM_UNPAUSE: { endpoint_t proc_e; proc_e = job_m_in.PM_PROC; unpause(proc_e); m_out.m_type = PM_UNPAUSE_REPLY; m_out.PM_PROC = proc_e; } break; case PM_REBOOT: pm_reboot(); /* Reply dummy status to PM for synchronization */ m_out.m_type = PM_REBOOT_REPLY; break; default: printf("VFS: don't know how to handle PM request %d\n", job_call_nr); return; } r = send(PM_PROC_NR, &m_out); if (r != OK) panic("service_pm: send failed: %d", r); }
/*===========================================================================* * service_pm * *===========================================================================*/ static void service_pm(void) { /* Process a request from PM. This function is called from the main thread, and * may therefore not block. Any requests that may require blocking the calling * thread must be executed in a separate thread. Aside from VFS_PM_REBOOT, all * requests from PM involve another, target process: for example, PM tells VFS * that a process is performing a setuid() call. For some requests however, * that other process may not be idle, and in that case VFS must serialize the * PM request handling with any operation is it handling for that target * process. As it happens, the requests that may require blocking are also the * ones where the target process may not be idle. For both these reasons, such * requests are run in worker threads associated to the target process. */ struct fproc *rfp; int r, slot; message m_out; memset(&m_out, 0, sizeof(m_out)); switch (call_nr) { case VFS_PM_SETUID: { endpoint_t proc_e; uid_t euid, ruid; proc_e = m_in.VFS_PM_ENDPT; euid = m_in.VFS_PM_EID; ruid = m_in.VFS_PM_RID; pm_setuid(proc_e, euid, ruid); m_out.m_type = VFS_PM_SETUID_REPLY; m_out.VFS_PM_ENDPT = proc_e; } break; case VFS_PM_SETGID: { endpoint_t proc_e; gid_t egid, rgid; proc_e = m_in.VFS_PM_ENDPT; egid = m_in.VFS_PM_EID; rgid = m_in.VFS_PM_RID; pm_setgid(proc_e, egid, rgid); m_out.m_type = VFS_PM_SETGID_REPLY; m_out.VFS_PM_ENDPT = proc_e; } break; case VFS_PM_SETSID: { endpoint_t proc_e; proc_e = m_in.VFS_PM_ENDPT; pm_setsid(proc_e); m_out.m_type = VFS_PM_SETSID_REPLY; m_out.VFS_PM_ENDPT = proc_e; } break; case VFS_PM_EXEC: case VFS_PM_EXIT: case VFS_PM_DUMPCORE: case VFS_PM_UNPAUSE: { endpoint_t proc_e = m_in.VFS_PM_ENDPT; if(isokendpt(proc_e, &slot) != OK) { printf("VFS: proc ep %d not ok\n", proc_e); return; } rfp = &fproc[slot]; /* PM requests on behalf of a proc are handled after the * system call that might be in progress for that proc has * finished. If the proc is not busy, we start a new thread. */ worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/); return; } case VFS_PM_FORK: case VFS_PM_SRV_FORK: { endpoint_t pproc_e, proc_e; pid_t child_pid; uid_t reuid; gid_t regid; pproc_e = m_in.VFS_PM_PENDPT; proc_e = m_in.VFS_PM_ENDPT; child_pid = m_in.VFS_PM_CPID; reuid = m_in.VFS_PM_REUID; regid = m_in.VFS_PM_REGID; pm_fork(pproc_e, proc_e, child_pid); m_out.m_type = VFS_PM_FORK_REPLY; if (call_nr == VFS_PM_SRV_FORK) { m_out.m_type = VFS_PM_SRV_FORK_REPLY; pm_setuid(proc_e, reuid, reuid); pm_setgid(proc_e, regid, regid); } m_out.VFS_PM_ENDPT = proc_e; } break; case VFS_PM_SETGROUPS: { endpoint_t proc_e; int group_no; gid_t *group_addr; proc_e = m_in.VFS_PM_ENDPT; group_no = m_in.VFS_PM_GROUP_NO; group_addr = (gid_t *) m_in.VFS_PM_GROUP_ADDR; pm_setgroups(proc_e, group_no, group_addr); m_out.m_type = VFS_PM_SETGROUPS_REPLY; m_out.VFS_PM_ENDPT = proc_e; } break; case VFS_PM_REBOOT: /* Reboot requests are not considered postponed PM work and are instead * handled from a separate worker thread that is associated with PM's * process. PM makes no regular VFS calls, and thus, from VFS's * perspective, PM is always idle. Therefore, we can safely do this. * We do assume that PM sends us only one VFS_PM_REBOOT message at * once, or ever for that matter. :) */ worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in, FALSE /*use_spare*/); return; default: printf("VFS: don't know how to handle PM request %d\n", call_nr); return; } r = ipc_send(PM_PROC_NR, &m_out); if (r != OK) panic("service_pm: ipc_send failed: %d", r); }