sesutil.c revision 287485
1287473Sbapt/*-
2287473Sbapt * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3287473Sbapt * All rights reserved.
4287473Sbapt *
5287473Sbapt * Redistribution and use in source and binary forms, with or without
6287473Sbapt * modification, are permitted provided that the following conditions
7287473Sbapt * are met:
8287473Sbapt * 1. Redistributions of source code must retain the above copyright
9287473Sbapt *    notice, this list of conditions and the following disclaimer
10287473Sbapt *    in this position and unchanged.
11287473Sbapt * 2. Redistributions in binary form must reproduce the above copyright
12287473Sbapt *    notice, this list of conditions and the following disclaimer in the
13287473Sbapt *    documentation and/or other materials provided with the distribution.
14287473Sbapt *
15287473Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16287473Sbapt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17287473Sbapt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18287473Sbapt * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19287473Sbapt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20287473Sbapt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21287473Sbapt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22287473Sbapt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23287473Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24287473Sbapt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25287473Sbapt */
26287473Sbapt
27287473Sbapt#include <sys/cdefs.h>
28287473Sbapt__FBSDID("$FreeBSD: head/usr.sbin/sesutil/sesutil.c 287485 2015-09-05 16:59:30Z bapt $");
29287473Sbapt
30287473Sbapt#include <sys/param.h>
31287473Sbapt#include <sys/ioctl.h>
32287473Sbapt
33287473Sbapt#include <err.h>
34287473Sbapt#include <errno.h>
35287473Sbapt#include <fcntl.h>
36287473Sbapt#include <glob.h>
37287473Sbapt#include <stdbool.h>
38287473Sbapt#include <stddef.h>
39287473Sbapt#include <stdint.h>
40287473Sbapt#include <stdio.h>
41287473Sbapt#include <stdlib.h>
42287473Sbapt#include <string.h>
43287473Sbapt#include <unistd.h>
44287473Sbapt
45287473Sbapt#include <cam/scsi/scsi_all.h>
46287473Sbapt#include <cam/scsi/scsi_enc.h>
47287473Sbapt
48287473Sbaptstatic int locate(int argc, char **argv);
49287473Sbapt
50287473Sbaptstatic struct command {
51287473Sbapt	const char *name;
52287473Sbapt	const char *desc;
53287473Sbapt	int (*exec)(int argc, char **argv);
54287473Sbapt} cmds[] = {
55287473Sbapt	{ "locate", "Change the state of the external LED associated with a"
56287473Sbapt	    " disk", locate} ,
57287473Sbapt};
58287473Sbapt
59287473Sbaptstatic const int nbcmds = nitems(cmds);
60287473Sbapt
61287473Sbaptstatic void
62287473Sbaptdo_locate(int fd, unsigned int idx, bool onoff)
63287473Sbapt{
64287473Sbapt	encioc_elm_status_t o;
65287473Sbapt
66287473Sbapt	o.elm_idx = idx;
67287473Sbapt	if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) {
68287473Sbapt		close(fd);
69287473Sbapt		err(EXIT_FAILURE, "ENCIOC_GETELMSTAT");
70287473Sbapt	}
71287473Sbapt	o.cstat[0] |= 0x80;
72287473Sbapt	if (onoff)
73287473Sbapt		o.cstat[2] |= 0x02;
74287473Sbapt	else
75287473Sbapt		o.cstat[2] &= 0xfd;
76287473Sbapt
77287473Sbapt	if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) {
78287473Sbapt		close(fd);
79287473Sbapt		err(EXIT_FAILURE, "ENCIOC_SETELMSTAT");
80287473Sbapt	}
81287473Sbapt}
82287473Sbapt
83287473Sbaptstatic bool
84287473Sbaptdisk_match(const char *devnames, const char *disk, size_t len)
85287473Sbapt{
86287473Sbapt	const char *devname;
87287473Sbapt
88287473Sbapt	devname = devnames;
89287473Sbapt	while ((devname = strstr(devname, disk)) != NULL) {
90287473Sbapt		if (devname[len] == '\0' || devname[len] == ',')
91287473Sbapt			return (true);
92287473Sbapt		devname++;
93287473Sbapt	}
94287473Sbapt	return (false);
95287473Sbapt}
96287473Sbapt
97287473Sbaptstatic int
98287473Sbaptlocate(int argc, char **argv)
99287473Sbapt{
100287473Sbapt	encioc_elm_devnames_t objdn;
101287473Sbapt	encioc_element_t *objp;
102287473Sbapt	glob_t g;
103287473Sbapt	char *disk;
104287473Sbapt	size_t len, i;
105287473Sbapt	int fd, nobj, j;
106287473Sbapt	bool all = false;
107287485Sbapt	bool onoff;
108287473Sbapt
109287473Sbapt	if (argc != 2) {
110287473Sbapt		errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]",
111287473Sbapt		    getprogname());
112287473Sbapt	}
113287473Sbapt
114287473Sbapt	disk = argv[0];
115287473Sbapt
116287473Sbapt	if (strcmp(argv[1], "on") == 0) {
117287485Sbapt		onoff = true;
118287473Sbapt	} else if (strcmp(argv[1], "off") == 0) {
119287485Sbapt		onoff = false;
120287473Sbapt	} else {
121287473Sbapt		errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]",
122287473Sbapt		    getprogname());
123287473Sbapt	}
124287473Sbapt
125287473Sbapt	if (strcmp(disk, "all") == 0) {
126287473Sbapt		all = true;
127287473Sbapt	}
128287473Sbapt	len = strlen(disk);
129287473Sbapt
130287473Sbapt	/* Get the list of ses devices */
131287473Sbapt	if (glob("/dev/ses[0-9]*", 0, NULL, &g) == GLOB_NOMATCH) {
132287473Sbapt		globfree(&g);
133287473Sbapt		errx(EXIT_FAILURE, "No SES devices found");
134287473Sbapt	}
135287473Sbapt	for (i = 0; i < g.gl_pathc; i++) {
136287473Sbapt		/* ensure we only got numbers after ses */
137287473Sbapt		if (strspn(g.gl_pathv[i] + 8, "0123456789") !=
138287473Sbapt		    strlen(g.gl_pathv[i] + 8))
139287473Sbapt			continue;
140287473Sbapt		if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) {
141287473Sbapt			if (errno == EACCES)
142287473Sbapt				err(EXIT_FAILURE, "enable to access SES device");
143287473Sbapt			break;
144287473Sbapt		}
145287473Sbapt
146287473Sbapt		if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0)
147287473Sbapt			err(EXIT_FAILURE, "ENCIOC_GETNELM");
148287473Sbapt
149287473Sbapt		objp = calloc(nobj, sizeof(encioc_element_t));
150287473Sbapt		if (objp == NULL)
151287473Sbapt			err(EXIT_FAILURE, "calloc()");
152287473Sbapt
153287473Sbapt		if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0)
154287473Sbapt			err(EXIT_FAILURE, "ENCIOC_GETELMMAP");
155287473Sbapt
156287473Sbapt		for (j = 0; j < nobj; j++) {
157287473Sbapt			memset(&objdn, 0, sizeof(objdn));
158287473Sbapt			objdn.elm_idx = objp[j].elm_idx;
159287473Sbapt			objdn.elm_names_size = 128;
160287473Sbapt			objdn.elm_devnames = calloc(128, sizeof(char));
161287473Sbapt			if (objdn.elm_devnames == NULL)
162287473Sbapt				err(EXIT_FAILURE, "calloc()");
163287473Sbapt			if (ioctl(fd, ENCIOC_GETELMDEVNAMES,
164287473Sbapt			    (caddr_t) &objdn) <0)
165287473Sbapt				continue;
166287473Sbapt			if (objdn.elm_names_len > 0) {
167287473Sbapt				if (all) {
168287485Sbapt					do_locate(fd, objdn.elm_idx, onoff);
169287473Sbapt					continue;
170287473Sbapt				}
171287473Sbapt				if (disk_match(objdn.elm_devnames, disk, len)) {
172287485Sbapt					do_locate(fd, objdn.elm_idx, onoff);
173287473Sbapt					break;
174287473Sbapt				}
175287473Sbapt			}
176287473Sbapt		}
177287473Sbapt		close(fd);
178287473Sbapt		i++;
179287473Sbapt	}
180287473Sbapt	globfree(&g);
181287473Sbapt
182287473Sbapt	return (EXIT_SUCCESS);
183287473Sbapt}
184287473Sbapt
185287473Sbaptstatic void
186287473Sbaptusage(FILE *out)
187287473Sbapt{
188287473Sbapt	int i;
189287473Sbapt
190287473Sbapt	fprintf(out, "Usage: %s [command] [options]\n", getprogname());
191287473Sbapt	fprintf(out, "Commands supported:\n");
192287473Sbapt	for (i = 0; i < nbcmds; i++)
193287473Sbapt		fprintf(out, "\t%-15s%s\n", cmds[i].name, cmds[i].desc);
194287473Sbapt}
195287473Sbapt
196287473Sbaptint
197287473Sbaptmain(int argc, char **argv)
198287473Sbapt{
199287473Sbapt	int i;
200287473Sbapt	struct command *cmd = NULL;
201287473Sbapt
202287473Sbapt	if (argc < 2) {
203287473Sbapt		warnx("Missing command");
204287473Sbapt		usage(stderr);
205287473Sbapt		return (EXIT_FAILURE);
206287473Sbapt	}
207287473Sbapt
208287473Sbapt	for (i = 0; i < nbcmds; i++) {
209287473Sbapt		if (strcmp(argv[1], cmds[i].name) == 0) {
210287473Sbapt			cmd = &cmds[i];
211287473Sbapt			break;
212287473Sbapt		}
213287473Sbapt	}
214287473Sbapt
215287473Sbapt	if (cmd == NULL) {
216287473Sbapt		warnx("unknown command %s", argv[1]);
217287473Sbapt		usage(stderr);
218287473Sbapt		return (EXIT_FAILURE);
219287473Sbapt	}
220287473Sbapt
221287473Sbapt	argc-=2;
222287473Sbapt	argv+=2;
223287473Sbapt
224287473Sbapt	return (cmd->exec(argc, argv));
225287473Sbapt}
226