summaryrefslogtreecommitdiffstats
path: root/usr.sbin/jls
diff options
context:
space:
mode:
authorjamie <jamie@FreeBSD.org>2009-05-27 14:30:26 +0000
committerjamie <jamie@FreeBSD.org>2009-05-27 14:30:26 +0000
commit8dbff96dac0a8009a4169eedbbe59be58a480889 (patch)
tree4a406964696e0ebb946248969d86b305f81eab7b /usr.sbin/jls
parenta013e0afcbb44052a86a7977277d669d8883b7e7 (diff)
downloadFreeBSD-src-8dbff96dac0a8009a4169eedbbe59be58a480889.zip
FreeBSD-src-8dbff96dac0a8009a4169eedbbe59be58a480889.tar.gz
Add support for the arbitrary named jail parameters used by jail_set(2)
and jail_get(2). Jail(8) can now create jails using a "name=value" format instead of just specifying a limited set of fixed parameters; it can also modify parameters of existing jails. Jls(8) can display all parameters of jails, or a specified set of parameters. The available parameters are gathered from the kernel, and not hard-coded into these programs. Small patches on killall(1) and jexec(8) to support jail names with jail_get(2). Approved by: bz (mentor)
Diffstat (limited to 'usr.sbin/jls')
-rw-r--r--usr.sbin/jls/Makefile2
-rw-r--r--usr.sbin/jls/jls.884
-rw-r--r--usr.sbin/jls/jls.c878
3 files changed, 750 insertions, 214 deletions
diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile
index 01294bd..3968946 100644
--- a/usr.sbin/jls/Makefile
+++ b/usr.sbin/jls/Makefile
@@ -4,6 +4,4 @@ PROG= jls
MAN= jls.8
WARNS?= 6
-CFLAGS+= -DSUPPORT_OLD_XPRISON
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/jls/jls.8 b/usr.sbin/jls/jls.8
index aff9848..c0eed8d 100644
--- a/usr.sbin/jls/jls.8
+++ b/usr.sbin/jls/jls.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 29, 2008
+.Dd May 27, 2009
.Dt JLS 8
.Os
.Sh NAME
@@ -33,38 +33,68 @@
.Nd "list jails"
.Sh SYNOPSIS
.Nm
-.Op Fl av
+.Op Fl dhnqsv
+.Op Fl j Ar jail
+.Op Ar parameter ...
.Sh DESCRIPTION
The
.Nm
-utility lists all jails.
-By default only active jails are listed.
+utility lists all active jails, or the specified jail.
+Each jail is represented by one row which contains space-separated values of
+the listed
+.Ar parameters ,
+including the pseudo-parameter
+.Va all
+which will show all available jail parameters.
+A list of available parameters can be retrieved via
+.Dq Nm sysctl Fl d Va security.jail.param .
+See
+.Xr jail 8
+for a description of some core parameters.
.Pp
-The options are as follows:
-.Bl -tag -width ".Fl a"
-.It Fl a
-Show jails in all states, not only active ones.
-.It Fl v
-Show more verbose information.
-This also lists cpusets, jail state, multi-IP, etc. instead of the
-classic single-IP jail output.
-.El
+If no
+.Ar parameters
+are given, the following four columns will be printed:
+jail identifier (jid), IP address (ip4.addr), hostname (host.hostname),
+and path (path).
.Pp
-Each jail is represented by rows which, depending on
-.Fl v ,
-contain the following columns:
-.Bl -item -offset indent -compact
-.It
-jail identifier (JID), hostname and path
-.It
-jail state and name
-.It
-jail cpuset
-.It
-followed by one IP adddress per line.
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+List
+.Va dying
+as well as active jails.
+.It Fl h
+Print a header line containing the parameters listed.
+If no parameters are given on the command line, the default output always
+contains a header.
+.It Fl n
+Print parameters in
+.Dq name=value
+format, where each parameter is preceded by its name.
+This option is ignored for the default four-column output.
+.It Fl q
+Put quotes around parameters if they contain spaces or quotes, or are
+the empty string.
+.It Fl c
+Print parameters suitable for passing to
+.Xr jail 8 ,
+skipping read-only and unused parameters.
+Implies
+.Fl nq .
+.It Fl v
+Print a multiple-line summary per jail, with the following parameters:
+jail identifier (jid), hostname (host.hostname), path (path),
+jail name (name), jail state (dying), cpuset ID (cpuset),
+IP address(es) (ip4.addr and ip6.addr).
+.It Fl j Ar jail
+The jid or name of the
+.Ar jail
+to list.
+Without this option, all active jails will be listed.
.El
.Sh SEE ALSO
-.Xr jail 2 ,
+.Xr jail_get 2 ,
.Xr jail 8 ,
.Xr jexec 8
.Sh HISTORY
@@ -72,3 +102,5 @@ The
.Nm
utility was added in
.Fx 5.1 .
+Extensible jail parameters were introduced in
+.Fx 8.0 .
diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c
index 95f17d4..cc8dabd 100644
--- a/usr.sbin/jls/jls.c
+++ b/usr.sbin/jls/jls.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
+ * Copyright (c) 2009 James Gritton <jamie@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -23,18 +24,20 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/jail.h>
+#include <sys/socket.h>
#include <sys/sysctl.h>
+#include <sys/uio.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
+#include <netinet/in.h>
+
#include <err.h>
#include <errno.h>
#include <limits.h>
@@ -43,215 +46,718 @@
#include <string.h>
#include <unistd.h>
-#define FLAG_A 0x00001
-#define FLAG_V 0x00002
+#define SJPARAM "security.jail.param"
+#define ARRAY_SLOP 5
+
+#define CTLTYPE_BOOL (CTLTYPE + 1)
+#define CTLTYPE_NOBOOL (CTLTYPE + 2)
+#define CTLTYPE_IPADDR (CTLTYPE + 3)
+#define CTLTYPE_IP6ADDR (CTLTYPE + 4)
+
+#define PARAM_KEY 0x01
+#define PARAM_USER 0x02
+#define PARAM_ARRAY 0x04
+#define PARAM_OPT 0x08
+#define PARAM_WR 0x10
+
+#define PRINT_DEFAULT 0x01
+#define PRINT_HEADER 0x02
+#define PRINT_NAMEVAL 0x04
+#define PRINT_QUOTED 0x08
+#define PRINT_SKIP 0x10
+#define PRINT_VERBOSE 0x20
+
+struct param {
+ char *name;
+ void *value;
+ size_t size;
+ int type;
+ unsigned flags;
+ int noparent;
+};
+
+struct iovec2 {
+ struct iovec name;
+ struct iovec value;
+};
+
+static struct param *params;
+static int nparams;
+static char errmsg[256];
+
+static int add_param(const char *name, void *value, unsigned flags);
+static int get_param(const char *name, struct param *param);
+static int sort_param(const void *a, const void *b);
+static char *noname(const char *name);
+static char *nononame(const char *name);
+static int print_jail(int pflags, int jflags);
+static void quoted_print(char *str, int len);
-#ifdef SUPPORT_OLD_XPRISON
-static
-char *print_xprison_v1(void *p, char *end, unsigned flags)
+int
+main(int argc, char **argv)
{
- struct xprison_v1 *xp;
- struct in_addr in;
-
- if ((char *)p + sizeof(struct xprison_v1) > end)
- errx(1, "Invalid length for jail");
-
- xp = (struct xprison_v1 *)p;
- if (flags & FLAG_V) {
- printf("%6d %-29.29s %.74s\n",
- xp->pr_id, xp->pr_host, xp->pr_path);
- /* We are not printing an empty line here for state and name. */
- /* We are not printing an empty line here for cpusetid. */
- /* IPv4 address. */
- in.s_addr = htonl(xp->pr_ip);
- printf("%6s %-15.15s\n", "", inet_ntoa(in));
+ char *dot, *ep, *jname, *nname;
+ int c, i, jflags, jid, lastjid, pflags, spc;
+
+ jname = NULL;
+ pflags = jflags = jid = 0;
+ while ((c = getopt(argc, argv, "adj:hnqsv")) >= 0)
+ switch (c) {
+ case 'a':
+ case 'd':
+ jflags |= JAIL_DYING;
+ break;
+ case 'j':
+ jid = strtoul(optarg, &ep, 10);
+ if (!*optarg || *ep)
+ jname = optarg;
+ break;
+ case 'h':
+ pflags = (pflags & ~PRINT_SKIP) | PRINT_HEADER;
+ break;
+ case 'n':
+ pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL;
+ break;
+ case 'q':
+ pflags |= PRINT_QUOTED;
+ break;
+ case 's':
+ pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) |
+ PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP;
+ break;
+ case 'v':
+ pflags = (pflags & ~(PRINT_NAMEVAL | PRINT_SKIP)) |
+ PRINT_VERBOSE;
+ break;
+ default:
+ errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]");
+ }
+
+ /* Add the parameters to print. */
+ if (optind == argc) {
+ if (pflags & PRINT_VERBOSE) {
+ add_param("jid", NULL, PARAM_USER);
+ add_param("host.hostname", NULL, PARAM_USER);
+ add_param("path", NULL, PARAM_USER);
+ add_param("name", NULL, PARAM_USER);
+ add_param("dying", NULL, PARAM_USER);
+ add_param("cpuset", NULL, PARAM_USER);
+ add_param("ip4.addr", NULL, PARAM_USER);
+ add_param("ip6.addr", NULL, PARAM_USER | PARAM_OPT);
+ } else {
+ pflags = (pflags &
+ ~(PRINT_NAMEVAL | PRINT_SKIP | PRINT_VERBOSE)) |
+ PRINT_DEFAULT;
+ add_param("jid", NULL, PARAM_USER);
+ add_param("ip4.addr", NULL, PARAM_USER);
+ add_param("host.hostname", NULL, PARAM_USER);
+ add_param("path", NULL, PARAM_USER);
+ }
+ } else
+ while (optind < argc)
+ add_param(argv[optind++], NULL, PARAM_USER);
+
+ if (pflags & PRINT_SKIP) {
+ /* Check for parameters with boolean parents. */
+ for (i = 0; i < nparams; i++) {
+ if ((params[i].flags & PARAM_USER) &&
+ (dot = strchr(params[i].name, '.'))) {
+ *dot = 0;
+ nname = noname(params[i].name);
+ *dot = '.';
+ params[i].noparent =
+ add_param(nname, NULL, PARAM_OPT);
+ free(nname);
+ }
+ }
+ }
+
+ /* Add the index key and errmsg parameters. */
+ if (jid != 0)
+ add_param("jid", &jid, PARAM_KEY);
+ else if (jname != NULL)
+ add_param("name", jname, PARAM_KEY);
+ else
+ add_param("lastjid", &lastjid, PARAM_KEY);
+ add_param("errmsg", errmsg, PARAM_KEY);
+
+ /* Print a header line if requested. */
+ if (pflags & PRINT_VERBOSE)
+ printf(" JID Hostname Path\n"
+ " Name State\n"
+ " CPUSetID\n"
+ " IP Address(es)\n");
+ else if (pflags & PRINT_DEFAULT)
+ printf(" JID IP Address "
+ "Hostname Path\n");
+ else if (pflags & PRINT_HEADER) {
+ for (i = spc = 0; i < nparams; i++)
+ if (params[i].flags & PARAM_USER) {
+ if (spc)
+ putchar(' ');
+ else
+ spc = 1;
+ fputs(params[i].name, stdout);
+ }
+ putchar('\n');
+ }
+
+ /* Fetch the jail(s) and print the paramters. */
+ if (jid != 0 || jname != NULL) {
+ if (print_jail(pflags, jflags) < 0) {
+ if (errmsg[0])
+ errx(1, "%s", errmsg);
+ err(1, "jail_get");
+ }
} else {
- printf("%6d %-15.15s %-29.29s %.74s\n",
- xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
+ for (lastjid = 0;
+ (lastjid = print_jail(pflags, jflags)) >= 0; )
+ ;
+ if (errno != 0 && errno != ENOENT) {
+ if (errmsg[0])
+ errx(1, "%s", errmsg);
+ err(1, "jail_get");
+ }
}
- return ((char *)(xp + 1));
+ return (0);
}
-#endif
-static
-char *print_xprison_v3(void *p, char *end, unsigned flags)
+static int
+add_param(const char *name, void *value, unsigned flags)
{
- struct xprison *xp;
- struct in_addr *iap, in;
- struct in6_addr *ia6p;
- char buf[INET6_ADDRSTRLEN];
- const char *state;
- char *q;
- uint32_t i;
-
- if ((char *)p + sizeof(struct xprison) > end)
- errx(1, "Invalid length for jail");
- xp = (struct xprison *)p;
-
- if (xp->pr_state < 0 || xp->pr_state >= (int)
- ((sizeof(prison_states) / sizeof(struct prison_state))))
- state = "(bogus)";
- else
- state = prison_states[xp->pr_state].state_name;
-
- /* See if we should print non-ACTIVE jails. No? */
- if ((flags & FLAG_A) == 0 && strcmp(state, "ALIVE")) {
- q = (char *)(xp + 1);
- q += (xp->pr_ip4s * sizeof(struct in_addr));
- if (q > end)
- errx(1, "Invalid length for jail");
- q += (xp->pr_ip6s * sizeof(struct in6_addr));
- if (q > end)
- errx(1, "Invalid length for jail");
- return (q);
+ struct param *param;
+ char *nname;
+ size_t mlen1, mlen2, buflen;
+ int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
+ int i, tnparams;
+ char buf[MAXPATHLEN];
+
+ static int paramlistsize;
+
+ /* The pseudo-parameter "all" scans the list of available parameters. */
+ if (!strcmp(name, "all")) {
+ tnparams = nparams;
+ mib1[0] = 0;
+ mib1[1] = 2;
+ mlen1 = CTL_MAXNAME - 2;
+ if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0)
+ err(1, "sysctlnametomib(" SJPARAM ")");
+ for (;;) {
+ /* Get the next parameter. */
+ mlen2 = sizeof(mib2);
+ if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0)
+ err(1, "sysctl(0.2)");
+ if (mib2[0] != mib1[2] || mib2[1] != mib1[3] ||
+ mib2[2] != mib1[4])
+ break;
+ /* Convert it to an ascii name. */
+ memcpy(mib1 + 2, mib2, mlen2);
+ mlen1 = mlen2 / sizeof(int);
+ mib1[1] = 1;
+ buflen = sizeof(buf);
+ if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0)
+ err(1, "sysctl(0.1)");
+ add_param(buf + sizeof(SJPARAM), NULL, flags);
+ /*
+ * Convert nobool parameters to bool if their
+ * counterpart is a node, ortherwise discard them.
+ */
+ param = &params[nparams - 1];
+ if (param->type == CTLTYPE_NOBOOL) {
+ nname = nononame(param->name);
+ if (get_param(nname, param) >= 0 &&
+ param->type != CTLTYPE_NODE) {
+ free(nname);
+ nparams--;
+ } else {
+ free(param->name);
+ param->name = nname;
+ param->type = CTLTYPE_BOOL;
+ param->size = sizeof(int);
+ param->value = NULL;
+ }
+ }
+ mib1[1] = 2;
+ }
+
+ qsort(params + tnparams, (size_t)(nparams - tnparams),
+ sizeof(struct param), sort_param);
+ return -1;
+ }
+
+ /* Check for repeat parameters. */
+ for (i = 0; i < nparams; i++)
+ if (!strcmp(name, params[i].name)) {
+ params[i].value = value;
+ params[i].flags |= flags;
+ return i;
+ }
+
+ /* Make sure there is room for the new param record. */
+ if (!nparams) {
+ paramlistsize = 32;
+ params = malloc(paramlistsize * sizeof(*params));
+ if (params == NULL)
+ err(1, "malloc");
+ } else if (nparams >= paramlistsize) {
+ paramlistsize *= 2;
+ params = realloc(params, paramlistsize * sizeof(*params));
+ if (params == NULL)
+ err(1, "realloc");
+ }
+
+ /* Look up the parameter. */
+ param = params + nparams++;
+ memset(param, 0, sizeof *param);
+ param->name = strdup(name);
+ if (param->name == NULL)
+ err(1, "strdup");
+ param->flags = flags;
+ param->noparent = -1;
+ /* We have to know about pseudo-parameters without asking. */
+ if (!strcmp(param->name, "lastjid")) {
+ param->type = CTLTYPE_INT;
+ param->size = sizeof(int);
+ goto got_type;
+ }
+ if (!strcmp(param->name, "errmsg")) {
+ param->type = CTLTYPE_STRING;
+ param->size = sizeof(errmsg);
+ goto got_type;
+ }
+ if (get_param(name, param) < 0) {
+ if (errno != ENOENT)
+ err(1, "sysctl(0.3.%s)", name);
+ /* See if this the "no" part of an existing boolean. */
+ if ((nname = nononame(name))) {
+ i = get_param(nname, param);
+ free(nname);
+ if (i >= 0 && param->type == CTLTYPE_BOOL) {
+ param->type = CTLTYPE_NOBOOL;
+ goto got_type;
+ }
+ }
+ if (flags & PARAM_OPT) {
+ nparams--;
+ return -1;
+ }
+ errx(1, "unknown parameter: %s", name);
+ }
+ if (param->type == CTLTYPE_NODE) {
+ /*
+ * A node isn't normally a parameter, but may be a boolean
+ * if its "no" counterpart exists.
+ */
+ nname = noname(name);
+ i = get_param(nname, param);
+ free(nname);
+ if (i >= 0 && param->type == CTLTYPE_NOBOOL) {
+ param->type = CTLTYPE_BOOL;
+ goto got_type;
+ }
+ errx(1, "unknown parameter: %s", name);
}
- if (flags & FLAG_V)
- printf("%6d %-29.29s %.74s\n",
- xp->pr_id, xp->pr_host, xp->pr_path);
-
- /* Jail state and name. */
- if (flags & FLAG_V)
- printf("%6s %-29.29s %.74s\n",
- "", (xp->pr_name[0] != '\0') ? xp->pr_name : "", state);
-
- /* cpusetid. */
- if (flags & FLAG_V)
- printf("%6s %-6d\n",
- "", xp->pr_cpusetid);
-
- q = (char *)(xp + 1);
- /* IPv4 addresses. */
- iap = (struct in_addr *)(void *)q;
- q += (xp->pr_ip4s * sizeof(struct in_addr));
- if (q > end)
- errx(1, "Invalid length for jail");
- in.s_addr = 0;
- for (i = 0; i < xp->pr_ip4s; i++) {
- if (i == 0 || flags & FLAG_V)
- in.s_addr = iap[i].s_addr;
- if (flags & FLAG_V)
- printf("%6s %-15.15s\n", "", inet_ntoa(in));
+ got_type:
+ param->value = value;
+ return param - params;
+}
+
+static int
+get_param(const char *name, struct param *param)
+{
+ char *p;
+ size_t buflen, mlen;
+ int mib[CTL_MAXNAME];
+ struct {
+ int i;
+ char s[MAXPATHLEN];
+ } buf;
+
+ /* Look up the MIB. */
+ mib[0] = 0;
+ mib[1] = 3;
+ snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name);
+ mlen = sizeof(mib) - 2 * sizeof(int);
+ if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0)
+ return (-1);
+ /* Get the type and size. */
+ mib[1] = 4;
+ buflen = sizeof(buf);
+ if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0)
+ err(1, "sysctl(0.4.%s)", name);
+ param->type = buf.i & CTLTYPE;
+ if (buf.i & (CTLFLAG_WR | CTLFLAG_TUN))
+ param->flags |= PARAM_WR;
+ p = strchr(buf.s, '\0');
+ if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) {
+ p[-2] = 0;
+ param->flags |= PARAM_ARRAY;
}
- /* IPv6 addresses. */
- ia6p = (struct in6_addr *)(void *)q;
- q += (xp->pr_ip6s * sizeof(struct in6_addr));
- if (q > end)
- errx(1, "Invalid length for jail");
- for (i = 0; i < xp->pr_ip6s; i++) {
- if (flags & FLAG_V) {
- inet_ntop(AF_INET6, &ia6p[i], buf, sizeof(buf));
- printf("%6s %s\n", "", buf);
+ switch (param->type) {
+ case CTLTYPE_INT:
+ /* An integer parameter might be a boolean. */
+ if (buf.s[0] == 'B')
+ param->type = buf.s[1] == 'N'
+ ? CTLTYPE_NOBOOL : CTLTYPE_BOOL;
+ case CTLTYPE_UINT:
+ param->size = sizeof(int);
+ break;
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ param->size = sizeof(long);
+ break;
+ case CTLTYPE_STRUCT:
+ if (!strcmp(buf.s, "S,in_addr")) {
+ param->type = CTLTYPE_IPADDR;
+ param->size = sizeof(struct in_addr);
+ } else if (!strcmp(buf.s, "S,in6_addr")) {
+ param->type = CTLTYPE_IP6ADDR;
+ param->size = sizeof(struct in6_addr);
}
+ break;
+ case CTLTYPE_STRING:
+ buf.s[0] = 0;
+ sysctl(mib + 2, mlen / sizeof(int), buf.s, &buflen, NULL, 0);
+ param->size = strtoul(buf.s, NULL, 10);
+ if (param->size == 0)
+ param->size = BUFSIZ;
}
+ return (0);
+}
- /* If requested print the old style single line version. */
- if (!(flags & FLAG_V))
- printf("%6d %-15.15s %-29.29s %.74s\n",
- xp->pr_id, (in.s_addr) ? inet_ntoa(in) : "",
- xp->pr_host, xp->pr_path);
+static int
+sort_param(const void *a, const void *b)
+{
+ const struct param *parama, *paramb;
+ char *ap, *bp;
- return (q);
+ /* Put top-level parameters first. */
+ parama = a;
+ paramb = b;
+ ap = strchr(parama->name, '.');
+ bp = strchr(paramb->name, '.');
+ if (ap && !bp)
+ return (1);
+ if (bp && !ap)
+ return (-1);
+ return (strcmp(parama->name, paramb->name));
}
-static void
-usage(void)
+static char *
+noname(const char *name)
{
+ char *nname, *p;
- (void)fprintf(stderr, "usage: jls [-av]\n");
- exit(1);
+ nname = malloc(strlen(name) + 3);
+ if (nname == NULL)
+ err(1, "malloc");
+ p = strrchr(name, '.');
+ if (p != NULL)
+ sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
+ else
+ sprintf(nname, "no%s", name);
+ return nname;
}
-int
-main(int argc, char *argv[])
-{
- int ch, version;
- unsigned flags;
- size_t i, j, len;
- void *p, *q;
+static char *
+nononame(const char *name)
+{
+ char *nname, *p;
- flags = 0;
- while ((ch = getopt(argc, argv, "av")) != -1) {
- switch (ch) {
- case 'a':
- flags |= FLAG_A;
- break;
- case 'v':
- flags |= FLAG_V;
- break;
- default:
- usage();
+ p = strrchr(name, '.');
+ if (strncmp(p ? p + 1 : name, "no", 2))
+ return NULL;
+ nname = malloc(strlen(name) - 1);
+ if (nname == NULL)
+ err(1, "malloc");
+ if (p != NULL)
+ sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
+ else
+ strcpy(nname, name + 2);
+ return nname;
+}
+
+static int
+print_jail(int pflags, int jflags)
+{
+ char *nname;
+ int i, ai, jid, count, sanity, spc;
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ static struct iovec2 *iov, *aiov;
+ static int narray, nkey;
+
+ /* Set up the parameter list(s) the first time around. */
+ if (iov == NULL) {
+ iov = malloc(nparams * sizeof(struct iovec2));
+ if (iov == NULL)
+ err(1, "malloc");
+ for (i = narray = 0; i < nparams; i++) {
+ iov[i].name.iov_base = params[i].name;
+ iov[i].name.iov_len = strlen(params[i].name) + 1;
+ iov[i].value.iov_base = params[i].value;
+ iov[i].value.iov_len =
+ params[i].type == CTLTYPE_STRING &&
+ params[i].value != NULL &&
+ ((char *)params[i].value)[0] != '\0'
+ ? strlen(params[i].value) + 1 : params[i].size;
+ if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
+ narray++;
+ if (params[i].flags & PARAM_KEY)
+ nkey++;
+ }
+ }
+ if (narray > nkey) {
+ aiov = malloc(narray * sizeof(struct iovec2));
+ if (aiov == NULL)
+ err(1, "malloc");
+ for (i = ai = 0; i < nparams; i++)
+ if (params[i].flags &
+ (PARAM_KEY | PARAM_ARRAY))
+ aiov[ai++] = iov[i];
}
}
- argc -= optind;
- argv += optind;
-
- if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
- err(1, "sysctlbyname(): security.jail.list");
-
- j = len;
- for (i = 0; i < 4; i++) {
- if (len <= 0)
- exit(0);
- p = q = malloc(len);
- if (p == NULL)
- err(1, "malloc()");
-
- if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
- if (errno == ENOMEM) {
- free(p);
- p = NULL;
- len += j;
- continue;
+ /* If there are array parameters, find their sizes. */
+ if (aiov != NULL) {
+ for (ai = 0; ai < narray; ai++)
+ if (aiov[ai].value.iov_base == NULL)
+ aiov[ai].value.iov_len = 0;
+ if (jail_get((struct iovec *)aiov, 2 * narray, jflags) < 0)
+ return (-1);
+ }
+ /* Allocate storage for all parameters. */
+ for (i = ai = 0; i < nparams; i++) {
+ if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
+ if (params[i].flags & PARAM_ARRAY) {
+ iov[i].value.iov_len = aiov[ai].value.iov_len +
+ ARRAY_SLOP * params[i].size;
+ iov[i].value.iov_base =
+ malloc(iov[i].value.iov_len);
}
- err(1, "sysctlbyname(): security.jail.list");
- }
- break;
+ ai++;
+ } else
+ iov[i].value.iov_base = malloc(params[i].size);
+ if (iov[i].value.iov_base == NULL)
+ err(1, "malloc");
+ if (params[i].value == NULL)
+ memset(iov[i].value.iov_base, 0, iov[i].value.iov_len);
}
- if (p == NULL)
- err(1, "sysctlbyname(): security.jail.list");
- if (len < sizeof(int))
- errx(1, "This is no prison. Kernel and userland out of sync?");
- version = *(int *)p;
- if (version > XPRISON_VERSION)
- errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
-
- if (flags & FLAG_V) {
- printf(" JID Hostname Path\n");
- printf(" Name State\n");
- printf(" CPUSetID\n");
- printf(" IP Address(es)\n");
- } else {
- printf(" JID IP Address Hostname"
- " Path\n");
+ /*
+ * Get the actual prison. If there are array elements, retry a few
+ * times in case the size changed from under us.
+ */
+ if ((jid = jail_get((struct iovec *)iov, 2 * nparams, jflags)) < 0) {
+ if (errno != EINVAL || aiov == NULL || errmsg[0])
+ return (-1);
+ for (sanity = 0;; sanity++) {
+ if (sanity == 10)
+ return (-1);
+ for (ai = 0; ai < narray; ai++)
+ if (params[i].flags & PARAM_ARRAY)
+ aiov[ai].value.iov_len = 0;
+ if (jail_get((struct iovec *)iov, 2 * narray, jflags) <
+ 0)
+ return (-1);
+ for (i = ai = 0; i < nparams; i++) {
+ if (!(params[i].flags &
+ (PARAM_KEY | PARAM_ARRAY)))
+ continue;
+ if (params[i].flags & PARAM_ARRAY) {
+ iov[i].value.iov_len =
+ aiov[ai].value.iov_len +
+ ARRAY_SLOP * params[i].size;
+ iov[i].value.iov_base =
+ realloc(iov[i].value.iov_base,
+ iov[i].value.iov_len);
+ if (iov[i].value.iov_base == NULL)
+ err(1, "malloc");
+ }
+ ai++;
+ }
+ }
}
- for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
- version = *(int *)q;
- if (version > XPRISON_VERSION)
- errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
- switch (version) {
-#ifdef SUPPORT_OLD_XPRISON
- case 1:
- q = print_xprison_v1(q, (char *)p + len, flags);
- break;
- case 2:
- errx(1, "Version 2 was used by multi-IPv4 jail "
- "implementations that never made it into the "
- "official kernel.");
- /* NOTREACHED */
- break;
-#endif
- case 3:
- q = print_xprison_v3(q, (char *)p + len, flags);
- break;
- default:
- errx(1, "Prison unknown. Kernel/userland out of sync?");
- /* NOTREACHED */
- break;
+ if (pflags & PRINT_VERBOSE) {
+ printf("%6d %-29.29s %.74s\n"
+ "%6s %-29.29s %.74s\n"
+ "%6s %-6d\n",
+ *(int *)iov[0].value.iov_base,
+ (char *)iov[1].value.iov_base,
+ (char *)iov[2].value.iov_base,
+ "",
+ (char *)iov[3].value.iov_base,
+ *(int *)iov[4].value.iov_base ? "DYING" : "ACTIVE",
+ "",
+ *(int *)iov[5].value.iov_base);
+ count = iov[6].value.iov_len / sizeof(struct in_addr);
+ for (ai = 0; ai < count; ai++)
+ if (inet_ntop(AF_INET,
+ &((struct in_addr *)iov[6].value.iov_base)[ai],
+ ipbuf, sizeof(ipbuf)) == NULL)
+ err(1, "inet_ntop");
+ else
+ printf("%6s %-15.15s\n", "", ipbuf);
+ if (!strcmp(params[7].name, "ip6.addr")) {
+ count = iov[7].value.iov_len / sizeof(struct in6_addr);
+ for (ai = 0; ai < count; ai++)
+ if (inet_ntop(AF_INET6, &((struct in_addr *)
+ iov[7].value.iov_base)[ai],
+ ipbuf, sizeof(ipbuf)) == NULL)
+ err(1, "inet_ntop");
+ else
+ printf("%6s %-15.15s\n", "", ipbuf);
}
+ } else if (pflags & PRINT_DEFAULT)
+ printf("%6d %-15.15s %-29.29s %.74s\n",
+ *(int *)iov[0].value.iov_base,
+ iov[1].value.iov_len == 0 ? "-"
+ : inet_ntoa(*(struct in_addr *)iov[1].value.iov_base),
+ (char *)iov[2].value.iov_base,
+ (char *)iov[3].value.iov_base);
+ else {
+ for (i = spc = 0; i < nparams; i++) {
+ if (!(params[i].flags & PARAM_USER))
+ continue;
+ if ((pflags & PRINT_SKIP) &&
+ ((!(params[i].flags & PARAM_WR)) ||
+ (params[i].noparent >= 0 &&
+ *(int *)iov[params[i].noparent].value.iov_base)))
+ continue;
+ if (spc)
+ putchar(' ');
+ else
+ spc = 1;
+ if (pflags & PRINT_NAMEVAL) {
+ /*
+ * Generally "name=value", but for booleans
+ * either "name" or "noname".
+ */
+ switch (params[i].type) {
+ case CTLTYPE_BOOL:
+ if (*(int *)iov[i].value.iov_base)
+ printf("%s", params[i].name);
+ else {
+ nname = noname(params[i].name);
+ printf("%s", nname);
+ free(nname);
+ }
+ break;
+ case CTLTYPE_NOBOOL:
+ if (*(int *)iov[i].value.iov_base)
+ printf("%s", params[i].name);
+ else {
+ nname =
+ nononame(params[i].name);
+ printf("%s", nname);
+ free(nname);
+ }
+ break;
+ default:
+ printf("%s=", params[i].name);
+ }
+ }
+ count = params[i].flags & PARAM_ARRAY
+ ? iov[i].value.iov_len / params[i].size : 1;
+ if (count == 0) {
+ if (pflags & PRINT_QUOTED)
+ printf("\"\"");
+ else if (!(pflags & PRINT_NAMEVAL))
+ putchar('-');
+ }
+ for (ai = 0; ai < count; ai++) {
+ if (ai > 0)
+ putchar(',');
+ switch (params[i].type) {
+ case CTLTYPE_INT:
+ printf("%d", ((int *)
+ iov[i].value.iov_base)[ai]);
+ break;
+ case CTLTYPE_UINT:
+ printf("%u", ((int *)
+ iov[i].value.iov_base)[ai]);
+ break;
+ case CTLTYPE_IPADDR:
+ if (inet_ntop(AF_INET,
+ &((struct in_addr *)
+ iov[i].value.iov_base)[ai],
+ ipbuf, sizeof(ipbuf)) == NULL)
+ err(1, "inet_ntop");
+ else
+ printf("%s", ipbuf);
+ break;
+ case CTLTYPE_IP6ADDR:
+ if (inet_ntop(AF_INET6,
+ &((struct in6_addr *)
+ iov[i].value.iov_base)[ai],
+ ipbuf, sizeof(ipbuf)) == NULL)
+ err(1, "inet_ntop");
+ else
+ printf("%s", ipbuf);
+ break;
+ case CTLTYPE_LONG:
+ printf("%ld", ((long *)
+ iov[i].value.iov_base)[ai]);
+ case CTLTYPE_ULONG:
+ printf("%lu", ((long *)
+ iov[i].value.iov_base)[ai]);
+ break;
+ case CTLTYPE_STRING:
+ if (pflags & PRINT_QUOTED)
+ quoted_print((char *)
+ iov[i].value.iov_base,
+ params[i].size);
+ else
+ printf("%.*s",
+ (int)params[i].size,
+ (char *)
+ iov[i].value.iov_base);
+ break;
+ case CTLTYPE_BOOL:
+ case CTLTYPE_NOBOOL:
+ if (!(pflags & PRINT_NAMEVAL))
+ printf(((int *)
+ iov[i].value.iov_base)[ai]
+ ? "true" : "false");
+ }
+ }
+ }
+ putchar('\n');
}
+ for (i = 0; i < nparams; i++)
+ if (params[i].value == NULL)
+ free(iov[i].value.iov_base);
+ return (jid);
+}
+
+static void
+quoted_print(char *str, int len)
+{
+ int c, qc;
+ char *p = str;
+ char *ep = str + len;
- free(p);
- exit(0);
+ /* An empty string needs quoting. */
+ if (!*p) {
+ fputs("\"\"", stdout);
+ return;
+ }
+
+ /*
+ * The value will be surrounded by quotes if it contains spaces
+ * or quotes.
+ */
+ qc = strchr(p, '\'') ? '"'
+ : strchr(p, '"') ? '\''
+ : strchr(p, ' ') || strchr(p, '\t') ? '"'
+ : 0;
+ if (qc)
+ putchar(qc);
+ while (p < ep && (c = *p++)) {
+ if (c == '\\' || c == qc)
+ putchar('\\');
+ putchar(c);
+ }
+ if (qc)
+ putchar(qc);
}
OpenPOWER on IntegriCloud