Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_jail.c
Context not available. | |||||
.pr_path = "/", | .pr_path = "/", | ||||
.pr_securelevel = -1, | .pr_securelevel = -1, | ||||
.pr_devfs_rsnum = 0, | .pr_devfs_rsnum = 0, | ||||
.pr_state = PRISON_STATE_ALIVE, | |||||
.pr_childmax = JAIL_MAX, | .pr_childmax = JAIL_MAX, | ||||
.pr_hostuuid = DEFAULT_HOSTUUID, | .pr_hostuuid = DEFAULT_HOSTUUID, | ||||
.pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), | .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), | ||||
Context not available. | |||||
TAILQ_FOREACH(inspr, &allprison, pr_list) { | TAILQ_FOREACH(inspr, &allprison, pr_list) { | ||||
if (inspr->pr_id == jid) { | if (inspr->pr_id == jid) { | ||||
mtx_lock(&inspr->pr_mtx); | mtx_lock(&inspr->pr_mtx); | ||||
if (inspr->pr_ref > 0) { | if (inspr->pr_ref > 0 && | ||||
inspr->pr_state != PRISON_STATE_INVALID) { | |||||
pr = inspr; | pr = inspr; | ||||
inspr = NULL; | inspr = NULL; | ||||
} else | } else | ||||
Context not available. | |||||
*/ | */ | ||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
pr = NULL; | pr = NULL; | ||||
} else if (pr->pr_uref == 0) { | } else if (pr->pr_state == PRISON_STATE_DYING) { | ||||
if (!(flags & JAIL_DYING)) { | if (!(flags & JAIL_DYING)) { | ||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
error = ENOENT; | error = ENOENT; | ||||
Context not available. | |||||
deadpr = NULL; | deadpr = NULL; | ||||
FOREACH_PRISON_CHILD(ppr, tpr) { | FOREACH_PRISON_CHILD(ppr, tpr) { | ||||
if (tpr != pr && tpr->pr_ref > 0 && | if (tpr != pr && tpr->pr_ref > 0 && | ||||
tpr->pr_state != PRISON_STATE_INVALID && | |||||
!strcmp(tpr->pr_name + pnamelen, namelc)) { | !strcmp(tpr->pr_name + pnamelen, namelc)) { | ||||
if (pr == NULL && | if (pr == NULL && | ||||
cuflags != JAIL_CREATE) { | cuflags != JAIL_CREATE) { | ||||
mtx_lock(&tpr->pr_mtx); | mtx_lock(&tpr->pr_mtx); | ||||
if (tpr->pr_ref > 0) { | if (tpr->pr_ref > 0) { | ||||
/* | if (tpr->pr_state == | ||||
* Use this jail | PRISON_STATE_ALIVE) | ||||
* for updates. | { | ||||
*/ | /* | ||||
if (tpr->pr_uref > 0) { | * Use this jail | ||||
* for updates. | |||||
*/ | |||||
pr = tpr; | pr = tpr; | ||||
break; | break; | ||||
} | } | ||||
deadpr = tpr; | else if (tpr->pr_state == | ||||
PRISON_STATE_DYING) | |||||
deadpr = tpr; | |||||
} | } | ||||
mtx_unlock(&tpr->pr_mtx); | mtx_unlock(&tpr->pr_mtx); | ||||
} else if (tpr->pr_uref > 0) { | } else if (tpr->pr_state == | ||||
PRISON_STATE_ALIVE) { | |||||
/* | /* | ||||
* Create, or update(jid): | * Create, or update(jid): | ||||
* name must not exist in an | * name must not exist in an | ||||
Context not available. | |||||
} | } | ||||
/* If there's no prison to update, create a new one and link it in. */ | /* If there's no prison to update, create a new one and link it in. */ | ||||
if (pr == NULL) { | created = pr == NULL; | ||||
if (created) { | |||||
for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) | for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) | ||||
if (tpr->pr_childcount >= tpr->pr_childmax) { | if (tpr->pr_childcount >= tpr->pr_childmax) { | ||||
error = EPERM; | error = EPERM; | ||||
vfs_opterror(opts, "prison limit exceeded"); | vfs_opterror(opts, "prison limit exceeded"); | ||||
goto done_unlock_list; | goto done_unlock_list; | ||||
} | } | ||||
created = 1; | |||||
mtx_lock(&ppr->pr_mtx); | mtx_lock(&ppr->pr_mtx); | ||||
if (ppr->pr_ref == 0) { | if (ppr->pr_ref == 0 || ppr->pr_state == PRISON_STATE_INVALID) { | ||||
mtx_unlock(&ppr->pr_mtx); | mtx_unlock(&ppr->pr_mtx); | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, "jail \"%s\" not found", | vfs_opterror(opts, "jail \"%s\" not found", | ||||
Context not available. | |||||
} | } | ||||
ppr->pr_ref++; | ppr->pr_ref++; | ||||
ppr->pr_uref++; | ppr->pr_uref++; | ||||
ppr->pr_state = PRISON_STATE_ALIVE; | |||||
mtx_unlock(&ppr->pr_mtx); | mtx_unlock(&ppr->pr_mtx); | ||||
pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); | |||||
if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) { | if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) { | ||||
error = EAGAIN; | error = EAGAIN; | ||||
vfs_opterror(opts, "no available jail IDs"); | vfs_opterror(opts, "no available jail IDs"); | ||||
free(pr, M_PRISON); | |||||
prison_deref(ppr, | prison_deref(ppr, | ||||
PD_DEREF | PD_DEUREF | PD_LIST_XLOCKED); | PD_DEREF | PD_DEUREF | PD_LIST_XLOCKED); | ||||
goto done_releroot; | goto done_releroot; | ||||
} | } | ||||
/* | |||||
* Start the prison with a reference, matching the one added to | |||||
* existing prisons. | |||||
*/ | |||||
pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); | |||||
pr->pr_state = PRISON_STATE_INVALID; | |||||
pr->pr_ref = 1; | |||||
mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); | |||||
TASK_INIT(&pr->pr_task, 0, prison_complete, pr); | |||||
LIST_INIT(&pr->pr_children); | |||||
/* | |||||
* Link the prison into the allprison list in ID order, | |||||
* and into its parent's child list in no particular order. | |||||
*/ | |||||
pr->pr_id = jid; | pr->pr_id = jid; | ||||
pr->pr_parent = ppr; | |||||
if (inspr != NULL) | if (inspr != NULL) | ||||
TAILQ_INSERT_BEFORE(inspr, pr, pr_list); | TAILQ_INSERT_BEFORE(inspr, pr, pr_list); | ||||
else | else | ||||
TAILQ_INSERT_TAIL(&allprison, pr, pr_list); | TAILQ_INSERT_TAIL(&allprison, pr, pr_list); | ||||
pr->pr_parent = ppr; | |||||
LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); | LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); | ||||
for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | ||||
tpr->pr_childcount++; | tpr->pr_childcount++; | ||||
Context not available. | |||||
strlcpy(pr->pr_osrelease, osrelstr, | strlcpy(pr->pr_osrelease, osrelstr, | ||||
sizeof(pr->pr_osrelease)); | sizeof(pr->pr_osrelease)); | ||||
LIST_INIT(&pr->pr_children); | |||||
mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); | |||||
TASK_INIT(&pr->pr_task, 0, prison_complete, pr); | |||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
/* Allocate a new vnet if specified. */ | /* Allocate a new vnet if specified. */ | ||||
pr->pr_vnet = (pr_flags & PR_VNET) | pr->pr_vnet = (pr_flags & PR_VNET) | ||||
Context not available. | |||||
*/ | */ | ||||
error = cpuset_create_root(ppr, &pr->pr_cpuset); | error = cpuset_create_root(ppr, &pr->pr_cpuset); | ||||
if (error) { | if (error) { | ||||
prison_deref(pr, PD_LIST_XLOCKED); | prison_deref(pr, PD_DEREF | PD_LIST_XLOCKED); | ||||
goto done_releroot; | goto done_releroot; | ||||
} | } | ||||
mtx_lock(&pr->pr_mtx); | |||||
/* | /* | ||||
* New prisons do not yet have a reference, because we do not | * The new prison hasn't yet needed locking, because its | ||||
* want others to see the incomplete prison once the | * invalid state prevents it from being used elsewhere. | ||||
* allprison_lock is downgraded. | * But lock it now to match existing prisons. | ||||
*/ | */ | ||||
mtx_lock(&pr->pr_mtx); | |||||
} else { | } else { | ||||
created = 0; | |||||
/* | /* | ||||
* Grab a reference for existing prisons, to ensure they | * Grab a reference for existing prisons, to ensure they | ||||
* continue to exist for the duration of the call. | * continue to exist for the duration of the call. | ||||
Context not available. | |||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
(tpr != tppr && (tpr->pr_flags & PR_VNET)) || | (tpr != tppr && (tpr->pr_flags & PR_VNET)) || | ||||
#endif | #endif | ||||
tpr->pr_uref == 0) { | tpr->pr_state != PRISON_STATE_ALIVE) { | ||||
descend = 0; | descend = 0; | ||||
continue; | continue; | ||||
} | } | ||||
Context not available. | |||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
(tpr != tppr && (tpr->pr_flags & PR_VNET)) || | (tpr != tppr && (tpr->pr_flags & PR_VNET)) || | ||||
#endif | #endif | ||||
tpr->pr_uref == 0) { | tpr->pr_state != PRISON_STATE_ALIVE) { | ||||
descend = 0; | descend = 0; | ||||
continue; | continue; | ||||
} | } | ||||
Context not available. | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
error = osd_jail_call(pr, PR_METHOD_CHECK, opts); | error = osd_jail_call(pr, PR_METHOD_CHECK, opts); | ||||
if (error != 0) { | if (error != 0) { | ||||
prison_deref(pr, created | prison_deref(pr, PD_DEREF | PD_LIST_XLOCKED); | ||||
? PD_LIST_XLOCKED | |||||
: PD_DEREF | PD_LIST_XLOCKED); | |||||
goto done_releroot; | goto done_releroot; | ||||
} | } | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
Context not available. | |||||
/* Try to keep a real-rooted full pathname. */ | /* Try to keep a real-rooted full pathname. */ | ||||
strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); | strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); | ||||
pr->pr_root = root; | pr->pr_root = root; | ||||
root = NULL; | |||||
} | } | ||||
if (PR_HOST & ch_flags & ~pr_flags) { | if (PR_HOST & ch_flags & ~pr_flags) { | ||||
if (pr->pr_flags & PR_HOST) { | if (pr->pr_flags & PR_HOST) { | ||||
Context not available. | |||||
prison_set_allow_locked(pr, tallow, 0); | prison_set_allow_locked(pr, tallow, 0); | ||||
/* | /* | ||||
* Persistent prisons get an extra reference, and prisons losing their | * Persistent prisons get an extra reference, and prisons losing their | ||||
* persist flag lose that reference. Only do this for existing prisons | * persist flag lose that reference. | ||||
* for now, so new ones will remain unseen until after the module | |||||
* handlers have completed. | |||||
*/ | */ | ||||
born = pr->pr_uref == 0; | born = pr->pr_state != PRISON_STATE_ALIVE; | ||||
if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { | if (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags)) { | ||||
if (pr_flags & PR_PERSIST) { | if (pr_flags & PR_PERSIST) { | ||||
pr->pr_ref++; | pr->pr_ref++; | ||||
pr->pr_uref++; | pr->pr_uref++; | ||||
Context not available. | |||||
sx_downgrade(&allprison_lock); | sx_downgrade(&allprison_lock); | ||||
if (born) { | if (born) { | ||||
error = osd_jail_call(pr, PR_METHOD_CREATE, opts); | error = osd_jail_call(pr, PR_METHOD_CREATE, opts); | ||||
if (error) { | if (error) | ||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | goto done_remove; | ||||
prison_deref(pr, created | |||||
? PD_LIST_SLOCKED | |||||
: PD_DEREF | PD_LIST_SLOCKED); | |||||
goto done_errmsg; | |||||
} | |||||
} | } | ||||
error = osd_jail_call(pr, PR_METHOD_SET, opts); | error = osd_jail_call(pr, PR_METHOD_SET, opts); | ||||
if (error) { | if (error) { | ||||
if (born) | if (born) | ||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | goto done_remove; | ||||
prison_deref(pr, created | prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); | ||||
? PD_LIST_SLOCKED | |||||
: PD_DEREF | PD_LIST_SLOCKED); | |||||
goto done_errmsg; | goto done_errmsg; | ||||
} | } | ||||
Context not available. | |||||
vfs_opterror(opts, "attach failed"); | vfs_opterror(opts, "attach failed"); | ||||
if (born) { | if (born) { | ||||
sx_slock(&allprison_lock); | sx_slock(&allprison_lock); | ||||
slocked = PD_LIST_SLOCKED; | goto done_remove; | ||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | |||||
} | } | ||||
prison_deref(pr, created | prison_deref(pr, PD_DEREF); | ||||
? slocked | |||||
: PD_DEREF | slocked); | |||||
goto done_errmsg; | goto done_errmsg; | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
td->td_retval[0] = pr->pr_id; | td->td_retval[0] = pr->pr_id; | ||||
/* | /* | ||||
* Now that it is all there, drop the temporary reference from existing | * Now that everything is done, the prison is usually alive, though | ||||
* prisons. Or add a reference to newly created persistent prisons | * it might have been either new (invalid) or dying before. Drop | ||||
* (which was not done earlier so that the prison would not be publicly | * the temporary reference before returning. | ||||
* visible). | |||||
*/ | */ | ||||
if (!created) | mtx_lock(&pr->pr_mtx); | ||||
prison_deref(pr, PD_DEREF | slocked); | if (pr->pr_uref > 0) | ||||
else { | pr->pr_state = PRISON_STATE_ALIVE; | ||||
if (pr_flags & PR_PERSIST) { | prison_deref(pr, PD_DEREF | PD_LOCKED | slocked); | ||||
mtx_lock(&pr->pr_mtx); | |||||
pr->pr_ref++; | |||||
pr->pr_uref++; | |||||
mtx_unlock(&pr->pr_mtx); | |||||
} | |||||
if (slocked) | |||||
sx_sunlock(&allprison_lock); | |||||
} | |||||
goto done_free; | goto done_free; | ||||
done_deref_locked: | done_deref_locked: | ||||
prison_deref(pr, created | prison_deref(pr, PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); | ||||
? PD_LOCKED | PD_LIST_XLOCKED | |||||
: PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); | |||||
goto done_releroot; | goto done_releroot; | ||||
done_remove: | |||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | |||||
mtx_lock(&pr->pr_mtx); | |||||
if (pr->pr_flags & PR_PERSIST) { | |||||
pr->pr_flags &= ~PR_PERSIST; | |||||
pr->pr_ref--; | |||||
prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LOCKED | | |||||
PD_LIST_SLOCKED); | |||||
} else | |||||
prison_deref(pr, PD_DEREF | PD_LOCKED | PD_LIST_SLOCKED); | |||||
goto done_errmsg; | |||||
done_unlock_list: | done_unlock_list: | ||||
sx_xunlock(&allprison_lock); | sx_xunlock(&allprison_lock); | ||||
done_releroot: | done_releroot: | ||||
Context not available. | |||||
if (pr->pr_id > jid && prison_ischild(mypr, pr)) { | if (pr->pr_id > jid && prison_ischild(mypr, pr)) { | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
if (pr->pr_ref > 0 && | if (pr->pr_ref > 0 && | ||||
(pr->pr_uref > 0 || (flags & JAIL_DYING))) | (pr->pr_state == PRISON_STATE_ALIVE || | ||||
(pr->pr_state == PRISON_STATE_DYING && | |||||
(flags & JAIL_DYING)))) | |||||
break; | break; | ||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
} | } | ||||
Context not available. | |||||
if (jid != 0) { | if (jid != 0) { | ||||
pr = prison_find_child(mypr, jid); | pr = prison_find_child(mypr, jid); | ||||
if (pr != NULL) { | if (pr != NULL) { | ||||
if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { | if (pr->pr_state == PRISON_STATE_DYING && | ||||
!(flags & JAIL_DYING)) { | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, "jail %d is dying", | vfs_opterror(opts, "jail %d is dying", | ||||
Context not available. | |||||
} | } | ||||
pr = prison_find_name(mypr, name); | pr = prison_find_name(mypr, name); | ||||
if (pr != NULL) { | if (pr != NULL) { | ||||
if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { | if (pr->pr_state == PRISON_STATE_DYING && | ||||
!(flags & JAIL_DYING)) { | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, "jail \"%s\" is dying", | vfs_opterror(opts, "jail \"%s\" is dying", | ||||
Context not available. | |||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
i = (pr->pr_uref == 0); | i = pr->pr_state == PRISON_STATE_DYING; | ||||
error = vfs_setopt(opts, "dying", &i, sizeof(i)); | error = vfs_setopt(opts, "dying", &i, sizeof(i)); | ||||
if (error != 0 && error != ENOENT) | if (error != 0 && error != ENOENT) | ||||
goto done_deref; | goto done_deref; | ||||
Context not available. | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* | /* Do not allow a process to attach to a prison that is not alive. */ | ||||
* Do not allow a process to attach to a prison that is not | if (pr->pr_state != PRISON_STATE_ALIVE) { | ||||
* considered to be "alive". | |||||
*/ | |||||
if (pr->pr_uref == 0) { | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
sx_sunlock(&allprison_lock); | sx_sunlock(&allprison_lock); | ||||
return (EINVAL); | return (EINVAL); | ||||
Context not available. | |||||
TAILQ_FOREACH(pr, &allprison, pr_list) { | TAILQ_FOREACH(pr, &allprison, pr_list) { | ||||
if (pr->pr_id == prid) { | if (pr->pr_id == prid) { | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
if (pr->pr_ref > 0) | if (pr->pr_ref > 0 && | ||||
pr->pr_state != PRISON_STATE_INVALID) | |||||
return (pr); | return (pr); | ||||
/* | /* | ||||
* Any active prison with the same ID would have | * Any active prison with the same ID would have | ||||
Context not available. | |||||
FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { | FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { | ||||
if (pr->pr_id == prid) { | if (pr->pr_id == prid) { | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
if (pr->pr_ref > 0) | if (pr->pr_ref > 0 && | ||||
pr->pr_state != PRISON_STATE_INVALID) | |||||
return (pr); | return (pr); | ||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
} | } | ||||
Context not available. | |||||
FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { | FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { | ||||
if (!strcmp(pr->pr_name + mylen, name)) { | if (!strcmp(pr->pr_name + mylen, name)) { | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
if (pr->pr_ref > 0) { | if (pr->pr_ref > 0 && | ||||
if (pr->pr_uref > 0) | pr->pr_state != PRISON_STATE_INVALID) { | ||||
if (pr->pr_state == PRISON_STATE_ALIVE) | |||||
return (pr); | return (pr); | ||||
deadpr = pr; | deadpr = pr; | ||||
} | } | ||||
Context not available. | |||||
("prison_deref PD_DEUREF on a dead prison (jid=%d)", | ("prison_deref PD_DEUREF on a dead prison (jid=%d)", | ||||
pr->pr_id)); | pr->pr_id)); | ||||
pr->pr_uref--; | pr->pr_uref--; | ||||
lasturef = pr->pr_uref == 0; | |||||
if (lasturef) | |||||
pr->pr_ref++; | |||||
KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0")); | KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0")); | ||||
} else | } | ||||
lasturef = 0; | lasturef = pr->pr_uref == 0 && | ||||
pr->pr_state == PRISON_STATE_ALIVE; | |||||
if (lasturef) { | |||||
pr->pr_ref++; | |||||
pr->pr_state = PRISON_STATE_DYING; | |||||
} | |||||
if (flags & PD_DEREF) { | if (flags & PD_DEREF) { | ||||
KASSERT(pr->pr_ref > 0, | KASSERT(pr->pr_ref > 0, | ||||
("prison_deref PD_DEREF on a dead prison (jid=%d)", | ("prison_deref PD_DEREF on a dead prison (jid=%d)", | ||||
Context not available. | |||||
cpr->pr_ip6s * sizeof(struct in6_addr)); | cpr->pr_ip6s * sizeof(struct in6_addr)); | ||||
} | } | ||||
#endif | #endif | ||||
if (cpr->pr_ref == 0) { | if (cpr->pr_ref == 0 || cpr->pr_state == PRISON_STATE_INVALID) { | ||||
mtx_unlock(&cpr->pr_mtx); | mtx_unlock(&cpr->pr_mtx); | ||||
continue; | continue; | ||||
} | } | ||||
bzero(xp, sizeof(*xp)); | bzero(xp, sizeof(*xp)); | ||||
xp->pr_version = XPRISON_VERSION; | xp->pr_version = XPRISON_VERSION; | ||||
xp->pr_id = cpr->pr_id; | xp->pr_id = cpr->pr_id; | ||||
xp->pr_state = cpr->pr_uref > 0 | xp->pr_state = cpr->pr_state; | ||||
? PRISON_STATE_ALIVE : PRISON_STATE_DYING; | |||||
strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); | strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); | ||||
strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); | strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); | ||||
strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); | strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); | ||||
Context not available. | |||||
db_printf(" parent = %p\n", pr->pr_parent); | db_printf(" parent = %p\n", pr->pr_parent); | ||||
db_printf(" ref = %d\n", pr->pr_ref); | db_printf(" ref = %d\n", pr->pr_ref); | ||||
db_printf(" uref = %d\n", pr->pr_uref); | db_printf(" uref = %d\n", pr->pr_uref); | ||||
db_printf(" state = %d\n", pr->pr_state); | |||||
db_printf(" path = %s\n", pr->pr_path); | db_printf(" path = %s\n", pr->pr_path); | ||||
db_printf(" cpuset = %d\n", pr->pr_cpuset | db_printf(" cpuset = %d\n", pr->pr_cpuset | ||||
? pr->pr_cpuset->cs_id : -1); | ? pr->pr_cpuset->cs_id : -1); | ||||
Context not available. |