diff options
-rw-r--r-- | usr.sbin/jail/command.c | 316 | ||||
-rw-r--r-- | usr.sbin/jail/config.c | 1 | ||||
-rw-r--r-- | usr.sbin/jail/jail.c | 239 | ||||
-rw-r--r-- | usr.sbin/jail/jailp.h | 13 |
4 files changed, 266 insertions, 303 deletions
diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c index f757a83..ce90797 100644 --- a/usr.sbin/jail/command.c +++ b/usr.sbin/jail/command.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include "jailp.h" -#define COMSTRING_DUMMY ((struct cfstring *)1) #define DEFAULT_STOP_TIMEOUT 10 #define PHASH_SIZE 256 @@ -66,12 +65,13 @@ int paralimit = -1; extern char **environ; -static int get_user_info(struct cfjail *j, const char *username, - const struct passwd **pwdp, login_cap_t **lcapp); +static int run_command(struct cfjail *j); static void add_proc(struct cfjail *j, pid_t pid); static void clear_procs(struct cfjail *j); static struct cfjail *find_proc(pid_t pid); static int term_procs(struct cfjail *j); +static int get_user_info(struct cfjail *j, const char *username, + const struct passwd **pwdp, login_cap_t **lcapp); static int check_path(struct cfjail *j, const char *pname, const char *path, int isfile, const char *umount_type); @@ -81,58 +81,188 @@ static struct phhead phash[PHASH_SIZE]; static int kq; /* - * Run a command associated with a jail, possibly inside the jail. + * Run the next command associated with a jail. + */ +int +next_command(struct cfjail *j) +{ + const struct cfstring *comstring; + enum intparam comparam; + int rval, create_failed; + + static struct cfstring dummystring = { .len = 1 }; + + rval = 0; + create_failed = (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED; + for (; (comparam = *j->comparam) && comparam != IP__OP; + j->comparam += create_failed ? -1 : 1) { + if (j->comstring == NULL) { + switch (comparam) { + case IP_MOUNT_DEVFS: + if (!bool_param(j->intparams[IP_MOUNT_DEVFS])) + continue; + /* FALLTHROUGH */ + case IP_STOP_TIMEOUT: + j->comstring = &dummystring; + break; + default: + if (j->intparams[comparam] == NULL) + continue; + j->comstring = create_failed + ? TAILQ_LAST(&j->intparams[comparam]->val, + cfstrings) + : TAILQ_FIRST(&j->intparams[comparam]->val); + } + } + for (; j->comstring != NULL; + j->comstring = create_failed + ? TAILQ_PREV(j->comstring, cfstrings, tq) + : TAILQ_NEXT(j->comstring, tq)) { + if (rval != 0) + return rval; + if (j->comstring->len == 0 || (create_failed && + (comparam == IP_EXEC_PRESTART || comparam == + IP_EXEC_START || comparam == IP_COMMAND || + comparam == IP_EXEC_POSTSTART))) + continue; + if (paralimit == 0) { + requeue(j, &runnable); + return 1; + } + rval = run_command(j); + create_failed = + (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED; + } + } + return rval; +} + +/* + * Check command exit status */ int -run_command(struct cfjail *j, enum intparam comparam) +finish_command(struct cfjail *j) +{ + int error; + + if (!(j->flags & JF_SLEEPQ)) + return 0; + j->flags &= ~JF_SLEEPQ; + if (*j->comparam != IP_STOP_TIMEOUT) { + paralimit++; + if (!TAILQ_EMPTY(&runnable)) + requeue(TAILQ_FIRST(&runnable), &ready); + } + error = 0; + if (j->flags & JF_TIMEOUT) { + j->flags &= ~JF_TIMEOUT; + if (*j->comparam != IP_STOP_TIMEOUT) { + jail_warnx(j, "%s: timed out", j->comline); + failed(j); + error = -1; + } else if (verbose > 0) + jail_note(j, "timed out\n"); + } else if (j->pstatus != 0) { + if (WIFSIGNALED(j->pstatus)) + jail_warnx(j, "%s: exited on signal %d", + j->comline, WTERMSIG(j->pstatus)); + else + jail_warnx(j, "%s: failed", j->comline); + j->pstatus = 0; + failed(j); + error = -1; + } + free(j->comline); + j->comline = NULL; + return error; +} + +/* + * Check for finished processed or timeouts. + */ +struct cfjail * +next_proc(int nonblock) +{ + struct kevent ke; + struct timespec ts; + struct timespec *tsp; + struct cfjail *j; + + if (!TAILQ_EMPTY(&sleeping)) { + again: + tsp = NULL; + if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec = j->timeout.tv_sec - ts.tv_sec; + ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000; + } + if (ts.tv_sec < 0 || + (ts.tv_sec == 0 && ts.tv_nsec == 0)) { + j->flags |= JF_TIMEOUT; + clear_procs(j); + return j; + } + tsp = &ts; + } + if (nonblock) { + ts.tv_sec = 0; + ts.tv_nsec = 0; + tsp = &ts; + } + switch (kevent(kq, NULL, 0, &ke, 1, tsp)) { + case -1: + if (errno != EINTR) + err(1, "kevent"); + goto again; + case 0: + if (!nonblock) { + j = TAILQ_FIRST(&sleeping); + j->flags |= JF_TIMEOUT; + clear_procs(j); + return j; + } + break; + case 1: + (void)waitpid(ke.ident, NULL, WNOHANG); + if ((j = find_proc(ke.ident))) { + j->pstatus = ke.data; + return j; + } + goto again; + } + } + return NULL; +} + +/* + * Run a single command for a jail, possible inside the jail. + */ +int +run_command(struct cfjail *j) { const struct passwd *pwd; - struct cfstring *comstring, *s; + const struct cfstring *comstring, *s; login_cap_t *lcap; char **argv; char *cs, *addr, *comcs, *devpath; const char *jidstr, *conslog, *path, *ruleset, *term, *username; + enum intparam comparam; size_t comlen; pid_t pid; int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout; static char *cleanenv; - if (comparam) { - switch (comparam) { - case IP_MOUNT_DEVFS: - if (!bool_param(j->intparams[IP_MOUNT_DEVFS])) - return 0; - /* FALLTHROUGH */ - case IP_STOP_TIMEOUT: - j->comstring = COMSTRING_DUMMY; - break; - default: - if (j->intparams[comparam] == NULL) - return 0; - j->comstring = - TAILQ_FIRST(&j->intparams[comparam]->val); - } - j->comparam = comparam; - } else - comparam = j->comparam; - next_comstring: - comstring = j->comstring; - if (comstring == NULL) - return 0; - if (paralimit == 0) { - requeue(j, &runnable); - return 1; - } - j->comstring = - comstring == COMSTRING_DUMMY ? NULL : TAILQ_NEXT(comstring, tq); - if (comstring != COMSTRING_DUMMY && comstring->len == 0) - goto next_comstring; /* * Collect exec arguments. Internal commands for network and * mounting build their own argument lists. */ - bg = j->flags & JF_FAILED; + comparam = *j->comparam; + comstring = j->comstring; + bg = 0; down = j->flags & (JF_STOP | JF_FAILED); switch (comparam) { case IP_STOP_TIMEOUT: @@ -169,7 +299,6 @@ run_command(struct cfjail *j, enum intparam comparam) } *(const char **)&argv[argc] = down ? "-alias" : "alias"; argv[argc + 1] = NULL; - j->flags |= JF_IFUP; break; #ifdef INET6 @@ -195,7 +324,6 @@ run_command(struct cfjail *j, enum intparam comparam) argc = 4; *(const char **)&argv[argc] = down ? "-alias" : "alias"; argv[argc + 1] = NULL; - j->flags |= JF_IFUP; break; #endif @@ -208,7 +336,6 @@ run_command(struct cfjail *j, enum intparam comparam) *(const char **)&argv[3] = jidstr ? jidstr : string_param(j->intparams[KP_NAME]); argv[4] = NULL; - j->flags |= JF_IFUP; break; case IP_MOUNT: @@ -221,7 +348,7 @@ run_command(struct cfjail *j, enum intparam comparam) cs = strtok(NULL, " \t\f\v\r\n")) argv[argc++] = cs; if (argc == 0) - goto next_comstring; + return 0; if (argc < 3) { jail_warnx(j, "%s: %s: missing information", j->intparams[comparam]->name, comstring->s); @@ -252,7 +379,6 @@ run_command(struct cfjail *j, enum intparam comparam) *(const char **)&argv[0] = _PATH_MOUNT; } *(const char **)&argv[1] = "-t"; - j->flags |= JF_MOUNTED; break; case IP_MOUNT_DEVFS: @@ -287,7 +413,6 @@ run_command(struct cfjail *j, enum intparam comparam) ruleset ? " " : "", ruleset ? ruleset : ""); argv[3] = NULL; } - j->flags |= JF_MOUNTED; break; case IP_COMMAND: @@ -333,9 +458,9 @@ run_command(struct cfjail *j, enum intparam comparam) argv[argc] = NULL; } } - if (argv[0] == NULL) - goto next_comstring; + return 0; + if (int_param(j->intparams[IP_EXEC_TIMEOUT], &timeout) && timeout != 0) { clock_gettime(CLOCK_REALTIME, &j->timeout); @@ -399,6 +524,7 @@ run_command(struct cfjail *j, enum intparam comparam) if (bg) setsid(); + /* Set up the environment and run the command */ pwd = NULL; lcap = NULL; if ((clean || username) && injail && sjuser && @@ -462,106 +588,6 @@ run_command(struct cfjail *j, enum intparam comparam) } /* - * Check command exit status - */ -int -finish_command(struct cfjail *j) -{ - int error; - - if (!(j->flags & JF_SLEEPQ)) - return 0; - j->flags &= ~JF_SLEEPQ; - if (j->comparam != IP_STOP_TIMEOUT) { - paralimit++; - if (!TAILQ_EMPTY(&runnable)) - requeue(TAILQ_FIRST(&runnable), &ready); - } - error = 0; - if (j->flags & JF_TIMEOUT) { - j->flags &= ~JF_TIMEOUT; - if (j->comparam != IP_STOP_TIMEOUT) { - jail_warnx(j, "%s: timed out", j->comline); - failed(j); - error = -1; - } else if (verbose > 0) - jail_note(j, "timed out\n"); - } else if (j->pstatus != 0) { - if (WIFSIGNALED(j->pstatus)) - jail_warnx(j, "%s: exited on signal %d", - j->comline, WTERMSIG(j->pstatus)); - else - jail_warnx(j, "%s: failed", j->comline); - j->pstatus = 0; - failed(j); - error = -1; - } - free(j->comline); - j->comline = NULL; - return error; -} - -/* - * Check for finished processed or timeouts. - */ -struct cfjail * -next_proc(int nonblock) -{ - struct kevent ke; - struct timespec ts; - struct timespec *tsp; - struct cfjail *j; - - if (!TAILQ_EMPTY(&sleeping)) { - again: - tsp = NULL; - if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) { - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec = j->timeout.tv_sec - ts.tv_sec; - ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec; - if (ts.tv_nsec < 0) { - ts.tv_sec--; - ts.tv_nsec += 1000000000; - } - if (ts.tv_sec < 0 || - (ts.tv_sec == 0 && ts.tv_nsec == 0)) { - j->flags |= JF_TIMEOUT; - clear_procs(j); - return j; - } - tsp = &ts; - } - if (nonblock) { - ts.tv_sec = 0; - ts.tv_nsec = 0; - tsp = &ts; - } - switch (kevent(kq, NULL, 0, &ke, 1, tsp)) { - case -1: - if (errno != EINTR) - err(1, "kevent"); - goto again; - case 0: - if (!nonblock) { - j = TAILQ_FIRST(&sleeping); - j->flags |= JF_TIMEOUT; - clear_procs(j); - return j; - } - break; - case 1: - (void)waitpid(ke.ident, NULL, WNOHANG); - if ((j = find_proc(ke.ident))) { - j->pstatus = ke.data; - return j; - } - goto again; - } - } - return NULL; -} - -/* * Add a process to the hash, tied to a jail. */ static void diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c index 6e8d31e..850f632 100644 --- a/usr.sbin/jail/config.c +++ b/usr.sbin/jail/config.c @@ -87,6 +87,7 @@ static const struct ipspec intparams[] = { [IP__IP6_IFADDR] = {"ip6.addr", PF_INTERNAL | PF_CONV}, #endif [IP__MOUNT_FROM_FSTAB] = {"mount.fstab", PF_INTERNAL | PF_CONV}, + [IP__OP] = {NULL, PF_CONV}, [KP_ALLOW_CHFLAGS] = {"allow.chflags", 0}, [KP_ALLOW_MOUNT] = {"allow.mount", 0}, [KP_ALLOW_RAW_SOCKETS] = {"allow.raw_sockets", 0}, diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c index 55cc269..9f16a57 100644 --- a/usr.sbin/jail/jail.c +++ b/usr.sbin/jail/jail.c @@ -78,6 +78,41 @@ static struct permspec perm_sysctl[] = { { "security.jail.socket_unixiproute_only", KP_ALLOW_SOCKET_AF, 1 }, }; +static const enum intparam startcommands[] = { + 0, + IP__IP4_IFADDR, +#ifdef INET6 + IP__IP6_IFADDR, +#endif + IP_MOUNT, + IP__MOUNT_FROM_FSTAB, + IP_MOUNT_DEVFS, + IP_EXEC_PRESTART, + IP__OP, + IP_VNET_INTERFACE, + IP_EXEC_START, + IP_COMMAND, + IP_EXEC_POSTSTART, + 0 +}; + +static const enum intparam stopcommands[] = { + 0, + IP_EXEC_PRESTOP, + IP_EXEC_STOP, + IP_STOP_TIMEOUT, + IP__OP, + IP_EXEC_POSTSTOP, + IP_MOUNT_DEVFS, + IP__MOUNT_FROM_FSTAB, + IP_MOUNT, +#ifdef INET6 + IP__IP6_IFADDR, +#endif + IP__IP4_IFADDR, + 0 +}; + int main(int argc, char **argv) { @@ -290,25 +325,11 @@ main(int argc, char **argv) while ((j = next_jail())) { if (j->flags & JF_FAILED) { - clear_persist(j); - if (j->flags & JF_MOUNTED) { - (void)run_command(j, IP_MOUNT_DEVFS); - if (run_command(j, IP__MOUNT_FROM_FSTAB)) - while (run_command(j, 0)) ; - if (run_command(j, IP_MOUNT)) - while (run_command(j, 0)) ; - } - if (j->flags & JF_IFUP) { - if (run_command(j, IP__IP4_IFADDR)) - while (run_command(j, 0)) ; -#ifdef INET6 - if (run_command(j, IP__IP6_IFADDR)) - while (run_command(j, 0)) ; -#endif - } error = 1; - dep_done(j, 0); - continue; + if (j->comparam == NULL) { + dep_done(j, 0); + continue; + } } if (!(j->flags & JF_PARAMS)) { @@ -326,7 +347,7 @@ main(int argc, char **argv) (j->flags & (JF_SET | JF_DEPEND)) == JF_SET ? dflag || bool_param(j->intparams[IP_ALLOW_DYING]) : 0); - if (finish_command(j) || run_command(j, 0)) + if (finish_command(j)) continue; switch (j->flags & JF_OP_MASK) { @@ -356,17 +377,7 @@ main(int argc, char **argv) switch (j->flags & JF_OP_MASK) { case JF_START: - /* - * 1: check existence and dependencies - * 2: configure IP addresses - * 3: run any exec.prestart commands - * 4: create the jail - * 5: configure vnet interfaces - * 6: run any exec.start or "command" commands - * 7: run any exec.poststart commands - */ - switch (j->comparam) { - default: + if (j->comparam == NULL) { if (j->jid > 0 && !(j->flags & (JF_DEPEND | JF_WILD))) { warnx("\"%s\" already exists", j->name); @@ -377,70 +388,38 @@ main(int argc, char **argv) continue; if (j->jid > 0) goto jail_create_done; - if (run_command(j, IP__IP4_IFADDR)) - continue; - /* FALLTHROUGH */ - case IP__IP4_IFADDR: -#ifdef INET6 - if (run_command(j, IP__IP6_IFADDR)) - continue; - /* FALLTHROUGH */ - case IP__IP6_IFADDR: -#endif - if (run_command(j, IP_MOUNT)) - continue; - /* FALLTHROUGH */ - case IP_MOUNT: - if (run_command(j, - IP__MOUNT_FROM_FSTAB)) - continue; - /* FALLTHROUGH */ - case IP__MOUNT_FROM_FSTAB: - if (run_command(j, IP_MOUNT_DEVFS)) - continue; - /* FALLTHROUGH */ - case IP_MOUNT_DEVFS: - if (run_command(j, IP_EXEC_PRESTART)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_PRESTART: - if (create_jail(j) < 0) - continue; - if (iflag) - printf("%d\n", j->jid); - if (jfp != NULL) - print_jail(jfp, j, oldcl); - if (verbose >= 0 && (j->name || verbose > 0)) - jail_note(j, "created\n"); - dep_done(j, DF_LIGHT); - if (bool_param(j->intparams[KP_VNET]) && - run_command(j, IP_VNET_INTERFACE)) - continue; - /* FALLTHROUGH */ - case IP_VNET_INTERFACE: - if (run_command(j, IP_EXEC_START)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_START: - if (run_command(j, IP_COMMAND)) - continue; - /* FALLTHROUGH */ - case IP_COMMAND: - if (run_command(j, IP_EXEC_POSTSTART)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_POSTSTART: - jail_create_done: - clear_persist(j); - dep_done(j, 0); + j->comparam == startcommands + 1; + } else if (*j->comparam == IP__OP) { + if (j->flags & JF_FAILED) { + if (jail_remove(j->jid) == 0 && + verbose >= 0 && + (j->name || verbose > 0)) + jail_note(j, "removed\n"); + j->jid = -1; + j->flags &= ~JF_PERSIST; + j->comparam--; + } else if (create_jail(j) < 0) { + j->comparam--; + } else { + if (verbose >= 0 && + (j->name || verbose > 0)) + jail_note(j, "created\n"); + dep_done(j, DF_LIGHT); + j->comparam++; + } } + if (next_command(j)) + continue; + jail_create_done: + clear_persist(j); + if (iflag) + printf("%d\n", j->jid); + if (jfp != NULL) + print_jail(jfp, j, oldcl); + dep_done(j, 0); break; case JF_SET: - /* - * 1: check existence and dependencies - * 2: update the jail - */ if (j->jid < 0 && !(j->flags & JF_DEPEND)) { warnx("\"%s\" not found", j->name); failed(j); @@ -460,17 +439,7 @@ main(int argc, char **argv) case JF_STOP: case JF_RESTART: - /* - * 1: check dependencies and existence (note order) - * 2: run any exec.prestop commands - * 3: run any exec.stop commands - * 4: send SIGTERM to all jail processes - * 5: remove the jail - * 6: run any exec.poststop commands - * 7: take down IP addresses - */ - switch (j->comparam) { - default: + if (j->comparam == NULL) { if (dep_check(j)) continue; if (j->jid < 0) { @@ -480,60 +449,28 @@ main(int argc, char **argv) j->name); goto jail_remove_done; } - if (run_command(j, IP_EXEC_PRESTOP)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_PRESTOP: - if (run_command(j, IP_EXEC_STOP)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_STOP: - if (run_command(j, IP_STOP_TIMEOUT)) - continue; - /* FALLTHROUGH */ - case IP_STOP_TIMEOUT: - (void)jail_remove(j->jid); - j->jid = -1; - if (verbose >= 0 && + j->comparam == stopcommands + 1; + } else if ((j->flags & JF_FAILED) && j->jid > 0) { + goto jail_remove_done; + } else if (*j->comparam == IP__OP) { + if (jail_remove(j->jid) == 0 && + verbose >= 0 && (docf || argc > 1 || wild_jail_name(argv[0]) || verbose > 0)) jail_note(j, "removed\n"); + j->jid = -1; dep_done(j, DF_LIGHT); - if (run_command(j, IP_EXEC_POSTSTOP)) - continue; - /* FALLTHROUGH */ - case IP_EXEC_POSTSTOP: - if (run_command(j, IP_MOUNT_DEVFS)) - continue; - /* FALLTHROUGH */ - case IP_MOUNT_DEVFS: - if (run_command(j, IP__MOUNT_FROM_FSTAB)) - continue; - /* FALLTHROUGH */ - case IP__MOUNT_FROM_FSTAB: - if (run_command(j, IP_MOUNT)) - continue; - /* FALLTHROUGH */ - case IP_MOUNT: - if (run_command(j, IP__IP4_IFADDR)) - continue; - /* FALLTHROUGH */ - case IP__IP4_IFADDR: -#ifdef INET6 - if (run_command(j, IP__IP6_IFADDR)) - continue; - /* FALLTHROUGH */ - case IP__IP6_IFADDR: -#endif - jail_remove_done: - dep_done(j, 0); - if (j->flags & JF_START) { - j->comparam = 0; - j->flags &= ~JF_STOP; - dep_reset(j); - requeue(j, - j->ndeps ? &depend : &ready); - } + j->comparam++; + } + if (next_command(j)) + continue; + jail_remove_done: + dep_done(j, 0); + if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { + j->comparam = NULL; + j->flags &= ~JF_STOP; + dep_reset(j); + requeue(j, j->ndeps ? &depend : &ready); } break; } diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h index f5a4317..d712921 100644 --- a/usr.sbin/jail/jailp.h +++ b/usr.sbin/jail/jailp.h @@ -59,11 +59,9 @@ #define JF_FAILED 0x0020 /* Operation failed */ #define JF_PARAMS 0x0040 /* Parameters checked and imported */ #define JF_RDTUN 0x0080 /* Create-only parameter check has been done */ -#define JF_IFUP 0x0100 /* IP addresses have been configured */ -#define JF_MOUNTED 0x0200 /* Filesystems have been mounted */ -#define JF_PERSIST 0x0400 /* Jail is temporarily persistent */ -#define JF_TIMEOUT 0x0800 /* A command (or process kill) timed out */ -#define JF_SLEEPQ 0x2000 /* Waiting on a command and/or timeout */ +#define JF_PERSIST 0x0100 /* Jail is temporarily persistent */ +#define JF_TIMEOUT 0x0200 /* A command (or process kill) timed out */ +#define JF_SLEEPQ 0x0400 /* Waiting on a command and/or timeout */ #define JF_OP_MASK (JF_START | JF_SET | JF_STOP) #define JF_RESTART (JF_START | JF_STOP) @@ -102,6 +100,7 @@ enum intparam { IP__IP6_IFADDR, /* Copy of ip6.addr with interface/prefixlen */ #endif IP__MOUNT_FROM_FSTAB, /* Line from mount.fstab file */ + IP__OP, /* Placeholder for requested operation */ KP_ALLOW_CHFLAGS, KP_ALLOW_MOUNT, KP_ALLOW_RAW_SOCKETS, @@ -164,7 +163,7 @@ struct cfjail { struct cfstring *comstring; struct jailparam *jp; struct timespec timeout; - enum intparam comparam; + const enum intparam *comparam; unsigned flags; int jid; int seq; @@ -187,7 +186,7 @@ extern void failed(struct cfjail *j); extern void jail_note(const struct cfjail *j, const char *fmt, ...); extern void jail_warnx(const struct cfjail *j, const char *fmt, ...); -extern int run_command(struct cfjail *j, enum intparam comparam); +extern int next_command(struct cfjail *j); extern int finish_command(struct cfjail *j); extern struct cfjail *next_proc(int nonblock); |