xref: /freebsd/usr.sbin/jail/state.c (revision d50685b303e3353aa1aeaea022a80f31e3732a29)
12671ee73SJamie Gritton /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4d8352076SJamie Gritton  * Copyright (c) 2011 James Gritton
52671ee73SJamie Gritton  * All rights reserved.
62671ee73SJamie Gritton  *
72671ee73SJamie Gritton  * Redistribution and use in source and binary forms, with or without
82671ee73SJamie Gritton  * modification, are permitted provided that the following conditions
92671ee73SJamie Gritton  * are met:
102671ee73SJamie Gritton  * 1. Redistributions of source code must retain the above copyright
112671ee73SJamie Gritton  *    notice, this list of conditions and the following disclaimer.
122671ee73SJamie Gritton  * 2. Redistributions in binary form must reproduce the above copyright
132671ee73SJamie Gritton  *    notice, this list of conditions and the following disclaimer in the
142671ee73SJamie Gritton  *    documentation and/or other materials provided with the distribution.
152671ee73SJamie Gritton  *
162671ee73SJamie Gritton  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172671ee73SJamie Gritton  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182671ee73SJamie Gritton  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192671ee73SJamie Gritton  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202671ee73SJamie Gritton  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212671ee73SJamie Gritton  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222671ee73SJamie Gritton  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232671ee73SJamie Gritton  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242671ee73SJamie Gritton  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252671ee73SJamie Gritton  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262671ee73SJamie Gritton  * SUCH DAMAGE.
272671ee73SJamie Gritton  */
282671ee73SJamie Gritton 
292671ee73SJamie Gritton #include <sys/cdefs.h>
302671ee73SJamie Gritton #include <sys/uio.h>
312671ee73SJamie Gritton 
322671ee73SJamie Gritton #include <err.h>
332671ee73SJamie Gritton #include <stdlib.h>
342671ee73SJamie Gritton #include <string.h>
352671ee73SJamie Gritton 
362671ee73SJamie Gritton #include "jailp.h"
372671ee73SJamie Gritton 
382671ee73SJamie Gritton struct cfjails ready = TAILQ_HEAD_INITIALIZER(ready);
39aa02af54SJamie Gritton struct cfjails depend = TAILQ_HEAD_INITIALIZER(depend);
402671ee73SJamie Gritton 
412671ee73SJamie Gritton static void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags);
422671ee73SJamie Gritton static int cmp_jailptr(const void *a, const void *b);
432671ee73SJamie Gritton static int cmp_jailptr_name(const void *a, const void *b);
442671ee73SJamie Gritton static struct cfjail *find_jail(const char *name);
45cd38a86cSMichael Zhilin static struct cfjail *running_jail(const char *name, int flags);
462671ee73SJamie Gritton 
472671ee73SJamie Gritton static struct cfjail **jails_byname;
482671ee73SJamie Gritton static size_t njails;
492671ee73SJamie Gritton 
502671ee73SJamie Gritton /*
512671ee73SJamie Gritton  * Set up jail dependency lists.
522671ee73SJamie Gritton  */
532671ee73SJamie Gritton void
dep_setup(int docf)542671ee73SJamie Gritton dep_setup(int docf)
552671ee73SJamie Gritton {
562671ee73SJamie Gritton 	struct cfjail *j, *dj;
572671ee73SJamie Gritton 	struct cfparam *p;
582671ee73SJamie Gritton 	struct cfstring *s;
592671ee73SJamie Gritton 	struct cfdepend *d;
602671ee73SJamie Gritton 	const char *cs;
612671ee73SJamie Gritton 	char *pname;
622671ee73SJamie Gritton 	size_t plen;
63d031802bSJamie Gritton 	int deps, ldeps;
642671ee73SJamie Gritton 
652671ee73SJamie Gritton 	if (!docf) {
662671ee73SJamie Gritton 		/*
672671ee73SJamie Gritton 		 * With no config file, let "depend" for a single jail
682671ee73SJamie Gritton 		 * look at currently running jails.
692671ee73SJamie Gritton 		 */
702671ee73SJamie Gritton 		if ((j = TAILQ_FIRST(&cfjails)) &&
712671ee73SJamie Gritton 		    (p = j->intparams[IP_DEPEND])) {
722a194551SJamie Gritton 			TAILQ_FOREACH(s, &p->val, tq) {
73cd38a86cSMichael Zhilin 				if (running_jail(s->s, 0) == NULL) {
742671ee73SJamie Gritton 					warnx("depends on nonexistent jail "
752671ee73SJamie Gritton 					    "\"%s\"", s->s);
762671ee73SJamie Gritton 					j->flags |= JF_FAILED;
772671ee73SJamie Gritton 				}
782671ee73SJamie Gritton 			}
792671ee73SJamie Gritton 		}
802671ee73SJamie Gritton 		return;
812671ee73SJamie Gritton 	}
822671ee73SJamie Gritton 
832671ee73SJamie Gritton 	njails = 0;
842671ee73SJamie Gritton 	TAILQ_FOREACH(j, &cfjails, tq)
852671ee73SJamie Gritton 		njails++;
862671ee73SJamie Gritton 	jails_byname = emalloc(njails * sizeof(struct cfjail *));
872671ee73SJamie Gritton 	njails = 0;
882671ee73SJamie Gritton 	TAILQ_FOREACH(j, &cfjails, tq)
892671ee73SJamie Gritton 		jails_byname[njails++] = j;
902671ee73SJamie Gritton 	qsort(jails_byname, njails, sizeof(struct cfjail *), cmp_jailptr);
912671ee73SJamie Gritton 	deps = 0;
922671ee73SJamie Gritton 	ldeps = 0;
932671ee73SJamie Gritton 	plen = 0;
942671ee73SJamie Gritton 	pname = NULL;
952671ee73SJamie Gritton 	TAILQ_FOREACH(j, &cfjails, tq) {
962671ee73SJamie Gritton 		if (j->flags & JF_FAILED)
972671ee73SJamie Gritton 			continue;
982671ee73SJamie Gritton 		if ((p = j->intparams[IP_DEPEND])) {
992a194551SJamie Gritton 			TAILQ_FOREACH(s, &p->val, tq) {
1002671ee73SJamie Gritton 				dj = find_jail(s->s);
1012671ee73SJamie Gritton 				if (dj != NULL) {
1022671ee73SJamie Gritton 					deps++;
1032671ee73SJamie Gritton 					dep_add(j, dj, 0);
1042671ee73SJamie Gritton 				} else {
1052671ee73SJamie Gritton 					jail_warnx(j,
1062671ee73SJamie Gritton 					    "depends on undefined jail \"%s\"",
1072671ee73SJamie Gritton 					    s->s);
1082671ee73SJamie Gritton 					j->flags |= JF_FAILED;
1092671ee73SJamie Gritton 				}
1102671ee73SJamie Gritton 			}
1112671ee73SJamie Gritton 		}
1122671ee73SJamie Gritton 		/* A jail has an implied dependency on its parent. */
1132671ee73SJamie Gritton 		if ((cs = strrchr(j->name, '.')))
1142671ee73SJamie Gritton 		{
1152671ee73SJamie Gritton 			if (plen < (size_t)(cs - j->name + 1)) {
1162671ee73SJamie Gritton 				plen = (cs - j->name) + 1;
1172671ee73SJamie Gritton 				pname = erealloc(pname, plen);
1182671ee73SJamie Gritton 			}
1192671ee73SJamie Gritton 			strlcpy(pname, j->name, plen);
1202671ee73SJamie Gritton 			dj = find_jail(pname);
1212671ee73SJamie Gritton 			if (dj != NULL) {
1222671ee73SJamie Gritton 				ldeps++;
1232671ee73SJamie Gritton 				dep_add(j, dj, DF_LIGHT);
1242671ee73SJamie Gritton 			}
1252671ee73SJamie Gritton 		}
1262671ee73SJamie Gritton 	}
1272671ee73SJamie Gritton 
1282671ee73SJamie Gritton 	/* Look for dependency loops. */
1292671ee73SJamie Gritton 	if (deps && (deps > 1 || ldeps)) {
1301ca35de4SJamie Gritton 		(void)start_state(NULL, 0, 0, 0);
1312671ee73SJamie Gritton 		while ((j = TAILQ_FIRST(&ready))) {
1322671ee73SJamie Gritton 			requeue(j, &cfjails);
1332671ee73SJamie Gritton 			dep_done(j, DF_NOFAIL);
1342671ee73SJamie Gritton 		}
135aa02af54SJamie Gritton 		while ((j = TAILQ_FIRST(&depend)) != NULL) {
1362671ee73SJamie Gritton 			jail_warnx(j, "dependency loop");
1372671ee73SJamie Gritton 			j->flags |= JF_FAILED;
1382671ee73SJamie Gritton 			do {
1392671ee73SJamie Gritton 				requeue(j, &cfjails);
1402671ee73SJamie Gritton 				dep_done(j, DF_NOFAIL);
1412671ee73SJamie Gritton 			} while ((j = TAILQ_FIRST(&ready)));
1422671ee73SJamie Gritton 		}
1432671ee73SJamie Gritton 		TAILQ_FOREACH(j, &cfjails, tq)
1442671ee73SJamie Gritton 			STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM])
1452671ee73SJamie Gritton 				d->flags &= ~DF_SEEN;
1462671ee73SJamie Gritton 	}
1472671ee73SJamie Gritton 	if (pname != NULL)
1482671ee73SJamie Gritton 		free(pname);
1492671ee73SJamie Gritton }
1502671ee73SJamie Gritton 
1512671ee73SJamie Gritton /*
1522671ee73SJamie Gritton  * Return if a jail has dependencies.
1532671ee73SJamie Gritton  */
1542671ee73SJamie Gritton int
dep_check(struct cfjail * j)1552671ee73SJamie Gritton dep_check(struct cfjail *j)
1562671ee73SJamie Gritton {
1572671ee73SJamie Gritton 	int reset, depfrom, depto, ndeps, rev;
1582671ee73SJamie Gritton 	struct cfjail *dj;
1592671ee73SJamie Gritton 	struct cfdepend *d;
1602671ee73SJamie Gritton 
1612671ee73SJamie Gritton 	static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
1622671ee73SJamie Gritton 
1632671ee73SJamie Gritton 	if (j->ndeps == 0)
1642671ee73SJamie Gritton 		return 0;
1652671ee73SJamie Gritton 	ndeps = 0;
1662671ee73SJamie Gritton 	if ((rev = JF_DO_STOP(j->flags))) {
1672671ee73SJamie Gritton 		depfrom = DEP_TO;
1682671ee73SJamie Gritton 		depto = DEP_FROM;
1692671ee73SJamie Gritton 	} else {
1702671ee73SJamie Gritton 		depfrom = DEP_FROM;
1712671ee73SJamie Gritton 		depto = DEP_TO;
1722671ee73SJamie Gritton 	}
1732671ee73SJamie Gritton 	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) {
1742671ee73SJamie Gritton 		if (d->flags & DF_SEEN)
1752671ee73SJamie Gritton 			continue;
1762671ee73SJamie Gritton 		dj = d->j[depto];
1772671ee73SJamie Gritton 		if (dj->flags & JF_FAILED) {
1782671ee73SJamie Gritton 			if (!(j->flags & (JF_DEPEND | JF_FAILED)) &&
1792671ee73SJamie Gritton 			    verbose >= 0)
1802671ee73SJamie Gritton 				jail_warnx(j, "skipped");
1812671ee73SJamie Gritton 			j->flags |= JF_FAILED;
1822671ee73SJamie Gritton 			continue;
1832671ee73SJamie Gritton 		}
1842671ee73SJamie Gritton 		/*
1852671ee73SJamie Gritton 		 * The dependee's state may be set (or changed) as a result of
1862671ee73SJamie Gritton 		 * being in a dependency it wasn't in earlier.
1872671ee73SJamie Gritton 		 */
1882671ee73SJamie Gritton 		reset = 0;
1892671ee73SJamie Gritton 		if (bits[dj->flags & JF_OP_MASK] <= 1) {
1902671ee73SJamie Gritton 			if (!(dj->flags & JF_OP_MASK)) {
1912671ee73SJamie Gritton 				reset = 1;
1922671ee73SJamie Gritton 				dj->flags |= JF_DEPEND;
1932671ee73SJamie Gritton 				requeue(dj, &ready);
1942671ee73SJamie Gritton 			}
1952671ee73SJamie Gritton 			/* Set or change the dependee's state. */
1962671ee73SJamie Gritton 			switch (j->flags & JF_OP_MASK) {
1972671ee73SJamie Gritton 			case JF_START:
1982671ee73SJamie Gritton 				dj->flags |= JF_START;
1992671ee73SJamie Gritton 				break;
2002671ee73SJamie Gritton 			case JF_SET:
2012671ee73SJamie Gritton 				if (!(dj->flags & JF_OP_MASK))
2022671ee73SJamie Gritton 					dj->flags |= JF_SET;
2032671ee73SJamie Gritton 				else if (dj->flags & JF_STOP)
2042671ee73SJamie Gritton 					dj->flags |= JF_START;
2052671ee73SJamie Gritton 				break;
2062671ee73SJamie Gritton 			case JF_STOP:
2072671ee73SJamie Gritton 			case JF_RESTART:
2082671ee73SJamie Gritton 				if (!(dj->flags & JF_STOP))
2092671ee73SJamie Gritton 					reset = 1;
2102671ee73SJamie Gritton 				dj->flags |= JF_STOP;
2112671ee73SJamie Gritton 				if (dj->flags & JF_SET)
2122671ee73SJamie Gritton 					dj->flags ^= (JF_START | JF_SET);
2132671ee73SJamie Gritton 				break;
2142671ee73SJamie Gritton 			}
2152671ee73SJamie Gritton 		}
2162671ee73SJamie Gritton 		if (reset)
2172671ee73SJamie Gritton 			dep_reset(dj);
2182671ee73SJamie Gritton 		if (!((d->flags & DF_LIGHT) &&
2192671ee73SJamie Gritton 		    (rev ? dj->jid < 0 : dj->jid > 0)))
2202671ee73SJamie Gritton 			ndeps++;
2212671ee73SJamie Gritton 	}
2222671ee73SJamie Gritton 	if (ndeps == 0)
2232671ee73SJamie Gritton 		return 0;
224aa02af54SJamie Gritton 	requeue(j, &depend);
2252671ee73SJamie Gritton 	return 1;
2262671ee73SJamie Gritton }
2272671ee73SJamie Gritton 
2282671ee73SJamie Gritton /*
2292671ee73SJamie Gritton  * Resolve any dependencies from a finished jail.
2302671ee73SJamie Gritton  */
2312671ee73SJamie Gritton void
dep_done(struct cfjail * j,unsigned flags)2322671ee73SJamie Gritton dep_done(struct cfjail *j, unsigned flags)
2332671ee73SJamie Gritton {
2342671ee73SJamie Gritton 	struct cfjail *dj;
2352671ee73SJamie Gritton 	struct cfdepend *d;
2362671ee73SJamie Gritton 	int depfrom, depto;
2372671ee73SJamie Gritton 
2382671ee73SJamie Gritton 	if (JF_DO_STOP(j->flags)) {
2392671ee73SJamie Gritton 		depfrom = DEP_TO;
2402671ee73SJamie Gritton 		depto = DEP_FROM;
2412671ee73SJamie Gritton 	} else {
2422671ee73SJamie Gritton 		depfrom = DEP_FROM;
2432671ee73SJamie Gritton 		depto = DEP_TO;
2442671ee73SJamie Gritton 	}
2452671ee73SJamie Gritton 	STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) {
2462671ee73SJamie Gritton 		if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT))
2472671ee73SJamie Gritton 			continue;
2482671ee73SJamie Gritton 		d->flags |= DF_SEEN;
2492671ee73SJamie Gritton 		dj = d->j[depfrom];
2502671ee73SJamie Gritton 		if (!(flags & DF_NOFAIL) && (j->flags & JF_FAILED) &&
2512671ee73SJamie Gritton 		    (j->flags & (JF_OP_MASK | JF_DEPEND)) !=
2522671ee73SJamie Gritton 		    (JF_SET | JF_DEPEND)) {
2532671ee73SJamie Gritton 			if (!(dj->flags & (JF_DEPEND | JF_FAILED)) &&
2542671ee73SJamie Gritton 			    verbose >= 0)
2552671ee73SJamie Gritton 				jail_warnx(dj, "skipped");
2562671ee73SJamie Gritton 			dj->flags |= JF_FAILED;
2572671ee73SJamie Gritton 		}
258aa02af54SJamie Gritton 		if (!--dj->ndeps && dj->queue == &depend)
2592671ee73SJamie Gritton 			requeue(dj, &ready);
2602671ee73SJamie Gritton 	}
2612671ee73SJamie Gritton }
2622671ee73SJamie Gritton 
2632671ee73SJamie Gritton /*
2642671ee73SJamie Gritton  * Count a jail's dependencies and mark them as unseen.
2652671ee73SJamie Gritton  */
2662671ee73SJamie Gritton void
dep_reset(struct cfjail * j)2672671ee73SJamie Gritton dep_reset(struct cfjail *j)
2682671ee73SJamie Gritton {
2692671ee73SJamie Gritton 	int depfrom;
2702671ee73SJamie Gritton 	struct cfdepend *d;
2712671ee73SJamie Gritton 
2722671ee73SJamie Gritton 	depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM;
2732671ee73SJamie Gritton 	j->ndeps = 0;
2742671ee73SJamie Gritton 	STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom])
2752671ee73SJamie Gritton 		j->ndeps++;
2762671ee73SJamie Gritton }
2772671ee73SJamie Gritton 
2782671ee73SJamie Gritton /*
2792671ee73SJamie Gritton  * Find the next jail ready to do something.
2802671ee73SJamie Gritton  */
2812671ee73SJamie Gritton struct cfjail *
next_jail(void)2822671ee73SJamie Gritton next_jail(void)
2832671ee73SJamie Gritton {
2842671ee73SJamie Gritton 	struct cfjail *j;
2852671ee73SJamie Gritton 
2862671ee73SJamie Gritton 	if (!(j = next_proc(!TAILQ_EMPTY(&ready))) &&
2872671ee73SJamie Gritton 	    (j = TAILQ_FIRST(&ready)) && JF_DO_STOP(j->flags) &&
2882671ee73SJamie Gritton 	    (j = TAILQ_LAST(&ready, cfjails)) && !JF_DO_STOP(j->flags)) {
2892671ee73SJamie Gritton 		TAILQ_FOREACH_REVERSE(j, &ready, cfjails, tq)
2902671ee73SJamie Gritton 			if (JF_DO_STOP(j->flags))
2912671ee73SJamie Gritton 				break;
2922671ee73SJamie Gritton 	}
2932671ee73SJamie Gritton 	if (j != NULL)
2942671ee73SJamie Gritton 		requeue(j, &cfjails);
2952671ee73SJamie Gritton 	return j;
2962671ee73SJamie Gritton }
2972671ee73SJamie Gritton 
2982671ee73SJamie Gritton /*
2992671ee73SJamie Gritton  * Set jails to the proper start state.
3002671ee73SJamie Gritton  */
3012671ee73SJamie Gritton int
start_state(const char * target,int docf,unsigned state,int running)3021ca35de4SJamie Gritton start_state(const char *target, int docf, unsigned state, int running)
3032671ee73SJamie Gritton {
3042671ee73SJamie Gritton 	struct iovec jiov[6];
3052671ee73SJamie Gritton 	struct cfjail *j, *tj;
3062671ee73SJamie Gritton 	int jid;
3072671ee73SJamie Gritton 	char namebuf[MAXHOSTNAMELEN];
3082671ee73SJamie Gritton 
309*d50685b3SJamie Gritton 	if (!target || (!docf && (state & JF_OP_MASK) != JF_STOP) ||
3101ca35de4SJamie Gritton 	    (!running && !strcmp(target, "*"))) {
3112671ee73SJamie Gritton 		/*
3121ca35de4SJamie Gritton 		 * For a global wildcard (including no target specified),
3131ca35de4SJamie Gritton 		 * set the state on all jails and start with those that
3141ca35de4SJamie Gritton 		 * have no dependencies.
3152671ee73SJamie Gritton 		 */
3162671ee73SJamie Gritton 		TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
3171ca35de4SJamie Gritton 			j->flags = (j->flags & JF_FAILED) | state |
3181ca35de4SJamie Gritton 			    (docf ? JF_WILD : 0);
3192671ee73SJamie Gritton 			dep_reset(j);
320aa02af54SJamie Gritton 			requeue(j, j->ndeps ? &depend : &ready);
3212671ee73SJamie Gritton 		}
3222671ee73SJamie Gritton 	} else if (wild_jail_name(target)) {
3232671ee73SJamie Gritton 		/*
3242671ee73SJamie Gritton 		 * For targets specified singly, or with a non-global wildcard,
3252671ee73SJamie Gritton 		 * set their state and call them ready (even if there are
3262671ee73SJamie Gritton 		 * dependencies).  Leave everything else unqueued for now.
3272671ee73SJamie Gritton 		 */
3282671ee73SJamie Gritton 		if (running) {
3292671ee73SJamie Gritton 			/*
3302671ee73SJamie Gritton 			 * -R matches its wildcards against currently running
3312671ee73SJamie Gritton 			 * jails, not against the config file.
3322671ee73SJamie Gritton 			 */
333d031802bSJamie Gritton 			jiov[0].iov_base = __DECONST(char *, "lastjid");
3342671ee73SJamie Gritton 			jiov[0].iov_len = sizeof("lastjid");
3352671ee73SJamie Gritton 			jiov[1].iov_base = &jid;
3362671ee73SJamie Gritton 			jiov[1].iov_len = sizeof(jid);
337d031802bSJamie Gritton 			jiov[2].iov_base = __DECONST(char *, "jid");
3382671ee73SJamie Gritton 			jiov[2].iov_len = sizeof("jid");
3392671ee73SJamie Gritton 			jiov[3].iov_base = &jid;
3402671ee73SJamie Gritton 			jiov[3].iov_len = sizeof(jid);
341d031802bSJamie Gritton 			jiov[4].iov_base = __DECONST(char *, "name");
3422671ee73SJamie Gritton 			jiov[4].iov_len = sizeof("name");
3432671ee73SJamie Gritton 			jiov[5].iov_base = &namebuf;
3442671ee73SJamie Gritton 			jiov[5].iov_len = sizeof(namebuf);
3452671ee73SJamie Gritton 			for (jid = 0; jail_get(jiov, 6, 0) > 0; ) {
3462671ee73SJamie Gritton 				if (wild_jail_match(namebuf, target)) {
3472671ee73SJamie Gritton 					j = add_jail();
3482671ee73SJamie Gritton 					j->name = estrdup(namebuf);
3492671ee73SJamie Gritton 					j->jid = jid;
3502671ee73SJamie Gritton 					j->flags = (j->flags & JF_FAILED) |
3512671ee73SJamie Gritton 					    state | JF_WILD;
3522671ee73SJamie Gritton 					dep_reset(j);
3532671ee73SJamie Gritton 					requeue(j, &ready);
3542671ee73SJamie Gritton 				}
3552671ee73SJamie Gritton 			}
3562671ee73SJamie Gritton 		} else {
3572671ee73SJamie Gritton 			TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
3582671ee73SJamie Gritton 				if (wild_jail_match(j->name, target)) {
3592671ee73SJamie Gritton 					j->flags = (j->flags & JF_FAILED) |
3602671ee73SJamie Gritton 					    state | JF_WILD;
3612671ee73SJamie Gritton 					dep_reset(j);
3622671ee73SJamie Gritton 					requeue(j, &ready);
3632671ee73SJamie Gritton 				}
3642671ee73SJamie Gritton 			}
3652671ee73SJamie Gritton 		}
3662671ee73SJamie Gritton 	} else {
3672671ee73SJamie Gritton 		j = find_jail(target);
368*d50685b3SJamie Gritton 		if (j == NULL && (state & JF_OP_MASK) == JF_STOP) {
3692671ee73SJamie Gritton 			/* Allow -[rR] to specify a currently running jail. */
370cd38a86cSMichael Zhilin 			j = running_jail(target, JAIL_DYING);
3712671ee73SJamie Gritton 		}
3722671ee73SJamie Gritton 		if (j == NULL) {
3732671ee73SJamie Gritton 			warnx("\"%s\" not found", target);
3742671ee73SJamie Gritton 			return -1;
3752671ee73SJamie Gritton 		}
3762671ee73SJamie Gritton 		j->flags = (j->flags & JF_FAILED) | state;
3772671ee73SJamie Gritton 		dep_reset(j);
3782671ee73SJamie Gritton 		requeue(j, &ready);
3792671ee73SJamie Gritton 	}
3802671ee73SJamie Gritton 	return 0;
3812671ee73SJamie Gritton }
3822671ee73SJamie Gritton 
3832671ee73SJamie Gritton /*
3842671ee73SJamie Gritton  * Move a jail to a new list.
3852671ee73SJamie Gritton  */
3862671ee73SJamie Gritton void
requeue(struct cfjail * j,struct cfjails * queue)3872671ee73SJamie Gritton requeue(struct cfjail *j, struct cfjails *queue)
3882671ee73SJamie Gritton {
3892671ee73SJamie Gritton 	if (j->queue != queue) {
3902671ee73SJamie Gritton 		TAILQ_REMOVE(j->queue, j, tq);
3912671ee73SJamie Gritton 		TAILQ_INSERT_TAIL(queue, j, tq);
3922671ee73SJamie Gritton 		j->queue = queue;
3932671ee73SJamie Gritton 	}
3942671ee73SJamie Gritton }
3952671ee73SJamie Gritton 
3964c86c0faSJamie Gritton void
requeue_head(struct cfjail * j,struct cfjails * queue)3974c86c0faSJamie Gritton requeue_head(struct cfjail *j, struct cfjails *queue)
3984c86c0faSJamie Gritton {
3994c86c0faSJamie Gritton     TAILQ_REMOVE(j->queue, j, tq);
4004c86c0faSJamie Gritton     TAILQ_INSERT_HEAD(queue, j, tq);
4014c86c0faSJamie Gritton     j->queue = queue;
4024c86c0faSJamie Gritton }
4034c86c0faSJamie Gritton 
4042671ee73SJamie Gritton /*
4052671ee73SJamie Gritton  * Add a dependency edge between two jails.
4062671ee73SJamie Gritton  */
4072671ee73SJamie Gritton static void
dep_add(struct cfjail * from,struct cfjail * to,unsigned flags)4082671ee73SJamie Gritton dep_add(struct cfjail *from, struct cfjail *to, unsigned flags)
4092671ee73SJamie Gritton {
4102671ee73SJamie Gritton 	struct cfdepend *d;
4112671ee73SJamie Gritton 
4122671ee73SJamie Gritton 	d = emalloc(sizeof(struct cfdepend));
4132671ee73SJamie Gritton 	d->flags = flags;
4142671ee73SJamie Gritton 	d->j[DEP_FROM] = from;
4152671ee73SJamie Gritton 	d->j[DEP_TO] = to;
4162671ee73SJamie Gritton 	STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]);
4172671ee73SJamie Gritton 	STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]);
4182671ee73SJamie Gritton }
4192671ee73SJamie Gritton 
4202671ee73SJamie Gritton /*
4212671ee73SJamie Gritton  * Compare jail pointers for qsort/bsearch.
4222671ee73SJamie Gritton  */
4232671ee73SJamie Gritton static int
cmp_jailptr(const void * a,const void * b)4242671ee73SJamie Gritton cmp_jailptr(const void *a, const void *b)
4252671ee73SJamie Gritton {
4262671ee73SJamie Gritton 	return strcmp((*((struct cfjail * const *)a))->name,
4272671ee73SJamie Gritton 	    ((*(struct cfjail * const *)b))->name);
4282671ee73SJamie Gritton }
4292671ee73SJamie Gritton 
4302671ee73SJamie Gritton static int
cmp_jailptr_name(const void * a,const void * b)4312671ee73SJamie Gritton cmp_jailptr_name(const void *a, const void *b)
4322671ee73SJamie Gritton {
4332671ee73SJamie Gritton 	return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name);
4342671ee73SJamie Gritton }
4352671ee73SJamie Gritton 
4362671ee73SJamie Gritton /*
4372671ee73SJamie Gritton  * Find a jail object by name.
4382671ee73SJamie Gritton  */
4392671ee73SJamie Gritton static struct cfjail *
find_jail(const char * name)4402671ee73SJamie Gritton find_jail(const char *name)
4412671ee73SJamie Gritton {
4422671ee73SJamie Gritton 	struct cfjail **jp;
4432671ee73SJamie Gritton 
444cd38a86cSMichael Zhilin 	if (jails_byname == NULL)
445cd38a86cSMichael Zhilin 		return NULL;
446cd38a86cSMichael Zhilin 
4472671ee73SJamie Gritton 	jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *),
4482671ee73SJamie Gritton 	    cmp_jailptr_name);
4492671ee73SJamie Gritton 	return jp ? *jp : NULL;
4502671ee73SJamie Gritton }
4512671ee73SJamie Gritton 
4522671ee73SJamie Gritton /*
453cd38a86cSMichael Zhilin  * Return jail if it is running, and NULL if it isn't.
4542671ee73SJamie Gritton  */
455cd38a86cSMichael Zhilin static struct cfjail *
running_jail(const char * name,int flags)456cd38a86cSMichael Zhilin running_jail(const char *name, int flags)
4572671ee73SJamie Gritton {
458cd38a86cSMichael Zhilin 	struct iovec jiov[4];
459cd38a86cSMichael Zhilin 	struct cfjail *jail;
4602671ee73SJamie Gritton 	char *ep;
461cd38a86cSMichael Zhilin 	char jailname[MAXHOSTNAMELEN];
462cd38a86cSMichael Zhilin 	int jid, ret, len;
4632671ee73SJamie Gritton 
4642671ee73SJamie Gritton 	if ((jid = strtol(name, &ep, 10)) && !*ep) {
465cd38a86cSMichael Zhilin 		memset(jailname,0,sizeof(jailname));
466cd38a86cSMichael Zhilin 		len = sizeof(jailname);
467cd38a86cSMichael Zhilin 	} else {
468cd38a86cSMichael Zhilin 		strncpy(jailname, name,sizeof(jailname));
469cd38a86cSMichael Zhilin 		len = strlen(name) + 1;
470cd38a86cSMichael Zhilin 		jid = 0;
471cd38a86cSMichael Zhilin 	}
472cd38a86cSMichael Zhilin 
473d031802bSJamie Gritton 	jiov[0].iov_base = __DECONST(char *, "jid");
4742671ee73SJamie Gritton 	jiov[0].iov_len = sizeof("jid");
4752671ee73SJamie Gritton 	jiov[1].iov_base = &jid;
4762671ee73SJamie Gritton 	jiov[1].iov_len = sizeof(jid);
477cd38a86cSMichael Zhilin 	jiov[2].iov_base = __DECONST(char *, "name");
478cd38a86cSMichael Zhilin 	jiov[2].iov_len = sizeof("name");
479cd38a86cSMichael Zhilin 	jiov[3].iov_base = &jailname;
480cd38a86cSMichael Zhilin 	jiov[3].iov_len = len;
481cd38a86cSMichael Zhilin 
482cd38a86cSMichael Zhilin 	if ((ret = jail_get(jiov, 4, flags)) < 0)
483cd38a86cSMichael Zhilin 		return (NULL);
484cd38a86cSMichael Zhilin 
485cd38a86cSMichael Zhilin 	if ((jail = find_jail(jailname)) == NULL) {
486cd38a86cSMichael Zhilin 		jail = add_jail();
487cd38a86cSMichael Zhilin 		jail->name = estrdup(jailname);
488cd38a86cSMichael Zhilin 		jail->jid = ret;
4892671ee73SJamie Gritton 	}
490cd38a86cSMichael Zhilin 
491cd38a86cSMichael Zhilin 	return (jail);
4922671ee73SJamie Gritton }
493