2 * Copyright (c) 2011 James Gritton
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
38 struct cfjails ready = TAILQ_HEAD_INITIALIZER(ready);
39 struct cfjails depend = TAILQ_HEAD_INITIALIZER(depend);
41 static void dep_add(struct cfjail *from, struct cfjail *to, unsigned flags);
42 static int cmp_jailptr(const void *a, const void *b);
43 static int cmp_jailptr_name(const void *a, const void *b);
44 static struct cfjail *find_jail(const char *name);
45 static int running_jid(const char *name, int flags);
47 static struct cfjail **jails_byname;
51 * Set up jail dependency lists.
56 struct cfjail *j, *dj;
63 int error, deps, ldeps;
67 * With no config file, let "depend" for a single jail
68 * look at currently running jails.
70 if ((j = TAILQ_FIRST(&cfjails)) &&
71 (p = j->intparams[IP_DEPEND])) {
72 TAILQ_FOREACH(s, &p->val, tq) {
73 if (running_jid(s->s, 0) < 0) {
74 warnx("depends on nonexistent jail "
76 j->flags |= JF_FAILED;
84 TAILQ_FOREACH(j, &cfjails, tq)
86 jails_byname = emalloc(njails * sizeof(struct cfjail *));
88 TAILQ_FOREACH(j, &cfjails, tq)
89 jails_byname[njails++] = j;
90 qsort(jails_byname, njails, sizeof(struct cfjail *), cmp_jailptr);
96 TAILQ_FOREACH(j, &cfjails, tq) {
97 if (j->flags & JF_FAILED)
99 if ((p = j->intparams[IP_DEPEND])) {
100 TAILQ_FOREACH(s, &p->val, tq) {
101 dj = find_jail(s->s);
107 "depends on undefined jail \"%s\"",
109 j->flags |= JF_FAILED;
113 /* A jail has an implied dependency on its parent. */
114 if ((cs = strrchr(j->name, '.')))
116 if (plen < (size_t)(cs - j->name + 1)) {
117 plen = (cs - j->name) + 1;
118 pname = erealloc(pname, plen);
120 strlcpy(pname, j->name, plen);
121 dj = find_jail(pname);
124 dep_add(j, dj, DF_LIGHT);
129 /* Look for dependency loops. */
130 if (deps && (deps > 1 || ldeps)) {
131 (void)start_state(NULL, 0, 0, 0);
132 while ((j = TAILQ_FIRST(&ready))) {
133 requeue(j, &cfjails);
134 dep_done(j, DF_NOFAIL);
136 while ((j = TAILQ_FIRST(&depend)) != NULL) {
137 jail_warnx(j, "dependency loop");
138 j->flags |= JF_FAILED;
140 requeue(j, &cfjails);
141 dep_done(j, DF_NOFAIL);
142 } while ((j = TAILQ_FIRST(&ready)));
144 TAILQ_FOREACH(j, &cfjails, tq)
145 STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM])
146 d->flags &= ~DF_SEEN;
153 * Return if a jail has dependencies.
156 dep_check(struct cfjail *j)
158 int reset, depfrom, depto, ndeps, rev;
162 static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
167 if ((rev = JF_DO_STOP(j->flags))) {
174 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) {
175 if (d->flags & DF_SEEN)
178 if (dj->flags & JF_FAILED) {
179 if (!(j->flags & (JF_DEPEND | JF_FAILED)) &&
181 jail_warnx(j, "skipped");
182 j->flags |= JF_FAILED;
186 * The dependee's state may be set (or changed) as a result of
187 * being in a dependency it wasn't in earlier.
190 if (bits[dj->flags & JF_OP_MASK] <= 1) {
191 if (!(dj->flags & JF_OP_MASK)) {
193 dj->flags |= JF_DEPEND;
196 /* Set or change the dependee's state. */
197 switch (j->flags & JF_OP_MASK) {
199 dj->flags |= JF_START;
202 if (!(dj->flags & JF_OP_MASK))
204 else if (dj->flags & JF_STOP)
205 dj->flags |= JF_START;
209 if (!(dj->flags & JF_STOP))
211 dj->flags |= JF_STOP;
212 if (dj->flags & JF_SET)
213 dj->flags ^= (JF_START | JF_SET);
219 if (!((d->flags & DF_LIGHT) &&
220 (rev ? dj->jid < 0 : dj->jid > 0)))
230 * Resolve any dependencies from a finished jail.
233 dep_done(struct cfjail *j, unsigned flags)
239 if (JF_DO_STOP(j->flags)) {
246 STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) {
247 if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT))
251 if (!(flags & DF_NOFAIL) && (j->flags & JF_FAILED) &&
252 (j->flags & (JF_OP_MASK | JF_DEPEND)) !=
253 (JF_SET | JF_DEPEND)) {
254 if (!(dj->flags & (JF_DEPEND | JF_FAILED)) &&
256 jail_warnx(dj, "skipped");
257 dj->flags |= JF_FAILED;
259 if (!--dj->ndeps && dj->queue == &depend)
265 * Count a jail's dependencies and mark them as unseen.
268 dep_reset(struct cfjail *j)
273 depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM;
275 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom])
280 * Find the next jail ready to do something.
287 if (!(j = next_proc(!TAILQ_EMPTY(&ready))) &&
288 (j = TAILQ_FIRST(&ready)) && JF_DO_STOP(j->flags) &&
289 (j = TAILQ_LAST(&ready, cfjails)) && !JF_DO_STOP(j->flags)) {
290 TAILQ_FOREACH_REVERSE(j, &ready, cfjails, tq)
291 if (JF_DO_STOP(j->flags))
295 requeue(j, &cfjails);
300 * Set jails to the proper start state.
303 start_state(const char *target, int docf, unsigned state, int running)
305 struct iovec jiov[6];
306 struct cfjail *j, *tj;
308 char namebuf[MAXHOSTNAMELEN];
310 if (!target || (!docf && state != JF_STOP) ||
311 (!running && !strcmp(target, "*"))) {
313 * For a global wildcard (including no target specified),
314 * set the state on all jails and start with those that
315 * have no dependencies.
317 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
318 j->flags = (j->flags & JF_FAILED) | state |
319 (docf ? JF_WILD : 0);
321 requeue(j, j->ndeps ? &depend : &ready);
323 } else if (wild_jail_name(target)) {
325 * For targets specified singly, or with a non-global wildcard,
326 * set their state and call them ready (even if there are
327 * dependencies). Leave everything else unqueued for now.
331 * -R matches its wildcards against currently running
332 * jails, not against the config file.
334 *(const void **)&jiov[0].iov_base = "lastjid";
335 jiov[0].iov_len = sizeof("lastjid");
336 jiov[1].iov_base = &jid;
337 jiov[1].iov_len = sizeof(jid);
338 *(const void **)&jiov[2].iov_base = "jid";
339 jiov[2].iov_len = sizeof("jid");
340 jiov[3].iov_base = &jid;
341 jiov[3].iov_len = sizeof(jid);
342 *(const void **)&jiov[4].iov_base = "name";
343 jiov[4].iov_len = sizeof("name");
344 jiov[5].iov_base = &namebuf;
345 jiov[5].iov_len = sizeof(namebuf);
346 for (jid = 0; jail_get(jiov, 6, 0) > 0; ) {
347 if (wild_jail_match(namebuf, target)) {
349 j->name = estrdup(namebuf);
351 j->flags = (j->flags & JF_FAILED) |
358 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
359 if (wild_jail_match(j->name, target)) {
360 j->flags = (j->flags & JF_FAILED) |
368 j = find_jail(target);
369 if (j == NULL && state == JF_STOP) {
370 /* Allow -[rR] to specify a currently running jail. */
371 if ((jid = running_jid(target, JAIL_DYING)) > 0) {
373 j->name = estrdup(target);
378 warnx("\"%s\" not found", target);
381 j->flags = (j->flags & JF_FAILED) | state;
389 * Move a jail to a new list.
392 requeue(struct cfjail *j, struct cfjails *queue)
394 if (j->queue != queue) {
395 TAILQ_REMOVE(j->queue, j, tq);
396 TAILQ_INSERT_TAIL(queue, j, tq);
402 requeue_head(struct cfjail *j, struct cfjails *queue)
404 TAILQ_REMOVE(j->queue, j, tq);
405 TAILQ_INSERT_HEAD(queue, j, tq);
410 * Add a dependency edge between two jails.
413 dep_add(struct cfjail *from, struct cfjail *to, unsigned flags)
417 d = emalloc(sizeof(struct cfdepend));
419 d->j[DEP_FROM] = from;
421 STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]);
422 STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]);
426 * Compare jail pointers for qsort/bsearch.
429 cmp_jailptr(const void *a, const void *b)
431 return strcmp((*((struct cfjail * const *)a))->name,
432 ((*(struct cfjail * const *)b))->name);
436 cmp_jailptr_name(const void *a, const void *b)
438 return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name);
442 * Find a jail object by name.
444 static struct cfjail *
445 find_jail(const char *name)
449 jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *),
451 return jp ? *jp : NULL;
455 * Return the named jail's jid if it is running, and -1 if it isn't.
458 running_jid(const char *name, int flags)
460 struct iovec jiov[2];
464 if ((jid = strtol(name, &ep, 10)) && !*ep) {
465 *(const void **)&jiov[0].iov_base = "jid";
466 jiov[0].iov_len = sizeof("jid");
467 jiov[1].iov_base = &jid;
468 jiov[1].iov_len = sizeof(jid);
470 *(const void **)&jiov[0].iov_base = "name";
471 jiov[0].iov_len = sizeof("name");
472 jiov[1].iov_len = strlen(name) + 1;
473 jiov[1].iov_base = alloca(jiov[1].iov_len);
474 strcpy(jiov[1].iov_base, name);
476 return jail_get(jiov, 2, flags);