command.c (223188) | command.c (223189) |
---|---|
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 --- 11 unchanged lines hidden (view full) --- 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 --- 11 unchanged lines hidden (view full) --- 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> |
28__FBSDID("$FreeBSD: projects/jailconf/usr.sbin/jail/command.c 223188 2011-06-17 16:06:13Z jamie $"); | 28__FBSDID("$FreeBSD: projects/jailconf/usr.sbin/jail/command.c 223189 2011-06-17 16:18:44Z jamie $"); |
29 30#include <sys/types.h> 31#include <sys/event.h> 32#include <sys/mount.h> 33#include <sys/stat.h> 34#include <sys/sysctl.h> 35#include <sys/user.h> 36#include <sys/wait.h> --- 8 unchanged lines hidden (view full) --- 45#include <signal.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <unistd.h> 50 51#include "jailp.h" 52 | 29 30#include <sys/types.h> 31#include <sys/event.h> 32#include <sys/mount.h> 33#include <sys/stat.h> 34#include <sys/sysctl.h> 35#include <sys/user.h> 36#include <sys/wait.h> --- 8 unchanged lines hidden (view full) --- 45#include <signal.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <unistd.h> 50 51#include "jailp.h" 52 |
53#define COMSTRING_DUMMY ((struct cfstring *)1) | |
54#define DEFAULT_STOP_TIMEOUT 10 55#define PHASH_SIZE 256 56 57LIST_HEAD(phhead, phash); 58 59struct phash { 60 LIST_ENTRY(phash) le; 61 struct cfjail *j; 62 pid_t pid; 63}; 64 65int paralimit = -1; 66 67extern char **environ; 68 | 53#define DEFAULT_STOP_TIMEOUT 10 54#define PHASH_SIZE 256 55 56LIST_HEAD(phhead, phash); 57 58struct phash { 59 LIST_ENTRY(phash) le; 60 struct cfjail *j; 61 pid_t pid; 62}; 63 64int paralimit = -1; 65 66extern char **environ; 67 |
69static int get_user_info(struct cfjail *j, const char *username, 70 const struct passwd **pwdp, login_cap_t **lcapp); | 68static int run_command(struct cfjail *j); |
71static void add_proc(struct cfjail *j, pid_t pid); 72static void clear_procs(struct cfjail *j); 73static struct cfjail *find_proc(pid_t pid); 74static int term_procs(struct cfjail *j); | 69static void add_proc(struct cfjail *j, pid_t pid); 70static void clear_procs(struct cfjail *j); 71static struct cfjail *find_proc(pid_t pid); 72static int term_procs(struct cfjail *j); |
73static int get_user_info(struct cfjail *j, const char *username, 74 const struct passwd **pwdp, login_cap_t **lcapp); |
|
75static int check_path(struct cfjail *j, const char *pname, const char *path, 76 int isfile, const char *umount_type); 77 78static struct cfjails sleeping = TAILQ_HEAD_INITIALIZER(sleeping); 79static struct cfjails runnable = TAILQ_HEAD_INITIALIZER(runnable); 80static struct phhead phash[PHASH_SIZE]; 81static int kq; 82 83/* | 75static int check_path(struct cfjail *j, const char *pname, const char *path, 76 int isfile, const char *umount_type); 77 78static struct cfjails sleeping = TAILQ_HEAD_INITIALIZER(sleeping); 79static struct cfjails runnable = TAILQ_HEAD_INITIALIZER(runnable); 80static struct phhead phash[PHASH_SIZE]; 81static int kq; 82 83/* |
84 * Run a command associated with a jail, possibly inside the jail. | 84 * Run the next command associated with a jail. |
85 */ 86int | 85 */ 86int |
87run_command(struct cfjail *j, enum intparam comparam) | 87next_command(struct cfjail *j) |
88{ | 88{ |
89 const struct cfstring *comstring; 90 enum intparam comparam; 91 int rval, create_failed; 92 93 static struct cfstring dummystring = { .len = 1 }; 94 95 rval = 0; 96 create_failed = (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED; 97 for (; (comparam = *j->comparam) && comparam != IP__OP; 98 j->comparam += create_failed ? -1 : 1) { 99 if (j->comstring == NULL) { 100 switch (comparam) { 101 case IP_MOUNT_DEVFS: 102 if (!bool_param(j->intparams[IP_MOUNT_DEVFS])) 103 continue; 104 /* FALLTHROUGH */ 105 case IP_STOP_TIMEOUT: 106 j->comstring = &dummystring; 107 break; 108 default: 109 if (j->intparams[comparam] == NULL) 110 continue; 111 j->comstring = create_failed 112 ? TAILQ_LAST(&j->intparams[comparam]->val, 113 cfstrings) 114 : TAILQ_FIRST(&j->intparams[comparam]->val); 115 } 116 } 117 for (; j->comstring != NULL; 118 j->comstring = create_failed 119 ? TAILQ_PREV(j->comstring, cfstrings, tq) 120 : TAILQ_NEXT(j->comstring, tq)) { 121 if (rval != 0) 122 return rval; 123 if (j->comstring->len == 0 || (create_failed && 124 (comparam == IP_EXEC_PRESTART || comparam == 125 IP_EXEC_START || comparam == IP_COMMAND || 126 comparam == IP_EXEC_POSTSTART))) 127 continue; 128 if (paralimit == 0) { 129 requeue(j, &runnable); 130 return 1; 131 } 132 rval = run_command(j); 133 create_failed = 134 (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED; 135 } 136 } 137 return rval; 138} 139 140/* 141 * Check command exit status 142 */ 143int 144finish_command(struct cfjail *j) 145{ 146 int error; 147 148 if (!(j->flags & JF_SLEEPQ)) 149 return 0; 150 j->flags &= ~JF_SLEEPQ; 151 if (*j->comparam != IP_STOP_TIMEOUT) { 152 paralimit++; 153 if (!TAILQ_EMPTY(&runnable)) 154 requeue(TAILQ_FIRST(&runnable), &ready); 155 } 156 error = 0; 157 if (j->flags & JF_TIMEOUT) { 158 j->flags &= ~JF_TIMEOUT; 159 if (*j->comparam != IP_STOP_TIMEOUT) { 160 jail_warnx(j, "%s: timed out", j->comline); 161 failed(j); 162 error = -1; 163 } else if (verbose > 0) 164 jail_note(j, "timed out\n"); 165 } else if (j->pstatus != 0) { 166 if (WIFSIGNALED(j->pstatus)) 167 jail_warnx(j, "%s: exited on signal %d", 168 j->comline, WTERMSIG(j->pstatus)); 169 else 170 jail_warnx(j, "%s: failed", j->comline); 171 j->pstatus = 0; 172 failed(j); 173 error = -1; 174 } 175 free(j->comline); 176 j->comline = NULL; 177 return error; 178} 179 180/* 181 * Check for finished processed or timeouts. 182 */ 183struct cfjail * 184next_proc(int nonblock) 185{ 186 struct kevent ke; 187 struct timespec ts; 188 struct timespec *tsp; 189 struct cfjail *j; 190 191 if (!TAILQ_EMPTY(&sleeping)) { 192 again: 193 tsp = NULL; 194 if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) { 195 clock_gettime(CLOCK_REALTIME, &ts); 196 ts.tv_sec = j->timeout.tv_sec - ts.tv_sec; 197 ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec; 198 if (ts.tv_nsec < 0) { 199 ts.tv_sec--; 200 ts.tv_nsec += 1000000000; 201 } 202 if (ts.tv_sec < 0 || 203 (ts.tv_sec == 0 && ts.tv_nsec == 0)) { 204 j->flags |= JF_TIMEOUT; 205 clear_procs(j); 206 return j; 207 } 208 tsp = &ts; 209 } 210 if (nonblock) { 211 ts.tv_sec = 0; 212 ts.tv_nsec = 0; 213 tsp = &ts; 214 } 215 switch (kevent(kq, NULL, 0, &ke, 1, tsp)) { 216 case -1: 217 if (errno != EINTR) 218 err(1, "kevent"); 219 goto again; 220 case 0: 221 if (!nonblock) { 222 j = TAILQ_FIRST(&sleeping); 223 j->flags |= JF_TIMEOUT; 224 clear_procs(j); 225 return j; 226 } 227 break; 228 case 1: 229 (void)waitpid(ke.ident, NULL, WNOHANG); 230 if ((j = find_proc(ke.ident))) { 231 j->pstatus = ke.data; 232 return j; 233 } 234 goto again; 235 } 236 } 237 return NULL; 238} 239 240/* 241 * Run a single command for a jail, possible inside the jail. 242 */ 243int 244run_command(struct cfjail *j) 245{ |
|
89 const struct passwd *pwd; | 246 const struct passwd *pwd; |
90 struct cfstring *comstring, *s; | 247 const struct cfstring *comstring, *s; |
91 login_cap_t *lcap; 92 char **argv; 93 char *cs, *addr, *comcs, *devpath; 94 const char *jidstr, *conslog, *path, *ruleset, *term, *username; | 248 login_cap_t *lcap; 249 char **argv; 250 char *cs, *addr, *comcs, *devpath; 251 const char *jidstr, *conslog, *path, *ruleset, *term, *username; |
252 enum intparam comparam; |
|
95 size_t comlen; 96 pid_t pid; 97 int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout; 98 99 static char *cleanenv; 100 | 253 size_t comlen; 254 pid_t pid; 255 int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout; 256 257 static char *cleanenv; 258 |
101 if (comparam) { 102 switch (comparam) { 103 case IP_MOUNT_DEVFS: 104 if (!bool_param(j->intparams[IP_MOUNT_DEVFS])) 105 return 0; 106 /* FALLTHROUGH */ 107 case IP_STOP_TIMEOUT: 108 j->comstring = COMSTRING_DUMMY; 109 break; 110 default: 111 if (j->intparams[comparam] == NULL) 112 return 0; 113 j->comstring = 114 TAILQ_FIRST(&j->intparams[comparam]->val); 115 } 116 j->comparam = comparam; 117 } else 118 comparam = j->comparam; 119 next_comstring: 120 comstring = j->comstring; 121 if (comstring == NULL) 122 return 0; 123 if (paralimit == 0) { 124 requeue(j, &runnable); 125 return 1; 126 } 127 j->comstring = 128 comstring == COMSTRING_DUMMY ? NULL : TAILQ_NEXT(comstring, tq); 129 if (comstring != COMSTRING_DUMMY && comstring->len == 0) 130 goto next_comstring; | |
131 /* 132 * Collect exec arguments. Internal commands for network and 133 * mounting build their own argument lists. 134 */ | 259 /* 260 * Collect exec arguments. Internal commands for network and 261 * mounting build their own argument lists. 262 */ |
135 bg = j->flags & JF_FAILED; | 263 comparam = *j->comparam; 264 comstring = j->comstring; 265 bg = 0; |
136 down = j->flags & (JF_STOP | JF_FAILED); 137 switch (comparam) { 138 case IP_STOP_TIMEOUT: 139 /* This isn't really a command */ 140 return term_procs(j); 141 142 case IP__IP4_IFADDR: 143 argv = alloca(8 * sizeof(char *)); --- 20 unchanged lines hidden (view full) --- 164 *(const char **)&argv[5] = cs + 1; 165 argc = 6; 166 } else { 167 argv[3] = addr; 168 argc = 4; 169 } 170 *(const char **)&argv[argc] = down ? "-alias" : "alias"; 171 argv[argc + 1] = NULL; | 266 down = j->flags & (JF_STOP | JF_FAILED); 267 switch (comparam) { 268 case IP_STOP_TIMEOUT: 269 /* This isn't really a command */ 270 return term_procs(j); 271 272 case IP__IP4_IFADDR: 273 argv = alloca(8 * sizeof(char *)); --- 20 unchanged lines hidden (view full) --- 294 *(const char **)&argv[5] = cs + 1; 295 argc = 6; 296 } else { 297 argv[3] = addr; 298 argc = 4; 299 } 300 *(const char **)&argv[argc] = down ? "-alias" : "alias"; 301 argv[argc + 1] = NULL; |
172 j->flags |= JF_IFUP; | |
173 break; 174 175#ifdef INET6 176 case IP__IP6_IFADDR: 177 argv = alloca(8 * sizeof(char *)); 178 *(const char **)&argv[0] = _PATH_IFCONFIG; 179 if ((cs = strchr(comstring->s, '|'))) { 180 argv[1] = alloca(cs - comstring->s + 1); --- 9 unchanged lines hidden (view full) --- 190 if (!(cs = strchr(addr, '/'))) { 191 *(const char **)&argv[4] = "prefixlen"; 192 *(const char **)&argv[5] = "128"; 193 argc = 6; 194 } else 195 argc = 4; 196 *(const char **)&argv[argc] = down ? "-alias" : "alias"; 197 argv[argc + 1] = NULL; | 302 break; 303 304#ifdef INET6 305 case IP__IP6_IFADDR: 306 argv = alloca(8 * sizeof(char *)); 307 *(const char **)&argv[0] = _PATH_IFCONFIG; 308 if ((cs = strchr(comstring->s, '|'))) { 309 argv[1] = alloca(cs - comstring->s + 1); --- 9 unchanged lines hidden (view full) --- 319 if (!(cs = strchr(addr, '/'))) { 320 *(const char **)&argv[4] = "prefixlen"; 321 *(const char **)&argv[5] = "128"; 322 argc = 6; 323 } else 324 argc = 4; 325 *(const char **)&argv[argc] = down ? "-alias" : "alias"; 326 argv[argc + 1] = NULL; |
198 j->flags |= JF_IFUP; | |
199 break; 200#endif 201 202 case IP_VNET_INTERFACE: 203 argv = alloca(5 * sizeof(char *)); 204 *(const char **)&argv[0] = _PATH_IFCONFIG; 205 argv[1] = comstring->s; 206 *(const char **)&argv[2] = down ? "-vnet" : "vnet"; 207 jidstr = string_param(j->intparams[KP_JID]); 208 *(const char **)&argv[3] = 209 jidstr ? jidstr : string_param(j->intparams[KP_NAME]); 210 argv[4] = NULL; | 327 break; 328#endif 329 330 case IP_VNET_INTERFACE: 331 argv = alloca(5 * sizeof(char *)); 332 *(const char **)&argv[0] = _PATH_IFCONFIG; 333 argv[1] = comstring->s; 334 *(const char **)&argv[2] = down ? "-vnet" : "vnet"; 335 jidstr = string_param(j->intparams[KP_JID]); 336 *(const char **)&argv[3] = 337 jidstr ? jidstr : string_param(j->intparams[KP_NAME]); 338 argv[4] = NULL; |
211 j->flags |= JF_IFUP; | |
212 break; 213 214 case IP_MOUNT: 215 case IP__MOUNT_FROM_FSTAB: 216 argv = alloca(8 * sizeof(char *)); 217 comcs = alloca(comstring->len + 1); 218 strcpy(comcs, comstring->s); 219 argc = 0; 220 for (cs = strtok(comcs, " \t\f\v\r\n"); cs && argc < 4; 221 cs = strtok(NULL, " \t\f\v\r\n")) 222 argv[argc++] = cs; 223 if (argc == 0) | 339 break; 340 341 case IP_MOUNT: 342 case IP__MOUNT_FROM_FSTAB: 343 argv = alloca(8 * sizeof(char *)); 344 comcs = alloca(comstring->len + 1); 345 strcpy(comcs, comstring->s); 346 argc = 0; 347 for (cs = strtok(comcs, " \t\f\v\r\n"); cs && argc < 4; 348 cs = strtok(NULL, " \t\f\v\r\n")) 349 argv[argc++] = cs; 350 if (argc == 0) |
224 goto next_comstring; | 351 return 0; |
225 if (argc < 3) { 226 jail_warnx(j, "%s: %s: missing information", 227 j->intparams[comparam]->name, comstring->s); 228 failed(j); 229 return -1; 230 } 231 if (check_path(j, j->intparams[comparam]->name, argv[1], 0, 232 down ? argv[2] : NULL) < 0) { --- 14 unchanged lines hidden (view full) --- 247 } else { 248 argv[5] = NULL; 249 argv[4] = argv[1]; 250 argv[3] = argv[0]; 251 } 252 *(const char **)&argv[0] = _PATH_MOUNT; 253 } 254 *(const char **)&argv[1] = "-t"; | 352 if (argc < 3) { 353 jail_warnx(j, "%s: %s: missing information", 354 j->intparams[comparam]->name, comstring->s); 355 failed(j); 356 return -1; 357 } 358 if (check_path(j, j->intparams[comparam]->name, argv[1], 0, 359 down ? argv[2] : NULL) < 0) { --- 14 unchanged lines hidden (view full) --- 374 } else { 375 argv[5] = NULL; 376 argv[4] = argv[1]; 377 argv[3] = argv[0]; 378 } 379 *(const char **)&argv[0] = _PATH_MOUNT; 380 } 381 *(const char **)&argv[1] = "-t"; |
255 j->flags |= JF_MOUNTED; | |
256 break; 257 258 case IP_MOUNT_DEVFS: 259 path = string_param(j->intparams[KP_PATH]); 260 if (path == NULL) { 261 jail_warnx(j, "mount.devfs: no path"); 262 failed(j); 263 return -1; --- 18 unchanged lines hidden (view full) --- 282 [IP_MOUNT_DEVFS_RULESET]); 283 argv[2] = alloca(strlen(path) + 284 (ruleset ? strlen(ruleset) + 1 : 0) + 56); 285 sprintf(argv[2], ". /etc/rc.subr; load_rc_config .; " 286 "devfs_mount_jail %s/dev%s%s", path, 287 ruleset ? " " : "", ruleset ? ruleset : ""); 288 argv[3] = NULL; 289 } | 382 break; 383 384 case IP_MOUNT_DEVFS: 385 path = string_param(j->intparams[KP_PATH]); 386 if (path == NULL) { 387 jail_warnx(j, "mount.devfs: no path"); 388 failed(j); 389 return -1; --- 18 unchanged lines hidden (view full) --- 408 [IP_MOUNT_DEVFS_RULESET]); 409 argv[2] = alloca(strlen(path) + 410 (ruleset ? strlen(ruleset) + 1 : 0) + 56); 411 sprintf(argv[2], ". /etc/rc.subr; load_rc_config .; " 412 "devfs_mount_jail %s/dev%s%s", path, 413 ruleset ? " " : "", ruleset ? ruleset : ""); 414 argv[3] = NULL; 415 } |
290 j->flags |= JF_MOUNTED; | |
291 break; 292 293 case IP_COMMAND: 294 if (j->name != NULL) 295 goto default_command; 296 argc = 0; 297 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq) 298 argc++; --- 29 unchanged lines hidden (view full) --- 328 strcpy(comcs, comstring->s); 329 argc = 0; 330 for (cs = strtok(comcs, " \t\f\v\r\n"); cs; 331 cs = strtok(NULL, " \t\f\v\r\n")) 332 argv[argc++] = cs; 333 argv[argc] = NULL; 334 } 335 } | 416 break; 417 418 case IP_COMMAND: 419 if (j->name != NULL) 420 goto default_command; 421 argc = 0; 422 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq) 423 argc++; --- 29 unchanged lines hidden (view full) --- 453 strcpy(comcs, comstring->s); 454 argc = 0; 455 for (cs = strtok(comcs, " \t\f\v\r\n"); cs; 456 cs = strtok(NULL, " \t\f\v\r\n")) 457 argv[argc++] = cs; 458 argv[argc] = NULL; 459 } 460 } |
336 | |
337 if (argv[0] == NULL) | 461 if (argv[0] == NULL) |
338 goto next_comstring; | 462 return 0; 463 |
339 if (int_param(j->intparams[IP_EXEC_TIMEOUT], &timeout) && 340 timeout != 0) { 341 clock_gettime(CLOCK_REALTIME, &j->timeout); 342 j->timeout.tv_sec += timeout; 343 } else 344 j->timeout.tv_sec = 0; 345 346 injail = comparam == IP_EXEC_START || comparam == IP_COMMAND || --- 47 unchanged lines hidden (view full) --- 394 paralimit--; 395 add_proc(j, pid); 396 } 397 return 1; 398 } 399 if (bg) 400 setsid(); 401 | 464 if (int_param(j->intparams[IP_EXEC_TIMEOUT], &timeout) && 465 timeout != 0) { 466 clock_gettime(CLOCK_REALTIME, &j->timeout); 467 j->timeout.tv_sec += timeout; 468 } else 469 j->timeout.tv_sec = 0; 470 471 injail = comparam == IP_EXEC_START || comparam == IP_COMMAND || --- 47 unchanged lines hidden (view full) --- 519 paralimit--; 520 add_proc(j, pid); 521 } 522 return 1; 523 } 524 if (bg) 525 setsid(); 526 |
527 /* Set up the environment and run the command */ |
|
402 pwd = NULL; 403 lcap = NULL; 404 if ((clean || username) && injail && sjuser && 405 get_user_info(j, username, &pwd, &lcap) < 0) 406 exit(1); 407 if (injail) { 408 /* jail_attach won't chdir along with its chroot. */ 409 path = string_param(j->intparams[KP_PATH]); --- 47 unchanged lines hidden (view full) --- 457 } 458 closefrom(3); 459 execvp(argv[0], argv); 460 jail_warnx(j, "exec %s: %s", argv[0], strerror(errno)); 461 exit(1); 462} 463 464/* | 528 pwd = NULL; 529 lcap = NULL; 530 if ((clean || username) && injail && sjuser && 531 get_user_info(j, username, &pwd, &lcap) < 0) 532 exit(1); 533 if (injail) { 534 /* jail_attach won't chdir along with its chroot. */ 535 path = string_param(j->intparams[KP_PATH]); --- 47 unchanged lines hidden (view full) --- 583 } 584 closefrom(3); 585 execvp(argv[0], argv); 586 jail_warnx(j, "exec %s: %s", argv[0], strerror(errno)); 587 exit(1); 588} 589 590/* |
465 * Check command exit status 466 */ 467int 468finish_command(struct cfjail *j) 469{ 470 int error; 471 472 if (!(j->flags & JF_SLEEPQ)) 473 return 0; 474 j->flags &= ~JF_SLEEPQ; 475 if (j->comparam != IP_STOP_TIMEOUT) { 476 paralimit++; 477 if (!TAILQ_EMPTY(&runnable)) 478 requeue(TAILQ_FIRST(&runnable), &ready); 479 } 480 error = 0; 481 if (j->flags & JF_TIMEOUT) { 482 j->flags &= ~JF_TIMEOUT; 483 if (j->comparam != IP_STOP_TIMEOUT) { 484 jail_warnx(j, "%s: timed out", j->comline); 485 failed(j); 486 error = -1; 487 } else if (verbose > 0) 488 jail_note(j, "timed out\n"); 489 } else if (j->pstatus != 0) { 490 if (WIFSIGNALED(j->pstatus)) 491 jail_warnx(j, "%s: exited on signal %d", 492 j->comline, WTERMSIG(j->pstatus)); 493 else 494 jail_warnx(j, "%s: failed", j->comline); 495 j->pstatus = 0; 496 failed(j); 497 error = -1; 498 } 499 free(j->comline); 500 j->comline = NULL; 501 return error; 502} 503 504/* 505 * Check for finished processed or timeouts. 506 */ 507struct cfjail * 508next_proc(int nonblock) 509{ 510 struct kevent ke; 511 struct timespec ts; 512 struct timespec *tsp; 513 struct cfjail *j; 514 515 if (!TAILQ_EMPTY(&sleeping)) { 516 again: 517 tsp = NULL; 518 if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) { 519 clock_gettime(CLOCK_REALTIME, &ts); 520 ts.tv_sec = j->timeout.tv_sec - ts.tv_sec; 521 ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec; 522 if (ts.tv_nsec < 0) { 523 ts.tv_sec--; 524 ts.tv_nsec += 1000000000; 525 } 526 if (ts.tv_sec < 0 || 527 (ts.tv_sec == 0 && ts.tv_nsec == 0)) { 528 j->flags |= JF_TIMEOUT; 529 clear_procs(j); 530 return j; 531 } 532 tsp = &ts; 533 } 534 if (nonblock) { 535 ts.tv_sec = 0; 536 ts.tv_nsec = 0; 537 tsp = &ts; 538 } 539 switch (kevent(kq, NULL, 0, &ke, 1, tsp)) { 540 case -1: 541 if (errno != EINTR) 542 err(1, "kevent"); 543 goto again; 544 case 0: 545 if (!nonblock) { 546 j = TAILQ_FIRST(&sleeping); 547 j->flags |= JF_TIMEOUT; 548 clear_procs(j); 549 return j; 550 } 551 break; 552 case 1: 553 (void)waitpid(ke.ident, NULL, WNOHANG); 554 if ((j = find_proc(ke.ident))) { 555 j->pstatus = ke.data; 556 return j; 557 } 558 goto again; 559 } 560 } 561 return NULL; 562} 563 564/* | |
565 * Add a process to the hash, tied to a jail. 566 */ 567static void 568add_proc(struct cfjail *j, pid_t pid) 569{ 570 struct kevent ke; 571 struct cfjail *tj; 572 struct phash *ph; --- 230 unchanged lines hidden --- | 591 * Add a process to the hash, tied to a jail. 592 */ 593static void 594add_proc(struct cfjail *j, pid_t pid) 595{ 596 struct kevent ke; 597 struct cfjail *tj; 598 struct phash *ph; --- 230 unchanged lines hidden --- |