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
;
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
);
95 TAILQ_FOREACH(j
, &cfjails
, tq
) {
96 if (j
->flags
& JF_FAILED
)
98 if ((p
= j
->intparams
[IP_DEPEND
])) {
99 TAILQ_FOREACH(s
, &p
->val
, tq
) {
100 dj
= find_jail(s
->s
);
106 "depends on undefined jail \"%s\"",
108 j
->flags
|= JF_FAILED
;
112 /* A jail has an implied dependency on its parent. */
113 if ((cs
= strrchr(j
->name
, '.')))
115 if (plen
< (size_t)(cs
- j
->name
+ 1)) {
116 plen
= (cs
- j
->name
) + 1;
117 pname
= erealloc(pname
, plen
);
119 strlcpy(pname
, j
->name
, plen
);
120 dj
= find_jail(pname
);
123 dep_add(j
, dj
, DF_LIGHT
);
128 /* Look for dependency loops. */
129 if (deps
&& (deps
> 1 || ldeps
)) {
130 (void)start_state(NULL
, 0, 0, 0);
131 while ((j
= TAILQ_FIRST(&ready
))) {
132 requeue(j
, &cfjails
);
133 dep_done(j
, DF_NOFAIL
);
135 while ((j
= TAILQ_FIRST(&depend
)) != NULL
) {
136 jail_warnx(j
, "dependency loop");
137 j
->flags
|= JF_FAILED
;
139 requeue(j
, &cfjails
);
140 dep_done(j
, DF_NOFAIL
);
141 } while ((j
= TAILQ_FIRST(&ready
)));
143 TAILQ_FOREACH(j
, &cfjails
, tq
)
144 STAILQ_FOREACH(d
, &j
->dep
[DEP_FROM
], tq
[DEP_FROM
])
145 d
->flags
&= ~DF_SEEN
;
152 * Return if a jail has dependencies.
155 dep_check(struct cfjail
*j
)
157 int reset
, depfrom
, depto
, ndeps
, rev
;
161 static int bits
[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
166 if ((rev
= JF_DO_STOP(j
->flags
))) {
173 STAILQ_FOREACH(d
, &j
->dep
[depfrom
], tq
[depfrom
]) {
174 if (d
->flags
& DF_SEEN
)
177 if (dj
->flags
& JF_FAILED
) {
178 if (!(j
->flags
& (JF_DEPEND
| JF_FAILED
)) &&
180 jail_warnx(j
, "skipped");
181 j
->flags
|= JF_FAILED
;
185 * The dependee's state may be set (or changed) as a result of
186 * being in a dependency it wasn't in earlier.
189 if (bits
[dj
->flags
& JF_OP_MASK
] <= 1) {
190 if (!(dj
->flags
& JF_OP_MASK
)) {
192 dj
->flags
|= JF_DEPEND
;
195 /* Set or change the dependee's state. */
196 switch (j
->flags
& JF_OP_MASK
) {
198 dj
->flags
|= JF_START
;
201 if (!(dj
->flags
& JF_OP_MASK
))
203 else if (dj
->flags
& JF_STOP
)
204 dj
->flags
|= JF_START
;
208 if (!(dj
->flags
& JF_STOP
))
210 dj
->flags
|= JF_STOP
;
211 if (dj
->flags
& JF_SET
)
212 dj
->flags
^= (JF_START
| JF_SET
);
218 if (!((d
->flags
& DF_LIGHT
) &&
219 (rev
? dj
->jid
< 0 : dj
->jid
> 0)))
229 * Resolve any dependencies from a finished jail.
232 dep_done(struct cfjail
*j
, unsigned flags
)
238 if (JF_DO_STOP(j
->flags
)) {
245 STAILQ_FOREACH(d
, &j
->dep
[depto
], tq
[depto
]) {
246 if ((d
->flags
& DF_SEEN
) | (flags
& ~d
->flags
& DF_LIGHT
))
250 if (!(flags
& DF_NOFAIL
) && (j
->flags
& JF_FAILED
) &&
251 (j
->flags
& (JF_OP_MASK
| JF_DEPEND
)) !=
252 (JF_SET
| JF_DEPEND
)) {
253 if (!(dj
->flags
& (JF_DEPEND
| JF_FAILED
)) &&
255 jail_warnx(dj
, "skipped");
256 dj
->flags
|= JF_FAILED
;
258 if (!--dj
->ndeps
&& dj
->queue
== &depend
)
264 * Count a jail's dependencies and mark them as unseen.
267 dep_reset(struct cfjail
*j
)
272 depfrom
= JF_DO_STOP(j
->flags
) ? DEP_TO
: DEP_FROM
;
274 STAILQ_FOREACH(d
, &j
->dep
[depfrom
], tq
[depfrom
])
279 * Find the next jail ready to do something.
286 if (!(j
= next_proc(!TAILQ_EMPTY(&ready
))) &&
287 (j
= TAILQ_FIRST(&ready
)) && JF_DO_STOP(j
->flags
) &&
288 (j
= TAILQ_LAST(&ready
, cfjails
)) && !JF_DO_STOP(j
->flags
)) {
289 TAILQ_FOREACH_REVERSE(j
, &ready
, cfjails
, tq
)
290 if (JF_DO_STOP(j
->flags
))
294 requeue(j
, &cfjails
);
299 * Set jails to the proper start state.
302 start_state(const char *target
, int docf
, unsigned state
, int running
)
304 struct iovec jiov
[6];
305 struct cfjail
*j
, *tj
;
307 char namebuf
[MAXHOSTNAMELEN
];
309 if (!target
|| (!docf
&& state
!= JF_STOP
) ||
310 (!running
&& !strcmp(target
, "*"))) {
312 * For a global wildcard (including no target specified),
313 * set the state on all jails and start with those that
314 * have no dependencies.
316 TAILQ_FOREACH_SAFE(j
, &cfjails
, tq
, tj
) {
317 j
->flags
= (j
->flags
& JF_FAILED
) | state
|
318 (docf
? JF_WILD
: 0);
320 requeue(j
, j
->ndeps
? &depend
: &ready
);
322 } else if (wild_jail_name(target
)) {
324 * For targets specified singly, or with a non-global wildcard,
325 * set their state and call them ready (even if there are
326 * dependencies). Leave everything else unqueued for now.
330 * -R matches its wildcards against currently running
331 * jails, not against the config file.
333 jiov
[0].iov_base
= __DECONST(char *, "lastjid");
334 jiov
[0].iov_len
= sizeof("lastjid");
335 jiov
[1].iov_base
= &jid
;
336 jiov
[1].iov_len
= sizeof(jid
);
337 jiov
[2].iov_base
= __DECONST(char *, "jid");
338 jiov
[2].iov_len
= sizeof("jid");
339 jiov
[3].iov_base
= &jid
;
340 jiov
[3].iov_len
= sizeof(jid
);
341 jiov
[4].iov_base
= __DECONST(char *, "name");
342 jiov
[4].iov_len
= sizeof("name");
343 jiov
[5].iov_base
= &namebuf
;
344 jiov
[5].iov_len
= sizeof(namebuf
);
345 for (jid
= 0; jail_get(jiov
, 6, 0) > 0; ) {
346 if (wild_jail_match(namebuf
, target
)) {
348 j
->name
= estrdup(namebuf
);
350 j
->flags
= (j
->flags
& JF_FAILED
) |
357 TAILQ_FOREACH_SAFE(j
, &cfjails
, tq
, tj
) {
358 if (wild_jail_match(j
->name
, target
)) {
359 j
->flags
= (j
->flags
& JF_FAILED
) |
367 j
= find_jail(target
);
368 if (j
== NULL
&& state
== JF_STOP
) {
369 /* Allow -[rR] to specify a currently running jail. */
370 if ((jid
= running_jid(target
, JAIL_DYING
)) > 0) {
372 j
->name
= estrdup(target
);
377 warnx("\"%s\" not found", target
);
380 j
->flags
= (j
->flags
& JF_FAILED
) | state
;
388 * Move a jail to a new list.
391 requeue(struct cfjail
*j
, struct cfjails
*queue
)
393 if (j
->queue
!= queue
) {
394 TAILQ_REMOVE(j
->queue
, j
, tq
);
395 TAILQ_INSERT_TAIL(queue
, j
, tq
);
401 * Add a dependency edge between two jails.
404 dep_add(struct cfjail
*from
, struct cfjail
*to
, unsigned flags
)
408 d
= emalloc(sizeof(struct cfdepend
));
410 d
->j
[DEP_FROM
] = from
;
412 STAILQ_INSERT_TAIL(&from
->dep
[DEP_FROM
], d
, tq
[DEP_FROM
]);
413 STAILQ_INSERT_TAIL(&to
->dep
[DEP_TO
], d
, tq
[DEP_TO
]);
417 * Compare jail pointers for qsort/bsearch.
420 cmp_jailptr(const void *a
, const void *b
)
422 return strcmp((*((struct cfjail
* const *)a
))->name
,
423 ((*(struct cfjail
* const *)b
))->name
);
427 cmp_jailptr_name(const void *a
, const void *b
)
429 return strcmp((const char *)a
, ((*(struct cfjail
* const *)b
))->name
);
433 * Find a jail object by name.
435 static struct cfjail
*
436 find_jail(const char *name
)
440 jp
= bsearch(name
, jails_byname
, njails
, sizeof(struct cfjail
*),
442 return jp
? *jp
: NULL
;
446 * Return the named jail's jid if it is running, and -1 if it isn't.
449 running_jid(const char *name
, int flags
)
451 struct iovec jiov
[2];
455 if ((jid
= strtol(name
, &ep
, 10)) && !*ep
) {
456 jiov
[0].iov_base
= __DECONST(char *, "jid");
457 jiov
[0].iov_len
= sizeof("jid");
458 jiov
[1].iov_base
= &jid
;
459 jiov
[1].iov_len
= sizeof(jid
);
461 jiov
[0].iov_base
= __DECONST(char *, "name");
462 jiov
[0].iov_len
= sizeof("name");
463 jiov
[1].iov_len
= strlen(name
) + 1;
464 jiov
[1].iov_base
= alloca(jiov
[1].iov_len
);
465 strcpy(jiov
[1].iov_base
, name
);
467 return jail_get(jiov
, 2, flags
);