Package: freebsd-utils Tags: patch Hi,
At Tokyo Debian meeting, SUGIMOTO Norimitsu <dict...@live.jp> demonstrates kFreeBSD and it's interesting. And I heard about it lacks full jail support since jls and jexec doesn't be included. So, I made a patch for it :) It works, confirmed by Norimitsu as below $ sudo dpkg -i freebsd-utils_10.1~svn273304+jail1-1_kfreebsd-amd64.deb [norimitu@test-kf2]$ sudo jail -J /var/run/jail/1.jid -c jid=1 \ name=jail1 \ path=/srv/jail/jail_kf64_1 \ host.hostname=jail_kf64_1 \ ip4.addr=192.168.22.61 \ command=/bin/sh -- -c "/etc/init.d/rc S && /etc/init.d/rc 2" ## exec jls [norimitu@test-kf2]$ sudo jls JID IP Address Hostname Path 1 192.168.22.61 jail_kf64_1 /srv/jail/jail_kf64_1 ## exec jexec [norimitu@test-kf2]$ sudo jexec 1 touch /root/foobar.txt ## check file that was created with jexec [norimitu@test-kf2]$ sudo ls -l /srv/jail/jail_kf64_1/root 合計 0 -rw-r--r-- 1 root root 0 11月 23 15:52 foobar.txt ## seems ok :) -- Regards, Hideki Yamane henrich @ debian.or.jp/org http://wiki.debian.org/HidekiYamane
diff -urN freebsd-utils-10.1~svn273304.orig/debian/changelog freebsd-utils-10.1~svn273304/debian/changelog --- freebsd-utils-10.1~svn273304.orig/debian/changelog 2014-10-21 19:11:16.000000000 +0900 +++ freebsd-utils-10.1~svn273304/debian/changelog 2015-11-29 07:14:13.811304759 +0900 @@ -1,3 +1,9 @@ +freebsd-utils (10.1~svn273304+jail1-1) UNRELEASED; urgency=medium + + * add jls/jexec support + + -- Hideki Yamane <henr...@debian.org> Sun, 22 Nov 2015 01:54:31 +0900 + freebsd-utils (10.1~svn273304-1) unstable; urgency=medium [ Petr Salinger ] diff -urN freebsd-utils-10.1~svn273304.orig/debian/freebsd-utils.install freebsd-utils-10.1~svn273304/debian/freebsd-utils.install --- freebsd-utils-10.1~svn273304.orig/debian/freebsd-utils.install 2014-08-29 07:44:16.000000000 +0900 +++ freebsd-utils-10.1~svn273304/debian/freebsd-utils.install 2015-11-22 02:09:34.000000000 +0900 @@ -27,3 +27,5 @@ usr/sbin/acpiconf /usr/sbin usr/sbin/jail /usr/sbin +usr/sbin/jls /usr/sbin +usr/sbin/jexec /usr/sbin diff -urN freebsd-utils-10.1~svn273304.orig/debian/patches/makefiles.diff freebsd-utils-10.1~svn273304/debian/patches/makefiles.diff --- freebsd-utils-10.1~svn273304.orig/debian/patches/makefiles.diff 2014-10-06 04:59:11.000000000 +0900 +++ freebsd-utils-10.1~svn273304/debian/patches/makefiles.diff 2015-11-22 02:31:57.000000000 +0900 +Index: freebsd-utils-10.1~svn273304+jail1/src/usr.sbin/jexec/Makefile +=================================================================== +--- freebsd-utils-10.1~svn273304+jail1.orig/src/usr.sbin/jexec/Makefile ++++ freebsd-utils-10.1~svn273304+jail1/src/usr.sbin/jexec/Makefile +@@ -3,6 +3,8 @@ + PROG= jexec + MAN= jexec.8 + DPADD= ${LIBJAIL} ${LIBUTIL} +-LDADD= -ljail -lutil ++LDADD= -ljail -lutil-freebsd ++ ++LDADD+= -lfreebsd-glue + + .include <bsd.prog.mk> +Index: freebsd-utils-10.1~svn273304+jail1/src/usr.sbin/jls/Makefile +=================================================================== +--- freebsd-utils-10.1~svn273304+jail1.orig/src/usr.sbin/jls/Makefile ++++ freebsd-utils-10.1~svn273304+jail1/src/usr.sbin/jls/Makefile +@@ -7,6 +7,8 @@ MAN= jls.8 + DPADD= ${LIBJAIL} + LDADD= -ljail + ++LDADD+= -lfreebsd-glue ++ + .if ${MK_INET6_SUPPORT} != "no" + CFLAGS+= -DINET6 + .endif diff -urN freebsd-utils-10.1~svn273304.orig/debian/rules freebsd-utils-10.1~svn273304/debian/rules --- freebsd-utils-10.1~svn273304.orig/debian/rules 2014-10-20 20:14:18.000000000 +0900 +++ freebsd-utils-10.1~svn273304/debian/rules 2015-11-22 02:02:32.000000000 +0900 @@ -113,6 +113,7 @@ sys/i386/linux/syscalls.master \ \ usr.sbin/jail bin/chflags \ + usr.sbin/jls usr.sbin/jexec \ sbin/devd etc/devd.conf etc/devd sys/dev/usb/usbdevs \ usr.sbin/acpi/acpiconf \ usr.sbin/acpi/Makefile \ diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/Makefile freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/Makefile --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/Makefile 2015-11-24 07:00:09.000000000 +0900 @@ -0,0 +1,10 @@ +# $FreeBSD: release/10.1.0/usr.sbin/jexec/Makefile 201390 2010-01-02 11:07:44Z ed $ + +PROG= jexec +MAN= jexec.8 +DPADD= ${LIBJAIL} ${LIBUTIL} +LDADD= -ljail -lutil-freebsd + +LDADD+= -lfreebsd-glue + +.include <bsd.prog.mk> diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/jexec.8 freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/jexec.8 --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/jexec.8 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/jexec.8 2015-11-22 01:46:49.000000000 +0900 @@ -0,0 +1,76 @@ +.\" +.\" Copyright (c) 2003 Mike Barcroft <m...@freebsd.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" 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: release/10.1.0/usr.sbin/jexec/jexec.8 192896 2009-05-27 14:30:26Z jamie $ +.\" +.Dd May 27, 2009 +.Dt JEXEC 8 +.Os +.Sh NAME +.Nm jexec +.Nd "execute a command inside an existing jail" +.Sh SYNOPSIS +.Nm +.Op Fl u Ar username | Fl U Ar username +.Ar jail command ... +.Sh DESCRIPTION +The +.Nm +utility executes +.Ar command +inside the +.Ar jail +identified by its jid or name. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl u Ar username +The user name from host environment as whom the +.Ar command +should run. +.It Fl U Ar username +The user name from jailed environment as whom the +.Ar command +should run. +.El +.Sh SEE ALSO +.Xr jail_attach 2 , +.Xr jail 8 , +.Xr jls 8 +.Sh HISTORY +The +.Nm +utility was added in +.Fx 5.1 . +.Sh BUGS +If the jail is not identified by +.Ar jid +there is a possible race in between the lookup of the jail +and executing the command inside the jail. +Giving a +.Ar jid +has a similar race as another process can stop the jail and +start another one after the user looked up the +.Ar jid . diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/jexec.c freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/jexec.c --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jexec/jexec.c 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jexec/jexec.c 2015-11-22 01:46:49.000000000 +0900 @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2003 Mike Barcroft <m...@freebsd.org> + * Copyright (c) 2008 Bjoern A. Zeeb <b...@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * 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: release/10.1.0/usr.sbin/jexec/jexec.c 194869 2009-06-24 18:18:35Z jamie $ + */ + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include <err.h> +#include <errno.h> +#include <jail.h> +#include <limits.h> +#include <login_cap.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <unistd.h> + +static void usage(void); + +#define GET_USER_INFO do { \ + pwd = getpwnam(username); \ + if (pwd == NULL) { \ + if (errno) \ + err(1, "getpwnam: %s", username); \ + else \ + errx(1, "%s: no such user", username); \ + } \ + lcap = login_getpwclass(pwd); \ + if (lcap == NULL) \ + err(1, "getpwclass: %s", username); \ + ngroups = ngroups_max; \ + if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \ + err(1, "getgrouplist: %s", username); \ +} while (0) + +int +main(int argc, char *argv[]) +{ + int jid; + login_cap_t *lcap = NULL; + struct passwd *pwd = NULL; + gid_t *groups = NULL; + int ch, ngroups, uflag, Uflag; + long ngroups_max; + char *username; + + ch = uflag = Uflag = 0; + username = NULL; + ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; + if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) + err(1, "malloc"); + + while ((ch = getopt(argc, argv, "nu:U:")) != -1) { + switch (ch) { + case 'n': + /* Specified name, now unused */ + break; + case 'u': + username = optarg; + uflag = 1; + break; + case 'U': + username = optarg; + Uflag = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc < 2) + usage(); + if (uflag && Uflag) + usage(); + if (uflag) + GET_USER_INFO; + jid = jail_getid(argv[0]); + if (jid < 0) + errx(1, "%s", jail_errmsg); + if (jail_attach(jid) == -1) + err(1, "jail_attach(%d)", jid); + if (chdir("/") == -1) + err(1, "chdir(): /"); + if (username != NULL) { + if (Uflag) + GET_USER_INFO; + if (setgroups(ngroups, groups) != 0) + err(1, "setgroups"); + if (setgid(pwd->pw_gid) != 0) + err(1, "setgid"); + if (setusercontext(lcap, pwd, pwd->pw_uid, + LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) + err(1, "setusercontext"); + login_close(lcap); + } + if (execvp(argv[1], argv + 1) == -1) + err(1, "execvp(): %s", argv[1]); + exit(0); +} + +static void +usage(void) +{ + + fprintf(stderr, "%s\n", + "usage: jexec [-u username | -U username] jail command ..."); + exit(1); +} diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/Makefile freebsd-utils-10.1~svn273304/src/usr.sbin/jls/Makefile --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jls/Makefile 2015-11-24 07:00:09.000000000 +0900 @@ -0,0 +1,19 @@ +# $FreeBSD: release/10.1.0/usr.sbin/jls/Makefile 222465 2011-05-29 21:03:40Z bz $ + +.include <bsd.own.mk> + +PROG= jls +MAN= jls.8 +DPADD= ${LIBJAIL} +LDADD= -ljail + +LDADD+= -lfreebsd-glue + +.if ${MK_INET6_SUPPORT} != "no" +CFLAGS+= -DINET6 +.endif +.if ${MK_INET_SUPPORT} != "no" +CFLAGS+= -DINET +.endif + +.include <bsd.prog.mk> diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/jls.8 freebsd-utils-10.1~svn273304/src/usr.sbin/jls/jls.8 --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/jls.8 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jls/jls.8 2015-11-22 01:46:45.000000000 +0900 @@ -0,0 +1,115 @@ +.\" +.\" Copyright (c) 2003 Mike Barcroft <m...@freebsd.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" 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: release/10.1.0/usr.sbin/jls/jls.8 250736 2013-05-17 08:48:16Z des $ +.\" +.Dd July 20, 2012 +.Dt JLS 8 +.Os +.Sh NAME +.Nm jls +.Nd "list jails" +.Sh SYNOPSIS +.Nm +.Op Fl dhNnqsv +.Op Fl j Ar jail +.Op Ar parameter ... +.Sh DESCRIPTION +The +.Nm +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 +If no +.Ar parameters +or any of the options +.Fl hns +are given, the following four columns will be printed: +jail identifier (jid), IP address (ip4.addr), hostname (host.hostname), +and path (path). +.Pp +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, +.Va all +is assumed. +.It Fl N +In the standard display mode, print each jail's name instead of its +numeric ID. +If the jail does not have a name, the numeric ID is printed instead. +.It Fl n +Print parameters in +.Dq name=value +format, where each parameter is preceded by its name. +If no parameters are given on the command line, +.Va all +is assumed. +.It Fl q +Put quotes around parameters if they contain spaces or quotes, or are +the empty string. +.It Fl s +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_get 2 , +.Xr jail 8 , +.Xr jexec 8 +.Sh HISTORY +The +.Nm +utility was added in +.Fx 5.1 . +Extensible jail parameters were introduced in +.Fx 8.0 . diff -urN freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/jls.c freebsd-utils-10.1~svn273304/src/usr.sbin/jls/jls.c --- freebsd-utils-10.1~svn273304.orig/src/usr.sbin/jls/jls.c 1970-01-01 09:00:00.000000000 +0900 +++ freebsd-utils-10.1~svn273304/src/usr.sbin/jls/jls.c 2015-11-22 01:46:45.000000000 +0900 @@ -0,0 +1,516 @@ +/*- + * Copyright (c) 2003 Mike Barcroft <m...@freebsd.org> + * Copyright (c) 2008 Bjoern A. Zeeb <b...@freebsd.org> + * Copyright (c) 2009 James Gritton <ja...@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: release/10.1.0/usr.sbin/jls/jls.c 250736 2013-05-17 08:48:16Z des $"); + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include <err.h> +#include <errno.h> +#include <jail.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define JP_USER 0x01000000 +#define JP_OPT 0x02000000 + +#define PRINT_DEFAULT 0x01 +#define PRINT_HEADER 0x02 +#define PRINT_NAMEVAL 0x04 +#define PRINT_QUOTED 0x08 +#define PRINT_SKIP 0x10 +#define PRINT_VERBOSE 0x20 +#define PRINT_JAIL_NAME 0x40 + +static struct jailparam *params; +static int *param_parent; +static int nparams; +#ifdef INET6 +static int ip6_ok; +#endif +#ifdef INET +static int ip4_ok; +#endif + +static int add_param(const char *name, void *value, size_t valuelen, + struct jailparam *source, unsigned flags); +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 +main(int argc, char **argv) +{ + char *dot, *ep, *jname; + int c, i, jflags, jid, lastjid, pflags, spc; + + jname = NULL; + pflags = jflags = jid = 0; + while ((c = getopt(argc, argv, "adj:hNnqsv")) >= 0) + switch (c) { + case 'a': + case 'd': + jflags |= JAIL_DYING; + break; + case 'j': + jid = strtoul(optarg, &ep, 10); + if (!jid || *ep) { + jid = 0; + jname = optarg; + } + break; + case 'h': + pflags = (pflags & ~(PRINT_SKIP | PRINT_VERBOSE)) | + PRINT_HEADER; + break; + case 'N': + pflags |= PRINT_JAIL_NAME; + 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_HEADER | PRINT_NAMEVAL | PRINT_SKIP)) | + PRINT_VERBOSE; + break; + default: + errx(1, "usage: jls [-dhNnqv] [-j jail] [param ...]"); + } + +#ifdef INET6 + ip6_ok = feature_present("inet6"); +#endif +#ifdef INET + ip4_ok = feature_present("inet"); +#endif + + /* Add the parameters to print. */ + if (optind == argc) { + if (pflags & (PRINT_HEADER | PRINT_NAMEVAL)) + add_param("all", NULL, (size_t)0, NULL, JP_USER); + else if (pflags & PRINT_VERBOSE) { + add_param("jid", NULL, (size_t)0, NULL, JP_USER); + add_param("host.hostname", NULL, (size_t)0, NULL, + JP_USER); + add_param("path", NULL, (size_t)0, NULL, JP_USER); + add_param("name", NULL, (size_t)0, NULL, JP_USER); + add_param("dying", NULL, (size_t)0, NULL, JP_USER); + add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER); +#ifdef INET + if (ip4_ok) + add_param("ip4.addr", NULL, (size_t)0, NULL, + JP_USER); +#endif +#ifdef INET6 + if (ip6_ok) + add_param("ip6.addr", NULL, (size_t)0, NULL, + JP_USER | JP_OPT); +#endif + } else { + pflags |= PRINT_DEFAULT; + if (pflags & PRINT_JAIL_NAME) + add_param("name", NULL, (size_t)0, NULL, JP_USER); + else + add_param("jid", NULL, (size_t)0, NULL, JP_USER); +#ifdef INET + if (ip4_ok) + add_param("ip4.addr", NULL, (size_t)0, NULL, + JP_USER); +#endif + add_param("host.hostname", NULL, (size_t)0, NULL, + JP_USER); + add_param("path", NULL, (size_t)0, NULL, JP_USER); + } + } else + while (optind < argc) + add_param(argv[optind++], NULL, (size_t)0, NULL, + JP_USER); + + if (pflags & PRINT_SKIP) { + /* Check for parameters with jailsys parents. */ + for (i = 0; i < nparams; i++) { + if ((params[i].jp_flags & JP_USER) && + (dot = strchr(params[i].jp_name, '.'))) { + *dot = 0; + param_parent[i] = add_param(params[i].jp_name, + NULL, (size_t)0, NULL, JP_OPT); + *dot = '.'; + } + } + } + + /* Add the index key parameters. */ + if (jid != 0) + add_param("jid", &jid, sizeof(jid), NULL, 0); + else if (jname != NULL) + add_param("name", jname, strlen(jname), NULL, 0); + else + add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); + + /* 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) + if (pflags & PRINT_JAIL_NAME) + printf(" JID IP Address " + "Hostname Path\n"); + else + printf(" JID IP Address " + "Hostname Path\n"); + else if (pflags & PRINT_HEADER) { + for (i = spc = 0; i < nparams; i++) + if (params[i].jp_flags & JP_USER) { + if (spc) + putchar(' '); + else + spc = 1; + fputs(params[i].jp_name, stdout); + } + putchar('\n'); + } + + /* Fetch the jail(s) and print the paramters. */ + if (jid != 0 || jname != NULL) { + if (print_jail(pflags, jflags) < 0) + errx(1, "%s", jail_errmsg); + } else { + for (lastjid = 0; + (lastjid = print_jail(pflags, jflags)) >= 0; ) + ; + if (errno != 0 && errno != ENOENT) + errx(1, "%s", jail_errmsg); + } + + return (0); +} + +static int +add_param(const char *name, void *value, size_t valuelen, + struct jailparam *source, unsigned flags) +{ + struct jailparam *param, *tparams; + int i, tnparams; + + static int paramlistsize; + + /* The pseudo-parameter "all" scans the list of available parameters. */ + if (!strcmp(name, "all")) { + tnparams = jailparam_all(&tparams); + if (tnparams < 0) + errx(1, "%s", jail_errmsg); + qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), + sort_param); + for (i = 0; i < tnparams; i++) + add_param(tparams[i].jp_name, NULL, (size_t)0, + tparams + i, flags); + free(tparams); + return -1; + } + + /* Check for repeat parameters. */ + for (i = 0; i < nparams; i++) + if (!strcmp(name, params[i].jp_name)) { + if (value != NULL && jailparam_import_raw(params + i, + value, valuelen) < 0) + errx(1, "%s", jail_errmsg); + params[i].jp_flags |= flags; + if (source != NULL) + jailparam_free(source, 1); + return i; + } + + /* Make sure there is room for the new param record. */ + if (!nparams) { + paramlistsize = 32; + params = malloc(paramlistsize * sizeof(*params)); + param_parent = malloc(paramlistsize * sizeof(*param_parent)); + if (params == NULL || param_parent == NULL) + err(1, "malloc"); + } else if (nparams >= paramlistsize) { + paramlistsize *= 2; + params = realloc(params, paramlistsize * sizeof(*params)); + param_parent = realloc(param_parent, + paramlistsize * sizeof(*param_parent)); + if (params == NULL || param_parent == NULL) + err(1, "realloc"); + } + + /* Look up the parameter. */ + param_parent[nparams] = -1; + param = params + nparams++; + if (source != NULL) { + *param = *source; + param->jp_flags |= flags; + return param - params; + } + if (jailparam_init(param, name) < 0) + errx(1, "%s", jail_errmsg); + param->jp_flags = flags; + if ((value != NULL ? jailparam_import_raw(param, value, valuelen) + : jailparam_import(param, value)) < 0) { + if (flags & JP_OPT) { + nparams--; + return (-1); + } + errx(1, "%s", jail_errmsg); + } + return param - params; +} + +static int +sort_param(const void *a, const void *b) +{ + const struct jailparam *parama, *paramb; + char *ap, *bp; + + /* Put top-level parameters first. */ + parama = a; + paramb = b; + ap = strchr(parama->jp_name, '.'); + bp = strchr(paramb->jp_name, '.'); + if (ap && !bp) + return (1); + if (bp && !ap) + return (-1); + return (strcmp(parama->jp_name, paramb->jp_name)); +} + +static char * +noname(const char *name) +{ + char *nname, *p; + + 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; +} + +static char * +nononame(const char *name) +{ + char *nname, *p; + + 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; + char **param_values; + int i, ai, jid, count, n, spc; + char ipbuf[INET6_ADDRSTRLEN]; + + jid = jailparam_get(params, nparams, jflags); + if (jid < 0) + return jid; + if (pflags & PRINT_VERBOSE) { + printf("%6d %-29.29s %.74s\n" + "%6s %-29.29s %.74s\n" + "%6s %-6d\n", + *(int *)params[0].jp_value, + (char *)params[1].jp_value, + (char *)params[2].jp_value, + "", + (char *)params[3].jp_value, + *(int *)params[4].jp_value ? "DYING" : "ACTIVE", + "", + *(int *)params[5].jp_value); + n = 6; +#ifdef INET + if (ip4_ok && !strcmp(params[n].jp_name, "ip4.addr")) { + count = params[n].jp_valuelen / sizeof(struct in_addr); + for (ai = 0; ai < count; ai++) + if (inet_ntop(AF_INET, + &((struct in_addr *)params[n].jp_value)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%6s %-15.15s\n", "", ipbuf); + n++; + } +#endif +#ifdef INET6 + if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) { + count = params[n].jp_valuelen / sizeof(struct in6_addr); + for (ai = 0; ai < count; ai++) + if (inet_ntop(AF_INET6, + &((struct in6_addr *) + params[n].jp_value)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%6s %s\n", "", ipbuf); + n++; + } +#endif + } else if (pflags & PRINT_DEFAULT) { + if (pflags & PRINT_JAIL_NAME) + printf(" %-15s ", (char *)params[0].jp_value); + else + printf("%6d ", *(int *)params[0].jp_value); + printf("%-15.15s %-29.29s %.74s\n", +#ifdef INET + (!ip4_ok || params[1].jp_valuelen == 0) ? "-" + : inet_ntoa(*(struct in_addr *)params[1].jp_value), + (char *)params[2-!ip4_ok].jp_value, + (char *)params[3-!ip4_ok].jp_value); +#else + "-", + (char *)params[1].jp_value, + (char *)params[2].jp_value); +#endif + } else { + param_values = alloca(nparams * sizeof(*param_values)); + for (i = 0; i < nparams; i++) { + if (!(params[i].jp_flags & JP_USER)) + continue; + param_values[i] = jailparam_export(params + i); + if (param_values[i] == NULL) + errx(1, "%s", jail_errmsg); + } + for (i = spc = 0; i < nparams; i++) { + if (!(params[i].jp_flags & JP_USER)) + continue; + if ((pflags & PRINT_SKIP) && + ((!(params[i].jp_ctltype & + (CTLFLAG_WR | CTLFLAG_TUN))) || + (param_parent[i] >= 0 && + *(int *)params[param_parent[i]].jp_value != + JAIL_SYS_NEW))) + continue; + if (spc) + putchar(' '); + else + spc = 1; + if (pflags & PRINT_NAMEVAL) { + /* + * Generally "name=value", but for booleans + * either "name" or "noname". + */ + if (params[i].jp_flags & + (JP_BOOL | JP_NOBOOL)) { + if (*(int *)params[i].jp_value) + printf("%s", params[i].jp_name); + else { + nname = (params[i].jp_flags & + JP_NOBOOL) ? + nononame(params[i].jp_name) + : noname(params[i].jp_name); + printf("%s", nname); + free(nname); + } + continue; + } + printf("%s=", params[i].jp_name); + } + if (params[i].jp_valuelen == 0) { + if (pflags & PRINT_QUOTED) + printf("\"\""); + else if (!(pflags & PRINT_NAMEVAL)) + putchar('-'); + } else + quoted_print(param_values[i]); + } + putchar('\n'); + for (i = 0; i < nparams; i++) + if (params[i].jp_flags & JP_USER) + free(param_values[i]); + } + return (jid); +} + +static void +quoted_print(char *str) +{ + int c, qc; + char *p = str; + + /* 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 ((c = *p++)) { + if (c == '\\' || c == qc) + putchar('\\'); + putchar(c); + } + if (qc) + putchar(qc); +}