Module Name:    src
Committed By:   mbalmer
Date:           Sat Jul 25 16:18:09 UTC 2009

Modified Files:
        src/usr.sbin/gpioctl: Makefile gpioctl.8 gpioctl.c
Added Files:
        src/usr.sbin/gpioctl: strtonum.c

Log Message:
Reworked gpioctl(8) command to reflect recent gpio(4) changes.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/gpioctl/Makefile
cvs rdiff -u -r1.4 -r1.5 src/usr.sbin/gpioctl/gpioctl.8
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/gpioctl/gpioctl.c
cvs rdiff -u -r0 -r1.1 src/usr.sbin/gpioctl/strtonum.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/gpioctl/Makefile
diff -u src/usr.sbin/gpioctl/Makefile:1.3 src/usr.sbin/gpioctl/Makefile:1.4
--- src/usr.sbin/gpioctl/Makefile:1.3	Wed Apr 22 15:23:03 2009
+++ src/usr.sbin/gpioctl/Makefile	Sat Jul 25 16:18:09 2009
@@ -1,7 +1,7 @@
-# $NetBSD: Makefile,v 1.3 2009/04/22 15:23:03 lukem Exp $
+# $NetBSD: Makefile,v 1.4 2009/07/25 16:18:09 mbalmer Exp $
 
 PROG=	gpioctl
-SRCS=	gpioctl.c
+SRCS=	gpioctl.c strtonum.c
 
 MAN=	gpioctl.8
 

Index: src/usr.sbin/gpioctl/gpioctl.8
diff -u src/usr.sbin/gpioctl/gpioctl.8:1.4 src/usr.sbin/gpioctl/gpioctl.8:1.5
--- src/usr.sbin/gpioctl/gpioctl.8:1.4	Wed Jan  9 15:56:27 2008
+++ src/usr.sbin/gpioctl/gpioctl.8	Sat Jul 25 16:18:09 2009
@@ -1,6 +1,6 @@
-.\" $NetBSD: gpioctl.8,v 1.4 2008/01/09 15:56:27 xtraeme Exp $
-.\"	$OpenBSD: gpioctl.8,v 1.5 2004/12/02 05:11:40 grange Exp $
+.\" $NetBSD: gpioctl.8,v 1.5 2009/07/25 16:18:09 mbalmer Exp $
 .\"
+.\" Copyright (c) 2009 Marc Balmer <[email protected]>
 .\" Copyright (c) 2004 Alexander Yurchenko <[email protected]>
 .\"
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -15,66 +15,71 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd January 9, 2008
+.Dd July 15, 2009
 .Dt GPIOCTL 8
 .Os
 .Sh NAME
 .Nm gpioctl
 .Nd control GPIO devices
 .Sh SYNOPSIS
-.Nm
-.Op Fl hq
-.Op Fl d Ar device
-.Op Ar pin
+.Nm gpioctl
+.Op Fl q
+.Ar device
+attach
+.Ar device
+.Ar offset
+.Ar mask
+.Nm gpioctl
+.Op Fl q
+.Ar device
+detach
+.Ar device
+.Nm gpioctl
+.Op Fl q
+.Ar device
+.Ar pin
 .Op Ar 0 | 1 | 2
-.Nm
-.Op Fl hq
-.Op Fl d Ar device
-.Fl c
+.Nm gpioctl
+.Op Fl q
+.Ar device
 .Ar pin
+.Op Ar on | off | toggle
+.Nm gpioctl
+.Op Fl q
+.Ar device
+.Ar pin
+set
 .Op Ar flags
+.Op Ar name
+.Nm gpioctl
+.Op Fl q
+.Ar device
+.Ar pin
+unset
 .Sh DESCRIPTION
 The
 .Nm
-program allows manipulation of
-.Tn GPIO
+program allows manipulation of GPIO
 (General Purpose Input/Output) device pins.
-Such devices can be either part of the chipset or embedded
-.Tn CPU ,
+Such devices can be either part of the chipset or embedded CPU,
 or a separate chip.
-The usual way of using
-.Tn GPIO
-is to connect some simple devices such as LEDs, 1-wire thermal sensors,
-etc., to its pins.
+The usual way of using GPIO
+is to connect some simple devices such as LEDs and 1-wire thermal sensors
+to its pins.
 .Pp
-Each
-.Tn GPIO
-device has an associated device file in the
+Each GPIO device has an associated device file in the
 .Pa /dev
 directory.
-By default
-.Nm
-uses
-.Pa /dev/gpio0 ,
-which corresponds to the first found
-.Tn GPIO
-device in the system.
-If more than one
-.Tn GPIO
-device is present, an alternative device file can be specified with the
-.Fl d
-option in order to access a particular
-.Tn GPIO
-device.
-.Pp
-When executed without any arguments,
-.Nm
-reads information about the
-.Tn GPIO
-device and displays it.
+.Ar device
+can be specified with or without the
+.Pa /dev
+prefix.
+For example,
+.Pa /dev/gpio0
+or
+.Pa gpio0 .
 .Pp
-.Tn GPIO
-pins can be either
+GPIO pins can be either
 .Dq read
 or
 .Dq written
@@ -82,9 +87,7 @@
 If only a
 .Ar pin
 number is specified on the command line, the pin state will be read
-from the
-.Tn GPIO
-controller and displayed.
+from the GPIO controller and displayed.
 To write to a pin, a value must be specified after the
 .Ar pin
 number.
@@ -92,15 +95,28 @@
 A value of 2 has a special meaning: it
 .Dq toggles
 the pin, i.e. changes its state to the opposite.
+Instead of the numerical values, the word
+.Ar on ,
+.Ar off ,
+or
+.Ar toggle
+can be used.
 .Pp
-Each pin can be configured with different flags with the
-.Fl c
-option.
-The following configuration flags are supported by the
-.Tn GPIO
-framework:
+Only pins that have been configured at securelevel 0, typically during system
+startup, are accessible once the securelevel has been raised.
+Pins can be given symbolic names for easier use.
+Besides using individual pins, device drivers that use GPIO pins can be
+attached to a
+.Xr gpio 4
+device using the
+.Nm
+command.
+.Pp
+The following configuration
+.Ar flags
+are supported by the GPIO framework:
 .Pp
-.Bl -tag -width XXXXXXX -offset indent -compact
+.Bl -tag -width Ds -offset indent -compact
 .It in
 input direction
 .It out
@@ -123,31 +139,23 @@
 invert output
 .El
 .Pp
-Note that not all the flags can be supported by the particular
-.Tn GPIO
-controller.
-The list of supported flags is always displayed when executing
-.Nm
-with the
-.Fl c
-option.
-If only a
-.Ar pin
-number is specified on the command line, the current pin flags will be
-displayed.
-To change pin flags, a new flags set separated by spaces must be
-specified after the
-.Ar pin
-number.
+Note that not all the flags may be supported by the particular GPIO controller.
 .Pp
-The
-.Fl q
-option causes
+When executed with only the
+.Xr gpio 4
+device name as argument,
 .Nm
-to operate quietly i.e. nothing is printed to stdout.
-The
-.Fl h
-option displays a usage summary.
+reads information about the
+.Tn GPIO
+device and displays it.
+At securelevel 0 the number of physically available pins is displayed,
+at higher securelevels the number of configured (set) pins is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl q
+Operate quietly i.e. nothing is printed to stdout.
+.El
 .Sh FILES
 .Bl -tag -width "/dev/gpiou" -compact
 .It /dev/gpio Ns Ar u
@@ -158,17 +166,33 @@
 .Sh EXAMPLES
 Configure pin 20 to have push-pull output:
 .Pp
-.Dl # gpioctl -c 20 out pp
+.Dl # gpioctl gpio0 20 set out pp
 .Pp
 Write logical 1 to pin 20:
 .Pp
-.Dl # gpioctl 20 1
+.Dl # gpioctl gpio0 20 1
+.Pp
+Attach a
+.Xr onewire 4
+bus on a
+.Xr gpioow 4
+device on pin 4:
+.Pp
+.Dl # gpioctl gpio0 attach gpioow 4 0x01
+.Pp
+Detach the gpioow0 device:
+.Pp
+.Dl # gpioctl gpio0 detach gpioow0
+.Pp
+Configure pin 5 as output and name it error_led:
+.Pp
+.Dl # gpioctl gpio0 5 set out error_led
+.Pp
+Toggle the error_led:
+.Pp
+.Dl # gpioctl gpio0 error_led 2
 .Sh SEE ALSO
-.Xr elansc 4 ,
-.Xr gcscpcib 4 ,
-.Xr gpio 4 ,
-.Xr gscpcib 4 ,
-.Xr nsclpcsio 4
+.Xr gpio 4
 .Sh HISTORY
 The
 .Nm
@@ -181,3 +205,5 @@
 .Nm
 program was written by
 .An Alexander Yurchenko Aq [email protected] .
+Device attachment was added by
+.An Marc Balmer Aq [email protected] .

Index: src/usr.sbin/gpioctl/gpioctl.c
diff -u src/usr.sbin/gpioctl/gpioctl.c:1.5 src/usr.sbin/gpioctl/gpioctl.c:1.6
--- src/usr.sbin/gpioctl/gpioctl.c:1.5	Wed Jan  9 16:08:33 2008
+++ src/usr.sbin/gpioctl/gpioctl.c	Sat Jul 25 16:18:09 2009
@@ -1,6 +1,7 @@
-/* $NetBSD: gpioctl.c,v 1.5 2008/01/09 16:08:33 xtraeme Exp $ */
-/*	$OpenBSD: gpioctl.c,v 1.2 2004/08/08 00:05:09 deraadt Exp $	*/
+/* $NetBSD: gpioctl.c,v 1.6 2009/07/25 16:18:09 mbalmer Exp $ */
+
 /*
+ * Copyright (c) 2008 Marc Balmer <[email protected]>
  * Copyright (c) 2004 Alexander Yurchenko <[email protected]>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -25,25 +26,34 @@
 #include <sys/ioctl.h>
 
 #include <err.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#define _PATH_DEV_GPIO	"/dev/gpio0"
 
-static const char *device = _PATH_DEV_GPIO;
-static int devfd = -1;
-static int quiet = 0;
-
-static void	getinfo(void);
-static void	pinread(int);
-static void	pinwrite(int, int);
-static void	pinctl(int, char *[], int);
-static void 	usage(void);
+char *dev;
+int devfd = -1;
+int quiet = 0;
+
+void	getinfo(void);
+void	gpioread(int, char *);
+void	gpiowrite(int, char *, int);
+void	gpioset(int pin, char *name, int flags, char *alias);
+void	gpiounset(int pin, char *name);
+void	devattach(char *, int, u_int32_t);
+void	devdetach(char *);
+
+__dead void usage(void);
+
+extern long long strtonum(const char *numstr, long long minval,
+    long long maxval, const char **errstrp);
 
-static const struct bitstr {
+const struct bitstr {
 	unsigned int mask;
 	const char *string;
 } pinflags[] = {
@@ -56,33 +66,28 @@
 	{ GPIO_PIN_PULLUP, "pu" },
 	{ GPIO_PIN_PULLDOWN, "pd" },
 	{ GPIO_PIN_INVIN, "iin" },
-	{ GPIO_PIN_INVOUT, "iiout" },
+	{ GPIO_PIN_INVOUT, "iout" },
 	{ 0, NULL },
 };
 
 int
 main(int argc, char *argv[])
 {
-	int ch;
+	const struct bitstr *bs;
+	int pin, ch, n, fl = 0, value = 0;
+	const char *errstr;
 	char *ep;
-	int do_ctl = 0;
-	int pin = 0, value = 0;
-
-	setprogname(argv[0]);
+	int ga_offset = -1;
+	u_int32_t ga_mask = 0;
+	long lval;
+	char *nam = NULL;
+	char devn[32];
 
-	while ((ch = getopt(argc, argv, "cd:hq")) != -1)
+	while ((ch = getopt(argc, argv, "q")) != -1)
 		switch (ch) {
-		case 'c':
-			do_ctl = 1;
-			break;
-		case 'd':
-			device = optarg;
-			break;
 		case 'q':
 			quiet = 1;
 			break;
-		case 'h':
-		case '?':
 		default:
 			usage();
 			/* NOTREACHED */
@@ -90,129 +95,199 @@
 	argc -= optind;
 	argv += optind;
 
-	if (argc > 0) {
-		pin = strtol(argv[0], &ep, 10);
-		if (*argv[0] == '\0' || *ep != '\0' || pin < 0)
-			errx(EXIT_FAILURE, "%s: invalid pin", argv[0]);
+	if (argc < 1)
+		usage();
+	dev = argv[0];
+
+	if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
+		(void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
+		dev = devn;
 	}
 
-	if ((devfd = open(device, O_RDWR)) == -1)
-		err(EXIT_FAILURE, "%s", device);
+	if ((devfd = open(dev, O_RDWR)) == -1)
+		err(EXIT_FAILURE, "%s", dev);
 
-	if (argc == 0 && !do_ctl) {
+	if (argc == 1) {
 		getinfo();
-	} else if (argc == 1) {
-		if (do_ctl)
-			pinctl(pin, NULL, 0);
-		else
-			pinread(pin);
-	} else if (argc > 1) {
-		if (do_ctl) {
-			pinctl(pin, argv + 1, argc - 1);
-		} else {
-			value = strtol(argv[1], &ep, 10);
-			if (*argv[1] == '\0' || *ep != '\0')
-				errx(EXIT_FAILURE, "%s: invalid value",
-				    argv[1]);
-			pinwrite(pin, value);
-		}
+		return EXIT_SUCCESS;
+	}
+
+	if (!strcmp(argv[1], "attach")) {
+		char *driver, *offset, *mask;
+
+		if (argc != 5)
+			usage();
+
+		driver = argv[2];
+		offset = argv[3];
+		mask = argv[4];
+
+		ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
+		if (errstr)
+			errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
+		lval = strtol(mask, &ep, 0);
+		if (*mask == '\0' || *ep != '\0')
+			errx(EXIT_FAILURE, "invalid mask (not a number)");
+		if ((errno == ERANGE && (lval == LONG_MAX
+		    || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
+			errx(EXIT_FAILURE, "mask out of range");
+		ga_mask = lval;
+		devattach(driver, ga_offset, ga_mask);
+		return EXIT_SUCCESS;
+	} else if (!strcmp(argv[1], "detach")) {
+		if (argc != 3)
+			usage();
+		devdetach(argv[2]);
 	} else {
-		usage();
-		/* NOTREACHED */
+		char *nm = NULL;
+	
+		/* expecting a pin number or name */
+		pin = strtonum(argv[1], 0, INT_MAX, &errstr);
+		if (errstr)
+			nm = argv[1];	/* try named pin */
+		if (argc > 2) { 
+			if (!strcmp(argv[2], "set")) {
+				for (n = 3; n < argc; n++) {
+					for (bs = pinflags; bs->string != NULL;
+					     bs++) {
+						if (!strcmp(argv[n],
+						    bs->string)) {
+							fl |= bs->mask;
+							break;
+						}
+					}
+					if (bs->string == NULL)
+						nam = argv[n];
+				}
+				gpioset(pin, nm, fl, nam);
+			} else if (!strcmp(argv[2], "unset")) {
+				gpiounset(pin, nm);
+			} else {
+				value = strtonum(argv[2], INT_MIN, INT_MAX,
+				   &errstr);
+				if (errstr) {
+					if (!strcmp(argv[2], "on"))
+						value = 1;
+					else if (!strcmp(argv[2], "off"))
+						value = 0;
+					else if (!strcmp(argv[2], "toggle"))
+						value = 2;
+					else
+						errx(EXIT_FAILURE,
+						    "%s: invalid value",
+						    argv[2]);
+				}
+				gpiowrite(pin, nm, value);
+			}
+		} else
+			gpioread(pin, nm);
 	}
 
 	return EXIT_SUCCESS;
 }
 
-static void
+void
 getinfo(void)
 {
 	struct gpio_info info;
 
-	memset(&info, 0, sizeof(info));
 	if (ioctl(devfd, GPIOINFO, &info) == -1)
 		err(EXIT_FAILURE, "GPIOINFO");
 
 	if (quiet)
 		return;
 
-	printf("%s: %d pins\n", device, info.gpio_npins);
+	printf("%s: %d pins\n", dev, info.gpio_npins);
 }
 
-static void
-pinread(int pin)
+void
+gpioread(int pin, char *gp_name)
 {
-	struct gpio_pin_op op;
+	struct gpio_req req;
 
-	memset(&op, 0, sizeof(op));
-	op.gp_pin = pin;
-	if (ioctl(devfd, GPIOPINREAD, &op) == -1)
-		err(EXIT_FAILURE, "GPIOPINREAD");
+	memset(&req, 0, sizeof(req));
+	if (gp_name != NULL)
+		strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
+	else
+		req.gp_pin = pin;
+
+	if (ioctl(devfd, GPIOREAD, &req) == -1)
+		err(EXIT_FAILURE, "GPIOREAD");
 
 	if (quiet)
 		return;
 
-	printf("pin %d: state %d\n", pin, op.gp_value);
+	if (gp_name)
+		printf("pin %s: state %d\n", gp_name, req.gp_value);
+	else
+		printf("pin %d: state %d\n", pin, req.gp_value);
 }
 
-static void
-pinwrite(int pin, int value)
+void
+gpiowrite(int pin, char *gp_name, int value)
 {
-	struct gpio_pin_op op;
+	struct gpio_req req;
 
 	if (value < 0 || value > 2)
 		errx(EXIT_FAILURE, "%d: invalid value", value);
 
-	memset(&op, 0, sizeof(op));
-	op.gp_pin = pin;
-	op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
+	memset(&req, 0, sizeof(req));
+	if (gp_name != NULL)
+		strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
+	else
+		req.gp_pin = pin;
+	req.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
 	if (value < 2) {
-		if (ioctl(devfd, GPIOPINWRITE, &op) == -1)
-			err(EXIT_FAILURE, "GPIOPINWRITE");
+		if (ioctl(devfd, GPIOWRITE, &req) == -1)
+			err(EXIT_FAILURE, "GPIOWRITE");
 	} else {
-		if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1)
-			err(EXIT_FAILURE, "GPIOPINTOGGLE");
+		if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
+			err(EXIT_FAILURE, "GPIOTOGGLE");
 	}
 
 	if (quiet)
 		return;
 
-	printf("pin %d: state %d -> %d\n", pin, op.gp_value,
-	    (value < 2 ? value : 1 - op.gp_value));
+	if (gp_name)
+		printf("pin %s: state %d -> %d\n", gp_name, req.gp_value,
+		    (value < 2 ? value : 1 - req.gp_value));
+	else
+		printf("pin %d: state %d -> %d\n", pin, req.gp_value,
+		    (value < 2 ? value : 1 - req.gp_value));
 }
 
-static void
-pinctl(int pin, char *flags[], int nflags)
+void
+gpioset(int pin, char *name, int fl, char *alias)
 {
-	struct gpio_pin_ctl ctl;
-	int fl = 0;
+	struct gpio_set set;
 	const struct bitstr *bs;
-	int i;
 
-	memset(&ctl, 0, sizeof(ctl));
-	ctl.gp_pin = pin;
-	if (flags != NULL) {
-		for (i = 0; i < nflags; i++)
-			for (bs = pinflags; bs->string != NULL; bs++)
-				if (strcmp(flags[i], bs->string) == 0) {
-					fl |= bs->mask;
-					break;
-				}
-	}
-	ctl.gp_flags = fl;
-	if (ioctl(devfd, GPIOPINCTL, &ctl) == -1)
-		err(EXIT_FAILURE, "GPIOPINCTL");
+	memset(&set, 0, sizeof(set));
+	if (name != NULL)
+		strlcpy(set.gp_name, name, sizeof(set.gp_name));
+	else
+		set.gp_pin = pin;
+	set.gp_flags = fl;
+
+	if (alias != NULL)
+		strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
+
+	if (ioctl(devfd, GPIOSET, &set) == -1)
+		err(EXIT_FAILURE, "GPIOSET");
 
 	if (quiet)
 		return;
 
-	printf("pin %d: caps:", pin);
+	if (name != NULL)
+		printf("pin %s: caps:", name);
+	else
+		printf("pin %d: caps:", pin);
 	for (bs = pinflags; bs->string != NULL; bs++)
-		if (ctl.gp_caps & bs->mask)
+		if (set.gp_caps & bs->mask)
 			printf(" %s", bs->string);
 	printf(", flags:");
 	for (bs = pinflags; bs->string != NULL; bs++)
-		if (ctl.gp_flags & bs->mask)
+		if (set.gp_flags & bs->mask)
 			printf(" %s", bs->string);
 	if (fl > 0) {
 		printf(" ->");
@@ -223,13 +298,58 @@
 	printf("\n");
 }
 
-static void
+void
+gpiounset(int pin, char *name)
+{
+	struct gpio_set set;
+
+	memset(&set, 0, sizeof(set));
+	if (name != NULL)
+		strlcpy(set.gp_name, name, sizeof(set.gp_name));
+	else
+		set.gp_pin = pin;
+
+	if (ioctl(devfd, GPIOUNSET, &set) == -1)
+		err(EXIT_FAILURE, "GPIOUNSET");
+}
+
+void
+devattach(char *dvname, int offset, u_int32_t mask)
+{
+	struct gpio_attach attach;
+
+	memset(&attach, 0, sizeof(attach));
+	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
+	attach.ga_offset = offset;
+	attach.ga_mask = mask;
+	if (ioctl(devfd, GPIOATTACH, &attach) == -1)
+		err(EXIT_FAILURE, "GPIOATTACH");
+}
+
+void
+devdetach(char *dvname)
+{
+	struct gpio_attach attach;
+
+	memset(&attach, 0, sizeof(attach));
+	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
+	if (ioctl(devfd, GPIODETACH, &attach) == -1)
+		err(EXIT_FAILURE, "GPIODETACH");
+}
+
+void
 usage(void)
 {
-	fprintf(stderr, "usage: %s [-hq] [-d device] [pin] [0 | 1 | 2]\n",
-	    getprogname());
-	fprintf(stderr, "       %s [-hq] [-d device] -c pin [flags]\n",
-	    getprogname());
+	extern char *__progname;
+
+	fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | "
+	    "on | off | toggle]\n", __progname);
+	fprintf(stderr, "       %s [-q] device pin set [flags] [name]\n",
+	    __progname);
+	fprintf(stderr, "       %s [-q] device pin unset\n", __progname);
+	fprintf(stderr, "       %s [-q] device attach device offset mask\n",
+	    __progname);
+	fprintf(stderr, "       %s [-q] device detach device\n", __progname);
 
 	exit(EXIT_FAILURE);
 }

Added files:

Index: src/usr.sbin/gpioctl/strtonum.c
diff -u /dev/null src/usr.sbin/gpioctl/strtonum.c:1.1
--- /dev/null	Sat Jul 25 16:18:09 2009
+++ src/usr.sbin/gpioctl/strtonum.c	Sat Jul 25 16:18:09 2009
@@ -0,0 +1,69 @@
+/* $NetBSD: strtonum.c,v 1.1 2009/07/25 16:18:09 mbalmer Exp $ */
+/*	$OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $	*/
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 	1
+#define TOOSMALL 	2
+#define TOOLARGE 	3
+
+long long strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp);
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	char *ep;
+	int error = 0;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL,		0 },
+		{ "invalid",	EINVAL },
+		{ "too small",	ERANGE },
+		{ "too large",	ERANGE },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval)
+		error = INVALID;
+	else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = INVALID;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = TOOSMALL;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = TOOLARGE;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}

Reply via email to