GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/hostctl/hostctl.c Lines: 0 89 0.0 %
Date: 2017-11-07 Branches: 0 70 0.0 %

Line Branch Exec Source
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
}