sesutil.c revision 288710
1/*-
2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/10/usr.sbin/sesutil/sesutil.c 288710 2015-10-05 08:18:31Z bapt $");
29
30#include <sys/param.h>
31#include <sys/ioctl.h>
32
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <glob.h>
37#include <stdbool.h>
38#include <stddef.h>
39#include <stdint.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <cam/scsi/scsi_all.h>
46#include <cam/scsi/scsi_enc.h>
47
48static int locate(int argc, char **argv);
49
50static struct command {
51	const char *name;
52	const char *desc;
53	int (*exec)(int argc, char **argv);
54} cmds[] = {
55	{ "locate", "Change the state of the external LED associated with a"
56	    " disk", locate} ,
57};
58
59static const int nbcmds = nitems(cmds);
60
61static void
62do_locate(int fd, unsigned int idx, bool onoff)
63{
64	encioc_elm_status_t o;
65
66	o.elm_idx = idx;
67	if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) {
68		close(fd);
69		err(EXIT_FAILURE, "ENCIOC_GETELMSTAT");
70	}
71	o.cstat[0] |= 0x80;
72	if (onoff)
73		o.cstat[2] |= 0x02;
74	else
75		o.cstat[2] &= 0xfd;
76
77	if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) {
78		close(fd);
79		err(EXIT_FAILURE, "ENCIOC_SETELMSTAT");
80	}
81}
82
83static bool
84disk_match(const char *devnames, const char *disk, size_t len)
85{
86	const char *dname;
87
88	dname = devnames;
89	while ((dname = strstr(dname, disk)) != NULL) {
90		if (dname[len] == '\0' || dname[len] == ',')
91			return (true);
92		dname++;
93	}
94	return (false);
95}
96
97static int
98locate(int argc, char **argv)
99{
100	encioc_elm_devnames_t objdn;
101	encioc_element_t *objp;
102	glob_t g;
103	char *disk;
104	size_t len, i;
105	int fd, nobj, j;
106	bool all = false;
107	bool onoff;
108
109	if (argc != 2) {
110		errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]",
111		    getprogname());
112	}
113
114	disk = argv[0];
115
116	if (strcmp(argv[1], "on") == 0) {
117		onoff = true;
118	} else if (strcmp(argv[1], "off") == 0) {
119		onoff = false;
120	} else {
121		errx(EXIT_FAILURE, "usage: %s locate [disk] [on|off]",
122		    getprogname());
123	}
124
125	if (strcmp(disk, "all") == 0) {
126		all = true;
127	}
128	len = strlen(disk);
129
130	/* Get the list of ses devices */
131	if (glob("/dev/ses[0-9]*", 0, NULL, &g) == GLOB_NOMATCH) {
132		globfree(&g);
133		errx(EXIT_FAILURE, "No SES devices found");
134	}
135	for (i = 0; i < g.gl_pathc; i++) {
136		/* ensure we only got numbers after ses */
137		if (strspn(g.gl_pathv[i] + 8, "0123456789") !=
138		    strlen(g.gl_pathv[i] + 8))
139			continue;
140		if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) {
141			if (errno == EACCES)
142				err(EXIT_FAILURE, "enable to access SES device");
143			break;
144		}
145
146		if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0)
147			err(EXIT_FAILURE, "ENCIOC_GETNELM");
148
149		objp = calloc(nobj, sizeof(encioc_element_t));
150		if (objp == NULL)
151			err(EXIT_FAILURE, "calloc()");
152
153		if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0)
154			err(EXIT_FAILURE, "ENCIOC_GETELMMAP");
155
156		for (j = 0; j < nobj; j++) {
157			memset(&objdn, 0, sizeof(objdn));
158			objdn.elm_idx = objp[j].elm_idx;
159			objdn.elm_names_size = 128;
160			objdn.elm_devnames = calloc(128, sizeof(char));
161			if (objdn.elm_devnames == NULL)
162				err(EXIT_FAILURE, "calloc()");
163			if (ioctl(fd, ENCIOC_GETELMDEVNAMES,
164			    (caddr_t) &objdn) <0)
165				continue;
166			if (objdn.elm_names_len > 0) {
167				if (all) {
168					do_locate(fd, objdn.elm_idx, onoff);
169					continue;
170				}
171				if (disk_match(objdn.elm_devnames, disk, len)) {
172					do_locate(fd, objdn.elm_idx, onoff);
173					break;
174				}
175			}
176		}
177		close(fd);
178	}
179	globfree(&g);
180
181	return (EXIT_SUCCESS);
182}
183
184static void
185usage(FILE *out)
186{
187	int i;
188
189	fprintf(out, "Usage: %s [command] [options]\n", getprogname());
190	fprintf(out, "Commands supported:\n");
191	for (i = 0; i < nbcmds; i++)
192		fprintf(out, "\t%-15s%s\n", cmds[i].name, cmds[i].desc);
193}
194
195int
196main(int argc, char **argv)
197{
198	int i;
199	struct command *cmd = NULL;
200
201	if (argc < 2) {
202		warnx("Missing command");
203		usage(stderr);
204		return (EXIT_FAILURE);
205	}
206
207	for (i = 0; i < nbcmds; i++) {
208		if (strcmp(argv[1], cmds[i].name) == 0) {
209			cmd = &cmds[i];
210			break;
211		}
212	}
213
214	if (cmd == NULL) {
215		warnx("unknown command %s", argv[1]);
216		usage(stderr);
217		return (EXIT_FAILURE);
218	}
219
220	argc-=2;
221	argv+=2;
222
223	return (cmd->exec(argc, argv));
224}
225