1 |
|
|
/* $OpenBSD: hostctl.c,v 1.3 2016/01/27 16:01:36 jmc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/ioctl.h> |
20 |
|
|
#include <sys/types.h> |
21 |
|
|
|
22 |
|
|
#include <dev/pv/pvvar.h> |
23 |
|
|
|
24 |
|
|
#include <stdio.h> |
25 |
|
|
#include <stdlib.h> |
26 |
|
|
#include <string.h> |
27 |
|
|
#include <unistd.h> |
28 |
|
|
#include <fcntl.h> |
29 |
|
|
#include <errno.h> |
30 |
|
|
#include <err.h> |
31 |
|
|
#include <vis.h> |
32 |
|
|
|
33 |
|
|
#define KVBUFSZ 4096 /* arbitrary value */ |
34 |
|
|
|
35 |
|
|
char *path_pvbus = "/dev/pvbus0"; /* the first hv interface */ |
36 |
|
|
int qflag = 0; /* quiet */ |
37 |
|
|
int tflag = 0; /* show type */ |
38 |
|
|
|
39 |
|
|
__dead void usage(void); |
40 |
|
|
int kvsetstr(char *, const char *, size_t); |
41 |
|
|
int kvsetfile(char *, const char *, size_t); |
42 |
|
|
|
43 |
|
|
__dead void |
44 |
|
|
usage(void) |
45 |
|
|
{ |
46 |
|
|
extern char *__progname; |
47 |
|
|
fprintf(stderr, "usage: %s [-qt] [-f device] " |
48 |
|
|
"[-i input] [-o output] key [value]\n", __progname); |
49 |
|
|
exit(1); |
50 |
|
|
} |
51 |
|
|
|
52 |
|
|
int |
53 |
|
|
kvsetstr(char *dst, const char *src, size_t dstlen) |
54 |
|
|
{ |
55 |
|
|
size_t sz; |
56 |
|
|
|
57 |
|
|
/* Sanitize the string before sending it to the kernel and host */ |
58 |
|
|
if ((sz = strnvis(dst, src, dstlen, VIS_SAFE | VIS_CSTYLE)) >= dstlen) |
59 |
|
|
return (-1); |
60 |
|
|
|
61 |
|
|
/* Remove trailing newline */ |
62 |
|
|
if (dst[sz - 1] == '\n') |
63 |
|
|
dst[sz - 1] = '\0'; |
64 |
|
|
|
65 |
|
|
return (0); |
66 |
|
|
} |
67 |
|
|
|
68 |
|
|
int |
69 |
|
|
kvsetfile(char *dst, const char *input, size_t dstlen) |
70 |
|
|
{ |
71 |
|
|
char *buf = NULL; |
72 |
|
|
int ret = -1; |
73 |
|
|
FILE *fp; |
74 |
|
|
|
75 |
|
|
if (strcmp("-", input) == 0) |
76 |
|
|
fp = stdin; |
77 |
|
|
else if ((fp = fopen(input, "r")) == NULL) |
78 |
|
|
return (-1); |
79 |
|
|
|
80 |
|
|
if ((buf = calloc(1, dstlen)) == NULL) |
81 |
|
|
goto done; |
82 |
|
|
if (fread(buf, 1, dstlen - 1, fp) == 0) |
83 |
|
|
goto done; |
84 |
|
|
if (kvsetstr(dst, buf, dstlen) == -1) |
85 |
|
|
goto done; |
86 |
|
|
|
87 |
|
|
ret = 0; |
88 |
|
|
done: |
89 |
|
|
free(buf); |
90 |
|
|
if (fp != stdin) |
91 |
|
|
fclose(fp); |
92 |
|
|
return (ret); |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
int |
96 |
|
|
main(int argc, char *argv[]) |
97 |
|
|
{ |
98 |
|
|
const char *key, *value, *in = NULL, *out = NULL; |
99 |
|
|
FILE *outfp = stdout; |
100 |
|
|
int fd, ret; |
101 |
|
|
struct pvbus_req pvr; |
102 |
|
|
int ch; |
103 |
|
|
unsigned long cmd = 0; |
104 |
|
|
char *str; |
105 |
|
|
|
106 |
|
|
while ((ch = getopt(argc, argv, "f:i:o:qt")) != -1) { |
107 |
|
|
switch (ch) { |
108 |
|
|
case 'f': |
109 |
|
|
path_pvbus = optarg; |
110 |
|
|
break; |
111 |
|
|
case 'i': |
112 |
|
|
in = optarg; |
113 |
|
|
break; |
114 |
|
|
case 'o': |
115 |
|
|
out = optarg; |
116 |
|
|
break; |
117 |
|
|
case 'q': |
118 |
|
|
qflag++; |
119 |
|
|
break; |
120 |
|
|
case 't': |
121 |
|
|
tflag++; |
122 |
|
|
break; |
123 |
|
|
default: |
124 |
|
|
usage(); |
125 |
|
|
} |
126 |
|
|
} |
127 |
|
|
argc -= optind; |
128 |
|
|
argv += optind; |
129 |
|
|
|
130 |
|
|
if ((fd = open(path_pvbus, O_RDONLY)) == -1) |
131 |
|
|
err(1, "open: %s", path_pvbus); |
132 |
|
|
|
133 |
|
|
if (out != NULL) { |
134 |
|
|
if (strcmp("-", out) == 0) |
135 |
|
|
outfp = stdout; |
136 |
|
|
else if ((outfp = fopen(out, "w")) == NULL) |
137 |
|
|
err(1, "fopen: %s", out); |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
memset(&pvr, 0, sizeof(pvr)); |
141 |
|
|
pvr.pvr_keylen = pvr.pvr_valuelen = KVBUFSZ; |
142 |
|
|
if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL || |
143 |
|
|
(pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL) |
144 |
|
|
err(1, "calloc"); |
145 |
|
|
|
146 |
|
|
if (tflag) { |
147 |
|
|
if (ioctl(fd, PVBUSIOC_TYPE, &pvr, sizeof(pvr)) != 0) |
148 |
|
|
err(1, "ioctl"); |
149 |
|
|
|
150 |
|
|
/* The returned type should be a simple single-line key */ |
151 |
|
|
if (stravis(&str, pvr.pvr_key, |
152 |
|
|
VIS_WHITE | VIS_DQ | VIS_CSTYLE) == -1) |
153 |
|
|
err(1, "stravis"); |
154 |
|
|
fprintf(outfp, "%s: %s\n", path_pvbus, str); |
155 |
|
|
free(str); |
156 |
|
|
goto done; |
157 |
|
|
} |
158 |
|
|
|
159 |
|
|
if (argc < 1) |
160 |
|
|
usage(); |
161 |
|
|
key = argv[0]; |
162 |
|
|
|
163 |
|
|
if (kvsetstr(pvr.pvr_key, key, pvr.pvr_keylen) == -1) |
164 |
|
|
errx(1, "key too long"); |
165 |
|
|
|
166 |
|
|
/* Validate command line options for reading or writing */ |
167 |
|
|
if (argc == 2 && in == NULL) { |
168 |
|
|
cmd = PVBUSIOC_KVWRITE; |
169 |
|
|
value = argv[1]; |
170 |
|
|
if (kvsetstr(pvr.pvr_value, value, pvr.pvr_valuelen) == -1) |
171 |
|
|
errx(1, "value too long"); |
172 |
|
|
} else if (argc == 1 && in != NULL) { |
173 |
|
|
cmd = PVBUSIOC_KVWRITE; |
174 |
|
|
if (kvsetfile(pvr.pvr_value, in, pvr.pvr_valuelen) == -1) |
175 |
|
|
errx(1, "input file"); |
176 |
|
|
} else if (argc == 1) { |
177 |
|
|
cmd = cmd == 0 ? PVBUSIOC_KVREAD : cmd; |
178 |
|
|
} else |
179 |
|
|
usage(); |
180 |
|
|
|
181 |
|
|
/* Re-open read-writable */ |
182 |
|
|
if (cmd == PVBUSIOC_KVWRITE) { |
183 |
|
|
close(fd); |
184 |
|
|
if ((fd = open(path_pvbus, O_RDWR)) == -1) |
185 |
|
|
err(1, "open: %s", path_pvbus); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
if ((ret = ioctl(fd, cmd, &pvr, sizeof(pvr))) != 0) |
189 |
|
|
err(1, "ioctl"); |
190 |
|
|
|
191 |
|
|
if (!qflag && strlen(pvr.pvr_value)) { |
192 |
|
|
/* |
193 |
|
|
* The value can contain newlines and basically anything; |
194 |
|
|
* only encode the unsafe characters that could perform |
195 |
|
|
* unexpected functions on the terminal. |
196 |
|
|
*/ |
197 |
|
|
if (stravis(&str, pvr.pvr_value, VIS_SAFE | VIS_CSTYLE) == -1) |
198 |
|
|
err(1, "stravis"); |
199 |
|
|
fprintf(outfp, "%s\n", str); |
200 |
|
|
free(str); |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
done: |
204 |
|
|
if (outfp != stdout) |
205 |
|
|
fclose(outfp); |
206 |
|
|
free(pvr.pvr_value); |
207 |
|
|
free(pvr.pvr_key); |
208 |
|
|
close(fd); |
209 |
|
|
|
210 |
|
|
return (0); |
211 |
|
|
} |