drvctl.c revision 1.10
1/* $NetBSD: drvctl.c,v 1.10 2009/04/20 21:41:50 dyoung Exp $ */
2
3/*
4 * Copyright (c) 2004
5 * 	Matthias Drochner.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <stdbool.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <err.h>
34#include <fcntl.h>
35#include <string.h>
36#include <sys/ioctl.h>
37#include <sys/drvctlio.h>
38
39#define OPTS "QRSa:dlnpr"
40
41#define	OPEN_MODE(mode)							\
42	(((mode) == 'd' || (mode) == 'r') ? O_RDWR			\
43					  : O_RDONLY)
44
45static void usage(void);
46
47static void
48usage(void)
49{
50
51	fprintf(stderr, "Usage: %s -r [-a attribute] busdevice [locator ...]\n"
52	    "       %s -d device\n"
53	    "       %s [-n] -l [device]\n"
54	    "       %s -p device\n"
55	    "       %s -Q device\n"
56	    "       %s -R device\n"
57	    "       %s -S device\n",
58	    getprogname(), getprogname(), getprogname(), getprogname(),
59	    getprogname(), getprogname(), getprogname());
60	exit(1);
61}
62
63int
64main(int argc, char **argv)
65{
66	bool nflag = false;
67	int c, mode;
68	char *attr = 0;
69	extern char *optarg;
70	extern int optind;
71	int fd, res;
72	size_t children;
73	struct devpmargs paa = {.devname = "", .flags = 0};
74	struct devlistargs laa = {.l_devname = "", .l_childname = NULL,
75				  .l_children = 0};
76	struct devdetachargs daa;
77	struct devrescanargs raa;
78	int *locs, i;
79	prop_dictionary_t command_dict, args_dict, results_dict,
80			  data_dict;
81	prop_string_t string;
82	prop_number_t number;
83	char *xml;
84
85	mode = 0;
86	while ((c = getopt(argc, argv, OPTS)) != -1) {
87		switch (c) {
88		case 'Q':
89		case 'R':
90		case 'S':
91		case 'd':
92		case 'l':
93		case 'p':
94		case 'r':
95			mode = c;
96			break;
97		case 'a':
98			attr = optarg;
99			break;
100		case 'n':
101			nflag = true;
102			break;
103		case '?':
104		default:
105			usage();
106		}
107	}
108
109	argc -= optind;
110	argv += optind;
111
112	if ((argc < 1 && mode != 'l') || mode == 0)
113		usage();
114
115	fd = open(DRVCTLDEV, OPEN_MODE(mode), 0);
116	if (fd < 0)
117		err(2, "open %s", DRVCTLDEV);
118
119	switch (mode) {
120	case 'Q':
121		paa.flags = DEVPM_F_SUBTREE;
122		/*FALLTHROUGH*/
123	case 'R':
124		strlcpy(paa.devname, argv[0], sizeof(paa.devname));
125
126		if (ioctl(fd, DRVRESUMEDEV, &paa) == -1)
127			err(3, "DRVRESUMEDEV");
128		break;
129	case 'S':
130		strlcpy(paa.devname, argv[0], sizeof(paa.devname));
131
132		if (ioctl(fd, DRVSUSPENDDEV, &paa) == -1)
133			err(3, "DRVSUSPENDDEV");
134		break;
135	case 'd':
136		strlcpy(daa.devname, argv[0], sizeof(daa.devname));
137
138		if (ioctl(fd, DRVDETACHDEV, &daa) == -1)
139			err(3, "DRVDETACHDEV");
140		break;
141	case 'l':
142		if (argc == 0)
143			*laa.l_devname = '\0';
144		else
145			strlcpy(laa.l_devname, argv[0], sizeof(laa.l_devname));
146
147		if (ioctl(fd, DRVLISTDEV, &laa) == -1)
148			err(3, "DRVLISTDEV");
149
150		children = laa.l_children;
151
152		laa.l_childname = malloc(children * sizeof(laa.l_childname[0]));
153		if (laa.l_childname == NULL)
154			err(5, "DRVLISTDEV");
155		if (ioctl(fd, DRVLISTDEV, &laa) == -1)
156			err(3, "DRVLISTDEV");
157		if (laa.l_children > children)
158			err(6, "DRVLISTDEV: number of children grew");
159
160		for (i = 0; i < (int)laa.l_children; i++) {
161			if (!nflag) {
162				printf("%s ",
163				    (argc == 0) ? "root" : laa.l_devname);
164			}
165			printf("%s\n", laa.l_childname[i]);
166		}
167		break;
168	case 'r':
169		memset(&raa, 0, sizeof(raa));
170		strlcpy(raa.busname, argv[0], sizeof(raa.busname));
171		if (attr)
172			strlcpy(raa.ifattr, attr, sizeof(raa.ifattr));
173		if (argc > 1) {
174			locs = malloc((argc - 1) * sizeof(int));
175			if (!locs)
176				err(5, "malloc int[%d]", argc - 1);
177			for (i = 0; i < argc - 1; i++)
178				locs[i] = atoi(argv[i + 1]);
179			raa.numlocators = argc - 1;
180			raa.locators = locs;
181		}
182
183		if (ioctl(fd, DRVRESCANBUS, &raa) == -1)
184			err(3, "DRVRESCANBUS");
185		break;
186	case 'p':
187
188		command_dict = prop_dictionary_create();
189		args_dict = prop_dictionary_create();
190
191		string = prop_string_create_cstring_nocopy("get-properties");
192		prop_dictionary_set(command_dict, "drvctl-command", string);
193		prop_object_release(string);
194
195		string = prop_string_create_cstring(argv[0]);
196		prop_dictionary_set(args_dict, "device-name", string);
197		prop_object_release(string);
198
199		prop_dictionary_set(command_dict, "drvctl-arguments",
200				    args_dict);
201		prop_object_release(args_dict);
202
203		res = prop_dictionary_sendrecv_ioctl(command_dict, fd,
204						     DRVCTLCOMMAND,
205						     &results_dict);
206		prop_object_release(command_dict);
207		if (res)
208			errx(3, "DRVCTLCOMMAND: %s", strerror(res));
209
210		number = prop_dictionary_get(results_dict, "drvctl-error");
211		if (prop_number_integer_value(number) != 0) {
212			errx(3, "get-properties: %s",
213			    strerror((int)prop_number_integer_value(number)));
214		}
215
216		data_dict = prop_dictionary_get(results_dict,
217						"drvctl-result-data");
218		if (data_dict == NULL) {
219			errx(3, "get-properties: failed to return result data");
220		}
221
222		xml = prop_dictionary_externalize(data_dict);
223		prop_object_release(results_dict);
224
225		printf("Properties for device `%s':\n%s",
226		       argv[0], xml);
227		free(xml);
228		break;
229	default:
230		errx(4, "unknown command");
231	}
232
233	return (0);
234}
235