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 <err.h> 41cddcb259SBaptiste Daroussin #include <errno.h> 42cddcb259SBaptiste Daroussin #include <fcntl.h> 438729f5ecSAllan Jude #include <getopt.h> 44cddcb259SBaptiste Daroussin #include <glob.h> 45cddcb259SBaptiste Daroussin #include <stdbool.h> 46cddcb259SBaptiste Daroussin #include <stddef.h> 47cddcb259SBaptiste Daroussin #include <stdint.h> 48cddcb259SBaptiste Daroussin #include <stdio.h> 49cddcb259SBaptiste Daroussin #include <stdlib.h> 50cddcb259SBaptiste Daroussin #include <string.h> 51cddcb259SBaptiste Daroussin #include <unistd.h> 52d25c1ff6SBaptiste Daroussin #include <libxo/xo.h> 53cddcb259SBaptiste Daroussin 54cddcb259SBaptiste Daroussin #include <cam/scsi/scsi_enc.h> 55cddcb259SBaptiste Daroussin 568729f5ecSAllan Jude #include "eltsub.h" 578729f5ecSAllan Jude 58d25c1ff6SBaptiste Daroussin #define SESUTIL_XO_VERSION "1" 59d25c1ff6SBaptiste Daroussin 608ad16e55SEdward Tomasz Napierala #define TEMPERATURE_OFFSET 20 618ad16e55SEdward Tomasz Napierala 628ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_DASHED 0 638ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_DASHED_2 1 648ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_CSV 2 658ad16e55SEdward Tomasz Napierala #define PRINT_STYLE_CSV_2 3 668ad16e55SEdward Tomasz Napierala 678729f5ecSAllan Jude static int encstatus(int argc, char **argv); 688729f5ecSAllan Jude static int fault(int argc, char **argv); 69cddcb259SBaptiste Daroussin static int locate(int argc, char **argv); 708729f5ecSAllan Jude static int objmap(int argc, char **argv); 718729f5ecSAllan Jude static int sesled(int argc, char **argv, bool fault); 728ad16e55SEdward Tomasz Napierala static int show(int argc, char **argv); 738ad16e55SEdward Tomasz Napierala static void sesutil_print(int *style, const char *fmt, ...) __printflike(2,3); 74cddcb259SBaptiste Daroussin 75cddcb259SBaptiste Daroussin static struct command { 76cddcb259SBaptiste Daroussin const char *name; 778729f5ecSAllan Jude const char *param; 78cddcb259SBaptiste Daroussin const char *desc; 79cddcb259SBaptiste Daroussin int (*exec)(int argc, char **argv); 80cddcb259SBaptiste Daroussin } cmds[] = { 818729f5ecSAllan Jude { "fault", 828729f5ecSAllan Jude "(<disk>|<sesid>|all) (on|off)", 838729f5ecSAllan Jude "Change the state of the fault LED associated with a disk", 848729f5ecSAllan Jude fault }, 858729f5ecSAllan Jude { "locate", 868729f5ecSAllan Jude "(<disk>|<sesid>|all) (on|off)", 878729f5ecSAllan Jude "Change the state of the locate LED associated with a disk", 888729f5ecSAllan Jude locate }, 898729f5ecSAllan Jude { "map", "", 908729f5ecSAllan Jude "Print a map of the devices managed by the enclosure", objmap } , 918ad16e55SEdward Tomasz Napierala { "show", "", 928ad16e55SEdward Tomasz Napierala "Print a human-friendly summary of the enclosure", show } , 938729f5ecSAllan Jude { "status", "", "Print the status of the enclosure", 948729f5ecSAllan Jude encstatus }, 95cddcb259SBaptiste Daroussin }; 96cddcb259SBaptiste Daroussin 97cddcb259SBaptiste Daroussin static const int nbcmds = nitems(cmds); 988729f5ecSAllan Jude static const char *uflag; 99cddcb259SBaptiste Daroussin 100cddcb259SBaptiste Daroussin static void 1018729f5ecSAllan Jude usage(FILE *out, const char *subcmd) 1028729f5ecSAllan Jude { 1038729f5ecSAllan Jude int i; 1048729f5ecSAllan Jude 1058729f5ecSAllan Jude if (subcmd == NULL) { 1068729f5ecSAllan Jude fprintf(out, "Usage: %s [-u /dev/ses<N>] <command> [options]\n", 1078729f5ecSAllan Jude getprogname()); 1088729f5ecSAllan Jude fprintf(out, "Commands supported:\n"); 1098729f5ecSAllan Jude } 1108729f5ecSAllan Jude for (i = 0; i < nbcmds; i++) { 1118729f5ecSAllan Jude if (subcmd != NULL) { 1128729f5ecSAllan Jude if (strcmp(subcmd, cmds[i].name) == 0) { 1138729f5ecSAllan Jude fprintf(out, "Usage: %s %s [-u /dev/ses<N>] " 1148729f5ecSAllan Jude "%s\n\t%s\n", getprogname(), subcmd, 1158729f5ecSAllan Jude cmds[i].param, cmds[i].desc); 1168729f5ecSAllan Jude break; 1178729f5ecSAllan Jude } 1188729f5ecSAllan Jude continue; 1198729f5ecSAllan Jude } 1208729f5ecSAllan Jude fprintf(out, " %-12s%s\n\t\t%s\n\n", cmds[i].name, 1218729f5ecSAllan Jude cmds[i].param, cmds[i].desc); 1228729f5ecSAllan Jude } 1238729f5ecSAllan Jude 1248729f5ecSAllan Jude exit(EXIT_FAILURE); 1258729f5ecSAllan Jude } 1268729f5ecSAllan Jude 1278729f5ecSAllan Jude static void 128fe74eaabSAlexander Motin do_led(int fd, unsigned int idx, elm_type_t type, bool onoff, bool setfault) 129cddcb259SBaptiste Daroussin { 130fe74eaabSAlexander Motin int state = onoff ? 1 : 0; 131cddcb259SBaptiste Daroussin encioc_elm_status_t o; 132fe74eaabSAlexander Motin struct ses_ctrl_dev_slot *slot; 133cddcb259SBaptiste Daroussin 134cddcb259SBaptiste Daroussin o.elm_idx = idx; 135cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &o) < 0) { 136cddcb259SBaptiste Daroussin close(fd); 137d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 138cddcb259SBaptiste Daroussin } 1392e19fae4SAlexander Motin ses_status_to_ctrl(type, &o.cstat[0]); 140fe74eaabSAlexander Motin switch (type) { 141fe74eaabSAlexander Motin case ELMTYP_DEVICE: 142fe74eaabSAlexander Motin case ELMTYP_ARRAY_DEV: 1432e19fae4SAlexander Motin slot = (struct ses_ctrl_dev_slot *) &o.cstat[0]; 144fe74eaabSAlexander Motin ses_ctrl_common_set_select(&slot->common, 1); 145fe74eaabSAlexander Motin if (setfault) 146fe74eaabSAlexander Motin ses_ctrl_dev_slot_set_rqst_fault(slot, state); 147efab8bfdSAlexander Motin else 148fe74eaabSAlexander Motin ses_ctrl_dev_slot_set_rqst_ident(slot, state); 149fe74eaabSAlexander Motin break; 150fe74eaabSAlexander Motin default: 151fe74eaabSAlexander Motin return; 1528729f5ecSAllan Jude } 153cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &o) < 0) { 154cddcb259SBaptiste Daroussin close(fd); 155d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_SETELMSTAT"); 156cddcb259SBaptiste Daroussin } 157cddcb259SBaptiste Daroussin } 158cddcb259SBaptiste Daroussin 159cddcb259SBaptiste Daroussin static bool 160cddcb259SBaptiste Daroussin disk_match(const char *devnames, const char *disk, size_t len) 161cddcb259SBaptiste Daroussin { 1621bc54324SBaptiste Daroussin const char *dname; 163cddcb259SBaptiste Daroussin 1641bc54324SBaptiste Daroussin dname = devnames; 1651bc54324SBaptiste Daroussin while ((dname = strstr(dname, disk)) != NULL) { 1668729f5ecSAllan Jude if (dname[len] == '\0' || dname[len] == ',') { 167cddcb259SBaptiste Daroussin return (true); 1688729f5ecSAllan Jude } 1691bc54324SBaptiste Daroussin dname++; 170cddcb259SBaptiste Daroussin } 1718729f5ecSAllan Jude 172cddcb259SBaptiste Daroussin return (false); 173cddcb259SBaptiste Daroussin } 174cddcb259SBaptiste Daroussin 175cddcb259SBaptiste Daroussin static int 1766af5d161SAllan Jude sesled(int argc, char **argv, bool setfault) 177cddcb259SBaptiste Daroussin { 178cddcb259SBaptiste Daroussin encioc_elm_devnames_t objdn; 179cddcb259SBaptiste Daroussin encioc_element_t *objp; 180cddcb259SBaptiste Daroussin glob_t g; 1818729f5ecSAllan Jude char *disk, *endptr; 1828729f5ecSAllan Jude size_t len, i, ndisks; 1838729f5ecSAllan Jude int fd; 1848729f5ecSAllan Jude unsigned int nobj, j, sesid; 1858729f5ecSAllan Jude bool all, isses, onoff; 186cddcb259SBaptiste Daroussin 1878729f5ecSAllan Jude isses = false; 1888729f5ecSAllan Jude all = false; 1898729f5ecSAllan Jude onoff = false; 1908729f5ecSAllan Jude 1918729f5ecSAllan Jude if (argc != 3) { 1926af5d161SAllan Jude usage(stderr, (setfault ? "fault" : "locate")); 193cddcb259SBaptiste Daroussin } 194cddcb259SBaptiste Daroussin 1958729f5ecSAllan Jude disk = argv[1]; 196cddcb259SBaptiste Daroussin 1978729f5ecSAllan Jude sesid = strtoul(disk, &endptr, 10); 1988729f5ecSAllan Jude if (*endptr == '\0') { 1998729f5ecSAllan Jude endptr = strrchr(uflag, '*'); 20096e6c444SBaptiste Daroussin if (endptr != NULL && *endptr == '*') { 201d25c1ff6SBaptiste Daroussin xo_warnx("Must specifying a SES device (-u) to use a SES " 2028729f5ecSAllan Jude "id# to identify a disk"); 2036af5d161SAllan Jude usage(stderr, (setfault ? "fault" : "locate")); 2048729f5ecSAllan Jude } 2058729f5ecSAllan Jude isses = true; 2068729f5ecSAllan Jude } 2078729f5ecSAllan Jude 2088729f5ecSAllan Jude if (strcmp(argv[2], "on") == 0) { 2094569e7cfSBaptiste Daroussin onoff = true; 2108729f5ecSAllan Jude } else if (strcmp(argv[2], "off") == 0) { 2114569e7cfSBaptiste Daroussin onoff = false; 212cddcb259SBaptiste Daroussin } else { 2136af5d161SAllan Jude usage(stderr, (setfault ? "fault" : "locate")); 214cddcb259SBaptiste Daroussin } 215cddcb259SBaptiste Daroussin 216cddcb259SBaptiste Daroussin if (strcmp(disk, "all") == 0) { 217cddcb259SBaptiste Daroussin all = true; 218cddcb259SBaptiste Daroussin } 219cddcb259SBaptiste Daroussin len = strlen(disk); 220cddcb259SBaptiste Daroussin 221cddcb259SBaptiste Daroussin /* Get the list of ses devices */ 2228729f5ecSAllan Jude if (glob((uflag != NULL ? uflag : "/dev/ses[0-9]*"), 0, NULL, &g) == 2238729f5ecSAllan Jude GLOB_NOMATCH) { 2248729f5ecSAllan Jude globfree(&g); 225d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 2268729f5ecSAllan Jude } 2278729f5ecSAllan Jude 2288729f5ecSAllan Jude ndisks = 0; 2298729f5ecSAllan Jude for (i = 0; i < g.gl_pathc; i++) { 2308729f5ecSAllan Jude /* ensure we only got numbers after ses */ 2318729f5ecSAllan Jude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 2328729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 2338729f5ecSAllan Jude continue; 2348729f5ecSAllan Jude } 2358729f5ecSAllan Jude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 2368729f5ecSAllan Jude /* 2378729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 2388729f5ecSAllan Jude * accessing all devices 2398729f5ecSAllan Jude */ 2408729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 241d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 2428729f5ecSAllan Jude } 243d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 2448729f5ecSAllan Jude continue; 2458729f5ecSAllan Jude } 2468729f5ecSAllan Jude 2478729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 2488729f5ecSAllan Jude close(fd); 249d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 2508729f5ecSAllan Jude } 2518729f5ecSAllan Jude 2528729f5ecSAllan Jude objp = calloc(nobj, sizeof(encioc_element_t)); 2538729f5ecSAllan Jude if (objp == NULL) { 2548729f5ecSAllan Jude close(fd); 255d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "calloc()"); 2568729f5ecSAllan Jude } 2578729f5ecSAllan Jude 2588729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) { 259a221b104SAlan Somers free(objp); 2608729f5ecSAllan Jude close(fd); 261d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 2628729f5ecSAllan Jude } 2638729f5ecSAllan Jude 2648729f5ecSAllan Jude if (isses) { 265691a834cSAlan Somers if (sesid >= nobj) { 266a221b104SAlan Somers free(objp); 2678729f5ecSAllan Jude close(fd); 268d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, 2698729f5ecSAllan Jude "Requested SES ID does not exist"); 2708729f5ecSAllan Jude } 271fe74eaabSAlexander Motin do_led(fd, sesid, objp[sesid].elm_type, onoff, setfault); 2728729f5ecSAllan Jude ndisks++; 273a221b104SAlan Somers free(objp); 2748729f5ecSAllan Jude close(fd); 2758729f5ecSAllan Jude break; 2768729f5ecSAllan Jude } 2778729f5ecSAllan Jude for (j = 0; j < nobj; j++) { 2789f96f106SAlan Somers const int devnames_size = 128; 2799f96f106SAlan Somers char devnames[devnames_size]; 2809f96f106SAlan Somers 28124ffc649SAllan Jude if (all) { 28257dc6f5eSAlan Somers encioc_elm_status_t es; 28357dc6f5eSAlan Somers memset(&es, 0, sizeof(es)); 28457dc6f5eSAlan Somers es.elm_idx = objp[j].elm_idx; 28557dc6f5eSAlan Somers if (ioctl(fd, ENCIOC_GETELMSTAT, &es) < 0) { 28657dc6f5eSAlan Somers close(fd); 28757dc6f5eSAlan Somers xo_err(EXIT_FAILURE, 28857dc6f5eSAlan Somers "ENCIOC_GETELMSTAT"); 28957dc6f5eSAlan Somers } 29057dc6f5eSAlan Somers if ((es.cstat[0] & 0xf) == SES_OBJSTAT_NOACCESS) 29157dc6f5eSAlan Somers continue; 292fe74eaabSAlexander Motin do_led(fd, objp[j].elm_idx, objp[j].elm_type, 293fe74eaabSAlexander Motin onoff, setfault); 29424ffc649SAllan Jude continue; 29524ffc649SAllan Jude } 2968729f5ecSAllan Jude memset(&objdn, 0, sizeof(objdn)); 2979f96f106SAlan Somers memset(devnames, 0, devnames_size); 2988729f5ecSAllan Jude objdn.elm_idx = objp[j].elm_idx; 2999f96f106SAlan Somers objdn.elm_names_size = devnames_size; 3009f96f106SAlan Somers objdn.elm_devnames = devnames; 3018729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 3028729f5ecSAllan Jude (caddr_t) &objdn) <0) { 3038729f5ecSAllan Jude continue; 3048729f5ecSAllan Jude } 3058729f5ecSAllan Jude if (objdn.elm_names_len > 0) { 3068729f5ecSAllan Jude if (disk_match(objdn.elm_devnames, disk, len)) { 307fe74eaabSAlexander Motin do_led(fd, objdn.elm_idx, objp[j].elm_type, 3086af5d161SAllan Jude onoff, setfault); 3098729f5ecSAllan Jude ndisks++; 3108729f5ecSAllan Jude break; 3118729f5ecSAllan Jude } 3128729f5ecSAllan Jude } 3138729f5ecSAllan Jude } 314f734685eSBaptiste Daroussin free(objp); 3158729f5ecSAllan Jude close(fd); 3168729f5ecSAllan Jude } 3178729f5ecSAllan Jude globfree(&g); 3188729f5ecSAllan Jude if (ndisks == 0 && all == false) { 319*7d893fceSJeremy Faulkner xo_errx(EXIT_FAILURE, "Could not find the SES id of device '%s'", 3208729f5ecSAllan Jude disk); 3218729f5ecSAllan Jude } 3228729f5ecSAllan Jude 3238729f5ecSAllan Jude return (EXIT_SUCCESS); 3248729f5ecSAllan Jude } 3258729f5ecSAllan Jude 3268729f5ecSAllan Jude static int 3278729f5ecSAllan Jude locate(int argc, char **argv) 3288729f5ecSAllan Jude { 3298729f5ecSAllan Jude 3308729f5ecSAllan Jude return (sesled(argc, argv, false)); 3318729f5ecSAllan Jude } 3328729f5ecSAllan Jude 3338729f5ecSAllan Jude static int 3348729f5ecSAllan Jude fault(int argc, char **argv) 3358729f5ecSAllan Jude { 3368729f5ecSAllan Jude 3378729f5ecSAllan Jude return (sesled(argc, argv, true)); 3388729f5ecSAllan Jude } 3398729f5ecSAllan Jude 34020a957e3SBaptiste Daroussin static void 3418ad16e55SEdward Tomasz Napierala sesutil_print(int *style, const char *fmt, ...) 34220a957e3SBaptiste Daroussin { 34320a957e3SBaptiste Daroussin va_list args; 34420a957e3SBaptiste Daroussin 3458ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED) { 346d25c1ff6SBaptiste Daroussin xo_open_container("extra_status"); 347d25c1ff6SBaptiste Daroussin xo_emit("\t\tExtra status:\n"); 3488ad16e55SEdward Tomasz Napierala *style = PRINT_STYLE_DASHED_2; 3498ad16e55SEdward Tomasz Napierala } else if (*style == PRINT_STYLE_CSV) { 3508ad16e55SEdward Tomasz Napierala xo_open_container("extra_status"); 3518ad16e55SEdward Tomasz Napierala *style = PRINT_STYLE_CSV_2; 35220a957e3SBaptiste Daroussin } 3538ad16e55SEdward Tomasz Napierala 3548ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED_2) 3558ad16e55SEdward Tomasz Napierala xo_emit("\t\t- "); 3568ad16e55SEdward Tomasz Napierala else if (*style == PRINT_STYLE_CSV_2) 3578ad16e55SEdward Tomasz Napierala xo_emit(", "); 35820a957e3SBaptiste Daroussin va_start(args, fmt); 359d25c1ff6SBaptiste Daroussin xo_emit_hv(NULL, fmt, args); 36020a957e3SBaptiste Daroussin va_end(args); 3618ad16e55SEdward Tomasz Napierala if (*style == PRINT_STYLE_DASHED_2) 3628ad16e55SEdward Tomasz Napierala xo_emit("\n"); 36320a957e3SBaptiste Daroussin } 36420a957e3SBaptiste Daroussin 36520a957e3SBaptiste Daroussin static void 3668ad16e55SEdward Tomasz Napierala print_extra_status(int eletype, u_char *cstat, int style) 36720a957e3SBaptiste Daroussin { 36820a957e3SBaptiste Daroussin 36920a957e3SBaptiste Daroussin if (cstat[0] & 0x40) { 3708ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:predicted_failure/true} Predicted Failure"); 37120a957e3SBaptiste Daroussin } 37220a957e3SBaptiste Daroussin if (cstat[0] & 0x20) { 3738ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:disabled/true} Disabled"); 37420a957e3SBaptiste Daroussin } 37520a957e3SBaptiste Daroussin if (cstat[0] & 0x10) { 3768ad16e55SEdward Tomasz Napierala sesutil_print(&style, "{e:swapped/true} Swapped"); 37720a957e3SBaptiste Daroussin } 37820a957e3SBaptiste Daroussin switch (eletype) { 37920a957e3SBaptiste Daroussin case ELMTYP_DEVICE: 38020a957e3SBaptiste Daroussin case ELMTYP_ARRAY_DEV: 38120a957e3SBaptiste Daroussin if (cstat[2] & 0x02) { 3828ad16e55SEdward Tomasz Napierala sesutil_print(&style, "LED={q:led/locate}"); 38320a957e3SBaptiste Daroussin } 38420a957e3SBaptiste Daroussin if (cstat[2] & 0x20) { 3858ad16e55SEdward Tomasz Napierala sesutil_print(&style, "LED={q:led/fault}"); 38620a957e3SBaptiste Daroussin } 38720a957e3SBaptiste Daroussin break; 38820a957e3SBaptiste Daroussin case ELMTYP_FAN: 3898ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Speed: {:speed/%d}{Uw:rpm}", 39020a957e3SBaptiste Daroussin (((0x7 & cstat[1]) << 8) + cstat[2]) * 10); 39120a957e3SBaptiste Daroussin break; 39220a957e3SBaptiste Daroussin case ELMTYP_THERM: 39320a957e3SBaptiste Daroussin if (cstat[2]) { 3948ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Temperature: {:temperature/%d}{Uw:C}", 39520a957e3SBaptiste Daroussin cstat[2] - TEMPERATURE_OFFSET); 39620a957e3SBaptiste Daroussin } else { 3978ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Temperature: -{q:temperature/reserved}"); 39820a957e3SBaptiste Daroussin } 39920a957e3SBaptiste Daroussin break; 40020a957e3SBaptiste Daroussin case ELMTYP_VOM: 4018ad16e55SEdward Tomasz Napierala sesutil_print(&style, "Voltage: {:voltage/%.2f}{Uw:V}", 40220a957e3SBaptiste Daroussin be16dec(cstat + 2) / 100.0); 40320a957e3SBaptiste Daroussin break; 40420a957e3SBaptiste Daroussin } 4058ad16e55SEdward Tomasz Napierala if (style) { 406d25c1ff6SBaptiste Daroussin xo_close_container("extra_status"); 407d25c1ff6SBaptiste Daroussin } 40820a957e3SBaptiste Daroussin } 40920a957e3SBaptiste Daroussin 4108729f5ecSAllan Jude static int 4118729f5ecSAllan Jude objmap(int argc, char **argv __unused) 4128729f5ecSAllan Jude { 41360f46640SBaptiste Daroussin encioc_string_t stri; 4148729f5ecSAllan Jude encioc_elm_devnames_t e_devname; 4158729f5ecSAllan Jude encioc_elm_status_t e_status; 4168729f5ecSAllan Jude encioc_elm_desc_t e_desc; 4178729f5ecSAllan Jude encioc_element_t *e_ptr; 4188729f5ecSAllan Jude glob_t g; 4198729f5ecSAllan Jude int fd; 4208729f5ecSAllan Jude unsigned int j, nobj; 4218729f5ecSAllan Jude size_t i; 42260f46640SBaptiste Daroussin char str[32]; 4238729f5ecSAllan Jude 4248729f5ecSAllan Jude if (argc != 1) { 4258729f5ecSAllan Jude usage(stderr, "map"); 4268729f5ecSAllan Jude } 4278729f5ecSAllan Jude 4284bd4e4b4SAlan Somers memset(&e_desc, 0, sizeof(e_desc)); 4294bd4e4b4SAlan Somers /* SES4r02 allows element descriptors of up to 65536 characters */ 4304bd4e4b4SAlan Somers e_desc.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); 4314bd4e4b4SAlan Somers if (e_desc.elm_desc_str == NULL) 4324bd4e4b4SAlan Somers xo_err(EXIT_FAILURE, "calloc()"); 4334bd4e4b4SAlan Somers 4344bd4e4b4SAlan Somers e_devname.elm_devnames = calloc(128, sizeof(char)); 4354bd4e4b4SAlan Somers if (e_devname.elm_devnames == NULL) 4364bd4e4b4SAlan Somers xo_err(EXIT_FAILURE, "calloc()"); 4374bd4e4b4SAlan Somers e_devname.elm_names_size = 128; 4384bd4e4b4SAlan Somers 4398729f5ecSAllan Jude /* Get the list of ses devices */ 4408729f5ecSAllan Jude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 441cddcb259SBaptiste Daroussin globfree(&g); 442d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 443cddcb259SBaptiste Daroussin } 444d25c1ff6SBaptiste Daroussin xo_set_version(SESUTIL_XO_VERSION); 445d25c1ff6SBaptiste Daroussin xo_open_container("sesutil"); 446d25c1ff6SBaptiste Daroussin xo_open_list("enclosures"); 447cddcb259SBaptiste Daroussin for (i = 0; i < g.gl_pathc; i++) { 448cddcb259SBaptiste Daroussin /* ensure we only got numbers after ses */ 449cddcb259SBaptiste Daroussin if (strspn(g.gl_pathv[i] + 8, "0123456789") != 4508729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 451cddcb259SBaptiste Daroussin continue; 4528729f5ecSAllan Jude } 453cddcb259SBaptiste Daroussin if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 4548729f5ecSAllan Jude /* 4558729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 4568729f5ecSAllan Jude * accessing all devices 4578729f5ecSAllan Jude */ 4588729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 459d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 4608729f5ecSAllan Jude } 461d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 4628729f5ecSAllan Jude continue; 463cddcb259SBaptiste Daroussin } 464cddcb259SBaptiste Daroussin 4658729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { 4668729f5ecSAllan Jude close(fd); 467d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETNELM"); 4688729f5ecSAllan Jude } 469cddcb259SBaptiste Daroussin 4708729f5ecSAllan Jude e_ptr = calloc(nobj, sizeof(encioc_element_t)); 4718729f5ecSAllan Jude if (e_ptr == NULL) { 4728729f5ecSAllan Jude close(fd); 473d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "calloc()"); 4748729f5ecSAllan Jude } 475cddcb259SBaptiste Daroussin 4768729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) e_ptr) < 0) { 4778729f5ecSAllan Jude close(fd); 478d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMMAP"); 4798729f5ecSAllan Jude } 480cddcb259SBaptiste Daroussin 481d25c1ff6SBaptiste Daroussin xo_open_instance("enclosures"); 482d25c1ff6SBaptiste Daroussin xo_emit("{t:enc/%s}:\n", g.gl_pathv[i] + 5); 48360f46640SBaptiste Daroussin stri.bufsiz = sizeof(str); 48460f46640SBaptiste Daroussin stri.buf = &str[0]; 48560f46640SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0) 486d25c1ff6SBaptiste Daroussin xo_emit("\tEnclosure Name: {t:name/%s}\n", stri.buf); 48760f46640SBaptiste Daroussin stri.bufsiz = sizeof(str); 48860f46640SBaptiste Daroussin stri.buf = &str[0]; 48960f46640SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0) 490d25c1ff6SBaptiste Daroussin xo_emit("\tEnclosure ID: {t:id/%s}\n", stri.buf); 49160f46640SBaptiste Daroussin 492d25c1ff6SBaptiste Daroussin xo_open_list("elements"); 493cddcb259SBaptiste Daroussin for (j = 0; j < nobj; j++) { 4948729f5ecSAllan Jude /* Get the status of the element */ 4958729f5ecSAllan Jude memset(&e_status, 0, sizeof(e_status)); 4968729f5ecSAllan Jude e_status.elm_idx = e_ptr[j].elm_idx; 4978729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMSTAT, 4988729f5ecSAllan Jude (caddr_t) &e_status) < 0) { 4998729f5ecSAllan Jude close(fd); 500d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT"); 5018729f5ecSAllan Jude } 5028729f5ecSAllan Jude /* Get the description of the element */ 5038729f5ecSAllan Jude e_desc.elm_idx = e_ptr[j].elm_idx; 5048729f5ecSAllan Jude e_desc.elm_desc_len = UINT16_MAX; 5058729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETELMDESC, 5068729f5ecSAllan Jude (caddr_t) &e_desc) < 0) { 5078729f5ecSAllan Jude close(fd); 508d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETELMDESC"); 5098729f5ecSAllan Jude } 5104bd4e4b4SAlan Somers e_desc.elm_desc_str[e_desc.elm_desc_len] = '\0'; 5118729f5ecSAllan Jude /* Get the device name(s) of the element */ 5128729f5ecSAllan Jude e_devname.elm_idx = e_ptr[j].elm_idx; 513cddcb259SBaptiste Daroussin if (ioctl(fd, ENCIOC_GETELMDEVNAMES, 5148729f5ecSAllan Jude (caddr_t) &e_devname) <0) { 51518acbeb3SAlan Somers /* Continue even if we can't look up devnames */ 5168729f5ecSAllan Jude e_devname.elm_devnames[0] = '\0'; 517cddcb259SBaptiste Daroussin } 518d25c1ff6SBaptiste Daroussin xo_open_instance("elements"); 519d25c1ff6SBaptiste Daroussin xo_emit("\tElement {:id/%u}, Type: {:type/%s}\n", e_ptr[j].elm_idx, 5208729f5ecSAllan Jude geteltnm(e_ptr[j].elm_type)); 521d25c1ff6SBaptiste Daroussin xo_emit("\t\tStatus: {:status/%s} ({q:status_code/0x%02x 0x%02x 0x%02x 0x%02x})\n", 522d7654478SBaptiste Daroussin scode2ascii(e_status.cstat[0]), e_status.cstat[0], 523d7654478SBaptiste Daroussin e_status.cstat[1], e_status.cstat[2], 524d7654478SBaptiste Daroussin e_status.cstat[3]); 5258729f5ecSAllan Jude if (e_desc.elm_desc_len > 0) { 526d25c1ff6SBaptiste Daroussin xo_emit("\t\tDescription: {:description/%s}\n", 5278729f5ecSAllan Jude e_desc.elm_desc_str); 528cddcb259SBaptiste Daroussin } 5298729f5ecSAllan Jude if (e_devname.elm_names_len > 0) { 530d25c1ff6SBaptiste Daroussin xo_emit("\t\tDevice Names: {:device_names/%s}\n", 5318729f5ecSAllan Jude e_devname.elm_devnames); 532cddcb259SBaptiste Daroussin } 5338ad16e55SEdward Tomasz Napierala print_extra_status(e_ptr[j].elm_type, e_status.cstat, PRINT_STYLE_DASHED); 534d25c1ff6SBaptiste Daroussin xo_close_instance("elements"); 535cddcb259SBaptiste Daroussin } 536d25c1ff6SBaptiste Daroussin xo_close_list("elements"); 537f734685eSBaptiste Daroussin free(e_ptr); 538cddcb259SBaptiste Daroussin close(fd); 539cddcb259SBaptiste Daroussin } 540cddcb259SBaptiste Daroussin globfree(&g); 5414bd4e4b4SAlan Somers free(e_devname.elm_devnames); 5424bd4e4b4SAlan Somers free(e_desc.elm_desc_str); 543d25c1ff6SBaptiste Daroussin xo_close_list("enclosures"); 544d25c1ff6SBaptiste Daroussin xo_close_container("sesutil"); 545d25c1ff6SBaptiste Daroussin xo_finish(); 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) 590f05cc0f1SAlan Somers err(1, "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) { 7328ad16e55SEdward Tomasz Napierala usage(stderr, "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"); 8748ad16e55SEdward Tomasz Napierala xo_finish(); 8758ad16e55SEdward Tomasz Napierala 8768ad16e55SEdward Tomasz Napierala return (EXIT_SUCCESS); 8778ad16e55SEdward Tomasz Napierala } 8788ad16e55SEdward Tomasz Napierala 8798729f5ecSAllan Jude static int 8808729f5ecSAllan Jude encstatus(int argc, char **argv __unused) 881cddcb259SBaptiste Daroussin { 8828729f5ecSAllan Jude glob_t g; 8838729f5ecSAllan Jude int fd, status; 8848729f5ecSAllan Jude size_t i, e; 8858729f5ecSAllan Jude u_char estat; 886cddcb259SBaptiste Daroussin 8878729f5ecSAllan Jude status = 0; 8888729f5ecSAllan Jude if (argc != 1) { 8898729f5ecSAllan Jude usage(stderr, "status"); 8908729f5ecSAllan Jude } 8918729f5ecSAllan Jude 8928729f5ecSAllan Jude /* Get the list of ses devices */ 8938729f5ecSAllan Jude if (glob(uflag, 0, NULL, &g) == GLOB_NOMATCH) { 8948729f5ecSAllan Jude globfree(&g); 895d25c1ff6SBaptiste Daroussin xo_errx(EXIT_FAILURE, "No SES devices found"); 8968729f5ecSAllan Jude } 897d25c1ff6SBaptiste Daroussin 898d25c1ff6SBaptiste Daroussin xo_set_version(SESUTIL_XO_VERSION); 899d25c1ff6SBaptiste Daroussin xo_open_container("sesutil"); 900d25c1ff6SBaptiste Daroussin xo_open_list("enclosures"); 9018729f5ecSAllan Jude for (i = 0; i < g.gl_pathc; i++) { 9028729f5ecSAllan Jude /* ensure we only got numbers after ses */ 9038729f5ecSAllan Jude if (strspn(g.gl_pathv[i] + 8, "0123456789") != 9048729f5ecSAllan Jude strlen(g.gl_pathv[i] + 8)) { 9058729f5ecSAllan Jude continue; 9068729f5ecSAllan Jude } 9078729f5ecSAllan Jude if ((fd = open(g.gl_pathv[i], O_RDWR)) < 0) { 9088729f5ecSAllan Jude /* 9098729f5ecSAllan Jude * Don't treat non-access errors as critical if we are 9108729f5ecSAllan Jude * accessing all devices 9118729f5ecSAllan Jude */ 9128729f5ecSAllan Jude if (errno == EACCES && g.gl_pathc > 1) { 913d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "unable to access SES device"); 9148729f5ecSAllan Jude } 915d25c1ff6SBaptiste Daroussin xo_warn("unable to access SES device: %s", g.gl_pathv[i]); 9168729f5ecSAllan Jude continue; 9178729f5ecSAllan Jude } 9188729f5ecSAllan Jude 9198729f5ecSAllan Jude if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) { 920d25c1ff6SBaptiste Daroussin xo_err(EXIT_FAILURE, "ENCIOC_GETENCSTAT"); 9218729f5ecSAllan Jude close(fd); 9228729f5ecSAllan Jude } 9238729f5ecSAllan Jude 924d25c1ff6SBaptiste Daroussin xo_open_instance("enclosures"); 925d25c1ff6SBaptiste Daroussin xo_emit("{:enc/%s}: ", g.gl_pathv[i] + 5); 9268729f5ecSAllan Jude e = 0; 9278729f5ecSAllan Jude if (estat == 0) { 9288729f5ecSAllan Jude if (status == 0) { 9298729f5ecSAllan Jude status = 1; 9308729f5ecSAllan Jude } 931d25c1ff6SBaptiste Daroussin xo_emit("{q:status/OK}"); 9328729f5ecSAllan Jude } else { 9338729f5ecSAllan Jude if (estat & SES_ENCSTAT_INFO) { 934d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/INFO}"); 9358729f5ecSAllan Jude e++; 9368729f5ecSAllan Jude } 9378729f5ecSAllan Jude if (estat & SES_ENCSTAT_NONCRITICAL) { 9388729f5ecSAllan Jude if (e) 939d25c1ff6SBaptiste Daroussin xo_emit(","); 940d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/NONCRITICAL}"); 9418729f5ecSAllan Jude e++; 9428729f5ecSAllan Jude } 9438729f5ecSAllan Jude if (estat & SES_ENCSTAT_CRITICAL) { 9448729f5ecSAllan Jude if (e) 945d25c1ff6SBaptiste Daroussin xo_emit(","); 946d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/CRITICAL}"); 9478729f5ecSAllan Jude e++; 9488729f5ecSAllan Jude status = -1; 9498729f5ecSAllan Jude } 9508729f5ecSAllan Jude if (estat & SES_ENCSTAT_UNRECOV) { 9518729f5ecSAllan Jude if (e) 952d25c1ff6SBaptiste Daroussin xo_emit(","); 953d25c1ff6SBaptiste Daroussin xo_emit("{lq:status/UNRECOV}"); 9548729f5ecSAllan Jude e++; 9558729f5ecSAllan Jude status = -1; 9568729f5ecSAllan Jude } 9578729f5ecSAllan Jude } 958d25c1ff6SBaptiste Daroussin xo_close_instance("enclosures"); 959d25c1ff6SBaptiste Daroussin xo_emit("\n"); 9608729f5ecSAllan Jude close(fd); 9618729f5ecSAllan Jude } 9628729f5ecSAllan Jude globfree(&g); 9638729f5ecSAllan Jude 964d25c1ff6SBaptiste Daroussin xo_close_list("enclosures"); 965d25c1ff6SBaptiste Daroussin xo_close_container("sesutil"); 966d25c1ff6SBaptiste Daroussin xo_finish(); 967d25c1ff6SBaptiste Daroussin 9688729f5ecSAllan Jude if (status == 1) { 9698729f5ecSAllan Jude return (EXIT_SUCCESS); 9708729f5ecSAllan Jude } else { 9718729f5ecSAllan Jude return (EXIT_FAILURE); 9728729f5ecSAllan Jude } 973cddcb259SBaptiste Daroussin } 974cddcb259SBaptiste Daroussin 975cddcb259SBaptiste Daroussin int 976cddcb259SBaptiste Daroussin main(int argc, char **argv) 977cddcb259SBaptiste Daroussin { 9788729f5ecSAllan Jude int i, ch; 979cddcb259SBaptiste Daroussin struct command *cmd = NULL; 980cddcb259SBaptiste Daroussin 981d25c1ff6SBaptiste Daroussin argc = xo_parse_args(argc, argv); 982d25c1ff6SBaptiste Daroussin if (argc < 0) 983d25c1ff6SBaptiste Daroussin exit(1); 984d25c1ff6SBaptiste Daroussin 9858729f5ecSAllan Jude uflag = "/dev/ses[0-9]*"; 9868729f5ecSAllan Jude while ((ch = getopt_long(argc, argv, "u:", NULL, NULL)) != -1) { 9878729f5ecSAllan Jude switch (ch) { 9888729f5ecSAllan Jude case 'u': 9898729f5ecSAllan Jude uflag = optarg; 9908729f5ecSAllan Jude break; 9918729f5ecSAllan Jude case '?': 9928729f5ecSAllan Jude default: 9938729f5ecSAllan Jude usage(stderr, NULL); 9948729f5ecSAllan Jude } 9958729f5ecSAllan Jude } 9968729f5ecSAllan Jude argc -= optind; 9978729f5ecSAllan Jude argv += optind; 9988729f5ecSAllan Jude 9998729f5ecSAllan Jude if (argc < 1) { 1000cddcb259SBaptiste Daroussin warnx("Missing command"); 10018729f5ecSAllan Jude usage(stderr, NULL); 1002cddcb259SBaptiste Daroussin } 1003cddcb259SBaptiste Daroussin 1004cddcb259SBaptiste Daroussin for (i = 0; i < nbcmds; i++) { 10058729f5ecSAllan Jude if (strcmp(argv[0], cmds[i].name) == 0) { 1006cddcb259SBaptiste Daroussin cmd = &cmds[i]; 1007cddcb259SBaptiste Daroussin break; 1008cddcb259SBaptiste Daroussin } 1009cddcb259SBaptiste Daroussin } 1010cddcb259SBaptiste Daroussin 1011cddcb259SBaptiste Daroussin if (cmd == NULL) { 10128729f5ecSAllan Jude warnx("unknown command %s", argv[0]); 10138729f5ecSAllan Jude usage(stderr, NULL); 1014cddcb259SBaptiste Daroussin } 1015cddcb259SBaptiste Daroussin 1016cddcb259SBaptiste Daroussin return (cmd->exec(argc, argv)); 1017cddcb259SBaptiste Daroussin } 1018