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