/* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const struct valstr sunoem_led_type_vals[] = { { 0, "OK2RM" }, { 1, "SERVICE" }, { 2, "ACT" }, { 3, "LOCATE" }, { 0xFF, NULL }, }; static const struct valstr sunoem_led_mode_vals[] = { { 0, "OFF" }, { 1, "ON" }, { 2, "STANDBY" }, { 3, "SLOW" }, { 4, "FAST" }, { 0xFF, NULL }, }; static const struct valstr sunoem_led_mode_optvals[] = { { 0, "STEADY_OFF" }, { 1, "STEADY_ON" }, { 2, "STANDBY_BLINK" }, { 3, "SLOW_BLINK" }, { 4, "FAST_BLINK" }, { 0xFF, NULL }, }; int is_sbcmd = 0; static void ipmi_sunoem_usage(void) { lprintf(LOG_NOTICE, "usage: sunoem [option...]"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " fan speed <0-100>"); lprintf(LOG_NOTICE, " Set system fan speed (PWM duty cycle)"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " sshkey set "); lprintf(LOG_NOTICE, " Set ssh key for a userid into authorized_keys,"); lprintf(LOG_NOTICE, " view users with 'user list' command."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " sshkey del "); lprintf(LOG_NOTICE, " Delete ssh key for userid from authorized_keys,"); lprintf(LOG_NOTICE, " view users with 'user list' command."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " led get [ledtype]"); lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " led set [ledtype]"); lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " sbled get [ledtype]"); lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator"); lprintf(LOG_NOTICE, " for Sun Blade Modular Systems."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " sbled set [ledtype]"); lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator"); lprintf(LOG_NOTICE, " for Sun Blade Modular Systems."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " Use 'sdr list generic' command to get list of Generic"); lprintf(LOG_NOTICE, " Devices that are controllable LEDs."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " Required SIS LED Mode:"); lprintf(LOG_NOTICE, " OFF Off"); lprintf(LOG_NOTICE, " ON Steady On"); lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate"); lprintf(LOG_NOTICE, " SLOW 1HZ blink rate"); lprintf(LOG_NOTICE, " FAST 4HZ blink rate"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " Optional SIS LED Type:"); lprintf(LOG_NOTICE, " OK2RM OK to Remove"); lprintf(LOG_NOTICE, " SERVICE Service Required"); lprintf(LOG_NOTICE, " ACT Activity"); lprintf(LOG_NOTICE, " LOCATE Locate"); lprintf(LOG_NOTICE, ""); } /* * IPMI Request Data: 1 byte * * [byte 0] FanSpeed Fan speed as percentage */ static int ipmi_sunoem_fan_speed(struct ipmi_intf * intf, uint8_t speed) { struct ipmi_rs * rsp; struct ipmi_rq req; /* * sunoem fan speed */ if (speed > 100) { lprintf(LOG_NOTICE, "Invalid fan speed: %d", speed); return -1; } req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SET_FAN_SPEED; req.msg.data = &speed; req.msg.data_len = 1; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed"); return -1; } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed: %s", val2str(rsp->ccode, completion_code_vals)); return -1; } printf("Set Fan speed to %d%%\n", speed); return 0; } static void __sdr_list_empty(struct sdr_record_list * head) { struct sdr_record_list * e, * f; for (e = head; e != NULL; e = f) { f = e->next; free(e); e = NULL; } head = NULL; } static void led_print(const char * name, uint8_t state) { if (csv_output) printf("%s,%s\n", name, val2str(state, sunoem_led_mode_vals)); else printf("%-16s | %s\n", name, val2str(state, sunoem_led_mode_vals)); } struct ipmi_rs * sunoem_led_get(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev, int ledtype) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t rqdata[7]; int rqdata_len = 5; if (dev == NULL) return NULL; rqdata[0] = dev->dev_slave_addr; if (ledtype == 0xFF) rqdata[1] = dev->oem; else rqdata[1] = ledtype; rqdata[2] = dev->dev_access_addr; rqdata[3] = dev->oem; if (is_sbcmd) { rqdata[4] = dev->entity.id; rqdata[5] = dev->entity.instance; rqdata[6] = 0; rqdata_len = 7; } else { rqdata[4] = 0; } req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_LED_GET; req.msg.lun = dev->lun; req.msg.data = rqdata; req.msg.data_len = rqdata_len; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM Get LED command failed"); return NULL; } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Sun OEM Get LED command failed: %s", val2str(rsp->ccode, completion_code_vals)); return NULL; } return rsp; } struct ipmi_rs * sunoem_led_set(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev, int ledtype, int ledmode) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t rqdata[9]; int rqdata_len = 7; if (dev == NULL) return NULL; rqdata[0] = dev->dev_slave_addr; if (ledtype == 0xFF) rqdata[1] = dev->oem; else rqdata[1] = ledtype; rqdata[2] = dev->dev_access_addr; rqdata[3] = dev->oem; rqdata[4] = ledmode; if (is_sbcmd) { rqdata[5] = dev->entity.id; rqdata[6] = dev->entity.instance; rqdata[7] = 0; rqdata[8] = 0; rqdata_len = 9; } else { rqdata[5] = 0; rqdata[6] = 0; } req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_LED_SET; req.msg.lun = dev->lun; req.msg.data = rqdata; req.msg.data_len = rqdata_len; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM Set LED command failed"); return NULL; } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s", val2str(rsp->ccode, completion_code_vals)); return NULL; } return rsp; } static void sunoem_led_get_byentity(struct ipmi_intf * intf, uint8_t entity_id, uint8_t entity_inst, int ledtype) { struct ipmi_rs * rsp; struct sdr_record_list *elist, *e; struct entity_id entity; if (entity_id == 0) return; /* lookup sdrs with this entity */ memset(&entity, 0, sizeof(struct entity_id)); entity.id = entity_id; entity.instance = entity_inst; elist = ipmi_sdr_find_sdr_byentity(intf, &entity); /* for each generic sensor set its led state */ for (e = elist; e != NULL; e = e->next) { if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; rsp = sunoem_led_get(intf, e->record.genloc, ledtype); if (rsp && rsp->data_len == 1) { led_print((const char *)e->record.genloc->id_string, rsp->data[0]); } } __sdr_list_empty(elist); } static void sunoem_led_set_byentity(struct ipmi_intf * intf, uint8_t entity_id, uint8_t entity_inst, int ledtype, int ledmode) { struct ipmi_rs * rsp; struct sdr_record_list *elist, *e; struct entity_id entity; if (entity_id == 0) return; /* lookup sdrs with this entity */ memset(&entity, 0, sizeof(struct entity_id)); entity.id = entity_id; entity.instance = entity_inst; elist = ipmi_sdr_find_sdr_byentity(intf, &entity); /* for each generic sensor set its led state */ for (e = elist; e != NULL; e = e->next) { if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; rsp = sunoem_led_set(intf, e->record.genloc, ledtype, ledmode); if (rsp && rsp->data_len == 0) { led_print((const char *)e->record.genloc->id_string, ledmode); } } __sdr_list_empty(elist); } /* * IPMI Request Data: 5 bytes * * [byte 0] devAddr Value from the "Device Slave Address" field in * LED's Generic Device Locator record in the SDR * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE * [byte 2] ctrlrAddr Controller address; value from the "Device * Access Address" field, 0x20 if the LED is local * [byte 3] hwInfo The OEM field from the SDR record * [byte 4] force 1 = directly access the device * 0 = go thru its controller * Ignored if LED is local * * The format below is for Sun Blade Modular systems only * [byte 4] entityID The entityID field from the SDR record * [byte 5] entityIns The entityIns field from the SDR record * [byte 6] force 1 = directly access the device * 0 = go thru its controller * Ignored if LED is local */ static int ipmi_sunoem_led_get(struct ipmi_intf * intf, int argc, char ** argv) { struct ipmi_rs * rsp; struct sdr_record_list *sdr; struct sdr_record_list *alist, *a; struct sdr_record_entity_assoc *assoc; int ledtype = 0xFF; int i; /* * sunoem led/sbled get [type] */ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ipmi_sunoem_usage(); return 0; } if (argc > 1) { ledtype = str2val(argv[1], sunoem_led_type_vals); if (ledtype == 0xFF) lprintf(LOG_ERR, "Unknow ledtype, will use data from the SDR oem field"); } if (strncasecmp(argv[0], "all", 3) == 0) { /* do all generic sensors */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; if (a->record.genloc->entity.logical) continue; rsp = sunoem_led_get(intf, a->record.genloc, ledtype); if (rsp && rsp->data_len == 1) { led_print((const char *)a->record.genloc->id_string, rsp->data[0]); } } __sdr_list_empty(alist); return 0; } /* look up generic device locator record in SDR */ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]); if (sdr == NULL) { lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); return -1; } if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type); return -1; } if (!sdr->record.genloc->entity.logical) { /* * handle physical entity */ rsp = sunoem_led_get(intf, sdr->record.genloc, ledtype); if (rsp && rsp->data_len == 1) { led_print((const char *)sdr->record.genloc->id_string, rsp->data[0]); } return 0; } /* * handle logical entity for LED grouping */ lprintf(LOG_INFO, "LED %s is logical device", argv[0]); /* get entity assoc records */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC) continue; assoc = a->record.entassoc; if (assoc == NULL) continue; /* check that the entity id/instance matches our generic record */ if (assoc->entity.id != sdr->record.genloc->entity.id || assoc->entity.instance != sdr->record.genloc->entity.instance) continue; if (assoc->flags.isrange) { /* * handle ranged entity associations * * the test for non-zero entity id is handled in * sunoem_led_get_byentity() */ /* first range set - id 1 and 2 must be equal */ if (assoc->entity_id_1 == assoc->entity_id_2) for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) sunoem_led_get_byentity(intf, assoc->entity_id_1, i, ledtype); /* second range set - id 3 and 4 must be equal */ if (assoc->entity_id_3 == assoc->entity_id_4) for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) sunoem_led_get_byentity(intf, assoc->entity_id_3, i, ledtype); } else { /* * handle entity list */ sunoem_led_get_byentity(intf, assoc->entity_id_1, assoc->entity_inst_1, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_2, assoc->entity_inst_2, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_3, assoc->entity_inst_3, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_4, assoc->entity_inst_4, ledtype); } } __sdr_list_empty(alist); return 0; } /* * IPMI Request Data: 7 bytes * * [byte 0] devAddr Value from the "Device Slave Address" field in * LED's Generic Device Locator record in the SDR * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE * [byte 2] ctrlrAddr Controller address; value from the "Device * Access Address" field, 0x20 if the LED is local * [byte 3] hwInfo The OEM field from the SDR record * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST * [byte 5] force TRUE - directly access the device * FALSE - go thru its controller * Ignored if LED is local * [byte 6] role Used by BMC for authorization purposes * * The format below is for Sun Blade Modular systems only * [byte 5] entityID The entityID field from the SDR record * [byte 6] entityIns The entityIns field from the SDR record * [byte 7] force TRUE - directly access the device * FALSE - go thru its controller * Ignored if LED is local * [byte 8] role Used by BMC for authorization purposes * * * IPMI Response Data: 1 byte * * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST */ static int ipmi_sunoem_led_set(struct ipmi_intf * intf, int argc, char ** argv) { struct ipmi_rs * rsp; struct sdr_record_list *sdr; struct sdr_record_list *alist, *a; struct sdr_record_entity_assoc *assoc; int ledmode; int ledtype = 0xFF; int i; /* * sunoem led/sbled set [type] */ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) { ipmi_sunoem_usage(); return 0; } ledmode = str2val(argv[1], sunoem_led_mode_vals); if (ledmode == 0xFF) { ledmode = str2val(argv[1], sunoem_led_mode_optvals); if (ledmode == 0xFF) { lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]); return -1; } } if (argc > 3) { ledtype = str2val(argv[2], sunoem_led_type_vals); if (ledtype == 0xFF) lprintf(LOG_ERR, "Unknow ledtype, will use data from the SDR oem field"); } if (strncasecmp(argv[0], "all", 3) == 0) { /* do all generic sensors */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; if (a->record.genloc->entity.logical) continue; rsp = sunoem_led_set(intf, a->record.genloc, ledtype, ledmode); if (rsp && rsp->ccode == 0) { led_print((const char *)a->record.genloc->id_string, ledmode); } } __sdr_list_empty(alist); return 0; } /* look up generic device locator records in SDR */ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]); if (sdr == NULL) { lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); return -1; } if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type); return -1; } if (!sdr->record.genloc->entity.logical) { /* * handle physical entity */ rsp = sunoem_led_set(intf, sdr->record.genloc, ledtype, ledmode); if (rsp && rsp->ccode == 0) { led_print(argv[0], ledmode); } return 0; } /* * handle logical entity for LED grouping */ lprintf(LOG_INFO, "LED %s is logical device", argv[0]); /* get entity assoc records */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC) continue; assoc = a->record.entassoc; if (assoc == NULL) continue; /* check that the entity id/instance matches our generic record */ if (assoc->entity.id != sdr->record.genloc->entity.id || assoc->entity.instance != sdr->record.genloc->entity.instance) continue; if (assoc->flags.isrange) { /* * handle ranged entity associations * * the test for non-zero entity id is handled in * sunoem_led_get_byentity() */ /* first range set - id 1 and 2 must be equal */ if (assoc->entity_id_1 == assoc->entity_id_2) for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) sunoem_led_set_byentity(intf, assoc->entity_id_1, i, ledtype, ledmode); /* second range set - id 3 and 4 must be equal */ if (assoc->entity_id_3 == assoc->entity_id_4) for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) sunoem_led_set_byentity(intf, assoc->entity_id_3, i, ledtype, ledmode); } else { /* * handle entity list */ sunoem_led_set_byentity(intf, assoc->entity_id_1, assoc->entity_inst_1, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_2, assoc->entity_inst_2, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_3, assoc->entity_inst_3, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_4, assoc->entity_inst_4, ledtype, ledmode); } } __sdr_list_empty(alist); return 0; } static int ipmi_sunoem_sshkey_del(struct ipmi_intf * intf, uint8_t uid) { struct ipmi_rs * rsp; struct ipmi_rq req; memset(&req, 0, sizeof(struct ipmi_rq)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY; req.msg.data = &uid; req.msg.data_len = 1; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid); return -1; } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid, val2str(rsp->ccode, completion_code_vals)); return -1; } printf("Deleted SSH key for user id %d\n", uid); return 0; } #define SSHKEY_BLOCK_SIZE 64 static int ipmi_sunoem_sshkey_set(struct ipmi_intf * intf, uint8_t uid, char * ifile) { struct ipmi_rs * rsp; struct ipmi_rq req; FILE * fp; int count; uint16_t i_size, r, size; uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3]; if (ifile == NULL) { lprintf(LOG_ERR, "Invalid or misisng input filename"); return -1; } fp = ipmi_open_file_read(ifile); if (fp == NULL) { lprintf(LOG_ERR, "Unable to open file %s for reading", ifile); return -1; } printf("Setting SSH key for user id %d...", uid); memset(&req, 0, sizeof(struct ipmi_rq)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY; req.msg.data = wbuf; fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); for (r = 0; r < size; r += i_size) { i_size = size - r; if (i_size > SSHKEY_BLOCK_SIZE) i_size = SSHKEY_BLOCK_SIZE; memset(wbuf, 0, SSHKEY_BLOCK_SIZE); if (-1 == fseek(fp, r, SEEK_SET)) { lprintf(LOG_ERR, "Seek error %s. %s", ifile, strerror(errno)); return -1; } count = fread(wbuf+3, 1, i_size, fp); if (count != i_size) { lprintf(LOG_ERR, "Unable to read %d bytes from file %s", i_size, ifile); fclose(fp); return -1; } printf("."); fflush(stdout); wbuf[0] = uid; if ((r + SSHKEY_BLOCK_SIZE) >= size) wbuf[1] = 0xff; else wbuf[1] = (uint8_t)(r / SSHKEY_BLOCK_SIZE); wbuf[2] = i_size; req.msg.data_len = i_size + 3; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Unable to set ssh key for UID %d", uid); break; } } printf("done\n"); fclose(fp); return 0; } int ipmi_sunoem_main(struct ipmi_intf * intf, int argc, char ** argv) { int rc = (-1); if (argc == 0 || strncmp(argv[0], "help", 4) == 0) { ipmi_sunoem_usage(); return 0; } if (strncmp(argv[0], "fan", 3) == 0) { if (argc == 3 && strncmp(argv[1], "speed", 5) == 0) { uint8_t pct = 0; if (str2uchar(argv[2], &pct) != 0 || pct > 100) { lprintf(LOG_ERR, "Fan speed is limited to range <0..100>."); return (-1); } rc = ipmi_sunoem_fan_speed(intf, pct); } else { ipmi_sunoem_usage(); return (-1); } } else if ((strncmp(argv[0], "led", 3) == 0) || (strncmp(argv[0], "sbled", 5) == 0)) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } if (strncmp(argv[0], "sbled", 5) == 0) { is_sbcmd = 1; } if (strncmp(argv[1], "get", 3) == 0) { if (argc < 3) { char * arg[] = { "all" }; rc = ipmi_sunoem_led_get(intf, 1, arg); } else { rc = ipmi_sunoem_led_get(intf, argc-2, &(argv[2])); } } else if (strncmp(argv[1], "set", 3) == 0) { if (argc < 4) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_led_set(intf, argc-2, &(argv[2])); } else { ipmi_sunoem_usage(); return (-1); } } else if (strncmp(argv[0], "sshkey", 6) == 0) { uint8_t uid = 0; if (argc < 3) { ipmi_sunoem_usage(); return (-1); } if (str2uchar(argv[2], &uid) != 0 || uid < 1 || uid > 63) { lprintf(LOG_ERR, "User ID is limited to range <1..63>."); return (-1); } if (strncmp(argv[1], "del", 3) == 0) { rc = ipmi_sunoem_sshkey_del(intf, uid); } else if (argc == 4 && strncmp(argv[1], "set", 3) == 0) { rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]); } else { ipmi_sunoem_usage(); return (-1); } } else { ipmi_sunoem_usage(); return (-1); } return rc; }