diff options
author | reyk <reyk@openbsd.org> | 2016-01-27 12:27:31 +0000 |
---|---|---|
committer | reyk <reyk@openbsd.org> | 2016-01-27 12:27:31 +0000 |
commit | 6fc48f48ca47010e94b6228ed7d4f7f8eb47d756 (patch) | |
tree | 2cfddec844068d9b85b00e901c78fbe6e2149fe5 /usr.sbin/hostctl | |
parent | Removes the abstraction layer to support multiple executable binaries. (diff) | |
download | wireguard-openbsd-6fc48f48ca47010e94b6228ed7d4f7f8eb47d756.tar.xz wireguard-openbsd-6fc48f48ca47010e94b6228ed7d4f7f8eb47d756.zip |
Add hostctl(8), a tool to access key-value stores on the host,
currently for hypervisor information stores on pvbus(4).
As discussed with deraadt@, the generic name is used to potentially
extend it for other use cases where the host or machine firmware
provides a key-value store, hypervisors or things like openprom.
Not enabled yet.
OK mikeb@
Diffstat (limited to 'usr.sbin/hostctl')
-rw-r--r-- | usr.sbin/hostctl/Makefile | 16 | ||||
-rw-r--r-- | usr.sbin/hostctl/hostctl.8 | 126 | ||||
-rw-r--r-- | usr.sbin/hostctl/hostctl.c | 211 |
3 files changed, 353 insertions, 0 deletions
diff --git a/usr.sbin/hostctl/Makefile b/usr.sbin/hostctl/Makefile new file mode 100644 index 00000000000..78b291862bd --- /dev/null +++ b/usr.sbin/hostctl/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.1 2016/01/27 12:27:31 reyk Exp $ + +.if ${MACHINE} == "i386" || ${MACHINE} == "amd64" + +PROG= hostctl + +CFLAGS+= -Wall + +.else +NOPROG= yes +.endif + +MAN= hostctl.8 +MANSUBDIR= i386 amd64 + +.include <bsd.prog.mk> diff --git a/usr.sbin/hostctl/hostctl.8 b/usr.sbin/hostctl/hostctl.8 new file mode 100644 index 00000000000..4ab071db2ac --- /dev/null +++ b/usr.sbin/hostctl/hostctl.8 @@ -0,0 +1,126 @@ +.\" $OpenBSD: hostctl.8,v 1.1 2016/01/27 12:27:31 reyk Exp $ +.\" +.\" Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: January 27 2016 $ +.Dt HOSTCTL 8 +.Os +.Sh NAME +.Nm hostctl +.Nd display or modify contents of the host's key-value store +.Sh SYNOPSIS +.Nm +.Op Fl qt +.Op Fl f Ar device +.Op Fl i Ar input +.Op Fl o Ar output +.Ar key +.Op Ar value +.Sh DESCRIPTION +The +.Nm +program provides a generic interface for accessing key-value stores on +the system's host. +It is primarily used for an abstracted way to exchange information +with hypervisors that are supported by the +.Xr pvbus 4 +subsystem. +When given the name of a specific +.Ar key , +.Nm +will display the value or list the key names of the subtree. +If the key is followed by a +.Ar value , +.Nm +will write the new key-value pair to the key-value store. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl q +Don't ask for confirmation of any default options. +.It Fl t +Print the type of the underlying driver. +.It Fl f Ar device +Use +.Ar device +instead of the default +.Pa /dev/pvbus0 . +.It Fl i Ar input +Read the new value for the specified +.Ar key +from the +.Ar input +file. +.It Fl o Ar output +Save the returned value in the +.Ar output +file. +.El +.Sh FILES +.Bl -tag -width "/dev/pvbusX" -compact +.It /dev/pvbus Ns Ar u +.Xr pvbus 4 +device unit +.Ar u +file. +.El +.Sh EXAMPLES +The +.Xr vmt 4 +driver provides access to the +.Dq guestinfo +information that is available in VMware virtual machines: +.Bd -literal -offset indent +# hostctl guestinfo.hostname +vm-111.example.com +# hostctl guestinfo.ip 192.168.100.111 +.Ed +.Pp +The +.Xr xen 4 +driver provices access to the XenStore that is available in Xen +virtual machines. +The +.Xr pvbus 4 +layer abstracts it as a simple key-value interface: +.Bd -literal -offset indent +# hostctl device/vif/0/mac +fe:e1:ba:d0:27:0f +# hostctl device/vif/0/description "My interface" +.Ed +.Pp +The XenStore is a virtual filesystem that also provides directories. +The directory name can be specified as a key to return the contents, +other keys, of the directory: +.Pp +.Bd -literal -offset indent +# hostctl device +vfb +vbd +vif +console +.Ed +.Sh SEE ALSO +.Xr pvbus 4 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox 5.9 . +.Sh AUTHORS +The +.Nm +program was written by +.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/usr.sbin/hostctl/hostctl.c b/usr.sbin/hostctl/hostctl.c new file mode 100644 index 00000000000..1a2b510fc13 --- /dev/null +++ b/usr.sbin/hostctl/hostctl.c @@ -0,0 +1,211 @@ +/* $OpenBSD: hostctl.c,v 1.1 2016/01/27 12:27:31 reyk Exp $ */ + +/* + * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <dev/pv/pvvar.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <err.h> +#include <vis.h> + +#define KVBUFSZ 4096 /* arbitrary value */ + +char *path_pvbus = "/dev/pvbus0"; /* the first hv interface */ +int qflag = 0; /* quiet */ +int tflag = 0; /* show type */ + +__dead void usage(void); +int kvsetstr(char *, const char *, size_t); +int kvsetfile(char *, const char *, size_t); + +__dead void +usage(void) +{ + extern char *__progname; + fprintf(stderr, "usage: %s [-t] [-f device] " + "[-i input] [-o output] key [value]\n", __progname); + exit(1); +} + +int +kvsetstr(char *dst, const char *src, size_t dstlen) +{ + size_t sz; + + /* Sanitize the string before sending it to the kernel and host */ + if ((sz = strnvis(dst, src, dstlen, VIS_OCTAL)) >= dstlen) + return (-1); + + /* Remove trailing newline */ + if (dst[sz - 1] == '\n') + dst[sz - 1] = '\0'; + + return (0); +} + +int +kvsetfile(char *dst, const char *input, size_t dstlen) +{ + char *buf = NULL; + int ret = -1; + FILE *fp; + + if (strcmp("-", input) == 0) + fp = stdin; + else if ((fp = fopen(input, "r")) == NULL) + return (-1); + + if ((buf = calloc(1, dstlen)) == NULL) + goto done; + if (fread(buf, 1, dstlen - 1, fp) == 0) + goto done; + if (kvsetstr(dst, buf, dstlen) == -1) + goto done; + + ret = 0; + done: + free(buf); + if (fp != stdin) + fclose(fp); + return (ret); +} + +int +main(int argc, char *argv[]) +{ + const char *key, *value, *in = NULL, *out = NULL; + FILE *outfp = stdout; + int fd, ret; + struct pvbus_req pvr; + int ch; + unsigned long cmd = 0; + char *str; + + while ((ch = getopt(argc, argv, "f:i:o:qt")) != -1) { + switch (ch) { + case 'f': + path_pvbus = optarg; + break; + case 'i': + in = optarg; + break; + case 'o': + out = optarg; + break; + case 'q': + qflag++; + break; + case 't': + tflag++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if ((fd = open(path_pvbus, O_RDONLY)) == -1) + err(1, "open: %s", path_pvbus); + + if (out != NULL) { + if (strcmp("-", out) == 0) + outfp = stdout; + else if ((outfp = fopen(out, "w")) == NULL) + err(1, "fopen: %s", out); + } + + memset(&pvr, 0, sizeof(pvr)); + pvr.pvr_keylen = pvr.pvr_valuelen = KVBUFSZ; + if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL || + (pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL) + err(1, "calloc"); + + if (tflag) { + if (ioctl(fd, PVBUSIOC_TYPE, &pvr, sizeof(pvr)) != 0) + err(1, "ioctl"); + + /* The returned type should be a simple single-line key */ + if (stravis(&str, pvr.pvr_key, + VIS_WHITE | VIS_DQ | VIS_OCTAL) == -1) + err(1, "stravis"); + fprintf(outfp, "%s: %s\n", path_pvbus, str); + free(str); + goto done; + } + + if (argc < 1) + usage(); + key = argv[0]; + + if (kvsetstr(pvr.pvr_key, key, pvr.pvr_keylen) == -1) + errx(1, "key too long"); + + /* Validate command line options for reading or writing */ + if (argc == 2 && in == NULL) { + cmd = PVBUSIOC_KVWRITE; + value = argv[1]; + if (kvsetstr(pvr.pvr_value, value, pvr.pvr_valuelen) == -1) + errx(1, "value too long"); + } else if (argc == 1 && in != NULL) { + cmd = PVBUSIOC_KVWRITE; + if (kvsetfile(pvr.pvr_value, in, pvr.pvr_valuelen) == -1) + errx(1, "input file"); + } else if (argc == 1) { + cmd = cmd == 0 ? PVBUSIOC_KVREAD : cmd; + } else + usage(); + + /* Re-open read-writable */ + if (cmd == PVBUSIOC_KVWRITE) { + close(fd); + if ((fd = open(path_pvbus, O_RDWR)) == -1) + err(1, "open: %s", path_pvbus); + } + + if ((ret = ioctl(fd, cmd, &pvr, sizeof(pvr))) != 0) + err(1, "ioctl"); + + if (!qflag && strlen(pvr.pvr_value)) { + /* + * The value can contain newlines and basically anything; + * only encode the unsafe characters that could perform + * unexpected functions on the terminal. + */ + if (stravis(&str, pvr.pvr_value, VIS_OCTAL) == -1) + err(1, "stravis"); + fprintf(outfp, "%s\n", str); + free(str); + } + + done: + if (outfp != stdout) + fclose(outfp); + free(pvr.pvr_value); + free(pvr.pvr_key); + close(fd); + + return (0); +} |