13b31921jamie/*-
27551d83pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37551d83pfg *
48d425bfjamie * Copyright (c) 2011 James Gritton
53b31921jamie * All rights reserved.
63b31921jamie *
73b31921jamie * Redistribution and use in source and binary forms, with or without
83b31921jamie * modification, are permitted provided that the following conditions
93b31921jamie * are met:
103b31921jamie * 1. Redistributions of source code must retain the above copyright
113b31921jamie *    notice, this list of conditions and the following disclaimer.
123b31921jamie * 2. Redistributions in binary form must reproduce the above copyright
133b31921jamie *    notice, this list of conditions and the following disclaimer in the
143b31921jamie *    documentation and/or other materials provided with the distribution.
153b31921jamie *
163b31921jamie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b31921jamie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b31921jamie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b31921jamie * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b31921jamie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b31921jamie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b31921jamie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b31921jamie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b31921jamie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b31921jamie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b31921jamie * SUCH DAMAGE.
273b31921jamie */
283b31921jamie
293b31921jamie#include <sys/cdefs.h>
303b31921jamie__FBSDID("$FreeBSD$");
313b31921jamie
323b31921jamie#include <sys/uio.h>
333b31921jamie
343b31921jamie#include <err.h>
353b31921jamie#include <stdlib.h>
363b31921jamie#include <string.h>
373b31921jamie
383b31921jamie#include "jailp.h"
393b31921jamie
403b31921jamiestruct cfjails ready = TAILQ_HEAD_INITIALIZER(ready);
413a156b8jamiestruct cfjails depend = TAILQ_HEAD_INITIALIZER(depend);
423b31921jamie
433b31921jamiestatic void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags);
443b31921jamiestatic int cmp_jailptr(const void *a, const void *b);
453b31921jamiestatic int cmp_jailptr_name(const void *a, const void *b);
463b31921jamiestatic struct cfjail *find_jail(const char *name);
47fd4e870mizhkastatic struct cfjail *running_jail(const char *name, int flags);
483b31921jamie
493b31921jamiestatic struct cfjail **jails_byname;
503b31921jamiestatic size_t njails;
513b31921jamie
523b31921jamie/*
533b31921jamie * Set up jail dependency lists.
543b31921jamie */
553b31921jamievoid
563b31921jamiedep_setup(int docf)
573b31921jamie{
583b31921jamie	struct cfjail *j, *dj;
593b31921jamie	struct cfparam *p;
603b31921jamie	struct cfstring *s;
613b31921jamie	struct cfdepend *d;
623b31921jamie	const char *cs;
633b31921jamie	char *pname;
643b31921jamie	size_t plen;
658665489jamie	int deps, ldeps;
663b31921jamie
673b31921jamie	if (!docf) {
683b31921jamie		/*
693b31921jamie		 * With no config file, let "depend" for a single jail
703b31921jamie		 * look at currently running jails.
713b31921jamie		 */
723b31921jamie		if ((j = TAILQ_FIRST(&cfjails)) &&
733b31921jamie		    (p = j->intparams[IP_DEPEND])) {
740e5ec9djamie			TAILQ_FOREACH(s, &p->val, tq) {
75fd4e870mizhka				if (running_jail(s->s, 0) == NULL) {
763b31921jamie					warnx("depends on nonexistent jail "
773b31921jamie					    "\"%s\"", s->s);
783b31921jamie					j->flags |= JF_FAILED;
793b31921jamie				}
803b31921jamie			}
813b31921jamie		}
823b31921jamie		return;
833b31921jamie	}
843b31921jamie
853b31921jamie	njails = 0;
863b31921jamie	TAILQ_FOREACH(j, &cfjails, tq)
873b31921jamie		njails++;
883b31921jamie	jails_byname = emalloc(njails * sizeof(struct cfjail *));
893b31921jamie	njails = 0;
903b31921jamie	TAILQ_FOREACH(j, &cfjails, tq)
913b31921jamie		jails_byname[njails++] = j;
923b31921jamie	qsort(jails_byname, njails, sizeof(struct cfjail *), cmp_jailptr);
933b31921jamie	deps = 0;
943b31921jamie	ldeps = 0;
953b31921jamie	plen = 0;
963b31921jamie	pname = NULL;
973b31921jamie	TAILQ_FOREACH(j, &cfjails, tq) {
983b31921jamie		if (j->flags & JF_FAILED)
993b31921jamie			continue;
1003b31921jamie		if ((p = j->intparams[IP_DEPEND])) {
1010e5ec9djamie			TAILQ_FOREACH(s, &p->val, tq) {
1023b31921jamie				dj = find_jail(s->s);
1033b31921jamie				if (dj != NULL) {
1043b31921jamie					deps++;
1053b31921jamie					dep_add(j, dj, 0);
1063b31921jamie				} else {
1073b31921jamie					jail_warnx(j,
1083b31921jamie					    "depends on undefined jail \"%s\"",
1093b31921jamie					    s->s);
1103b31921jamie					j->flags |= JF_FAILED;
1113b31921jamie				}
1123b31921jamie			}
1133b31921jamie		}
1143b31921jamie		/* A jail has an implied dependency on its parent. */
1153b31921jamie		if ((cs = strrchr(j->name, '.')))
1163b31921jamie		{
1173b31921jamie			if (plen < (size_t)(cs - j->name + 1)) {
1183b31921jamie				plen = (cs - j->name) + 1;
1193b31921jamie				pname = erealloc(pname, plen);
1203b31921jamie			}
1213b31921jamie			strlcpy(pname, j->name, plen);
1223b31921jamie			dj = find_jail(pname);
1233b31921jamie			if (dj != NULL) {
1243b31921jamie				ldeps++;
1253b31921jamie				dep_add(j, dj, DF_LIGHT);
1263b31921jamie			}
1273b31921jamie		}
1283b31921jamie	}
1293b31921jamie
1303b31921jamie	/* Look for dependency loops. */
1313b31921jamie	if (deps && (deps > 1 || ldeps)) {
132a85d762jamie		(void)start_state(NULL, 0, 0, 0);
1333b31921jamie		while ((j = TAILQ_FIRST(&ready))) {
1343b31921jamie			requeue(j, &cfjails);
1353b31921jamie			dep_done(j, DF_NOFAIL);
1363b31921jamie		}
1373a156b8jamie		while ((j = TAILQ_FIRST(&depend)) != NULL) {
1383b31921jamie			jail_warnx(j, "dependency loop");
1393b31921jamie			j->flags |= JF_FAILED;
1403b31921jamie			do {
1413b31921jamie				requeue(j, &cfjails);
1423b31921jamie				dep_done(j, DF_NOFAIL);
1433b31921jamie			} while ((j = TAILQ_FIRST(&ready)));
1443b31921jamie		}
1453b31921jamie		TAILQ_FOREACH(j, &cfjails, tq)
1463b31921jamie			STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM])
1473b31921jamie				d->flags &= ~DF_SEEN;
1483b31921jamie	}
1493b31921jamie	if (pname != NULL)
1503b31921jamie		free(pname);
1513b31921jamie}
1523b31921jamie
1533b31921jamie/*
1543b31921jamie * Return if a jail has dependencies.
1553b31921jamie */
1563b31921jamieint
1573b31921jamiedep_check(struct cfjail *j)
1583b31921jamie{
1593b31921jamie	int reset, depfrom, depto, ndeps, rev;
1603b31921jamie	struct cfjail *dj;
1613b31921jamie	struct cfdepend *d;
1623b31921jamie
1633b31921jamie	static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
1643b31921jamie
1653b31921jamie	if (j->ndeps == 0)
1663b31921jamie		return 0;
1673b31921jamie	ndeps = 0;
1683b31921jamie	if ((rev = JF_DO_STOP(j->flags))) {
1693b31921jamie		depfrom = DEP_TO;
1703b31921jamie		depto = DEP_FROM;
1713b31921jamie	} else {
1723b31921jamie		depfrom = DEP_FROM;
1733b31921jamie		depto = DEP_TO;
1743b31921jamie	}
1753b31921jamie	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) {
1763b31921jamie		if (d->flags & DF_SEEN)
1773b31921jamie			continue;
1783b31921jamie		dj = d->j[depto];
1793b31921jamie		if (dj->flags & JF_FAILED) {
1803b31921jamie			if (!(j->flags & (JF_DEPEND | JF_FAILED)) &&
1813b31921jamie			    verbose >= 0)
1823b31921jamie				jail_warnx(j, "skipped");
1833b31921jamie			j->flags |= JF_FAILED;
1843b31921jamie			continue;
1853b31921jamie		}
1863b31921jamie		/*
1873b31921jamie		 * The dependee's state may be set (or changed) as a result of
1883b31921jamie		 * being in a dependency it wasn't in earlier.
1893b31921jamie		 */
1903b31921jamie		reset = 0;
1913b31921jamie		if (bits[dj->flags & JF_OP_MASK] <= 1) {
1923b31921jamie			if (!(dj->flags & JF_OP_MASK)) {
1933b31921jamie				reset = 1;
1943b31921jamie				dj->flags |= JF_DEPEND;
1953b31921jamie				requeue(dj, &ready);
1963b31921jamie			}
1973b31921jamie			/* Set or change the dependee's state. */
1983b31921jamie			switch (j->flags & JF_OP_MASK) {
1993b31921jamie			case JF_START:
2003b31921jamie				dj->flags |= JF_START;
2013b31921jamie				break;
2023b31921jamie			case JF_SET:
2033b31921jamie				if (!(dj->flags & JF_OP_MASK))
2043b31921jamie					dj->flags |= JF_SET;
2053b31921jamie				else if (dj->flags & JF_STOP)
2063b31921jamie					dj->flags |= JF_START;
2073b31921jamie				break;
2083b31921jamie			case JF_STOP:
2093b31921jamie			case JF_RESTART:
2103b31921jamie				if (!(dj->flags & JF_STOP))
2113b31921jamie					reset = 1;
2123b31921jamie				dj->flags |= JF_STOP;
2133b31921jamie				if (dj->flags & JF_SET)
2143b31921jamie					dj->flags ^= (JF_START | JF_SET);
2153b31921jamie				break;
2163b31921jamie			}
2173b31921jamie		}
2183b31921jamie		if (reset)
2193b31921jamie			dep_reset(dj);
2203b31921jamie		if (!((d->flags & DF_LIGHT) &&
2213b31921jamie		    (rev ? dj->jid < 0 : dj->jid > 0)))
2223b31921jamie			ndeps++;
2233b31921jamie	}
2243b31921jamie	if (ndeps == 0)
2253b31921jamie		return 0;
2263a156b8jamie	requeue(j, &depend);
2273b31921jamie	return 1;
2283b31921jamie}
2293b31921jamie
2303b31921jamie/*
2313b31921jamie * Resolve any dependencies from a finished jail.
2323b31921jamie */
2333b31921jamievoid
2343b31921jamiedep_done(struct cfjail *j, unsigned flags)
2353b31921jamie{
2363b31921jamie	struct cfjail *dj;
2373b31921jamie	struct cfdepend *d;
2383b31921jamie	int depfrom, depto;
2393b31921jamie
2403b31921jamie	if (JF_DO_STOP(j->flags)) {
2413b31921jamie		depfrom = DEP_TO;
2423b31921jamie		depto = DEP_FROM;
2433b31921jamie	} else {
2443b31921jamie		depfrom = DEP_FROM;
2453b31921jamie		depto = DEP_TO;
2463b31921jamie	}
2473b31921jamie	STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) {
2483b31921jamie		if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT))
2493b31921jamie			continue;
2503b31921jamie		d->flags |= DF_SEEN;
2513b31921jamie		dj = d->j[depfrom];
2523b31921jamie		if (!(flags & DF_NOFAIL) && (j->flags & JF_FAILED) &&
2533b31921jamie		    (j->flags & (JF_OP_MASK | JF_DEPEND)) !=
2543b31921jamie		    (JF_SET | JF_DEPEND)) {
2553b31921jamie			if (!(dj->flags & (JF_DEPEND | JF_FAILED)) &&
2563b31921jamie			    verbose >= 0)
2573b31921jamie				jail_warnx(dj, "skipped");
2583b31921jamie			dj->flags |= JF_FAILED;
2593b31921jamie		}
2603a156b8jamie		if (!--dj->ndeps && dj->queue == &depend)
2613b31921jamie			requeue(dj, &ready);
2623b31921jamie	}
2633b31921jamie}
2643b31921jamie
2653b31921jamie/*
2663b31921jamie * Count a jail's dependencies and mark them as unseen.
2673b31921jamie */
2683b31921jamievoid
2693b31921jamiedep_reset(struct cfjail *j)
2703b31921jamie{
2713b31921jamie	int depfrom;
2723b31921jamie	struct cfdepend *d;
2733b31921jamie
2743b31921jamie	depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM;
2753b31921jamie	j->ndeps = 0;
2763b31921jamie	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom])
2773b31921jamie		j->ndeps++;
2783b31921jamie}
2793b31921jamie
2803b31921jamie/*
2813b31921jamie * Find the next jail ready to do something.
2823b31921jamie */
2833b31921jamiestruct cfjail *
2843b31921jamienext_jail(void)
2853b31921jamie{
2863b31921jamie	struct cfjail *j;
2873b31921jamie
2883b31921jamie	if (!(j = next_proc(!TAILQ_EMPTY(&ready))) &&
2893b31921jamie	    (j = TAILQ_FIRST(&ready)) && JF_DO_STOP(j->flags) &&
2903b31921jamie	    (j = TAILQ_LAST(&ready, cfjails)) && !JF_DO_STOP(j->flags)) {
2913b31921jamie		TAILQ_FOREACH_REVERSE(j, &ready, cfjails, tq)
2923b31921jamie			if (JF_DO_STOP(j->flags))
2933b31921jamie				break;
2943b31921jamie	}
2953b31921jamie	if (j != NULL)
2963b31921jamie		requeue(j, &cfjails);
2973b31921jamie	return j;
2983b31921jamie}
2993b31921jamie
3003b31921jamie/*
3013b31921jamie * Set jails to the proper start state.
3023b31921jamie */
3033b31921jamieint
304a85d762jamiestart_state(const char *target, int docf, unsigned state, int running)
3053b31921jamie{
3063b31921jamie	struct iovec jiov[6];
3073b31921jamie	struct cfjail *j, *tj;
3083b31921jamie	int jid;
3093b31921jamie	char namebuf[MAXHOSTNAMELEN];
3103b31921jamie
311a85d762jamie	if (!target || (!docf && state != JF_STOP) ||
312a85d762jamie	    (!running && !strcmp(target, "*"))) {
3133b31921jamie		/*
314a85d762jamie		 * For a global wildcard (including no target specified),
315a85d762jamie		 * set the state on all jails and start with those that
316a85d762jamie		 * have no dependencies.
3173b31921jamie		 */
3183b31921jamie		TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
319a85d762jamie			j->flags = (j->flags & JF_FAILED) | state |
320a85d762jamie			    (docf ? JF_WILD : 0);
3213b31921jamie			dep_reset(j);
3223a156b8jamie			requeue(j, j->ndeps ? &depend : &ready);
3233b31921jamie		}
3243b31921jamie	} else if (wild_jail_name(target)) {
3253b31921jamie		/*
3263b31921jamie		 * For targets specified singly, or with a non-global wildcard,
3273b31921jamie		 * set their state and call them ready (even if there are
3283b31921jamie		 * dependencies).  Leave everything else unqueued for now.
3293b31921jamie		 */
3303b31921jamie		if (running) {
3313b31921jamie			/*
3323b31921jamie			 * -R matches its wildcards against currently running
3333b31921jamie			 * jails, not against the config file.
3343b31921jamie			 */
3358665489jamie			jiov[0].iov_base = __DECONST(char *, "lastjid");
3363b31921jamie			jiov[0].iov_len = sizeof("lastjid");
3373b31921jamie			jiov[1].iov_base = &jid;
3383b31921jamie			jiov[1].iov_len = sizeof(jid);
3398665489jamie			jiov[2].iov_base = __DECONST(char *, "jid");
3403b31921jamie			jiov[2].iov_len = sizeof("jid");
3413b31921jamie			jiov[3].iov_base = &jid;
3423b31921jamie			jiov[3].iov_len = sizeof(jid);
3438665489jamie			jiov[4].iov_base = __DECONST(char *, "name");
3443b31921jamie			jiov[4].iov_len = sizeof("name");
3453b31921jamie			jiov[5].iov_base = &namebuf;
3463b31921jamie			jiov[5].iov_len = sizeof(namebuf);
3473b31921jamie			for (jid = 0; jail_get(jiov, 6, 0) > 0; ) {
3483b31921jamie				if (wild_jail_match(namebuf, target)) {
3493b31921jamie					j = add_jail();
3503b31921jamie					j->name = estrdup(namebuf);
3513b31921jamie					j->jid = jid;
3523b31921jamie					j->flags = (j->flags & JF_FAILED) |
3533b31921jamie					    state | JF_WILD;
3543b31921jamie					dep_reset(j);
3553b31921jamie					requeue(j, &ready);
3563b31921jamie				}
3573b31921jamie			}
3583b31921jamie		} else {
3593b31921jamie			TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
3603b31921jamie				if (wild_jail_match(j->name, target)) {
3613b31921jamie					j->flags = (j->flags & JF_FAILED) |
3623b31921jamie					    state | JF_WILD;
3633b31921jamie					dep_reset(j);
3643b31921jamie					requeue(j, &ready);
3653b31921jamie				}
3663b31921jamie			}
3673b31921jamie		}
3683b31921jamie	} else {
3693b31921jamie		j = find_jail(target);
3703b31921jamie		if (j == NULL && state == JF_STOP) {
3713b31921jamie			/* Allow -[rR] to specify a currently running jail. */
372fd4e870mizhka			j = running_jail(target, JAIL_DYING);
3733b31921jamie		}
3743b31921jamie		if (j == NULL) {
3753b31921jamie			warnx("\"%s\" not found", target);
3763b31921jamie			return -1;
3773b31921jamie		}
3783b31921jamie		j->flags = (j->flags & JF_FAILED) | state;
3793b31921jamie		dep_reset(j);
3803b31921jamie		requeue(j, &ready);
3813b31921jamie	}
3823b31921jamie	return 0;
3833b31921jamie}
3843b31921jamie
3853b31921jamie/*
3863b31921jamie * Move a jail to a new list.
3873b31921jamie */
3883b31921jamievoid
3893b31921jamierequeue(struct cfjail *j, struct cfjails *queue)
3903b31921jamie{
3913b31921jamie	if (j->queue != queue) {
3923b31921jamie		TAILQ_REMOVE(j->queue, j, tq);
3933b31921jamie		TAILQ_INSERT_TAIL(queue, j, tq);
3943b31921jamie		j->queue = queue;
3953b31921jamie	}
3963b31921jamie}
3973b31921jamie
3980e8a4f4jamievoid
3990e8a4f4jamierequeue_head(struct cfjail *j, struct cfjails *queue)
4000e8a4f4jamie{
4010e8a4f4jamie    TAILQ_REMOVE(j->queue, j, tq);
4020e8a4f4jamie    TAILQ_INSERT_HEAD(queue, j, tq);
4030e8a4f4jamie    j->queue = queue;
4040e8a4f4jamie}
4050e8a4f4jamie
4063b31921jamie/*
4073b31921jamie * Add a dependency edge between two jails.
4083b31921jamie */
4093b31921jamiestatic void
4103b31921jamiedep_add(struct cfjail *from, struct cfjail *to, unsigned flags)
4113b31921jamie{
4123b31921jamie	struct cfdepend *d;
4133b31921jamie
4143b31921jamie	d = emalloc(sizeof(struct cfdepend));
4153b31921jamie	d->flags = flags;
4163b31921jamie	d->j[DEP_FROM] = from;
4173b31921jamie	d->j[DEP_TO] = to;
4183b31921jamie	STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]);
4193b31921jamie	STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]);
4203b31921jamie}
4213b31921jamie
4223b31921jamie/*
4233b31921jamie * Compare jail pointers for qsort/bsearch.
4243b31921jamie */
4253b31921jamiestatic int
4263b31921jamiecmp_jailptr(const void *a, const void *b)
4273b31921jamie{
4283b31921jamie	return strcmp((*((struct cfjail * const *)a))->name,
4293b31921jamie	    ((*(struct cfjail * const *)b))->name);
4303b31921jamie}
4313b31921jamie
4323b31921jamiestatic int
4333b31921jamiecmp_jailptr_name(const void *a, const void *b)
4343b31921jamie{
4353b31921jamie	return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name);
4363b31921jamie}
4373b31921jamie
4383b31921jamie/*
4393b31921jamie * Find a jail object by name.
4403b31921jamie */
4413b31921jamiestatic struct cfjail *
4423b31921jamiefind_jail(const char *name)
4433b31921jamie{
4443b31921jamie	struct cfjail **jp;
445fd4e870mizhka
446fd4e870mizhka	if (jails_byname == NULL)
447fd4e870mizhka		return NULL;
4483b31921jamie
4493b31921jamie	jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *),
4503b31921jamie	    cmp_jailptr_name);
4513b31921jamie	return jp ? *jp : NULL;
4523b31921jamie}
4533b31921jamie
4543b31921jamie/*
455fd4e870mizhka * Return jail if it is running, and NULL if it isn't.
4563b31921jamie */
457fd4e870mizhkastatic struct cfjail *
458fd4e870mizhkarunning_jail(const char *name, int flags)
4593b31921jamie{
460fd4e870mizhka	struct iovec jiov[4];
461fd4e870mizhka	struct cfjail *jail;
4623b31921jamie	char *ep;
463fd4e870mizhka	char jailname[MAXHOSTNAMELEN];
464fd4e870mizhka	int jid, ret, len;
465fd4e870mizhka
4663b31921jamie	if ((jid = strtol(name, &ep, 10)) && !*ep) {
467fd4e870mizhka		memset(jailname,0,sizeof(jailname));
468fd4e870mizhka		len = sizeof(jailname);
4693b31921jamie	} else {
470fd4e870mizhka		strncpy(jailname, name,sizeof(jailname));
471fd4e870mizhka		len = strlen(name) + 1;
472fd4e870mizhka		jid = 0;
473fd4e870mizhka	}
474fd4e870mizhka
475fd4e870mizhka	jiov[0].iov_base = __DECONST(char *, "jid");
476fd4e870mizhka	jiov[0].iov_len = sizeof("jid");
477fd4e870mizhka	jiov[1].iov_base = &jid;
478fd4e870mizhka	jiov[1].iov_len = sizeof(jid);
479fd4e870mizhka	jiov[2].iov_base = __DECONST(char *, "name");
480fd4e870mizhka	jiov[2].iov_len = sizeof("name");
481fd4e870mizhka	jiov[3].iov_base = &jailname;
482fd4e870mizhka	jiov[3].iov_len = len;
483fd4e870mizhka
484fd4e870mizhka	if ((ret = jail_get(jiov, 4, flags)) < 0)
485fd4e870mizhka		return (NULL);
486fd4e870mizhka
487fd4e870mizhka	if ((jail = find_jail(jailname)) == NULL) {
488fd4e870mizhka		jail = add_jail();
489fd4e870mizhka		jail->name = estrdup(jailname);
490fd4e870mizhka		jail->jid = ret;
4913b31921jamie	}
492fd4e870mizhka
493fd4e870mizhka	return (jail);
4943b31921jamie}
495