1/*- 2 * Copyright (c) 2010 James Gritton 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2010 James Gritton 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
|
101 dj = find_jail(s->s); 102 if (dj != NULL) { 103 deps++; 104 dep_add(j, dj, 0); 105 } else { 106 jail_warnx(j, 107 "depends on undefined jail \"%s\"", 108 s->s); 109 j->flags |= JF_FAILED; 110 } 111 } 112 } 113 /* A jail has an implied dependency on its parent. */ 114 if ((cs = strrchr(j->name, '.'))) 115 { 116 if (plen < (size_t)(cs - j->name + 1)) { 117 plen = (cs - j->name) + 1; 118 pname = erealloc(pname, plen); 119 } 120 strlcpy(pname, j->name, plen); 121 dj = find_jail(pname); 122 if (dj != NULL) { 123 ldeps++; 124 dep_add(j, dj, DF_LIGHT); 125 } 126 } 127 } 128 129 /* Look for dependency loops. */ 130 if (deps && (deps > 1 || ldeps)) { 131 (void)start_state(NULL, 0, 0); 132 while ((j = TAILQ_FIRST(&ready))) { 133 requeue(j, &cfjails); 134 dep_done(j, DF_NOFAIL); 135 } 136 while ((j = TAILQ_FIRST(&depend)) != NULL) { 137 jail_warnx(j, "dependency loop"); 138 j->flags |= JF_FAILED; 139 do { 140 requeue(j, &cfjails); 141 dep_done(j, DF_NOFAIL); 142 } while ((j = TAILQ_FIRST(&ready))); 143 } 144 TAILQ_FOREACH(j, &cfjails, tq) 145 STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM]) 146 d->flags &= ~DF_SEEN; 147 } 148 if (pname != NULL) 149 free(pname); 150} 151 152/* 153 * Return if a jail has dependencies. 154 */ 155int 156dep_check(struct cfjail *j) 157{ 158 int reset, depfrom, depto, ndeps, rev; 159 struct cfjail *dj; 160 struct cfdepend *d; 161 162 static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 }; 163 164 if (j->ndeps == 0) 165 return 0; 166 ndeps = 0; 167 if ((rev = JF_DO_STOP(j->flags))) { 168 depfrom = DEP_TO; 169 depto = DEP_FROM; 170 } else { 171 depfrom = DEP_FROM; 172 depto = DEP_TO; 173 } 174 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) { 175 if (d->flags & DF_SEEN) 176 continue; 177 dj = d->j[depto]; 178 if (dj->flags & JF_FAILED) { 179 if (!(j->flags & (JF_DEPEND | JF_FAILED)) && 180 verbose >= 0) 181 jail_warnx(j, "skipped"); 182 j->flags |= JF_FAILED; 183 continue; 184 } 185 /* 186 * The dependee's state may be set (or changed) as a result of 187 * being in a dependency it wasn't in earlier. 188 */ 189 reset = 0; 190 if (bits[dj->flags & JF_OP_MASK] <= 1) { 191 if (!(dj->flags & JF_OP_MASK)) { 192 reset = 1; 193 dj->flags |= JF_DEPEND; 194 requeue(dj, &ready); 195 } 196 /* Set or change the dependee's state. */ 197 switch (j->flags & JF_OP_MASK) { 198 case JF_START: 199 dj->flags |= JF_START; 200 break; 201 case JF_SET: 202 if (!(dj->flags & JF_OP_MASK)) 203 dj->flags |= JF_SET; 204 else if (dj->flags & JF_STOP) 205 dj->flags |= JF_START; 206 break; 207 case JF_STOP: 208 case JF_RESTART: 209 if (!(dj->flags & JF_STOP)) 210 reset = 1; 211 dj->flags |= JF_STOP; 212 if (dj->flags & JF_SET) 213 dj->flags ^= (JF_START | JF_SET); 214 break; 215 } 216 } 217 if (reset) 218 dep_reset(dj); 219 if (!((d->flags & DF_LIGHT) && 220 (rev ? dj->jid < 0 : dj->jid > 0))) 221 ndeps++; 222 } 223 if (ndeps == 0) 224 return 0; 225 requeue(j, &depend); 226 return 1; 227} 228 229/* 230 * Resolve any dependencies from a finished jail. 231 */ 232void 233dep_done(struct cfjail *j, unsigned flags) 234{ 235 struct cfjail *dj; 236 struct cfdepend *d; 237 int depfrom, depto; 238 239 if (JF_DO_STOP(j->flags)) { 240 depfrom = DEP_TO; 241 depto = DEP_FROM; 242 } else { 243 depfrom = DEP_FROM; 244 depto = DEP_TO; 245 } 246 STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) { 247 if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT)) 248 continue; 249 d->flags |= DF_SEEN; 250 dj = d->j[depfrom]; 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)) && 255 verbose >= 0) 256 jail_warnx(dj, "skipped"); 257 dj->flags |= JF_FAILED; 258 } 259 if (!--dj->ndeps && dj->queue == &depend) 260 requeue(dj, &ready); 261 } 262} 263 264/* 265 * Count a jail's dependencies and mark them as unseen. 266 */ 267void 268dep_reset(struct cfjail *j) 269{ 270 int depfrom; 271 struct cfdepend *d; 272 273 depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM; 274 j->ndeps = 0; 275 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) 276 j->ndeps++; 277} 278 279/* 280 * Find the next jail ready to do something. 281 */ 282struct cfjail * 283next_jail(void) 284{ 285 struct cfjail *j; 286 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)) 292 break; 293 } 294 if (j != NULL) 295 requeue(j, &cfjails); 296 return j; 297} 298 299/* 300 * Set jails to the proper start state. 301 */ 302int 303start_state(const char *target, unsigned state, int running) 304{ 305 struct iovec jiov[6]; 306 struct cfjail *j, *tj; 307 int jid; 308 char namebuf[MAXHOSTNAMELEN]; 309 310 if (!target || (!running && !strcmp(target, "*"))) { 311 /* 312 * If there's no target specified, set the state on all jails, 313 * and start with those that have no dependencies. 314 */ 315 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 316 j->flags = (j->flags & JF_FAILED) | state | JF_WILD; 317 dep_reset(j); 318 requeue(j, j->ndeps ? &depend : &ready); 319 } 320 } else if (wild_jail_name(target)) { 321 /* 322 * For targets specified singly, or with a non-global wildcard, 323 * set their state and call them ready (even if there are 324 * dependencies). Leave everything else unqueued for now. 325 */ 326 if (running) { 327 /* 328 * -R matches its wildcards against currently running 329 * jails, not against the config file. 330 */ 331 *(const void **)&jiov[0].iov_base = "lastjid"; 332 jiov[0].iov_len = sizeof("lastjid"); 333 jiov[1].iov_base = &jid; 334 jiov[1].iov_len = sizeof(jid); 335 *(const void **)&jiov[2].iov_base = "jid"; 336 jiov[2].iov_len = sizeof("jid"); 337 jiov[3].iov_base = &jid; 338 jiov[3].iov_len = sizeof(jid); 339 *(const void **)&jiov[4].iov_base = "name"; 340 jiov[4].iov_len = sizeof("name"); 341 jiov[5].iov_base = &namebuf; 342 jiov[5].iov_len = sizeof(namebuf); 343 for (jid = 0; jail_get(jiov, 6, 0) > 0; ) { 344 if (wild_jail_match(namebuf, target)) { 345 j = add_jail(); 346 j->name = estrdup(namebuf); 347 j->jid = jid; 348 j->flags = (j->flags & JF_FAILED) | 349 state | JF_WILD; 350 dep_reset(j); 351 requeue(j, &ready); 352 } 353 } 354 } else { 355 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 356 if (wild_jail_match(j->name, target)) { 357 j->flags = (j->flags & JF_FAILED) | 358 state | JF_WILD; 359 dep_reset(j); 360 requeue(j, &ready); 361 } 362 } 363 } 364 } else { 365 j = find_jail(target); 366 if (j == NULL && state == JF_STOP) { 367 /* Allow -[rR] to specify a currently running jail. */ 368 if ((jid = running_jid(target, JAIL_DYING)) > 0) { 369 j = add_jail(); 370 j->name = estrdup(target); 371 j->jid = jid; 372 } 373 } 374 if (j == NULL) { 375 warnx("\"%s\" not found", target); 376 return -1; 377 } 378 j->flags = (j->flags & JF_FAILED) | state; 379 dep_reset(j); 380 requeue(j, &ready); 381 } 382 return 0; 383} 384 385/* 386 * Move a jail to a new list. 387 */ 388void 389requeue(struct cfjail *j, struct cfjails *queue) 390{ 391 if (j->queue != queue) { 392 TAILQ_REMOVE(j->queue, j, tq); 393 TAILQ_INSERT_TAIL(queue, j, tq); 394 j->queue = queue; 395 } 396} 397 398/* 399 * Add a dependency edge between two jails. 400 */ 401static void 402dep_add(struct cfjail *from, struct cfjail *to, unsigned flags) 403{ 404 struct cfdepend *d; 405 406 d = emalloc(sizeof(struct cfdepend)); 407 d->flags = flags; 408 d->j[DEP_FROM] = from; 409 d->j[DEP_TO] = to; 410 STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]); 411 STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]); 412} 413 414/* 415 * Compare jail pointers for qsort/bsearch. 416 */ 417static int 418cmp_jailptr(const void *a, const void *b) 419{ 420 return strcmp((*((struct cfjail * const *)a))->name, 421 ((*(struct cfjail * const *)b))->name); 422} 423 424static int 425cmp_jailptr_name(const void *a, const void *b) 426{ 427 return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name); 428} 429 430/* 431 * Find a jail object by name. 432 */ 433static struct cfjail * 434find_jail(const char *name) 435{ 436 struct cfjail **jp; 437 438 jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *), 439 cmp_jailptr_name); 440 return jp ? *jp : NULL; 441} 442 443/* 444 * Return the named jail's jid if it is running, and -1 if it isn't. 445 */ 446static int 447running_jid(const char *name, int flags) 448{ 449 struct iovec jiov[2]; 450 char *ep; 451 int jid; 452 453 if ((jid = strtol(name, &ep, 10)) && !*ep) { 454 *(const void **)&jiov[0].iov_base = "jid"; 455 jiov[0].iov_len = sizeof("jid"); 456 jiov[1].iov_base = &jid; 457 jiov[1].iov_len = sizeof(jid); 458 } else { 459 *(const void **)&jiov[0].iov_base = "name"; 460 jiov[0].iov_len = sizeof("name"); 461 jiov[1].iov_len = strlen(name) + 1; 462 jiov[1].iov_base = alloca(jiov[1].iov_len); 463 strcpy(jiov[1].iov_base, name); 464 } 465 return jail_get(jiov, 2, flags); 466}
| 101 dj = find_jail(s->s); 102 if (dj != NULL) { 103 deps++; 104 dep_add(j, dj, 0); 105 } else { 106 jail_warnx(j, 107 "depends on undefined jail \"%s\"", 108 s->s); 109 j->flags |= JF_FAILED; 110 } 111 } 112 } 113 /* A jail has an implied dependency on its parent. */ 114 if ((cs = strrchr(j->name, '.'))) 115 { 116 if (plen < (size_t)(cs - j->name + 1)) { 117 plen = (cs - j->name) + 1; 118 pname = erealloc(pname, plen); 119 } 120 strlcpy(pname, j->name, plen); 121 dj = find_jail(pname); 122 if (dj != NULL) { 123 ldeps++; 124 dep_add(j, dj, DF_LIGHT); 125 } 126 } 127 } 128 129 /* Look for dependency loops. */ 130 if (deps && (deps > 1 || ldeps)) { 131 (void)start_state(NULL, 0, 0); 132 while ((j = TAILQ_FIRST(&ready))) { 133 requeue(j, &cfjails); 134 dep_done(j, DF_NOFAIL); 135 } 136 while ((j = TAILQ_FIRST(&depend)) != NULL) { 137 jail_warnx(j, "dependency loop"); 138 j->flags |= JF_FAILED; 139 do { 140 requeue(j, &cfjails); 141 dep_done(j, DF_NOFAIL); 142 } while ((j = TAILQ_FIRST(&ready))); 143 } 144 TAILQ_FOREACH(j, &cfjails, tq) 145 STAILQ_FOREACH(d, &j->dep[DEP_FROM], tq[DEP_FROM]) 146 d->flags &= ~DF_SEEN; 147 } 148 if (pname != NULL) 149 free(pname); 150} 151 152/* 153 * Return if a jail has dependencies. 154 */ 155int 156dep_check(struct cfjail *j) 157{ 158 int reset, depfrom, depto, ndeps, rev; 159 struct cfjail *dj; 160 struct cfdepend *d; 161 162 static int bits[] = { 0, 1, 1, 2, 1, 2, 2, 3 }; 163 164 if (j->ndeps == 0) 165 return 0; 166 ndeps = 0; 167 if ((rev = JF_DO_STOP(j->flags))) { 168 depfrom = DEP_TO; 169 depto = DEP_FROM; 170 } else { 171 depfrom = DEP_FROM; 172 depto = DEP_TO; 173 } 174 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) { 175 if (d->flags & DF_SEEN) 176 continue; 177 dj = d->j[depto]; 178 if (dj->flags & JF_FAILED) { 179 if (!(j->flags & (JF_DEPEND | JF_FAILED)) && 180 verbose >= 0) 181 jail_warnx(j, "skipped"); 182 j->flags |= JF_FAILED; 183 continue; 184 } 185 /* 186 * The dependee's state may be set (or changed) as a result of 187 * being in a dependency it wasn't in earlier. 188 */ 189 reset = 0; 190 if (bits[dj->flags & JF_OP_MASK] <= 1) { 191 if (!(dj->flags & JF_OP_MASK)) { 192 reset = 1; 193 dj->flags |= JF_DEPEND; 194 requeue(dj, &ready); 195 } 196 /* Set or change the dependee's state. */ 197 switch (j->flags & JF_OP_MASK) { 198 case JF_START: 199 dj->flags |= JF_START; 200 break; 201 case JF_SET: 202 if (!(dj->flags & JF_OP_MASK)) 203 dj->flags |= JF_SET; 204 else if (dj->flags & JF_STOP) 205 dj->flags |= JF_START; 206 break; 207 case JF_STOP: 208 case JF_RESTART: 209 if (!(dj->flags & JF_STOP)) 210 reset = 1; 211 dj->flags |= JF_STOP; 212 if (dj->flags & JF_SET) 213 dj->flags ^= (JF_START | JF_SET); 214 break; 215 } 216 } 217 if (reset) 218 dep_reset(dj); 219 if (!((d->flags & DF_LIGHT) && 220 (rev ? dj->jid < 0 : dj->jid > 0))) 221 ndeps++; 222 } 223 if (ndeps == 0) 224 return 0; 225 requeue(j, &depend); 226 return 1; 227} 228 229/* 230 * Resolve any dependencies from a finished jail. 231 */ 232void 233dep_done(struct cfjail *j, unsigned flags) 234{ 235 struct cfjail *dj; 236 struct cfdepend *d; 237 int depfrom, depto; 238 239 if (JF_DO_STOP(j->flags)) { 240 depfrom = DEP_TO; 241 depto = DEP_FROM; 242 } else { 243 depfrom = DEP_FROM; 244 depto = DEP_TO; 245 } 246 STAILQ_FOREACH(d, &j->dep[depto], tq[depto]) { 247 if ((d->flags & DF_SEEN) | (flags & ~d->flags & DF_LIGHT)) 248 continue; 249 d->flags |= DF_SEEN; 250 dj = d->j[depfrom]; 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)) && 255 verbose >= 0) 256 jail_warnx(dj, "skipped"); 257 dj->flags |= JF_FAILED; 258 } 259 if (!--dj->ndeps && dj->queue == &depend) 260 requeue(dj, &ready); 261 } 262} 263 264/* 265 * Count a jail's dependencies and mark them as unseen. 266 */ 267void 268dep_reset(struct cfjail *j) 269{ 270 int depfrom; 271 struct cfdepend *d; 272 273 depfrom = JF_DO_STOP(j->flags) ? DEP_TO : DEP_FROM; 274 j->ndeps = 0; 275 STAILQ_FOREACH(d, &j->dep[depfrom], tq[depfrom]) 276 j->ndeps++; 277} 278 279/* 280 * Find the next jail ready to do something. 281 */ 282struct cfjail * 283next_jail(void) 284{ 285 struct cfjail *j; 286 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)) 292 break; 293 } 294 if (j != NULL) 295 requeue(j, &cfjails); 296 return j; 297} 298 299/* 300 * Set jails to the proper start state. 301 */ 302int 303start_state(const char *target, unsigned state, int running) 304{ 305 struct iovec jiov[6]; 306 struct cfjail *j, *tj; 307 int jid; 308 char namebuf[MAXHOSTNAMELEN]; 309 310 if (!target || (!running && !strcmp(target, "*"))) { 311 /* 312 * If there's no target specified, set the state on all jails, 313 * and start with those that have no dependencies. 314 */ 315 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 316 j->flags = (j->flags & JF_FAILED) | state | JF_WILD; 317 dep_reset(j); 318 requeue(j, j->ndeps ? &depend : &ready); 319 } 320 } else if (wild_jail_name(target)) { 321 /* 322 * For targets specified singly, or with a non-global wildcard, 323 * set their state and call them ready (even if there are 324 * dependencies). Leave everything else unqueued for now. 325 */ 326 if (running) { 327 /* 328 * -R matches its wildcards against currently running 329 * jails, not against the config file. 330 */ 331 *(const void **)&jiov[0].iov_base = "lastjid"; 332 jiov[0].iov_len = sizeof("lastjid"); 333 jiov[1].iov_base = &jid; 334 jiov[1].iov_len = sizeof(jid); 335 *(const void **)&jiov[2].iov_base = "jid"; 336 jiov[2].iov_len = sizeof("jid"); 337 jiov[3].iov_base = &jid; 338 jiov[3].iov_len = sizeof(jid); 339 *(const void **)&jiov[4].iov_base = "name"; 340 jiov[4].iov_len = sizeof("name"); 341 jiov[5].iov_base = &namebuf; 342 jiov[5].iov_len = sizeof(namebuf); 343 for (jid = 0; jail_get(jiov, 6, 0) > 0; ) { 344 if (wild_jail_match(namebuf, target)) { 345 j = add_jail(); 346 j->name = estrdup(namebuf); 347 j->jid = jid; 348 j->flags = (j->flags & JF_FAILED) | 349 state | JF_WILD; 350 dep_reset(j); 351 requeue(j, &ready); 352 } 353 } 354 } else { 355 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 356 if (wild_jail_match(j->name, target)) { 357 j->flags = (j->flags & JF_FAILED) | 358 state | JF_WILD; 359 dep_reset(j); 360 requeue(j, &ready); 361 } 362 } 363 } 364 } else { 365 j = find_jail(target); 366 if (j == NULL && state == JF_STOP) { 367 /* Allow -[rR] to specify a currently running jail. */ 368 if ((jid = running_jid(target, JAIL_DYING)) > 0) { 369 j = add_jail(); 370 j->name = estrdup(target); 371 j->jid = jid; 372 } 373 } 374 if (j == NULL) { 375 warnx("\"%s\" not found", target); 376 return -1; 377 } 378 j->flags = (j->flags & JF_FAILED) | state; 379 dep_reset(j); 380 requeue(j, &ready); 381 } 382 return 0; 383} 384 385/* 386 * Move a jail to a new list. 387 */ 388void 389requeue(struct cfjail *j, struct cfjails *queue) 390{ 391 if (j->queue != queue) { 392 TAILQ_REMOVE(j->queue, j, tq); 393 TAILQ_INSERT_TAIL(queue, j, tq); 394 j->queue = queue; 395 } 396} 397 398/* 399 * Add a dependency edge between two jails. 400 */ 401static void 402dep_add(struct cfjail *from, struct cfjail *to, unsigned flags) 403{ 404 struct cfdepend *d; 405 406 d = emalloc(sizeof(struct cfdepend)); 407 d->flags = flags; 408 d->j[DEP_FROM] = from; 409 d->j[DEP_TO] = to; 410 STAILQ_INSERT_TAIL(&from->dep[DEP_FROM], d, tq[DEP_FROM]); 411 STAILQ_INSERT_TAIL(&to->dep[DEP_TO], d, tq[DEP_TO]); 412} 413 414/* 415 * Compare jail pointers for qsort/bsearch. 416 */ 417static int 418cmp_jailptr(const void *a, const void *b) 419{ 420 return strcmp((*((struct cfjail * const *)a))->name, 421 ((*(struct cfjail * const *)b))->name); 422} 423 424static int 425cmp_jailptr_name(const void *a, const void *b) 426{ 427 return strcmp((const char *)a, ((*(struct cfjail * const *)b))->name); 428} 429 430/* 431 * Find a jail object by name. 432 */ 433static struct cfjail * 434find_jail(const char *name) 435{ 436 struct cfjail **jp; 437 438 jp = bsearch(name, jails_byname, njails, sizeof(struct cfjail *), 439 cmp_jailptr_name); 440 return jp ? *jp : NULL; 441} 442 443/* 444 * Return the named jail's jid if it is running, and -1 if it isn't. 445 */ 446static int 447running_jid(const char *name, int flags) 448{ 449 struct iovec jiov[2]; 450 char *ep; 451 int jid; 452 453 if ((jid = strtol(name, &ep, 10)) && !*ep) { 454 *(const void **)&jiov[0].iov_base = "jid"; 455 jiov[0].iov_len = sizeof("jid"); 456 jiov[1].iov_base = &jid; 457 jiov[1].iov_len = sizeof(jid); 458 } else { 459 *(const void **)&jiov[0].iov_base = "name"; 460 jiov[0].iov_len = sizeof("name"); 461 jiov[1].iov_len = strlen(name) + 1; 462 jiov[1].iov_base = alloca(jiov[1].iov_len); 463 strcpy(jiov[1].iov_base, name); 464 } 465 return jail_get(jiov, 2, flags); 466}
|