diff --git a/sbin/drvctl/Makefile b/sbin/drvctl/Makefile index df0edcffa49c..58a791ebd71b 100644 --- a/sbin/drvctl/Makefile +++ b/sbin/drvctl/Makefile @@ -1,6 +1,9 @@ -# $NetBSD: Makefile,v 1.3 2005/06/27 01:00:05 christos Exp $ +# $NetBSD: Makefile,v 1.4 2006/09/22 04:37:36 thorpej Exp $ PROG= drvctl MAN= drvctl.8 +LDADD+= -lprop +DPADD+= ${LIBPROP} + .include diff --git a/sbin/drvctl/drvctl.8 b/sbin/drvctl/drvctl.8 index eacbb47a9228..bc6293d46209 100644 --- a/sbin/drvctl/drvctl.8 +++ b/sbin/drvctl/drvctl.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: drvctl.8,v 1.2 2004/08/18 13:21:36 wiz Exp $ +.\" $NetBSD: drvctl.8,v 1.3 2006/09/22 04:37:36 thorpej Exp $ .\" .\" Copyright (c) 2004 .\" Matthias Drochner. All rights reserved. @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 17, 2004 +.Dd September 21, 2006 .Dt DRVCTL 8 .Os .Sh NAME @@ -39,6 +39,9 @@ .Nm .Fl d .Ar device +.Nm +.Fl p +.Ar device .Sh DESCRIPTION The .Nm @@ -66,10 +69,16 @@ has multiple attributes. Detach the device driver from the device given by the .Ar device argument. +.It Fl p +Get the properties for the device specified by the +.Ar device +argument. +The properties are displayed as an XML property list. .El .Sh FILES .Pa /dev/drvctl .Sh SEE ALSO +.Xr proplib 3 , .Xr drvctl 4 , .Xr autoconf 9 .Sh BUGS diff --git a/sbin/drvctl/drvctl.c b/sbin/drvctl/drvctl.c index ddcd63bee3b6..2b9992fe3542 100644 --- a/sbin/drvctl/drvctl.c +++ b/sbin/drvctl/drvctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: drvctl.c,v 1.4 2005/06/02 00:00:46 lukem Exp $ */ +/* $NetBSD: drvctl.c,v 1.5 2006/09/22 04:37:36 thorpej Exp $ */ /* * Copyright (c) 2004 @@ -35,7 +35,11 @@ #include #include -#define OPTS "dra:" +#define OPTS "dra:p" + +#define OPEN_MODE(mode) \ + (((mode) == 'd' || (mode) == 'r') ? O_RDWR \ + : O_RDONLY) static void usage(void); @@ -44,7 +48,9 @@ usage(void) { fprintf(stderr, "Usage: %s -r [-a attribute] busdevice [locator ...]\n" - " %s -d device\n", getprogname(), getprogname()); + " %s -d device\n" + " %s -p device\n", + getprogname(), getprogname(), getprogname()); exit(1); } @@ -65,6 +71,7 @@ main(int argc, char **argv) switch (c) { case 'd': case 'r': + case 'p': mode = c; break; case 'a': @@ -82,7 +89,7 @@ main(int argc, char **argv) if (argc < 1 || mode == 0) usage(); - fd = open(DRVCTLDEV, O_RDWR, 0); + fd = open(DRVCTLDEV, OPEN_MODE(mode), 0); if (fd < 0) err(2, "open %s", DRVCTLDEV); @@ -110,6 +117,53 @@ main(int argc, char **argv) res = ioctl(fd, DRVRESCANBUS, &raa); if (res) err(3, "DRVRESCANBUS"); + } else if (mode == 'p') { + prop_dictionary_t command_dict, args_dict, results_dict, + data_dict; + prop_string_t string; + prop_number_t number; + char *xml; + + command_dict = prop_dictionary_create(); + args_dict = prop_dictionary_create(); + + string = prop_string_create_cstring_nocopy("get-properties"); + prop_dictionary_set(command_dict, "drvctl-command", string); + prop_object_release(string); + + string = prop_string_create_cstring(argv[0]); + prop_dictionary_set(args_dict, "device-name", string); + prop_object_release(string); + + prop_dictionary_set(command_dict, "drvctl-arguments", + args_dict); + prop_object_release(args_dict); + + res = prop_dictionary_sendrecv_ioctl(command_dict, fd, + DRVCTLCOMMAND, + &results_dict); + prop_object_release(command_dict); + if (res) + errx(3, "DRVCTLCOMMAND: %s", strerror(res)); + + number = prop_dictionary_get(results_dict, "drvctl-error"); + if (prop_number_integer_value(number) != 0) { + errx(3, "get-properties: %s", + strerror((int)prop_number_integer_value(number))); + } + + data_dict = prop_dictionary_get(results_dict, + "drvctl-result-data"); + if (data_dict == NULL) { + errx(3, "get-properties: failed to return result data"); + } + + xml = prop_dictionary_externalize(data_dict); + prop_object_release(results_dict); + + printf("Properties for device `%s':\n%s", + argv[0], xml); + free(xml); } else errx(4, "unknown command"); diff --git a/sys/kern/kern_drvctl.c b/sys/kern/kern_drvctl.c index 898f61411b0f..59ca631f0e6b 100644 --- a/sys/kern/kern_drvctl.c +++ b/sys/kern/kern_drvctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_drvctl.c,v 1.4 2005/12/15 22:01:17 cube Exp $ */ +/* $NetBSD: kern_drvctl.c,v 1.5 2006/09/22 04:37:37 thorpej Exp $ */ /* * Copyright (c) 2004 @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.4 2005/12/15 22:01:17 cube Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.5 2006/09/22 04:37:37 thorpej Exp $"); #include #include @@ -37,6 +37,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.4 2005/12/15 22:01:17 cube Exp $") #include #include #include +#include #include dev_type_ioctl(drvctlioctl); @@ -50,6 +51,8 @@ void drvctlattach(int); #define MAXLOCATORS 100 +static int drvctl_command(struct lwp *, struct plistref *, u_long, int flag); + static int detachdevbyname(const char *devname) { @@ -162,9 +165,12 @@ drvctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *p) if (locs) free(locs, M_DEVBUF); #undef d - break; - default: - return (EPASSTHROUGH); + break; + case DRVCTLCOMMAND: + res = drvctl_command(p, (struct plistref *)data, cmd, flag); + break; + default: + return (EPASSTHROUGH); } return (res); } @@ -173,3 +179,111 @@ void drvctlattach(int arg) { } + +/***************************************************************************** + * Driver control command processing engine + *****************************************************************************/ + +static int +drvctl_command_get_properties(struct lwp *l, + prop_dictionary_t command_dict, + prop_dictionary_t results_dict) +{ + prop_dictionary_t args_dict; + prop_string_t devname_string; + device_t dev; + + args_dict = prop_dictionary_get(command_dict, "drvctl-arguments"); + if (args_dict == NULL) + return (EINVAL); + + devname_string = prop_dictionary_get(args_dict, "device-name"); + if (devname_string == NULL) + return (EINVAL); + + TAILQ_FOREACH(dev, &alldevs, dv_list) { + if (prop_string_equals_cstring(devname_string, + device_xname(dev))) + break; + } + + if (dev == NULL) + return (ESRCH); + + prop_dictionary_set(results_dict, "drvctl-result-data", + device_properties(dev)); + + return (0); +} + +struct drvctl_command_desc { + const char *dcd_name; /* command name */ + int (*dcd_func)(struct lwp *, /* handler function */ + prop_dictionary_t, + prop_dictionary_t); + int dcd_rw; /* read or write required */ +}; + +static const struct drvctl_command_desc drvctl_command_table[] = { + { .dcd_name = "get-properties", + .dcd_func = drvctl_command_get_properties, + .dcd_rw = FREAD, + }, + + { .dcd_name = NULL } +}; + +static int +drvctl_command(struct lwp *l, struct plistref *pref, u_long ioctl_cmd, + int fflag) +{ + prop_dictionary_t command_dict, results_dict; + prop_string_t command_string; + prop_number_t error_number; + const struct drvctl_command_desc *dcd; + int error; + + error = prop_dictionary_copyin_ioctl(pref, ioctl_cmd, &command_dict); + if (error) + return (error); + + results_dict = prop_dictionary_create(); + if (results_dict == NULL) { + prop_object_release(command_dict); + return (ENOMEM); + } + + command_string = prop_dictionary_get(command_dict, "drvctl-command"); + if (command_string == NULL) { + error = EINVAL; + goto out; + } + + for (dcd = drvctl_command_table; dcd->dcd_name != NULL; dcd++) { + if (prop_string_equals_cstring(command_string, + dcd->dcd_name)) + break; + } + + if (dcd->dcd_name == NULL) { + error = EINVAL; + goto out; + } + + if ((fflag & dcd->dcd_rw) == 0) { + error = EPERM; + goto out; + } + + error = (*dcd->dcd_func)(l, command_dict, results_dict); + + error_number = prop_number_create_integer(error); + prop_dictionary_set(results_dict, "drvctl-error", error_number); + prop_object_release(error_number); + + error = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, results_dict); + out: + prop_object_release(command_dict); + prop_object_release(results_dict); + return (error); +} diff --git a/sys/sys/drvctlio.h b/sys/sys/drvctlio.h index 881aa921aae9..bec4d93decfa 100644 --- a/sys/sys/drvctlio.h +++ b/sys/sys/drvctlio.h @@ -1,10 +1,49 @@ -/* $NetBSD: drvctlio.h,v 1.2 2005/12/03 17:10:46 christos Exp $ */ +/* $NetBSD: drvctlio.h,v 1.3 2006/09/22 04:37:37 thorpej Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ /* This interface is experimental and may change. */ #ifndef _SYS_DRVCTLIO_H_ #define _SYS_DRVCTLIO_H_ +#include +#include + #define DRVCTLDEV "/dev/drvctl" struct devdetachargs { @@ -21,4 +60,58 @@ struct devrescanargs { #define DRVDETACHDEV _IOW('D', 123, struct devdetachargs) #define DRVRESCANBUS _IOW('D', 124, struct devrescanargs) +/* + * Generic ioctl that takes a dictionary as an argument (specifies the + * command and arguments) and returns a dictionary with the results. + * + * Command arguments are structured like so: + * + * + * drvctl-command + * ... + * + * drvctl-arguments + * + * + * + * + * + * Results are returned like so: + * + * + * drvctl-error + * + * ... + * + * drvctl-error-message + * ... + * + * drvctl-result-data + * + * + * + * + */ +#define DRVCTLCOMMAND _IOWR('D', 125, struct plistref) + +/***************************************************************************** + * Commands recognized by DRVCTLCOMMAND + *****************************************************************************/ + +/* + * get-properties + * + * Arguments: + * + * + * device-name + * ... + * + * + * Results: + * + * + * + */ + #endif /* _SYS_DRVCTLIO_H_ */