sesutil.c revision 298382
1287473Sbapt/*-
2287473Sbapt * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3287988Sallanjude * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
4287988Sallanjude * Copyright (c) 2000 by Matthew Jacob
5287473Sbapt * All rights reserved.
6287473Sbapt *
7287473Sbapt * Redistribution and use in source and binary forms, with or without
8287473Sbapt * modification, are permitted provided that the following conditions
9287473Sbapt * are met:
10287473Sbapt * 1. Redistributions of source code must retain the above copyright
11287473Sbapt *    notice, this list of conditions and the following disclaimer
12287473Sbapt *    in this position and unchanged.
13287473Sbapt * 2. Redistributions in binary form must reproduce the above copyright
14287473Sbapt *    notice, this list of conditions and the following disclaimer in the
15287473Sbapt *    documentation and/or other materials provided with the distribution.
16287473Sbapt *
17287473Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18287473Sbapt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19287473Sbapt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20287473Sbapt * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21287473Sbapt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22287473Sbapt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23287473Sbapt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24287473Sbapt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25287473Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26287473Sbapt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27287473Sbapt */
28287473Sbapt
29287473Sbapt#include <sys/cdefs.h>
30287473Sbapt__FBSDID("$FreeBSD: head/usr.sbin/sesutil/sesutil.c 298382 2016-04-20 21:37:32Z bapt $");
31287473Sbapt
32287473Sbapt#include <sys/param.h>
33287473Sbapt#include <sys/ioctl.h>
34292121Sbapt#include <sys/types.h>
35292121Sbapt#include <sys/sbuf.h>
36287473Sbapt
37287473Sbapt#include <err.h>
38287473Sbapt#include <errno.h>
39287473Sbapt#include <fcntl.h>
40287988Sallanjude#include <getopt.h>
41287473Sbapt#include <glob.h>
42287473Sbapt#include <stdbool.h>
43287473Sbapt#include <stddef.h>
44287473Sbapt#include <stdint.h>
45287473Sbapt#include <stdio.h>
46287473Sbapt#include <stdlib.h>
47287473Sbapt#include <string.h>
48287473Sbapt#include <unistd.h>
49287473Sbapt
50287473Sbapt#include <cam/scsi/scsi_enc.h>
51287473Sbapt
52287988Sallanjude#include "eltsub.h"
53287988Sallanjude
54287988Sallanjudestatic int encstatus(int argc, char **argv);
55287988Sallanjudestatic int fault(int argc, char **argv);
56287473Sbaptstatic int locate(int argc, char **argv);
57287988Sallanjudestatic int objmap(int argc, char **argv);
58287988Sallanjudestatic int sesled(int argc, char **argv, bool fault);
59287473Sbapt
60287473Sbaptstatic struct command {
61287473Sbapt	const char *name;
62287988Sallanjude	const char *param;
63287473Sbapt	const char *desc;
64287473Sbapt	int (*exec)(int argc, char **argv);
65287473Sbapt} cmds[] = {
66287988Sallanjude	{ "fault",
67287988Sallanjude	    "(<disk>|<sesid>|all) (on|off)",
68287988Sallanjude	    "Change the state of the fault LED associated with a disk",
69287988Sallanjude	    fault },
70287988Sallanjude	{ "locate",
71287988Sallanjude	    "(<disk>|<sesid>|all) (on|off)",
72287988Sallanjude	    "Change the state of the locate LED associated with a disk",
73287988Sallanjude	    locate },
74287988Sallanjude	{ "map", "",
75287988Sallanjude	    "Print a map of the devices managed by the enclosure", objmap } ,
76287988Sallanjude	{ "status", "", "Print the status of the enclosure",
77287988Sallanjude	    encstatus },
78287473Sbapt};
79287473Sbapt
80287473Sbaptstatic const int nbcmds = nitems(cmds);
81287988Sallanjudestatic const char *uflag;
82287473Sbapt
83287473Sbaptstatic void
84287988Sallanjudeusage(FILE *out, const char *subcmd)
85287473Sbapt{
86287988Sallanjude	int i;
87287988Sallanjude
88287988Sallanjude	if (subcmd == NULL) {
89287988Sallanjude		fprintf(out, "Usage: %s [-u /dev/ses<N>] <command> [options]\n",
90287988Sallanjude		    getprogname());
91287988Sallanjude		fprintf(out, "Commands supported:\n");
92287988Sallanjude	}
93287988Sallanjude	for (i = 0; i < nbcmds; i++) {
94287988Sallanjude		if (subcmd != NULL) {
95287988Sallanjude			if (strcmp(subcmd, cmds[i].name) == 0) {
96287988Sallanjude				fprintf(out, "Usage: %s %s [-u /dev/ses<N>] "
97287988Sallanjude				    "%s\n\t%s\n", getprogname(), subcmd,
98287988Sallanjude				    cmds[i].param, cmds[i].desc);
99287988Sallanjude				break;
100287988Sallanjude			}
101287988Sallanjude			continue;
102287988Sallanjude		}
103287988Sallanjude		fprintf(out, "    %-12s%s\n\t\t%s\n\n", cmds[i].name,
104287988Sallanjude		    cmds[i].param, cmds[i].desc);
105287988Sallanjude	}
106287988Sallanjude
107287988Sallanjude	exit(EXIT_FAILURE);
108287988Sallanjude}
109287988Sallanjude
110287988Sallanjudestatic void
111287992Sallanjudedo_led(int fd, unsigned int idx, bool onoff, bool setfault)
112287988Sallanjude{
113287473Sbapt	encioc_elm_status_t o;
114287473Sbapt
115287473Sbapt	o.elm_idx = idx;
116287473Sbapt	if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) {
117287473Sbapt		close(fd);
118287473Sbapt		err(EXIT_FAILURE, "ENCIOC_GETELMSTAT");
119287473Sbapt	}
120287473Sbapt	o.cstat[0] |= 0x80;
121287988Sallanjude	if (onoff) {
122287992Sallanjude		o.cstat[2] |= (setfault ? 0x20 : 0x02);
123287988Sallanjude	} else {
124287992Sallanjude		o.cstat[2] &= (setfault ? 0xdf : 0xfd);
125287988Sallanjude	}
126287473Sbapt
127287473Sbapt	if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) {
128287473Sbapt		close(fd);
129287473Sbapt		err(EXIT_FAILURE, "ENCIOC_SETELMSTAT");
130287473Sbapt	}
131287473Sbapt}
132287473Sbapt
133287473Sbaptstatic bool
134287473Sbaptdisk_match(const char *devnames, const char *disk, size_t len)
135287473Sbapt{
136287494Sbapt	const char *dname;
137287473Sbapt
138287494Sbapt	dname = devnames;
139287494Sbapt	while ((dname = strstr(dname, disk)) != NULL) {
140287988Sallanjude		if (dname[len] == '\0' || dname[len] == ',') {
141287473Sbapt			return (true);
142287988Sallanjude		}
143287494Sbapt		dname++;
144287473Sbapt	}
145287988Sallanjude
146287473Sbapt	return (false);
147287473Sbapt}
148287473Sbapt
149287473Sbaptstatic int
150287992Sallanjudesesled(int argc, char **argv, bool setfault)
151287473Sbapt{
152287473Sbapt	encioc_elm_devnames_t objdn;
153287473Sbapt	encioc_element_t *objp;
154287473Sbapt	glob_t g;
155287988Sallanjude	char *disk, *endptr;
156287988Sallanjude	size_t len, i, ndisks;
157287988Sallanjude	int fd;
158287988Sallanjude	unsigned int nobj, j, sesid;
159287988Sallanjude	bool all, isses, onoff;
160287473Sbapt
161287988Sallanjude	isses = false;
162287988Sallanjude	all = false;
163287988Sallanjude	onoff = false;
164287988Sallanjude
165287988Sallanjude	if (argc != 3) {
166287992Sallanjude		usage(stderr, (setfault ? "fault" : "locate"));
167287473Sbapt	}
168287473Sbapt
169287988Sallanjude	disk = argv[1];
170287473Sbapt
171287988Sallanjude	sesid = strtoul(disk, &endptr, 10);
172287988Sallanjude	if (*endptr == '\0') {
173287988Sallanjude		endptr = strrchr(uflag, '*');
174292122Sbapt		if (endptr != NULL && *endptr == '*') {
175287988Sallanjude			warnx("Must specifying a SES device (-u) to use a SES "
176287988Sallanjude			    "id# to identify a disk");
177287992Sallanjude			usage(stderr, (setfault ? "fault" : "locate"));
178287988Sallanjude		}
179287988Sallanjude		isses = true;
180287988Sallanjude	}
181287988Sallanjude
182287988Sallanjude	if (strcmp(argv[2], "on") == 0) {
183287485Sbapt		onoff = true;
184287988Sallanjude	} else if (strcmp(argv[2], "off") == 0) {
185287485Sbapt		onoff = false;
186287473Sbapt	} else {
187287992Sallanjude		usage(stderr, (setfault ? "fault" : "locate"));
188287473Sbapt	}
189287473Sbapt
190287473Sbapt	if (strcmp(disk, "all") == 0) {
191287473Sbapt		all = true;
192287473Sbapt	}
193287473Sbapt	len = strlen(disk);
194287473Sbapt
195287473Sbapt	/* Get the list of ses devices */
196287988Sallanjude	if (glob((uflag != NULL ? uflag : "/dev/ses[0-9]*"), 0, NULL, &g) ==
197287988Sallanjude	    GLOB_NOMATCH) {
198287473Sbapt		globfree(&g);
199287473Sbapt		errx(EXIT_FAILURE, "No SES devices found");
200287473Sbapt	}
201287988Sallanjude
202287988Sallanjude	ndisks = 0;
203287473Sbapt	for (i = 0; i < g.gl_pathc; i++) {
204287473Sbapt		/* ensure we only got numbers after ses */
205287473Sbapt		if (strspn(g.gl_pathv[i] + 8, "0123456789") !=
206287988Sallanjude		    strlen(g.gl_pathv[i] + 8)) {
207287473Sbapt			continue;
208287988Sallanjude		}
209287473Sbapt		if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) {
210287988Sallanjude			/*
211287988Sallanjude			 * Don't treat non-access errors as critical if we are
212287988Sallanjude			 * accessing all devices
213287988Sallanjude			 */
214287988Sallanjude			if (errno == EACCES && g.gl_pathc > 1) {
215287988Sallanjude				err(EXIT_FAILURE, "unable to access SES device");
216287988Sallanjude			}
217287988Sallanjude			warn("unable to access SES device: %s", g.gl_pathv[i]);
218287988Sallanjude			continue;
219287473Sbapt		}
220287473Sbapt
221287988Sallanjude		if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) {
222287988Sallanjude			close(fd);
223287473Sbapt			err(EXIT_FAILURE, "ENCIOC_GETNELM");
224287988Sallanjude		}
225287473Sbapt
226287473Sbapt		objp = calloc(nobj, sizeof(encioc_element_t));
227287988Sallanjude		if (objp == NULL) {
228287988Sallanjude			close(fd);
229287473Sbapt			err(EXIT_FAILURE, "calloc()");
230287988Sallanjude		}
231287473Sbapt
232287988Sallanjude		if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) {
233287988Sallanjude			close(fd);
234287473Sbapt			err(EXIT_FAILURE, "ENCIOC_GETELMMAP");
235287988Sallanjude		}
236287473Sbapt
237287988Sallanjude		if (isses) {
238287988Sallanjude			if (sesid > nobj) {
239287988Sallanjude				close(fd);
240287988Sallanjude				errx(EXIT_FAILURE,
241287988Sallanjude				     "Requested SES ID does not exist");
242287988Sallanjude			}
243287992Sallanjude			do_led(fd, sesid, onoff, setfault);
244287988Sallanjude			ndisks++;
245287988Sallanjude			close(fd);
246287988Sallanjude			break;
247287988Sallanjude		}
248287473Sbapt		for (j = 0; j < nobj; j++) {
249287473Sbapt			memset(&objdn, 0, sizeof(objdn));
250287473Sbapt			objdn.elm_idx = objp[j].elm_idx;
251287473Sbapt			objdn.elm_names_size = 128;
252287473Sbapt			objdn.elm_devnames = calloc(128, sizeof(char));
253287988Sallanjude			if (objdn.elm_devnames == NULL) {
254287988Sallanjude				close(fd);
255287473Sbapt				err(EXIT_FAILURE, "calloc()");
256287988Sallanjude			}
257287473Sbapt			if (ioctl(fd, ENCIOC_GETELMDEVNAMES,
258287988Sallanjude			    (caddr_t) &objdn) <0) {
259287473Sbapt				continue;
260287988Sallanjude			}
261287473Sbapt			if (objdn.elm_names_len > 0) {
262287473Sbapt				if (all) {
263287988Sallanjude					do_led(fd, objdn.elm_idx,
264287992Sallanjude					    onoff, setfault);
265287473Sbapt					continue;
266287473Sbapt				}
267287473Sbapt				if (disk_match(objdn.elm_devnames, disk, len)) {
268287988Sallanjude					do_led(fd, objdn.elm_idx,
269287992Sallanjude					    onoff, setfault);
270287988Sallanjude					ndisks++;
271287473Sbapt					break;
272287473Sbapt				}
273287473Sbapt			}
274287988Sallanjude		}
275298382Sbapt		free(objp);
276287473Sbapt		close(fd);
277287473Sbapt	}
278287473Sbapt	globfree(&g);
279287988Sallanjude	if (ndisks == 0 && all == false) {
280287988Sallanjude		errx(EXIT_FAILURE, "Count not find the SES id of device '%s'",
281287988Sallanjude		    disk);
282287988Sallanjude	}
283287473Sbapt
284287473Sbapt	return (EXIT_SUCCESS);
285287473Sbapt}
286287473Sbapt
287287988Sallanjudestatic int
288287988Sallanjudelocate(int argc, char **argv)
289287473Sbapt{
290287473Sbapt
291287988Sallanjude	return (sesled(argc, argv, false));
292287473Sbapt}
293287473Sbapt
294287988Sallanjudestatic int
295287988Sallanjudefault(int argc, char **argv)
296287988Sallanjude{
297287988Sallanjude
298287988Sallanjude	return (sesled(argc, argv, true));
299287988Sallanjude}
300287988Sallanjude
301287988Sallanjudestatic int
302287988Sallanjudeobjmap(int argc, char **argv __unused)
303287988Sallanjude{
304292121Sbapt	struct sbuf *extra;
305292262Sbapt	encioc_string_t stri;
306287988Sallanjude	encioc_elm_devnames_t e_devname;
307287988Sallanjude	encioc_elm_status_t e_status;
308287988Sallanjude	encioc_elm_desc_t e_desc;
309287988Sallanjude	encioc_element_t *e_ptr;
310287988Sallanjude	glob_t g;
311287988Sallanjude	int fd;
312287988Sallanjude	unsigned int j, nobj;
313287988Sallanjude	size_t i;
314292262Sbapt	char str[32];
315287988Sallanjude
316287988Sallanjude	if (argc != 1) {
317287988Sallanjude		usage(stderr, "map");
318287988Sallanjude	}
319287988Sallanjude
320287988Sallanjude	/* Get the list of ses devices */
321287988Sallanjude	if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) {
322287988Sallanjude		globfree(&g);
323287988Sallanjude		errx(EXIT_FAILURE, "No SES devices found");
324287988Sallanjude	}
325287988Sallanjude	for (i = 0; i < g.gl_pathc; i++) {
326287988Sallanjude		/* ensure we only got numbers after ses */
327287988Sallanjude		if (strspn(g.gl_pathv[i] + 8, "0123456789") !=
328287988Sallanjude		    strlen(g.gl_pathv[i] + 8)) {
329287988Sallanjude			continue;
330287988Sallanjude		}
331287988Sallanjude		if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) {
332287988Sallanjude			/*
333287988Sallanjude			 * Don't treat non-access errors as critical if we are
334287988Sallanjude			 * accessing all devices
335287988Sallanjude			 */
336287988Sallanjude			if (errno == EACCES && g.gl_pathc > 1) {
337287988Sallanjude				err(EXIT_FAILURE, "unable to access SES device");
338287988Sallanjude			}
339287988Sallanjude			warn("unable to access SES device: %s", g.gl_pathv[i]);
340287988Sallanjude			continue;
341287988Sallanjude		}
342287988Sallanjude
343287988Sallanjude		if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) {
344287988Sallanjude			close(fd);
345287988Sallanjude			err(EXIT_FAILURE, "ENCIOC_GETNELM");
346287988Sallanjude		}
347287988Sallanjude
348287988Sallanjude		e_ptr = calloc(nobj, sizeof(encioc_element_t));
349287988Sallanjude		if (e_ptr == NULL) {
350287988Sallanjude			close(fd);
351287988Sallanjude			err(EXIT_FAILURE, "calloc()");
352287988Sallanjude		}
353287988Sallanjude
354287988Sallanjude		if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) e_ptr) < 0) {
355287988Sallanjude			close(fd);
356287988Sallanjude			err(EXIT_FAILURE, "ENCIOC_GETELMMAP");
357287988Sallanjude		}
358287988Sallanjude
359287988Sallanjude		printf("%s:\n", g.gl_pathv[i] + 5);
360292262Sbapt		stri.bufsiz = sizeof(str);
361292262Sbapt		stri.buf = &str[0];
362292262Sbapt		if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0)
363292262Sbapt			printf("\tEnclosure Name: %s\n", stri.buf);
364292262Sbapt		stri.bufsiz = sizeof(str);
365292262Sbapt		stri.buf = &str[0];
366292262Sbapt		if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0)
367292262Sbapt			printf("\tEnclosure ID: %s\n", stri.buf);
368292262Sbapt
369287988Sallanjude		for (j = 0; j < nobj; j++) {
370287988Sallanjude			/* Get the status of the element */
371287988Sallanjude			memset(&e_status, 0, sizeof(e_status));
372287988Sallanjude			e_status.elm_idx = e_ptr[j].elm_idx;
373287988Sallanjude			if (ioctl(fd, ENCIOC_GETELMSTAT,
374287988Sallanjude			    (caddr_t) &e_status) < 0) {
375287988Sallanjude				close(fd);
376287988Sallanjude				err(EXIT_FAILURE, "ENCIOC_GETELMSTAT");
377287988Sallanjude			}
378287988Sallanjude			/* Get the description of the element */
379287988Sallanjude			memset(&e_desc, 0, sizeof(e_desc));
380287988Sallanjude			e_desc.elm_idx = e_ptr[j].elm_idx;
381287988Sallanjude			e_desc.elm_desc_len = UINT16_MAX;
382287988Sallanjude			e_desc.elm_desc_str = calloc(UINT16_MAX, sizeof(char));
383287988Sallanjude			if (e_desc.elm_desc_str == NULL) {
384287988Sallanjude				close(fd);
385287988Sallanjude				err(EXIT_FAILURE, "calloc()");
386287988Sallanjude			}
387287988Sallanjude			if (ioctl(fd, ENCIOC_GETELMDESC,
388287988Sallanjude			    (caddr_t) &e_desc) < 0) {
389287988Sallanjude				close(fd);
390287988Sallanjude				err(EXIT_FAILURE, "ENCIOC_GETELMDESC");
391287988Sallanjude			}
392287988Sallanjude			/* Get the device name(s) of the element */
393287988Sallanjude			memset(&e_devname, 0, sizeof(e_devname));
394287988Sallanjude			e_devname.elm_idx = e_ptr[j].elm_idx;
395287988Sallanjude			e_devname.elm_names_size = 128;
396287988Sallanjude			e_devname.elm_devnames = calloc(128, sizeof(char));
397287988Sallanjude			if (e_devname.elm_devnames == NULL) {
398287988Sallanjude				close(fd);
399287988Sallanjude				err(EXIT_FAILURE, "calloc()");
400287988Sallanjude			}
401287988Sallanjude			if (ioctl(fd, ENCIOC_GETELMDEVNAMES,
402287988Sallanjude			    (caddr_t) &e_devname) <0) {
403287988Sallanjude				/* We don't care if this fails */
404287988Sallanjude				e_devname.elm_devnames[0] = '\0';
405287988Sallanjude			}
406287988Sallanjude			printf("\tElement %u, Type: %s\n", e_ptr[j].elm_idx,
407287988Sallanjude			    geteltnm(e_ptr[j].elm_type));
408292121Sbapt			printf("\t\tStatus: %s (0x%02x 0x%02x 0x%02x 0x%02x)\n",
409292121Sbapt			    scode2ascii(e_status.cstat[0]), e_status.cstat[0],
410292121Sbapt			    e_status.cstat[1], e_status.cstat[2],
411292121Sbapt			    e_status.cstat[3]);
412287988Sallanjude			if (e_desc.elm_desc_len > 0) {
413287988Sallanjude				printf("\t\tDescription: %s\n",
414287988Sallanjude				    e_desc.elm_desc_str);
415287988Sallanjude			}
416287988Sallanjude			if (e_devname.elm_names_len > 0) {
417287988Sallanjude				printf("\t\tDevice Names: %s\n",
418287988Sallanjude				    e_devname.elm_devnames);
419287988Sallanjude			}
420292121Sbapt			extra = stat2sbuf(e_ptr[j].elm_type, e_status.cstat);
421292121Sbapt			if (sbuf_len(extra) > 0) {
422292121Sbapt				printf("\t\tExtra status:\n%s",
423292121Sbapt				   sbuf_data(extra));
424292121Sbapt			}
425292121Sbapt			sbuf_delete(extra);
426287988Sallanjude			free(e_devname.elm_devnames);
427287988Sallanjude		}
428298382Sbapt		free(e_ptr);
429287988Sallanjude		close(fd);
430287988Sallanjude	}
431287988Sallanjude	globfree(&g);
432287988Sallanjude
433287988Sallanjude	return (EXIT_SUCCESS);
434287988Sallanjude}
435287988Sallanjude
436287988Sallanjudestatic int
437287988Sallanjudeencstatus(int argc, char **argv __unused)
438287988Sallanjude{
439287988Sallanjude	glob_t g;
440287988Sallanjude	int fd, status;
441287988Sallanjude	size_t i, e;
442287988Sallanjude	u_char estat;
443287988Sallanjude
444287988Sallanjude	status = 0;
445287988Sallanjude	if (argc != 1) {
446287988Sallanjude		usage(stderr, "status");
447287988Sallanjude	}
448287988Sallanjude
449287988Sallanjude	/* Get the list of ses devices */
450287988Sallanjude	if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) {
451287988Sallanjude		globfree(&g);
452287988Sallanjude		errx(EXIT_FAILURE, "No SES devices found");
453287988Sallanjude	}
454287988Sallanjude	for (i = 0; i < g.gl_pathc; i++) {
455287988Sallanjude		/* ensure we only got numbers after ses */
456287988Sallanjude		if (strspn(g.gl_pathv[i] + 8, "0123456789") !=
457287988Sallanjude		    strlen(g.gl_pathv[i] + 8)) {
458287988Sallanjude			continue;
459287988Sallanjude		}
460287988Sallanjude		if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) {
461287988Sallanjude			/*
462287988Sallanjude			 * Don't treat non-access errors as critical if we are
463287988Sallanjude			 * accessing all devices
464287988Sallanjude			 */
465287988Sallanjude			if (errno == EACCES && g.gl_pathc > 1) {
466287988Sallanjude				err(EXIT_FAILURE, "unable to access SES device");
467287988Sallanjude			}
468287988Sallanjude			warn("unable to access SES device: %s", g.gl_pathv[i]);
469287988Sallanjude			continue;
470287988Sallanjude		}
471287988Sallanjude
472287988Sallanjude		if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) {
473287988Sallanjude			close(fd);
474287988Sallanjude			err(EXIT_FAILURE, "ENCIOC_GETENCSTAT");
475287988Sallanjude		}
476287988Sallanjude
477287988Sallanjude		printf("%s: ", g.gl_pathv[i] + 5);
478287988Sallanjude		e = 0;
479287988Sallanjude		if (estat == 0) {
480287988Sallanjude			if (status == 0) {
481287988Sallanjude				status = 1;
482287988Sallanjude			}
483287988Sallanjude			printf("OK");
484287988Sallanjude		} else {
485287988Sallanjude			if (estat & SES_ENCSTAT_INFO) {
486287988Sallanjude				printf("INFO");
487287988Sallanjude				e++;
488287988Sallanjude			}
489287988Sallanjude			if (estat & SES_ENCSTAT_NONCRITICAL) {
490287988Sallanjude				if (e)
491287988Sallanjude					printf(",");
492287988Sallanjude				printf("NONCRITICAL");
493287988Sallanjude				e++;
494287988Sallanjude			}
495287988Sallanjude			if (estat & SES_ENCSTAT_CRITICAL) {
496287988Sallanjude				if (e)
497287988Sallanjude					printf(",");
498287988Sallanjude				printf("CRITICAL");
499287988Sallanjude				e++;
500287988Sallanjude				status = -1;
501287988Sallanjude			}
502287988Sallanjude			if (estat & SES_ENCSTAT_UNRECOV) {
503287988Sallanjude				if (e)
504287988Sallanjude					printf(",");
505287988Sallanjude				printf("UNRECOV");
506287988Sallanjude				e++;
507287988Sallanjude				status = -1;
508287988Sallanjude			}
509287988Sallanjude		}
510287988Sallanjude		printf("\n");
511287988Sallanjude
512287988Sallanjude		close(fd);
513287988Sallanjude	}
514287988Sallanjude	globfree(&g);
515287988Sallanjude
516287988Sallanjude	if (status == 1) {
517287988Sallanjude		return (EXIT_SUCCESS);
518287988Sallanjude	} else {
519287988Sallanjude		return (EXIT_FAILURE);
520287988Sallanjude	}
521287988Sallanjude}
522287988Sallanjude
523287473Sbaptint
524287473Sbaptmain(int argc, char **argv)
525287473Sbapt{
526287988Sallanjude	int i, ch;
527287473Sbapt	struct command *cmd = NULL;
528287473Sbapt
529287988Sallanjude	uflag = "/dev/ses[0-9]*";
530287988Sallanjude	while ((ch = getopt_long(argc, argv, "u:", NULL, NULL)) != -1) {
531287988Sallanjude		switch (ch) {
532287988Sallanjude		case 'u':
533287988Sallanjude			uflag = optarg;
534287988Sallanjude			break;
535287988Sallanjude		case '?':
536287988Sallanjude		default:
537287988Sallanjude			usage(stderr, NULL);
538287988Sallanjude		}
539287988Sallanjude	}
540287988Sallanjude	argc -= optind;
541287988Sallanjude	argv += optind;
542287988Sallanjude
543287988Sallanjude	if (argc < 1) {
544287473Sbapt		warnx("Missing command");
545287988Sallanjude		usage(stderr, NULL);
546287473Sbapt	}
547287473Sbapt
548287473Sbapt	for (i = 0; i < nbcmds; i++) {
549287988Sallanjude		if (strcmp(argv[0], cmds[i].name) == 0) {
550287473Sbapt			cmd = &cmds[i];
551287473Sbapt			break;
552287473Sbapt		}
553287473Sbapt	}
554287473Sbapt
555287473Sbapt	if (cmd == NULL) {
556287988Sallanjude		warnx("unknown command %s", argv[0]);
557287988Sallanjude		usage(stderr, NULL);
558287473Sbapt	}
559287473Sbapt
560287473Sbapt	return (cmd->exec(argc, argv));
561287473Sbapt}
562