1cddcb259SBaptiste Daroussin /*- 28ad16e55SEdward Tomasz Napierala * Copyright (c) 2019 Klara Inc. 3cddcb259SBaptiste Daroussin * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 48729f5ecSAllan Jude * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org> 58729f5ecSAllan Jude * Copyright (c) 2000 by Matthew Jacob 6cddcb259SBaptiste Daroussin * All rights reserved. 7cddcb259SBaptiste Daroussin * 88ad16e55SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 98ad16e55SEdward Tomasz Napierala * under sponsorship from Klara Inc. 108ad16e55SEdward Tomasz Napierala * 11cddcb259SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 12cddcb259SBaptiste Daroussin * modification, are permitted provided that the following conditions 13cddcb259SBaptiste Daroussin * are met: 14cddcb259SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 15cddcb259SBaptiste Daroussin * notice, this list of conditions and the following disclaimer 16cddcb259SBaptiste Daroussin * in this position and unchanged. 17cddcb259SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 18cddcb259SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 19cddcb259SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 20cddcb259SBaptiste Daroussin * 21cddcb259SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 22cddcb259SBaptiste Daroussin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23cddcb259SBaptiste Daroussin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24cddcb259SBaptiste Daroussin * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 25cddcb259SBaptiste Daroussin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26cddcb259SBaptiste Daroussin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27cddcb259SBaptiste Daroussin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28cddcb259SBaptiste Daroussin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29cddcb259SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30cddcb259SBaptiste Daroussin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31cddcb259SBaptiste Daroussin */ 32cddcb259SBaptiste Daroussin 33cddcb259SBaptiste Daroussin #include <sys/cdefs.h> 3420a957e3SBaptiste Daroussin #include <sys/endian.h> 35cddcb259SBaptiste Daroussin #include <sys/param.h> 368ad16e55SEdward Tomasz Napierala #include <sys/disk.h> 37cddcb259SBaptiste Daroussin #include <sys/ioctl.h> 38d7654478SBaptiste Daroussin #include <sys/types.h> 39cddcb259SBaptiste Daroussin 40cddcb259SBaptiste Daroussin #include <errno.h> 41cddcb259SBaptiste Daroussin #include <fcntl.h> 428729f5ecSAllan Jude #include <getopt.h> 43cddcb259SBaptiste Daroussin #include <glob.h> 44cddcb259SBaptiste Daroussin #include <stdbool.h> 45cddcb259SBaptiste Daroussin #include <stddef.h> 46cddcb259SBaptiste Daroussin #include <stdint.h> 47cddcb259SBaptiste Daroussin #include <stdio.h> 48cddcb259SBaptiste Daroussin #include <stdlib.h> 49cddcb259SBaptiste Daroussin #include <string.h> 50cddcb259SBaptiste Daroussin #include <unistd.h> 51d25c1ff6SBaptiste Daroussin #include <libxo/xo.h> 52cddcb259SBaptiste Daroussin 53cddcb259SBaptiste Daroussin #include <cam/scsi/scsi_enc.h> 54cddcb259SBaptiste Daroussin 558729f5ecSAllan Jude #include "eltsub.h" 568729f5ecSAllan Jude 57d25c1ff6SBaptiste Daroussin #define SESUTIL_XO_VERSION "1" 58d25c1ff6SBaptiste Daroussin 598ad16e55SEdward Tomasz Napierala #define TEMPERATURE_OFFSET 20 608ad16e55SEdward Tomasz Napierala 618ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_DASHED 0 628ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_DASHED_2 1 638ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_CSV 2 648ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_CSV_2 3 658ad16e55SEdward Tomasz Napierala 668729f5ecSAllan Jude static int encstatus(int argc, char **argv); 678729f5ecSAllan Jude static int fault(int argc, char **argv); 68cddcb259SBaptiste Daroussin static int locate(int argc, char **argv); 698729f5ecSAllan Jude static int objmap(int argc, char **argv); 708729f5ecSAllan Jude static int sesled(int argc, char **argv, bool fault); 718ad16e55SEdward Tomasz Napierala static int show(int argc, char **argv); 728ad16e55SEdward Tomasz Napierala static void sesutil_print(int *style, const char *fmt, ...) __printflike(2,3); 73cddcb259SBaptiste Daroussin 74cddcb259SBaptiste Daroussin static struct command { 75cddcb259SBaptiste Daroussin const char *name; 768729f5ecSAllan Jude const char *param; 77cddcb259SBaptiste Daroussin const char *desc; 78cddcb259SBaptiste Daroussin int (*exec)(int argc, char **argv); 79cddcb259SBaptiste Daroussin } cmds[] = { 808729f5ecSAllan Jude { "fault", 818729f5ecSAllan Jude "(<disk>|<sesid>|all) (on|off)", 828729f5ecSAllan Jude "Change the state of the fault LED associated with a disk", 838729f5ecSAllan Jude fault }, 848729f5ecSAllan Jude { "locate", 858729f5ecSAllan Jude "(<disk>|<sesid>|all) (on|off)", 868729f5ecSAllan Jude "Change the state of the locate LED associated with a disk", 878729f5ecSAllan Jude locate }, 888729f5ecSAllan Jude { "map", "", 898729f5ecSAllan Jude "Print a map of the devices managed by the enclosure", objmap } , 908ad16e55SEdward Tomasz Napierala { "show", "", 918ad16e55SEdward Tomasz Napierala "Print a human-friendly summary of the enclosure", show } , 928729f5ecSAllan Jude { "status", "", "Print the status of the enclosure", 938729f5ecSAllan Jude encstatus }, 94cddcb259SBaptiste Daroussin }; 95cddcb259SBaptiste Daroussin 96cddcb259SBaptiste Daroussin static const int nbcmds = nitems(cmds); 978729f5ecSAllan Jude static const char *uflag; 98cddcb259SBaptiste Daroussin 99cddcb259SBaptiste Daroussin static void 100*3d1b233eSYan-Hao Wang usage(const char *subcmd) 1018729f5ecSAllan Jude { 1028729f5ecSAllan Jude int i; 1038729f5ecSAllan Jude 1048729f5ecSAllan Jude if (subcmd == NULL) { 105*3d1b233eSYan-Hao Wang xo_error("usage: %s [-u /dev/ses<N>] <command> [options]\n", 1068729f5ecSAllan Jude getprogname()); 107*3d1b233eSYan-Hao Wang xo_error("Commands supported:\n"); 1088729f5ecSAllan Jude } 1098729f5ecSAllan Jude for (i = 0; i < nbcmds; i++) { 1108729f5ecSAllan Jude if (subcmd != NULL) { 1118729f5ecSAllan Jude if (strcmp(subcmd, cmds[i].name) == 0) { 112*3d1b233eSYan-Hao Wang xo_error("usage: %s %s [-u /dev/ses<N>] " 1138729f5ecSAllan Jude "%s\n\t%s\n", getprogname(), subcmd, 1148729f5ecSAllan Jude cmds[i].param, cmds[i].desc); 1158729f5ecSAllan Jude break; 1168729f5ecSAllan Jude } 1178729f5ecSAllan Jude continue; 1188729f5ecSAllan Jude } 119*3d1b233eSYan-Hao Wang xo_error(" %-12s%s\n\t\t%s\n\n", cmds[i].name, 1208729f5ecSAllan Jude cmds[i].param, cmds[i].desc); 1218729f5ecSAllan Jude } 1228729f5ecSAllan Jude 1238729f5ecSAllan Jude exit(EXIT_FAILURE); 1248729f5ecSAllan Jude } 1258729f5ecSAllan Jude 1268729f5ecSAllan Jude static void 127fe74eaabSAlexander Motin do_led(int fd, unsigned int idx, elm_type_t type, bool onoff, bool setfault) 128cddcb259SBaptiste Daroussin { 129fe74eaabSAlexander Motin int state = onoff ? 1 : 0; 130cddcb259SBaptiste Daroussin encioc_elm_status_t o; 131fe74eaabSAlexander Motin struct ses_ctrl_dev_slot *slot; 132cddcb259SBaptiste Daroussin 133cddcb259SBaptiste Daroussin o.elm_idx = idx; 134cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) { 135cddcb259SBaptiste Daroussin close(fd); 136d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 137cddcb259SBaptiste Daroussin } 1382e19fae4SAlexander Motin ses_status_to_ctrl(type, &o.cstat[0]); 139fe74eaabSAlexander Motin switch (type) { 140fe74eaabSAlexander Motin case ELMTYP_DEVICE: 141fe74eaabSAlexander Motin case ELMTYP_ARRAY_DEV: 1422e19fae4SAlexander Motin slot = (struct ses_ctrl_dev_slot *) &o.cstat[0]; 143fe74eaabSAlexander Motin ses_ctrl_common_set_select(&slot->common, 1); 144fe74eaabSAlexander Motin if (setfault) 145fe74eaabSAlexander Motin ses_ctrl_dev_slot_set_rqst_fault(slot, state); 146efab8bfdSAlexander Motin else 147fe74eaabSAlexander Motin ses_ctrl_dev_slot_set_rqst_ident(slot, state); 148fe74eaabSAlexander Motin break; 149fe74eaabSAlexander Motin default: 150fe74eaabSAlexander Motin return; 1518729f5ecSAllan Jude } 152cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) { 153cddcb259SBaptiste Daroussin close(fd); 154d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_SETELMSTAT"); 155cddcb259SBaptiste Daroussin } 156cddcb259SBaptiste Daroussin } 157cddcb259SBaptiste Daroussin 158cddcb259SBaptiste Daroussin static bool 159cddcb259SBaptiste Daroussin disk_match(const char *devnames, const char *disk, size_t len) 160cddcb259SBaptiste Daroussin { 1611bc54324SBaptiste Daroussin const char *dname; 162cddcb259SBaptiste Daroussin 1631bc54324SBaptiste Daroussin dname = devnames; 1641bc54324SBaptiste Daroussin while ((dname = strstr(dname, disk)) != NULL) { 1658729f5ecSAllan Jude if (dname[len] == '\0' || dname[len] == ',') { 166cddcb259SBaptiste Daroussin return (true); 1678729f5ecSAllan Jude } 1681bc54324SBaptiste Daroussin dname++; 169cddcb259SBaptiste Daroussin } 1708729f5ecSAllan Jude 171cddcb259SBaptiste Daroussin return (false); 172cddcb259SBaptiste Daroussin } 173cddcb259SBaptiste Daroussin 174cddcb259SBaptiste Daroussin static int 1756af5d161SAllan Jude sesled(int argc, char **argv, bool setfault) 176cddcb259SBaptiste Daroussin { 177cddcb259SBaptiste Daroussin encioc_elm_devnames_t objdn; 178cddcb259SBaptiste Daroussin encioc_element_t *objp; 179cddcb259SBaptiste Daroussin glob_t g; 1808729f5ecSAllan Jude char *disk, *endptr; 1818729f5ecSAllan Jude size_t len, i, ndisks; 1828729f5ecSAllan Jude int fd; 1838729f5ecSAllan Jude unsigned int nobj, j, sesid; 1848729f5ecSAllan Jude bool all, isses, onoff; 185cddcb259SBaptiste Daroussin 1868729f5ecSAllan Jude isses = false; 1878729f5ecSAllan Jude all = false; 1888729f5ecSAllan Jude onoff = false; 1898729f5ecSAllan Jude 1908729f5ecSAllan Jude if (argc != 3) { 191*3d1b233eSYan-Hao Wang usage(setfault ? "fault" : "locate"); 192cddcb259SBaptiste Daroussin } 193cddcb259SBaptiste Daroussin 1948729f5ecSAllan Jude disk = argv[1]; 195cddcb259SBaptiste Daroussin 1968729f5ecSAllan Jude sesid = strtoul(disk, &endptr, 10); 1978729f5ecSAllan Jude if (*endptr == '\0') { 1988729f5ecSAllan Jude endptr = strrchr(uflag, '*'); 19996e6c444SBaptiste Daroussin if (endptr != NULL && *endptr == '*') { 200d25c1ff6SBaptiste Daroussin xo_warnx("Must specifying a SES device (-u) to use a SES " 2018729f5ecSAllan Jude "id# to identify a disk"); 202*3d1b233eSYan-Hao Wang usage(setfault ? "fault" : "locate"); 2038729f5ecSAllan Jude } 2048729f5ecSAllan Jude isses = true; 2058729f5ecSAllan Jude } 2068729f5ecSAllan Jude 2078729f5ecSAllan Jude if (strcmp(argv[2], "on") == 0) { 2084569e7cfSBaptiste Daroussin onoff = true; 2098729f5ecSAllan Jude } else if (strcmp(argv[2], "off") == 0) { 2104569e7cfSBaptiste Daroussin onoff = false; 211cddcb259SBaptiste Daroussin } else { 212*3d1b233eSYan-Hao Wang usage(setfault ? "fault" : "locate"); 213cddcb259SBaptiste Daroussin } 214cddcb259SBaptiste Daroussin 215cddcb259SBaptiste Daroussin if (strcmp(disk, "all") == 0) { 216cddcb259SBaptiste Daroussin all = true; 217cddcb259SBaptiste Daroussin } 218cddcb259SBaptiste Daroussin len = strlen(disk); 219cddcb259SBaptiste Daroussin 220cddcb259SBaptiste Daroussin /* Get the list of ses devices */ 2218729f5ecSAllan Jude if (glob((uflag != NULL ? uflag : "/dev/ses[0-9]*"), 0, NULL, &g) == 2228729f5ecSAllan Jude GLOB_NOMATCH) { 2238729f5ecSAllan Jude globfree(&g); 224d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 2258729f5ecSAllan Jude } 2268729f5ecSAllan Jude 2278729f5ecSAllan Jude ndisks = 0; 2288729f5ecSAllan Jude for (i = 0; i < g.gl_pathc; i++) { 2298729f5ecSAllan Jude /* ensure we only got numbers after ses */ 2308729f5ecSAllan Jude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 2318729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 2328729f5ecSAllan Jude continue; 2338729f5ecSAllan Jude } 2348729f5ecSAllan Jude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 2358729f5ecSAllan Jude /* 2368729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 2378729f5ecSAllan Jude * accessing all devices 2388729f5ecSAllan Jude */ 2398729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 240d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 2418729f5ecSAllan Jude } 242d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 2438729f5ecSAllan Jude continue; 2448729f5ecSAllan Jude } 2458729f5ecSAllan Jude 2468729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 2478729f5ecSAllan Jude close(fd); 248d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 2498729f5ecSAllan Jude } 2508729f5ecSAllan Jude 2518729f5ecSAllan Jude objp = calloc(nobj, sizeof(encioc_element_t)); 2528729f5ecSAllan Jude if (objp == NULL) { 2538729f5ecSAllan Jude close(fd); 254d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "calloc()"); 2558729f5ecSAllan Jude } 2568729f5ecSAllan Jude 2578729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) { 258a221b104SAlan Somers free(objp); 2598729f5ecSAllan Jude close(fd); 260d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 2618729f5ecSAllan Jude } 2628729f5ecSAllan Jude 2638729f5ecSAllan Jude if (isses) { 264691a834cSAlan Somers if (sesid >= nobj) { 265a221b104SAlan Somers free(objp); 2668729f5ecSAllan Jude close(fd); 267d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, 2688729f5ecSAllan Jude "Requested SES ID does not exist"); 2698729f5ecSAllan Jude } 270fe74eaabSAlexander Motin do_led(fd, sesid, objp[sesid].elm_type, onoff, setfault); 2718729f5ecSAllan Jude ndisks++; 272a221b104SAlan Somers free(objp); 2738729f5ecSAllan Jude close(fd); 2748729f5ecSAllan Jude break; 2758729f5ecSAllan Jude } 2768729f5ecSAllan Jude for (j = 0; j < nobj; j++) { 2779f96f106SAlan Somers const int devnames_size = 128; 2789f96f106SAlan Somers char devnames[devnames_size]; 2799f96f106SAlan Somers 28024ffc649SAllan Jude if (all) { 28157dc6f5eSAlan Somers encioc_elm_status_t es; 28257dc6f5eSAlan Somers memset(&es, 0, sizeof(es)); 28357dc6f5eSAlan Somers es.elm_idx = objp[j].elm_idx; 28457dc6f5eSAlan Somers if (ioctl(fd, ENCIOC_GETELMSTAT, &es) < 0) { 28557dc6f5eSAlan Somers close(fd); 28657dc6f5eSAlan Somers xo_err(EXIT_FAILURE, 28757dc6f5eSAlan Somers "ENCIOC_GETELMSTAT"); 28857dc6f5eSAlan Somers } 28957dc6f5eSAlan Somers if ((es.cstat[0] & 0xf) == SES_OBJSTAT_NOACCESS) 29057dc6f5eSAlan Somers continue; 291fe74eaabSAlexander Motin do_led(fd, objp[j].elm_idx, objp[j].elm_type, 292fe74eaabSAlexander Motin onoff, setfault); 29324ffc649SAllan Jude continue; 29424ffc649SAllan Jude } 2958729f5ecSAllan Jude memset(&objdn, 0, sizeof(objdn)); 2969f96f106SAlan Somers memset(devnames, 0, devnames_size); 2978729f5ecSAllan Jude objdn.elm_idx = objp[j].elm_idx; 2989f96f106SAlan Somers objdn.elm_names_size = devnames_size; 2999f96f106SAlan Somers objdn.elm_devnames = devnames; 3008729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 3018729f5ecSAllan Jude (caddr_t) &objdn) <0) { 3028729f5ecSAllan Jude continue; 3038729f5ecSAllan Jude } 3048729f5ecSAllan Jude if (objdn.elm_names_len > 0) { 3058729f5ecSAllan Jude if (disk_match(objdn.elm_devnames, disk, len)) { 306fe74eaabSAlexander Motin do_led(fd, objdn.elm_idx, objp[j].elm_type, 3076af5d161SAllan Jude onoff, setfault); 3088729f5ecSAllan Jude ndisks++; 3098729f5ecSAllan Jude break; 3108729f5ecSAllan Jude } 3118729f5ecSAllan Jude } 3128729f5ecSAllan Jude } 313f734685eSBaptiste Daroussin free(objp); 3148729f5ecSAllan Jude close(fd); 3158729f5ecSAllan Jude } 3168729f5ecSAllan Jude globfree(&g); 3178729f5ecSAllan Jude if (ndisks == 0 && all == false) { 3187d893fceSJeremy Faulkner xo_errx(EXIT_FAILURE, "Could not find the SES id of device '%s'", 3198729f5ecSAllan Jude disk); 3208729f5ecSAllan Jude } 3218729f5ecSAllan Jude 3228729f5ecSAllan Jude return (EXIT_SUCCESS); 3238729f5ecSAllan Jude } 3248729f5ecSAllan Jude 3258729f5ecSAllan Jude static int 3268729f5ecSAllan Jude locate(int argc, char **argv) 3278729f5ecSAllan Jude { 3288729f5ecSAllan Jude 3298729f5ecSAllan Jude return (sesled(argc, argv, false)); 3308729f5ecSAllan Jude } 3318729f5ecSAllan Jude 3328729f5ecSAllan Jude static int 3338729f5ecSAllan Jude fault(int argc, char **argv) 3348729f5ecSAllan Jude { 3358729f5ecSAllan Jude 3368729f5ecSAllan Jude return (sesled(argc, argv, true)); 3378729f5ecSAllan Jude } 3388729f5ecSAllan Jude 33920a957e3SBaptiste Daroussin static void 3408ad16e55SEdward Tomasz Napierala sesutil_print(int *style, const char *fmt, ...) 34120a957e3SBaptiste Daroussin { 34220a957e3SBaptiste Daroussin va_list args; 34320a957e3SBaptiste Daroussin 3448ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED) { 345d25c1ff6SBaptiste Daroussin xo_open_container("extra_status"); 346d25c1ff6SBaptiste Daroussin xo_emit("\t\tExtra status:\n"); 3478ad16e55SEdward Tomasz Napierala *style = PRINT_STYLE_DASHED_2; 3488ad16e55SEdward Tomasz Napierala } else if (*style == PRINT_STYLE_CSV) { 3498ad16e55SEdward Tomasz Napierala xo_open_container("extra_status"); 3508ad16e55SEdward Tomasz Napierala *style = PRINT_STYLE_CSV_2; 35120a957e3SBaptiste Daroussin } 3528ad16e55SEdward Tomasz Napierala 3538ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED_2) 3548ad16e55SEdward Tomasz Napierala xo_emit("\t\t- "); 3558ad16e55SEdward Tomasz Napierala else if (*style == PRINT_STYLE_CSV_2) 3568ad16e55SEdward Tomasz Napierala xo_emit(", "); 35720a957e3SBaptiste Daroussin va_start(args, fmt); 358d25c1ff6SBaptiste Daroussin xo_emit_hv(NULL, fmt, args); 35920a957e3SBaptiste Daroussin va_end(args); 3608ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED_2) 3618ad16e55SEdward Tomasz Napierala xo_emit("\n"); 36220a957e3SBaptiste Daroussin } 36320a957e3SBaptiste Daroussin 36420a957e3SBaptiste Daroussin static void 3658ad16e55SEdward Tomasz Napierala print_extra_status(int eletype, u_char *cstat, int style) 36620a957e3SBaptiste Daroussin { 36720a957e3SBaptiste Daroussin 36820a957e3SBaptiste Daroussin if (cstat[0] & 0x40) { 3698ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:predicted_failure/true} Predicted Failure"); 37020a957e3SBaptiste Daroussin } 37120a957e3SBaptiste Daroussin if (cstat[0] & 0x20) { 3728ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:disabled/true} Disabled"); 37320a957e3SBaptiste Daroussin } 37420a957e3SBaptiste Daroussin if (cstat[0] & 0x10) { 3758ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:swapped/true} Swapped"); 37620a957e3SBaptiste Daroussin } 37720a957e3SBaptiste Daroussin switch (eletype) { 37820a957e3SBaptiste Daroussin case ELMTYP_DEVICE: 37920a957e3SBaptiste Daroussin case ELMTYP_ARRAY_DEV: 38020a957e3SBaptiste Daroussin if (cstat[2] & 0x02) { 3818ad16e55SEdward Tomasz Napierala sesutil_print(&style, "LED={q:led/locate}"); 38220a957e3SBaptiste Daroussin } 38320a957e3SBaptiste Daroussin if (cstat[2] & 0x20) { 3848ad16e55SEdward Tomasz Napierala sesutil_print(&style, "LED={q:led/fault}"); 38520a957e3SBaptiste Daroussin } 38620a957e3SBaptiste Daroussin break; 38720a957e3SBaptiste Daroussin case ELMTYP_FAN: 3888ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Speed: {:speed/%d}{Uw:rpm}", 38920a957e3SBaptiste Daroussin (((0x7 & cstat[1]) << 8) + cstat[2]) * 10); 39020a957e3SBaptiste Daroussin break; 39120a957e3SBaptiste Daroussin case ELMTYP_THERM: 39220a957e3SBaptiste Daroussin if (cstat[2]) { 3938ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Temperature: {:temperature/%d}{Uw:C}", 39420a957e3SBaptiste Daroussin cstat[2] - TEMPERATURE_OFFSET); 39520a957e3SBaptiste Daroussin } else { 3968ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Temperature: -{q:temperature/reserved}"); 39720a957e3SBaptiste Daroussin } 39820a957e3SBaptiste Daroussin break; 39920a957e3SBaptiste Daroussin case ELMTYP_VOM: 4008ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Voltage: {:voltage/%.2f}{Uw:V}", 40120a957e3SBaptiste Daroussin be16dec(cstat + 2) / 100.0); 40220a957e3SBaptiste Daroussin break; 40320a957e3SBaptiste Daroussin } 4048ad16e55SEdward Tomasz Napierala if (style) { 405d25c1ff6SBaptiste Daroussin xo_close_container("extra_status"); 406d25c1ff6SBaptiste Daroussin } 40720a957e3SBaptiste Daroussin } 40820a957e3SBaptiste Daroussin 4098729f5ecSAllan Jude static int 4108729f5ecSAllan Jude objmap(int argc, char **argv __unused) 4118729f5ecSAllan Jude { 41260f46640SBaptiste Daroussin encioc_string_t stri; 4138729f5ecSAllan Jude encioc_elm_devnames_t e_devname; 4148729f5ecSAllan Jude encioc_elm_status_t e_status; 4158729f5ecSAllan Jude encioc_elm_desc_t e_desc; 4168729f5ecSAllan Jude encioc_element_t *e_ptr; 4178729f5ecSAllan Jude glob_t g; 4188729f5ecSAllan Jude int fd; 4198729f5ecSAllan Jude unsigned int j, nobj; 4208729f5ecSAllan Jude size_t i; 42160f46640SBaptiste Daroussin char str[32]; 4228729f5ecSAllan Jude 4238729f5ecSAllan Jude if (argc != 1) { 424*3d1b233eSYan-Hao Wang usage("map"); 4258729f5ecSAllan Jude } 4268729f5ecSAllan Jude 4274bd4e4b4SAlan Somers memset(&e_desc, 0, sizeof(e_desc)); 4284bd4e4b4SAlan Somers /* SES4r02 allows element descriptors of up to 65536 characters */ 4294bd4e4b4SAlan Somers e_desc.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); 4304bd4e4b4SAlan Somers if (e_desc.elm_desc_str == NULL) 4314bd4e4b4SAlan Somers xo_err(EXIT_FAILURE, "calloc()"); 4324bd4e4b4SAlan Somers 4334bd4e4b4SAlan Somers e_devname.elm_devnames = calloc(128, sizeof(char)); 4344bd4e4b4SAlan Somers if (e_devname.elm_devnames == NULL) 4354bd4e4b4SAlan Somers xo_err(EXIT_FAILURE, "calloc()"); 4364bd4e4b4SAlan Somers e_devname.elm_names_size = 128; 4374bd4e4b4SAlan Somers 4388729f5ecSAllan Jude /* Get the list of ses devices */ 4398729f5ecSAllan Jude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 440cddcb259SBaptiste Daroussin globfree(&g); 441d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 442cddcb259SBaptiste Daroussin } 443d25c1ff6SBaptiste Daroussin xo_set_version(SESUTIL_XO_VERSION); 444d25c1ff6SBaptiste Daroussin xo_open_container("sesutil"); 445d25c1ff6SBaptiste Daroussin xo_open_list("enclosures"); 446cddcb259SBaptiste Daroussin for (i = 0; i < g.gl_pathc; i++) { 447cddcb259SBaptiste Daroussin /* ensure we only got numbers after ses */ 448cddcb259SBaptiste Daroussin if (strspn(g.gl_pathv[i] + 8, "0123456789") != 4498729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 450cddcb259SBaptiste Daroussin continue; 4518729f5ecSAllan Jude } 452cddcb259SBaptiste Daroussin if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 4538729f5ecSAllan Jude /* 4548729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 4558729f5ecSAllan Jude * accessing all devices 4568729f5ecSAllan Jude */ 4578729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 458d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 4598729f5ecSAllan Jude } 460d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 4618729f5ecSAllan Jude continue; 462cddcb259SBaptiste Daroussin } 463cddcb259SBaptiste Daroussin 4648729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 4658729f5ecSAllan Jude close(fd); 466d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 4678729f5ecSAllan Jude } 468cddcb259SBaptiste Daroussin 4698729f5ecSAllan Jude e_ptr = calloc(nobj, sizeof(encioc_element_t)); 4708729f5ecSAllan Jude if (e_ptr == NULL) { 4718729f5ecSAllan Jude close(fd); 472d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "calloc()"); 4738729f5ecSAllan Jude } 474cddcb259SBaptiste Daroussin 4758729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) e_ptr) < 0) { 4768729f5ecSAllan Jude close(fd); 477d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 4788729f5ecSAllan Jude } 479cddcb259SBaptiste Daroussin 480d25c1ff6SBaptiste Daroussin xo_open_instance("enclosures"); 481d25c1ff6SBaptiste Daroussin xo_emit("{t:enc/%s}:\n", g.gl_pathv[i] + 5); 48260f46640SBaptiste Daroussin stri.bufsiz = sizeof(str); 48360f46640SBaptiste Daroussin stri.buf = &str[0]; 48460f46640SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0) 485d25c1ff6SBaptiste Daroussin xo_emit("\tEnclosure Name: {t:name/%s}\n", stri.buf); 48660f46640SBaptiste Daroussin stri.bufsiz = sizeof(str); 48760f46640SBaptiste Daroussin stri.buf = &str[0]; 48860f46640SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0) 489d25c1ff6SBaptiste Daroussin xo_emit("\tEnclosure ID: {t:id/%s}\n", stri.buf); 49060f46640SBaptiste Daroussin 491d25c1ff6SBaptiste Daroussin xo_open_list("elements"); 492cddcb259SBaptiste Daroussin for (j = 0; j < nobj; j++) { 4938729f5ecSAllan Jude /* Get the status of the element */ 4948729f5ecSAllan Jude memset(&e_status, 0, sizeof(e_status)); 4958729f5ecSAllan Jude e_status.elm_idx = e_ptr[j].elm_idx; 4968729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMSTAT, 4978729f5ecSAllan Jude (caddr_t) &e_status) < 0) { 4988729f5ecSAllan Jude close(fd); 499d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 5008729f5ecSAllan Jude } 5018729f5ecSAllan Jude /* Get the description of the element */ 5028729f5ecSAllan Jude e_desc.elm_idx = e_ptr[j].elm_idx; 5038729f5ecSAllan Jude e_desc.elm_desc_len = UINT16_MAX; 5048729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMDESC, 5058729f5ecSAllan Jude (caddr_t) &e_desc) < 0) { 5068729f5ecSAllan Jude close(fd); 507d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMDESC"); 5088729f5ecSAllan Jude } 5094bd4e4b4SAlan Somers e_desc.elm_desc_str[e_desc.elm_desc_len] = '\0'; 5108729f5ecSAllan Jude /* Get the device name(s) of the element */ 5118729f5ecSAllan Jude e_devname.elm_idx = e_ptr[j].elm_idx; 512cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 5138729f5ecSAllan Jude (caddr_t) &e_devname) <0) { 51418acbeb3SAlan Somers /* Continue even if we can't look up devnames */ 5158729f5ecSAllan Jude e_devname.elm_devnames[0] = '\0'; 516cddcb259SBaptiste Daroussin } 517d25c1ff6SBaptiste Daroussin xo_open_instance("elements"); 518d25c1ff6SBaptiste Daroussin xo_emit("\tElement {:id/%u}, Type: {:type/%s}\n", e_ptr[j].elm_idx, 5198729f5ecSAllan Jude geteltnm(e_ptr[j].elm_type)); 520d25c1ff6SBaptiste Daroussin xo_emit("\t\tStatus: {:status/%s} ({q:status_code/0x%02x 0x%02x 0x%02x 0x%02x})\n", 521d7654478SBaptiste Daroussin scode2ascii(e_status.cstat[0]), e_status.cstat[0], 522d7654478SBaptiste Daroussin e_status.cstat[1], e_status.cstat[2], 523d7654478SBaptiste Daroussin e_status.cstat[3]); 5248729f5ecSAllan Jude if (e_desc.elm_desc_len > 0) { 525d25c1ff6SBaptiste Daroussin xo_emit("\t\tDescription: {:description/%s}\n", 5268729f5ecSAllan Jude e_desc.elm_desc_str); 527cddcb259SBaptiste Daroussin } 5288729f5ecSAllan Jude if (e_devname.elm_names_len > 0) { 529d25c1ff6SBaptiste Daroussin xo_emit("\t\tDevice Names: {:device_names/%s}\n", 5308729f5ecSAllan Jude e_devname.elm_devnames); 531cddcb259SBaptiste Daroussin } 5328ad16e55SEdward Tomasz Napierala print_extra_status(e_ptr[j].elm_type, e_status.cstat, PRINT_STYLE_DASHED); 533d25c1ff6SBaptiste Daroussin xo_close_instance("elements"); 534cddcb259SBaptiste Daroussin } 535d25c1ff6SBaptiste Daroussin xo_close_list("elements"); 536f734685eSBaptiste Daroussin free(e_ptr); 537cddcb259SBaptiste Daroussin close(fd); 538cddcb259SBaptiste Daroussin } 539cddcb259SBaptiste Daroussin globfree(&g); 5404bd4e4b4SAlan Somers free(e_devname.elm_devnames); 5414bd4e4b4SAlan Somers free(e_desc.elm_desc_str); 542d25c1ff6SBaptiste Daroussin xo_close_list("enclosures"); 543d25c1ff6SBaptiste Daroussin xo_close_container("sesutil"); 544*3d1b233eSYan-Hao Wang if (xo_finish() < 0) 545*3d1b233eSYan-Hao Wang xo_err(EXIT_FAILURE, "stdout"); 546cddcb259SBaptiste Daroussin 547cddcb259SBaptiste Daroussin return (EXIT_SUCCESS); 548cddcb259SBaptiste Daroussin } 549cddcb259SBaptiste Daroussin 5508ad16e55SEdward Tomasz Napierala /* 5518ad16e55SEdward Tomasz Napierala * Get rid of the 'passN' devices, unless there's nothing else to show. 5528ad16e55SEdward Tomasz Napierala */ 5538ad16e55SEdward Tomasz Napierala static void 5548ad16e55SEdward Tomasz Napierala skip_pass_devices(char *devnames, size_t devnameslen) 5558ad16e55SEdward Tomasz Napierala { 5568ad16e55SEdward Tomasz Napierala char *dev, devs[128], passes[128], *tmp; 5578ad16e55SEdward Tomasz Napierala 5588ad16e55SEdward Tomasz Napierala devs[0] = passes[0] = '\0'; 5598ad16e55SEdward Tomasz Napierala tmp = devnames; 5608ad16e55SEdward Tomasz Napierala 5618ad16e55SEdward Tomasz Napierala while ((dev = strsep(&tmp, ",")) != NULL) { 5628ad16e55SEdward Tomasz Napierala if (strncmp(dev, "pass", 4) == 0) { 5638ad16e55SEdward Tomasz Napierala if (passes[0] != '\0') 5648ad16e55SEdward Tomasz Napierala strlcat(passes, ",", sizeof(passes)); 5658ad16e55SEdward Tomasz Napierala strlcat(passes, dev, sizeof(passes)); 5668ad16e55SEdward Tomasz Napierala } else { 5678ad16e55SEdward Tomasz Napierala if (devs[0] != '\0') 5688ad16e55SEdward Tomasz Napierala strlcat(devs, ",", sizeof(devs)); 5698ad16e55SEdward Tomasz Napierala strlcat(devs, dev, sizeof(devs)); 5708ad16e55SEdward Tomasz Napierala } 5718ad16e55SEdward Tomasz Napierala } 5728ad16e55SEdward Tomasz Napierala strlcpy(devnames, devs, devnameslen); 5738ad16e55SEdward Tomasz Napierala if (devnames[0] == '\0') 5748ad16e55SEdward Tomasz Napierala strlcpy(devnames, passes, devnameslen); 5758ad16e55SEdward Tomasz Napierala } 5768ad16e55SEdward Tomasz Napierala 5778ad16e55SEdward Tomasz Napierala static void 5788ad16e55SEdward Tomasz Napierala fetch_device_details(char *devnames, char **model, char **serial, off_t *size) 5798ad16e55SEdward Tomasz Napierala { 5808ad16e55SEdward Tomasz Napierala char ident[DISK_IDENT_SIZE]; 5818ad16e55SEdward Tomasz Napierala struct diocgattr_arg arg; 582f05cc0f1SAlan Somers char *tmp; 5838ad16e55SEdward Tomasz Napierala off_t mediasize; 584f05cc0f1SAlan Somers int comma; 5858ad16e55SEdward Tomasz Napierala int fd; 5868ad16e55SEdward Tomasz Napierala 587f05cc0f1SAlan Somers comma = (int)strcspn(devnames, ","); 588f05cc0f1SAlan Somers asprintf(&tmp, "/dev/%.*s", comma, devnames); 5898ad16e55SEdward Tomasz Napierala if (tmp == NULL) 590*3d1b233eSYan-Hao Wang xo_err(EXIT_FAILURE, "asprintf"); 5918ad16e55SEdward Tomasz Napierala fd = open(tmp, O_RDONLY); 592f05cc0f1SAlan Somers free(tmp); 5938ad16e55SEdward Tomasz Napierala if (fd < 0) { 5948ad16e55SEdward Tomasz Napierala /* 5958ad16e55SEdward Tomasz Napierala * This can happen with a disk so broken it cannot 5968ad16e55SEdward Tomasz Napierala * be probed by GEOM. 5978ad16e55SEdward Tomasz Napierala */ 5988ad16e55SEdward Tomasz Napierala *model = strdup("?"); 5998ad16e55SEdward Tomasz Napierala *serial = strdup("?"); 6008ad16e55SEdward Tomasz Napierala *size = -1; 601f05cc0f1SAlan Somers close(fd); 6028ad16e55SEdward Tomasz Napierala return; 6038ad16e55SEdward Tomasz Napierala } 6048ad16e55SEdward Tomasz Napierala 6058ad16e55SEdward Tomasz Napierala strlcpy(arg.name, "GEOM::descr", sizeof(arg.name)); 6068ad16e55SEdward Tomasz Napierala arg.len = sizeof(arg.value.str); 6078ad16e55SEdward Tomasz Napierala if (ioctl(fd, DIOCGATTR, &arg) == 0) 6088ad16e55SEdward Tomasz Napierala *model = strdup(arg.value.str); 6098ad16e55SEdward Tomasz Napierala else 6108ad16e55SEdward Tomasz Napierala *model = NULL; 6118ad16e55SEdward Tomasz Napierala 6128ad16e55SEdward Tomasz Napierala if (ioctl(fd, DIOCGIDENT, ident) == 0) 6138ad16e55SEdward Tomasz Napierala *serial = strdup(ident); 6148ad16e55SEdward Tomasz Napierala else 6158ad16e55SEdward Tomasz Napierala *serial = NULL; 6168ad16e55SEdward Tomasz Napierala 6178ad16e55SEdward Tomasz Napierala if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0) 6188ad16e55SEdward Tomasz Napierala *size = mediasize; 6198ad16e55SEdward Tomasz Napierala else 6208ad16e55SEdward Tomasz Napierala *size = -1; 621f05cc0f1SAlan Somers close(fd); 6228ad16e55SEdward Tomasz Napierala } 6238ad16e55SEdward Tomasz Napierala 6248ad16e55SEdward Tomasz Napierala static void 6258ad16e55SEdward Tomasz Napierala show_device(int fd, int elm_idx, encioc_elm_status_t e_status, encioc_elm_desc_t e_desc) 6268ad16e55SEdward Tomasz Napierala { 6278ad16e55SEdward Tomasz Napierala encioc_elm_devnames_t e_devname; 62809f29b03SAlan Somers char *model = NULL, *serial = NULL; 6298ad16e55SEdward Tomasz Napierala off_t size; 6308ad16e55SEdward Tomasz Napierala 6318ad16e55SEdward Tomasz Napierala /* Get the device name(s) of the element */ 6328ad16e55SEdward Tomasz Napierala memset(&e_devname, 0, sizeof(e_devname)); 6338ad16e55SEdward Tomasz Napierala e_devname.elm_idx = elm_idx; 6348ad16e55SEdward Tomasz Napierala e_devname.elm_names_size = 128; 6358ad16e55SEdward Tomasz Napierala e_devname.elm_devnames = calloc(128, sizeof(char)); 6368ad16e55SEdward Tomasz Napierala if (e_devname.elm_devnames == NULL) { 6378ad16e55SEdward Tomasz Napierala close(fd); 6388ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "calloc()"); 6398ad16e55SEdward Tomasz Napierala } 6408ad16e55SEdward Tomasz Napierala 6418ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 6428ad16e55SEdward Tomasz Napierala (caddr_t) &e_devname) < 0) { 6438ad16e55SEdward Tomasz Napierala /* We don't care if this fails */ 6448ad16e55SEdward Tomasz Napierala e_devname.elm_devnames[0] = '\0'; 6458ad16e55SEdward Tomasz Napierala size = -1; 6468ad16e55SEdward Tomasz Napierala } else { 6478ad16e55SEdward Tomasz Napierala skip_pass_devices(e_devname.elm_devnames, 128); 6488ad16e55SEdward Tomasz Napierala fetch_device_details(e_devname.elm_devnames, &model, &serial, &size); 6498ad16e55SEdward Tomasz Napierala } 6508ad16e55SEdward Tomasz Napierala xo_open_instance("elements"); 6518ad16e55SEdward Tomasz Napierala xo_emit("{e:type/device_slot}"); 65279f38143SPoul-Henning Kamp xo_emit("{d:description/%-15s} ", e_desc.elm_desc_len > 0 ? e_desc.elm_desc_str : "-"); 65379f38143SPoul-Henning Kamp xo_emit("{e:description/%-15s}", e_desc.elm_desc_len > 0 ? e_desc.elm_desc_str : ""); 6548ad16e55SEdward Tomasz Napierala xo_emit("{d:device_names/%-7s} ", e_devname.elm_names_len > 0 ? e_devname.elm_devnames : "-"); 6558ad16e55SEdward Tomasz Napierala xo_emit("{e:device_names/%s}", e_devname.elm_names_len > 0 ? e_devname.elm_devnames : ""); 6568ad16e55SEdward Tomasz Napierala xo_emit("{d:model/%-25s} ", model ? model : "-"); 6578ad16e55SEdward Tomasz Napierala xo_emit("{e:model/%s}", model ? model : ""); 6588ad16e55SEdward Tomasz Napierala xo_emit("{d:serial/%-20s} ", serial != NULL ? serial : "-"); 6598ad16e55SEdward Tomasz Napierala xo_emit("{e:serial/%s}", serial != NULL ? serial : ""); 660a1571967SEdward Tomasz Napierala if ((e_status.cstat[0] & 0xf) == SES_OBJSTAT_OK && size >= 0) { 6618ad16e55SEdward Tomasz Napierala xo_emit("{h,hn-1000:size/%ld}{e:status/%s}", 6628ad16e55SEdward Tomasz Napierala size, scode2ascii(e_status.cstat[0])); 6638ad16e55SEdward Tomasz Napierala } else { 6648ad16e55SEdward Tomasz Napierala xo_emit("{:status/%s}", scode2ascii(e_status.cstat[0])); 6658ad16e55SEdward Tomasz Napierala } 6668ad16e55SEdward Tomasz Napierala print_extra_status(ELMTYP_ARRAY_DEV, e_status.cstat, PRINT_STYLE_CSV); 6678ad16e55SEdward Tomasz Napierala xo_emit("\n"); 6688ad16e55SEdward Tomasz Napierala xo_close_instance("elements"); 66909f29b03SAlan Somers free(serial); 67009f29b03SAlan Somers free(model); 6718ad16e55SEdward Tomasz Napierala free(e_devname.elm_devnames); 6728ad16e55SEdward Tomasz Napierala } 6738ad16e55SEdward Tomasz Napierala 6748ad16e55SEdward Tomasz Napierala static void 6758ad16e55SEdward Tomasz Napierala show_therm(encioc_elm_status_t e_status, encioc_elm_desc_t e_desc) 6768ad16e55SEdward Tomasz Napierala { 6778ad16e55SEdward Tomasz Napierala 6788ad16e55SEdward Tomasz Napierala if (e_desc.elm_desc_len <= 0) { 6798ad16e55SEdward Tomasz Napierala /* We don't have a label to display; might as well skip it. */ 6808ad16e55SEdward Tomasz Napierala return; 6818ad16e55SEdward Tomasz Napierala } 6828ad16e55SEdward Tomasz Napierala 6838ad16e55SEdward Tomasz Napierala if (e_status.cstat[2] == 0) { 6848ad16e55SEdward Tomasz Napierala /* No temperature to show. */ 6858ad16e55SEdward Tomasz Napierala return; 6868ad16e55SEdward Tomasz Napierala } 6878ad16e55SEdward Tomasz Napierala 6888ad16e55SEdward Tomasz Napierala xo_open_instance("elements"); 6898ad16e55SEdward Tomasz Napierala xo_emit("{e:type/temperature_sensor}"); 6908ad16e55SEdward Tomasz Napierala xo_emit("{:description/%s}: {:temperature/%d}{Uw:C}", 6918ad16e55SEdward Tomasz Napierala e_desc.elm_desc_str, e_status.cstat[2] - TEMPERATURE_OFFSET); 6928ad16e55SEdward Tomasz Napierala xo_close_instance("elements"); 6938ad16e55SEdward Tomasz Napierala } 6948ad16e55SEdward Tomasz Napierala 6958ad16e55SEdward Tomasz Napierala static void 6968ad16e55SEdward Tomasz Napierala show_vom(encioc_elm_status_t e_status, encioc_elm_desc_t e_desc) 6978ad16e55SEdward Tomasz Napierala { 6988ad16e55SEdward Tomasz Napierala 6998ad16e55SEdward Tomasz Napierala if (e_desc.elm_desc_len <= 0) { 7008ad16e55SEdward Tomasz Napierala /* We don't have a label to display; might as well skip it. */ 7018ad16e55SEdward Tomasz Napierala return; 7028ad16e55SEdward Tomasz Napierala } 7038ad16e55SEdward Tomasz Napierala 7048ad16e55SEdward Tomasz Napierala if (e_status.cstat[2] == 0) { 7058ad16e55SEdward Tomasz Napierala /* No voltage to show. */ 7068ad16e55SEdward Tomasz Napierala return; 7078ad16e55SEdward Tomasz Napierala } 7088ad16e55SEdward Tomasz Napierala 7098ad16e55SEdward Tomasz Napierala xo_open_instance("elements"); 7108ad16e55SEdward Tomasz Napierala xo_emit("{e:type/voltage_sensor}"); 7118ad16e55SEdward Tomasz Napierala xo_emit("{:description/%s}: {:voltage/%.2f}{Uw:V}", 7128ad16e55SEdward Tomasz Napierala e_desc.elm_desc_str, be16dec(e_status.cstat + 2) / 100.0); 7138ad16e55SEdward Tomasz Napierala xo_close_instance("elements"); 7148ad16e55SEdward Tomasz Napierala } 7158ad16e55SEdward Tomasz Napierala 7168ad16e55SEdward Tomasz Napierala static int 7178ad16e55SEdward Tomasz Napierala show(int argc, char **argv __unused) 7188ad16e55SEdward Tomasz Napierala { 7198ad16e55SEdward Tomasz Napierala encioc_string_t stri; 7208ad16e55SEdward Tomasz Napierala encioc_elm_status_t e_status; 7218ad16e55SEdward Tomasz Napierala encioc_elm_desc_t e_desc; 7228ad16e55SEdward Tomasz Napierala encioc_element_t *e_ptr; 7238ad16e55SEdward Tomasz Napierala glob_t g; 7248ad16e55SEdward Tomasz Napierala elm_type_t prev_type; 7258ad16e55SEdward Tomasz Napierala int fd; 7268ad16e55SEdward Tomasz Napierala unsigned int j, nobj; 7278ad16e55SEdward Tomasz Napierala size_t i; 7288ad16e55SEdward Tomasz Napierala bool first_ses; 7298ad16e55SEdward Tomasz Napierala char str[32]; 7308ad16e55SEdward Tomasz Napierala 7318ad16e55SEdward Tomasz Napierala if (argc != 1) { 732*3d1b233eSYan-Hao Wang usage("map"); 7338ad16e55SEdward Tomasz Napierala } 7348ad16e55SEdward Tomasz Napierala 7358ad16e55SEdward Tomasz Napierala first_ses = true; 7368ad16e55SEdward Tomasz Napierala 7374bd4e4b4SAlan Somers e_desc.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); 7384bd4e4b4SAlan Somers if (e_desc.elm_desc_str == NULL) 7394bd4e4b4SAlan Somers xo_err(EXIT_FAILURE, "calloc()"); 7404bd4e4b4SAlan Somers 7418ad16e55SEdward Tomasz Napierala /* Get the list of ses devices */ 7428ad16e55SEdward Tomasz Napierala if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 7438ad16e55SEdward Tomasz Napierala globfree(&g); 7448ad16e55SEdward Tomasz Napierala xo_errx(EXIT_FAILURE, "No SES devices found"); 7458ad16e55SEdward Tomasz Napierala } 7468ad16e55SEdward Tomasz Napierala xo_set_version(SESUTIL_XO_VERSION); 7478ad16e55SEdward Tomasz Napierala xo_open_container("sesutil"); 7488ad16e55SEdward Tomasz Napierala xo_open_list("enclosures"); 7498ad16e55SEdward Tomasz Napierala for (i = 0; i < g.gl_pathc; i++) { 7508ad16e55SEdward Tomasz Napierala /* ensure we only got numbers after ses */ 7518ad16e55SEdward Tomasz Napierala if (strspn(g.gl_pathv[i] + 8, "0123456789") != 7528ad16e55SEdward Tomasz Napierala strlen(g.gl_pathv[i] + 8)) { 7538ad16e55SEdward Tomasz Napierala continue; 7548ad16e55SEdward Tomasz Napierala } 7558ad16e55SEdward Tomasz Napierala if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 7568ad16e55SEdward Tomasz Napierala /* 7578ad16e55SEdward Tomasz Napierala * Don't treat non-access errors as critical if we are 7588ad16e55SEdward Tomasz Napierala * accessing all devices 7598ad16e55SEdward Tomasz Napierala */ 7608ad16e55SEdward Tomasz Napierala if (errno == EACCES && g.gl_pathc > 1) { 7618ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "unable to access SES device"); 7628ad16e55SEdward Tomasz Napierala } 7638ad16e55SEdward Tomasz Napierala xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 7648ad16e55SEdward Tomasz Napierala continue; 7658ad16e55SEdward Tomasz Napierala } 7668ad16e55SEdward Tomasz Napierala 7678ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 7688ad16e55SEdward Tomasz Napierala close(fd); 7698ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 7708ad16e55SEdward Tomasz Napierala } 7718ad16e55SEdward Tomasz Napierala 7728ad16e55SEdward Tomasz Napierala e_ptr = calloc(nobj, sizeof(encioc_element_t)); 7738ad16e55SEdward Tomasz Napierala if (e_ptr == NULL) { 7748ad16e55SEdward Tomasz Napierala close(fd); 7758ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "calloc()"); 7768ad16e55SEdward Tomasz Napierala } 7778ad16e55SEdward Tomasz Napierala 7788ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) e_ptr) < 0) { 7798ad16e55SEdward Tomasz Napierala close(fd); 7808ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 7818ad16e55SEdward Tomasz Napierala } 7828ad16e55SEdward Tomasz Napierala 7838ad16e55SEdward Tomasz Napierala xo_open_instance("enclosures"); 7848ad16e55SEdward Tomasz Napierala 7858ad16e55SEdward Tomasz Napierala if (first_ses) 7868ad16e55SEdward Tomasz Napierala first_ses = false; 7878ad16e55SEdward Tomasz Napierala else 7888ad16e55SEdward Tomasz Napierala xo_emit("\n"); 7898ad16e55SEdward Tomasz Napierala 7908ad16e55SEdward Tomasz Napierala xo_emit("{t:enc/%s}: ", g.gl_pathv[i] + 5); 7918ad16e55SEdward Tomasz Napierala stri.bufsiz = sizeof(str); 7928ad16e55SEdward Tomasz Napierala stri.buf = &str[0]; 7938ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0) 7948ad16e55SEdward Tomasz Napierala xo_emit("<{t:name/%s}>; ", stri.buf); 7958ad16e55SEdward Tomasz Napierala stri.bufsiz = sizeof(str); 7968ad16e55SEdward Tomasz Napierala stri.buf = &str[0]; 7978ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0) 7988ad16e55SEdward Tomasz Napierala xo_emit("ID: {t:id/%s}", stri.buf); 7998ad16e55SEdward Tomasz Napierala xo_emit("\n"); 8008ad16e55SEdward Tomasz Napierala 8018ad16e55SEdward Tomasz Napierala xo_open_list("elements"); 8028ad16e55SEdward Tomasz Napierala prev_type = -1; 8038ad16e55SEdward Tomasz Napierala for (j = 0; j < nobj; j++) { 8048ad16e55SEdward Tomasz Napierala /* Get the status of the element */ 8058ad16e55SEdward Tomasz Napierala memset(&e_status, 0, sizeof(e_status)); 8068ad16e55SEdward Tomasz Napierala e_status.elm_idx = e_ptr[j].elm_idx; 8078ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETELMSTAT, 8088ad16e55SEdward Tomasz Napierala (caddr_t) &e_status) < 0) { 8098ad16e55SEdward Tomasz Napierala close(fd); 8108ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 8118ad16e55SEdward Tomasz Napierala } 8128ad16e55SEdward Tomasz Napierala 8138ad16e55SEdward Tomasz Napierala /* 8148ad16e55SEdward Tomasz Napierala * Skip "Unsupported" elements; those usually precede 8158ad16e55SEdward Tomasz Napierala * the actual device entries and are not particularly 8168ad16e55SEdward Tomasz Napierala * interesting. 8178ad16e55SEdward Tomasz Napierala */ 8188ad16e55SEdward Tomasz Napierala if (e_status.cstat[0] == SES_OBJSTAT_UNSUPPORTED) 8198ad16e55SEdward Tomasz Napierala continue; 8208ad16e55SEdward Tomasz Napierala 8218ad16e55SEdward Tomasz Napierala /* Get the description of the element */ 8228ad16e55SEdward Tomasz Napierala e_desc.elm_idx = e_ptr[j].elm_idx; 8238ad16e55SEdward Tomasz Napierala e_desc.elm_desc_len = UINT16_MAX; 8248ad16e55SEdward Tomasz Napierala if (ioctl(fd, ENCIOC_GETELMDESC, 8258ad16e55SEdward Tomasz Napierala (caddr_t) &e_desc) < 0) { 8268ad16e55SEdward Tomasz Napierala close(fd); 8278ad16e55SEdward Tomasz Napierala xo_err(EXIT_FAILURE, "ENCIOC_GETELMDESC"); 8288ad16e55SEdward Tomasz Napierala } 8294bd4e4b4SAlan Somers e_desc.elm_desc_str[e_desc.elm_desc_len] = '\0'; 8308ad16e55SEdward Tomasz Napierala 8318ad16e55SEdward Tomasz Napierala switch (e_ptr[j].elm_type) { 8328ad16e55SEdward Tomasz Napierala case ELMTYP_DEVICE: 8338ad16e55SEdward Tomasz Napierala case ELMTYP_ARRAY_DEV: 8348ad16e55SEdward Tomasz Napierala if (e_ptr[j].elm_type != prev_type) 8358ad16e55SEdward Tomasz Napierala xo_emit("Desc Dev Model Ident Size/Status\n"); 8368ad16e55SEdward Tomasz Napierala 8378ad16e55SEdward Tomasz Napierala show_device(fd, e_ptr[j].elm_idx, e_status, e_desc); 8388ad16e55SEdward Tomasz Napierala prev_type = e_ptr[j].elm_type; 8398ad16e55SEdward Tomasz Napierala break; 8408ad16e55SEdward Tomasz Napierala case ELMTYP_THERM: 8418ad16e55SEdward Tomasz Napierala if (e_ptr[j].elm_type != prev_type) 8423d10bf72SEdward Tomasz Napierala xo_emit("\nTemperatures: "); 8438ad16e55SEdward Tomasz Napierala else 8448ad16e55SEdward Tomasz Napierala xo_emit(", "); 8458ad16e55SEdward Tomasz Napierala prev_type = e_ptr[j].elm_type; 8468ad16e55SEdward Tomasz Napierala show_therm(e_status, e_desc); 8478ad16e55SEdward Tomasz Napierala break; 8488ad16e55SEdward Tomasz Napierala case ELMTYP_VOM: 8498ad16e55SEdward Tomasz Napierala if (e_ptr[j].elm_type != prev_type) 8503d10bf72SEdward Tomasz Napierala xo_emit("\nVoltages: "); 8518ad16e55SEdward Tomasz Napierala else 8528ad16e55SEdward Tomasz Napierala xo_emit(", "); 8538ad16e55SEdward Tomasz Napierala prev_type = e_ptr[j].elm_type; 8548ad16e55SEdward Tomasz Napierala show_vom(e_status, e_desc); 8558ad16e55SEdward Tomasz Napierala break; 8568ad16e55SEdward Tomasz Napierala default: 8578ad16e55SEdward Tomasz Napierala /* 8588ad16e55SEdward Tomasz Napierala * Ignore stuff not interesting to the user. 8598ad16e55SEdward Tomasz Napierala */ 8608ad16e55SEdward Tomasz Napierala break; 8618ad16e55SEdward Tomasz Napierala } 8628ad16e55SEdward Tomasz Napierala } 8638ad16e55SEdward Tomasz Napierala if (prev_type != (elm_type_t)-1 && 8648ad16e55SEdward Tomasz Napierala prev_type != ELMTYP_DEVICE && prev_type != ELMTYP_ARRAY_DEV) 8658ad16e55SEdward Tomasz Napierala xo_emit("\n"); 8668ad16e55SEdward Tomasz Napierala xo_close_list("elements"); 8678ad16e55SEdward Tomasz Napierala free(e_ptr); 8688ad16e55SEdward Tomasz Napierala close(fd); 8698ad16e55SEdward Tomasz Napierala } 8708ad16e55SEdward Tomasz Napierala globfree(&g); 8714bd4e4b4SAlan Somers free(e_desc.elm_desc_str); 8728ad16e55SEdward Tomasz Napierala xo_close_list("enclosures"); 8738ad16e55SEdward Tomasz Napierala xo_close_container("sesutil"); 874*3d1b233eSYan-Hao Wang if (xo_finish() < 0) 875*3d1b233eSYan-Hao Wang xo_err(EXIT_FAILURE, "stdout"); 8768ad16e55SEdward Tomasz Napierala 8778ad16e55SEdward Tomasz Napierala return (EXIT_SUCCESS); 8788ad16e55SEdward Tomasz Napierala } 8798ad16e55SEdward Tomasz Napierala 8808729f5ecSAllan Jude static int 8818729f5ecSAllan Jude encstatus(int argc, char **argv __unused) 882cddcb259SBaptiste Daroussin { 8838729f5ecSAllan Jude glob_t g; 8848729f5ecSAllan Jude int fd, status; 8858729f5ecSAllan Jude size_t i, e; 8868729f5ecSAllan Jude u_char estat; 887cddcb259SBaptiste Daroussin 8888729f5ecSAllan Jude status = 0; 8898729f5ecSAllan Jude if (argc != 1) { 890*3d1b233eSYan-Hao Wang usage("status"); 8918729f5ecSAllan Jude } 8928729f5ecSAllan Jude 8938729f5ecSAllan Jude /* Get the list of ses devices */ 8948729f5ecSAllan Jude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 8958729f5ecSAllan Jude globfree(&g); 896d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 8978729f5ecSAllan Jude } 898d25c1ff6SBaptiste Daroussin 899d25c1ff6SBaptiste Daroussin xo_set_version(SESUTIL_XO_VERSION); 900d25c1ff6SBaptiste Daroussin xo_open_container("sesutil"); 901d25c1ff6SBaptiste Daroussin xo_open_list("enclosures"); 9028729f5ecSAllan Jude for (i = 0; i < g.gl_pathc; i++) { 9038729f5ecSAllan Jude /* ensure we only got numbers after ses */ 9048729f5ecSAllan Jude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 9058729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 9068729f5ecSAllan Jude continue; 9078729f5ecSAllan Jude } 9088729f5ecSAllan Jude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 9098729f5ecSAllan Jude /* 9108729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 9118729f5ecSAllan Jude * accessing all devices 9128729f5ecSAllan Jude */ 9138729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 914d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 9158729f5ecSAllan Jude } 916d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 9178729f5ecSAllan Jude continue; 9188729f5ecSAllan Jude } 9198729f5ecSAllan Jude 9208729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) { 921d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETENCSTAT"); 9228729f5ecSAllan Jude close(fd); 9238729f5ecSAllan Jude } 9248729f5ecSAllan Jude 925d25c1ff6SBaptiste Daroussin xo_open_instance("enclosures"); 926d25c1ff6SBaptiste Daroussin xo_emit("{:enc/%s}: ", g.gl_pathv[i] + 5); 9278729f5ecSAllan Jude e = 0; 9288729f5ecSAllan Jude if (estat == 0) { 9298729f5ecSAllan Jude if (status == 0) { 9308729f5ecSAllan Jude status = 1; 9318729f5ecSAllan Jude } 932d25c1ff6SBaptiste Daroussin xo_emit("{q:status/OK}"); 9338729f5ecSAllan Jude } else { 9348729f5ecSAllan Jude if (estat & SES_ENCSTAT_INFO) { 935d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/INFO}"); 9368729f5ecSAllan Jude e++; 9378729f5ecSAllan Jude } 9388729f5ecSAllan Jude if (estat & SES_ENCSTAT_NONCRITICAL) { 9398729f5ecSAllan Jude if (e) 940d25c1ff6SBaptiste Daroussin xo_emit(","); 941d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/NONCRITICAL}"); 9428729f5ecSAllan Jude e++; 9438729f5ecSAllan Jude } 9448729f5ecSAllan Jude if (estat & SES_ENCSTAT_CRITICAL) { 9458729f5ecSAllan Jude if (e) 946d25c1ff6SBaptiste Daroussin xo_emit(","); 947d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/CRITICAL}"); 9488729f5ecSAllan Jude e++; 9498729f5ecSAllan Jude status = -1; 9508729f5ecSAllan Jude } 9518729f5ecSAllan Jude if (estat & SES_ENCSTAT_UNRECOV) { 9528729f5ecSAllan Jude if (e) 953d25c1ff6SBaptiste Daroussin xo_emit(","); 954d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/UNRECOV}"); 9558729f5ecSAllan Jude e++; 9568729f5ecSAllan Jude status = -1; 9578729f5ecSAllan Jude } 9588729f5ecSAllan Jude } 959d25c1ff6SBaptiste Daroussin xo_close_instance("enclosures"); 960d25c1ff6SBaptiste Daroussin xo_emit("\n"); 9618729f5ecSAllan Jude close(fd); 9628729f5ecSAllan Jude } 9638729f5ecSAllan Jude globfree(&g); 9648729f5ecSAllan Jude 965d25c1ff6SBaptiste Daroussin xo_close_list("enclosures"); 966d25c1ff6SBaptiste Daroussin xo_close_container("sesutil"); 967*3d1b233eSYan-Hao Wang if (xo_finish() < 0) 968*3d1b233eSYan-Hao Wang xo_err(EXIT_FAILURE, "stdout"); 969d25c1ff6SBaptiste Daroussin 9708729f5ecSAllan Jude if (status == 1) { 9718729f5ecSAllan Jude return (EXIT_SUCCESS); 9728729f5ecSAllan Jude } else { 9738729f5ecSAllan Jude return (EXIT_FAILURE); 9748729f5ecSAllan Jude } 975cddcb259SBaptiste Daroussin } 976cddcb259SBaptiste Daroussin 977cddcb259SBaptiste Daroussin int 978cddcb259SBaptiste Daroussin main(int argc, char **argv) 979cddcb259SBaptiste Daroussin { 9808729f5ecSAllan Jude int i, ch; 981cddcb259SBaptiste Daroussin struct command *cmd = NULL; 982cddcb259SBaptiste Daroussin 983d25c1ff6SBaptiste Daroussin argc = xo_parse_args(argc, argv); 984d25c1ff6SBaptiste Daroussin if (argc < 0) 985*3d1b233eSYan-Hao Wang exit(EXIT_FAILURE); 986d25c1ff6SBaptiste Daroussin 9878729f5ecSAllan Jude uflag = "/dev/ses[0-9]*"; 9888729f5ecSAllan Jude while ((ch = getopt_long(argc, argv, "u:", NULL, NULL)) != -1) { 9898729f5ecSAllan Jude switch (ch) { 9908729f5ecSAllan Jude case 'u': 9918729f5ecSAllan Jude uflag = optarg; 9928729f5ecSAllan Jude break; 9938729f5ecSAllan Jude case '?': 9948729f5ecSAllan Jude default: 995*3d1b233eSYan-Hao Wang usage(NULL); 9968729f5ecSAllan Jude } 9978729f5ecSAllan Jude } 9988729f5ecSAllan Jude argc -= optind; 9998729f5ecSAllan Jude argv += optind; 10008729f5ecSAllan Jude 10018729f5ecSAllan Jude if (argc < 1) { 1002*3d1b233eSYan-Hao Wang xo_warnx("Missing command"); 1003*3d1b233eSYan-Hao Wang usage(NULL); 1004cddcb259SBaptiste Daroussin } 1005cddcb259SBaptiste Daroussin 1006cddcb259SBaptiste Daroussin for (i = 0; i < nbcmds; i++) { 10078729f5ecSAllan Jude if (strcmp(argv[0], cmds[i].name) == 0) { 1008cddcb259SBaptiste Daroussin cmd = &cmds[i]; 1009cddcb259SBaptiste Daroussin break; 1010cddcb259SBaptiste Daroussin } 1011cddcb259SBaptiste Daroussin } 1012cddcb259SBaptiste Daroussin 1013cddcb259SBaptiste Daroussin if (cmd == NULL) { 1014*3d1b233eSYan-Hao Wang xo_warnx("unknown command %s", argv[0]); 1015*3d1b233eSYan-Hao Wang usage(NULL); 1016cddcb259SBaptiste Daroussin } 1017cddcb259SBaptiste Daroussin 1018cddcb259SBaptiste Daroussin return (cmd->exec(argc, argv)); 1019cddcb259SBaptiste Daroussin } 1020