/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* This file is getting large unexpectly, a lex & yacc */ /* implementation is expected. */ #include #include #include #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_htab.h" #include "isns_msgq.h" #include "isns_obj.h" #include "isns_func.h" #include "isns_dd.h" #include "isns_cache.h" #include "isns_pdu.h" #ifdef DEBUG /* * external variables */ extern const int NUM_OF_CHILD[MAX_OBJ_TYPE]; extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE]; extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern const int NUM_OF_REF[MAX_OBJ_TYPE_FOR_SIZE]; extern lookup_ctrl_t *setup_ddid_lcp(lookup_ctrl_t *, uint32_t); extern lookup_ctrl_t *setup_ddsid_lcp(lookup_ctrl_t *, uint32_t); /* * global variables */ int verbose_mc = 0; int verbose_tc = 0; int verbose_lock = 0; int verbose_net = 0; int verbose_parser = 0; /* * local variables */ static void print_entity(char *, isns_obj_t *); static void print_iscsi(char *, isns_obj_t *); static void print_portal(char *, isns_obj_t *); static void print_pg(char *, isns_obj_t *); static void print_dd(char *, isns_obj_t *); static void print_dds(char *, isns_obj_t *); static void (*const print_func[MAX_OBJ_TYPE])(char *, isns_obj_t *) = { NULL, &print_entity, &print_iscsi, &print_portal, &print_pg, &print_dd, &print_dds }; static int run_cmd(char *); typedef struct { uint16_t func_id; char *fname; } isnsp_fnames_t; isnsp_fnames_t fnames[] = { { ISNS_DEV_ATTR_REG, "DevAttrReg" }, { ISNS_DEV_ATTR_QRY, "DevAttrQry" }, { ISNS_DEV_GET_NEXT, "DevGetNext" }, { ISNS_DEV_DEREG, "DevDereg" }, { ISNS_SCN_REG, "SCNReg" }, { ISNS_SCN_DEREG, "SCNDereg" }, { ISNS_DD_REG, "DDReg" }, { ISNS_DD_DEREG, "DDDereg" }, { ISNS_DDS_REG, "DDSReg" }, { ISNS_DDS_DEREG, "DDSDereg" }, { ISNS_SCN, "SCN" }, { ISNS_ESI, "ESI" }, { ISNS_HEARTBEAT, "Heartbeat" }, { ISNS_DEV_ATTR_REG_RSP, "DevAttrRegRsp" }, { ISNS_DEV_ATTR_QRY_RSP, "DevAttrQryRsp" }, { ISNS_DEV_GET_NEXT_RSP, "DevGetNextRsp" }, { ISNS_DEV_DEREG_RSP, "DevDeregRsp" }, { ISNS_SCN_REG_RSP, "SCNRegRsp" }, { ISNS_SCN_DEREG_RSP, "SCNDeregRsp" }, { ISNS_SCN_RSP, "SCNRsp" }, { ISNS_ESI_RSP, "ESIRsp" }, { 0xFFFF, "Unknown" } }; static char * get_func_name( uint16_t id ) { int i = 0; isnsp_fnames_t *fp = &fnames[i ++]; while (fp->func_id != 0xFFFF) { if (fp->func_id == id) { return (fp->fname); } fp = &fnames[i ++]; } return ("UNKNOWN"); } static char * get_tlv_tag_name( uint32_t tag ) { switch (tag) { case ISNS_DELIMITER_ATTR_ID: return ("Delimiter"); case ISNS_EID_ATTR_ID: return ("Entity Identifier"); case ISNS_ENTITY_PROTOCOL_ATTR_ID: return ("Entity Protocol"); case ISNS_ENTITY_REG_PERIOD_ATTR_ID: return ("Registration Period"); case ISNS_TIMESTAMP_ATTR_ID: return ("Timestamp"); case ISNS_PORTAL_IP_ADDR_ATTR_ID: return ("Portal IP Address"); case ISNS_PORTAL_PORT_ATTR_ID: return ("Portal TCP/UDP Port"); case ISNS_PORTAL_NAME_ATTR_ID: return ("Portal Symbolic Name"); case ISNS_ESI_INTERVAL_ATTR_ID: return ("ESI Interval"); case ISNS_ESI_PORT_ATTR_ID: return ("ESI Port"); case ISNS_SCN_PORT_ATTR_ID: return ("SCN Port"); case ISNS_PORTAL_SEC_BMP_ATTR_ID: return ("Portal Security Bitmap"); case ISNS_ISCSI_NAME_ATTR_ID: return ("iSCSI Name"); case ISNS_ISCSI_NODE_TYPE_ATTR_ID: return ("iSCSI Node Type"); case ISNS_ISCSI_ALIAS_ATTR_ID: return ("iSCSI Alias"); case ISNS_ISCSI_AUTH_METHOD_ATTR_ID: return ("iSCSI Auth Method"); case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: return ("iSCSI SCN Bitmap"); case ISNS_PG_ISCSI_NAME_ATTR_ID: return ("PG iSCSI Name"); case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: return ("PG Portal IP Addr"); case ISNS_PG_PORTAL_PORT_ATTR_ID: return ("PG Portal TCP/UDP Port"); case ISNS_PG_TAG_ATTR_ID: return ("PG Tag (PGT)"); case ISNS_PG_INDEX_ATTR_ID: return ("PG Index"); case ISNS_DD_NAME_ATTR_ID: return ("DD Name"); case ISNS_DD_ID_ATTR_ID: return ("DD Index"); case ISNS_DD_ISCSI_INDEX_ATTR_ID: return ("DD ISCSI Node Index"); case ISNS_DD_ISCSI_NAME_ATTR_ID: return ("DD ISCSI Node Name"); case ISNS_DD_SET_NAME_ATTR_ID: return ("DDS Name"); case ISNS_DD_SET_ID_ATTR_ID: return ("DDS Index"); case ISNS_DD_SET_STATUS_ATTR_ID: return ("DDS Status"); default: return ("Unknown"); } } static void dump_pdu( isns_pdu_t *pdu, int flag ) { short ver, id, len, flags, xid, seq; uint8_t *payload = pdu->payload; isns_resp_t *resp; /* convert the data */ if (flag) { ver = ntohs(pdu->version); id = ntohs(pdu->func_id); len = ntohs(pdu->payload_len); flags = ntohs(pdu->flags) & 0xFFFF; xid = ntohs(pdu->xid); seq = ntohs(pdu->seq); } else { ver = pdu->version; id = pdu->func_id; len = pdu->payload_len; flags = pdu->flags & 0xFFFF; xid = pdu->xid; seq = pdu->seq; } /* print the pdu header */ printf("iSNSP Version: %d\n", ver); printf("Function ID: %s\n", get_func_name(id)); printf("PDU Length: %d\n", len); printf("Flags: %x\n", flags); printf(" %d... .... .... .... : ISNS_FLAG_CLIENT\n", ((flags & ISNS_FLAG_CLIENT) == 0) ? 0 : 1); printf(" .%d.. .... .... .... : ISNS_FLAG_SERVER\n", ((flags & ISNS_FLAG_SERVER) == 0) ? 0 : 1); printf(" ..%d. .... .... .... : ISNS_FLAG_AUTH_BLK_PRESENTED\n", ((flags & ISNS_FLAG_AUTH_BLK_PRESENTED) == 0) ? 0 : 1); printf(" ...%d .... .... .... : ISNS_FLAG_REPLACE_REG\n", ((flags & ISNS_FLAG_REPLACE_REG) == 0) ? 0 : 1); printf(" .... %d... .... .... : ISNS_FLAG_LAST_PDU\n", ((flags & ISNS_FLAG_LAST_PDU) == 0) ? 0 : 1); printf(" .... .%d.. .... .... : ISNS_FLAG_FIRST_PDU\n", ((flags & ISNS_FLAG_FIRST_PDU) == 0) ? 0 : 1); printf("Transaction ID: %d\n", xid); printf("Sequence ID: %d\n", seq); printf("Payload: ...\n"); if (id & ISNS_RSP_MASK) { resp = (isns_resp_t *)payload; printf(" ErrorCode: %d\n", ntohl(resp->status)); len -= 4; payload += 4; } /* print the payload */ while (len > 0) { isns_tlv_t *tlvp; int t, l; uint8_t *v; char *s; int i; in6_addr_t *ip; char pbuff[256] = { 0 }; tlvp = (isns_tlv_t *)payload; /* convert the data */ t = ntohl(tlvp->attr_id); l = ntohl(tlvp->attr_len); v = &(tlvp->attr_value[0]); /* print payload */ if (l > 0) { printf("%s: ", get_tlv_tag_name(t)); switch (t) { case ISNS_EID_ATTR_ID: case ISNS_ISCSI_NAME_ATTR_ID: case ISNS_ISCSI_ALIAS_ATTR_ID: case ISNS_ISCSI_AUTH_METHOD_ATTR_ID: case ISNS_PG_ISCSI_NAME_ATTR_ID: case ISNS_DD_NAME_ATTR_ID: case ISNS_DD_SET_NAME_ATTR_ID: s = (char *)v; printf("%s\n", s); break; case ISNS_ENTITY_PROTOCOL_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("%s (%d)\n", ((i == 1) ? "No Protocol" : ((i == 2) ? "iSCSI" : ((i == 3) ? "iFCP" : "Others"))), i); break; case ISNS_PORTAL_IP_ADDR_ATTR_ID: case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: ip = (in6_addr_t *)v; inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); printf("%s\n", pbuff); break; case ISNS_PORTAL_PORT_ATTR_ID: case ISNS_ESI_PORT_ATTR_ID: case ISNS_SCN_PORT_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("%d\n", (i & 0x0000FFFF)); printf(" .... .... %d... .... : " "0=TCP\n", ((i & 0x10000) == 0) ? 0 : 1); break; case ISNS_ISCSI_NODE_TYPE_ATTR_ID: i = ntohl(*(uint32_t *)v); printf("0x%x\t", i); if (i & ISNS_CONTROL_NODE_TYPE) { printf("Control "); } if (i & ISNS_INITIATOR_NODE_TYPE) { printf("Initiator "); } if (i & ISNS_TARGET_NODE_TYPE) { printf("Target "); } printf("\n"); break; case ISNS_PG_TAG_ATTR_ID: default: i = ntohl(*(uint32_t *)v); printf("%d\n", i); break; } printf(" Attribute Tag: %s (%d)\n", get_tlv_tag_name(t), t); printf(" Attribute Length: %d\n", l); } else { printf("%s: (%d)\n", get_tlv_tag_name(t), t); } len -= (sizeof (uint32_t) * 2 + l); payload += (sizeof (uint32_t) * 2 + l); } } void dump_pdu1( isns_pdu_t *pdu ) { if (verbose_net) { printf("### PDU RECEIVED ###\n"); dump_pdu(pdu, 0); } } void dump_pdu2( isns_pdu_t *pdu ) { if (verbose_net) { printf("### PDU SENT ###\n"); dump_pdu(pdu, 1); } } void dump_db( ) { #if 0 isns_list_t *list, *lista, *listb; isns_dds_t *dds; isns_dd_t *dd; isns_iscsi2_t *iscsi2; printf("### DUMP DATABASE ###\n"); /* dump dds(s) */ list = dds_list; while (list != NULL) { dds = list->obj.dds; printf("[DDS:%d]%s(%s)\n", dds->id, dds->name, dds->status ? "enabled" : "disabled"); lista = dds->dd_list; /* dd(s) that belong to this dds */ while (lista != NULL) { dd = lista->obj.dd; printf("\t[DD:%d]%s\n", dd->id, dd->name); lista = lista->next; } list = list->next; } /* dump dd(s) */ list = dd_list; while (list != NULL) { dd = list->obj.dd; printf("[DD:%d]%s\n", dd->id, dd->name); /* dds(s) this dd belongs to */ lista = dd->dds_list; while (lista != NULL) { dds = lista->obj.dds; printf("\t[DDS:%d]%s\n", dds->id, dds->name); lista = lista->next; } /* node(s) that this dd have */ listb = dd->iscsi_list; while (listb != NULL) { iscsi2 = listb->obj.iscsi2; printf("\t[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name); listb = listb->next; } list = list->next; } /* dump node(s) */ list = iscsi_list; while (list != NULL) { iscsi2 = list->obj.iscsi2; printf("[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name); lista = iscsi2->dd_list; /* dd(s) that this node belongs to */ while (lista != NULL) { dd = lista->obj.dd; printf("\t[DD:%d]%s\n", dd->id, dd->name); lista = lista->next; } list = list->next; } #endif } static void test_cli_help( ) { printf("list - list all of storage node.\n"); printf("list dd [id] - list all of dd or one with member.\n"); printf("list dds [id] - list all of dd-set or one with member.\n"); printf("\n"); printf("new dd - create a dd with name.\n"); printf("new dds - create a dd-set with name.\n"); printf("new ddn - create a dd with id and name.\n"); printf("new ddsn - create a dd-set with id and name.\n"); printf("del dd - delete a dd.\n"); printf("del dds - delete a dd-set.\n"); printf("\n"); printf("add dd - add a node to dd.\n"); printf("add ddn - add a node to dd.\n"); printf("add ddsn - add a dd to dd-set.\n"); printf("remove dd - remove a node from dd.\n"); printf("remove ddn - remove a node from dd.\n"); printf("remove ddsn - remove a dd from dd-set.\n"); printf("\n"); printf("enable - enable a dd-set.\n"); printf("disable - disable a dd-set.\n"); printf("\n"); printf("file - loading command from a file.\n"); printf("pause - suspend batch until enter key is pressed.\n"); printf("help - print this help.\n"); printf("quit - stop iSNS server and quit.\n"); } static enum { CMD_LIST, CMD_LISTNE, CMD_LISTP, CMD_LISTPG, CMD_LISTDD, CMD_LISTDDS, CMD_LISTDDN, CMD_LISTDDSN, CMD_NEWDD, CMD_NEWDDS, CMD_NEWDDN, CMD_NEWDDSN, CMD_DELDD, CMD_DELDDS, CMD_ENABLE, CMD_DISABLE, CMD_ADDDD, CMD_ADDDDN, CMD_ADDDDSN, CMD_REMDD, CMD_REMDDN, CMD_REMDDSN, CMD_VIEW, CMD_FILE, CMD_PAUSE, CMD_HELP, CMD_VERBOSE_MEMORY, CMD_VERBOSE_NET, CMD_VERBOSE_PARSER, CMD_VERBOSE_TIME, CMD_VERBOSE_LOCK, CMD_QUIT, CMD_NONE, CMD_INVALID }; static int getcmd( int *argc, int *argv, char *cmd ) { int j = 0; char tmp[256] = { 0 }; *argc = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_NONE); } else if (*cmd == '?') { return (CMD_HELP); } /* list, list dd, list dds, list dd 0 */ if (strncmp(cmd, "list ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LIST); } else if (*cmd == 'p') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTP); } } else if (*cmd == 'g') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTPG); } } else if (*cmd == 'e') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTNE); } } else if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTDDS); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_LISTDDSN); } } else if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_LISTDD); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_LISTDDN); } } return (CMD_INVALID); } /* view 0 */ if (strncmp(cmd, "view ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_VIEW); } return (CMD_INVALID); } /* add dd name */ /* add ddn/ddsn id id */ if (strncmp(cmd, "add ", 4) == 0) { int addcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; addcmd = CMD_ADDDD; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; addcmd = CMD_ADDDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; addcmd = CMD_ADDDDSN; } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; if (*cmd != 0) { switch (addcmd) { case CMD_ADDDDN: case CMD_ADDDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } break; case CMD_ADDDD: j = strlen(cmd); while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } else { return (CMD_INVALID); } break; } return (addcmd); } return (CMD_INVALID); } /* remove dd name */ /* remove ddn/ddsn id id */ if (strncmp(cmd, "remove ", 7) == 0) { int rmcmd = CMD_INVALID; cmd += 7; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDD; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; rmcmd = CMD_REMDDSN; } else { return (CMD_INVALID); } j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } while (*cmd == ' ') cmd ++; if (*cmd != 0) { switch (rmcmd) { case CMD_REMDDN: case CMD_REMDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } break; case CMD_REMDD: j = strlen(cmd); while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } else { return (CMD_INVALID); } break; } return (rmcmd); } return (CMD_INVALID); } /* new dd, new dds */ if (strncmp(cmd, "new ", 4) == 0) { int newcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; newcmd = CMD_NEWDD; } else if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; newcmd = CMD_NEWDDS; } else if (strncmp(cmd, "ddn ", 4) == 0) { cmd += 4; newcmd = CMD_NEWDDN; } else if (strncmp(cmd, "ddsn ", 5) == 0) { cmd += 5; newcmd = CMD_NEWDDSN; } if (newcmd != CMD_INVALID) { while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (newcmd); } switch (newcmd) { case CMD_NEWDDN: case CMD_NEWDDSN: j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; if (*cmd == ' ' && j > 0) { argv[(*argc)++] = atoi(tmp); } else { return (CMD_INVALID); } case CMD_NEWDD: case CMD_NEWDDS: while (*cmd == ' ') cmd ++; if (*cmd != 0) { j = strlen(cmd); } else { j = 0; } while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; } } return (newcmd); } return (CMD_INVALID); } /* del dd, del dds, disable 0 */ if (strncmp(cmd, "del ", 4) == 0) { int delcmd = CMD_INVALID; cmd += 4; while (*cmd == ' ') cmd ++; if (strncmp(cmd, "dds ", 4) == 0) { cmd += 4; delcmd = CMD_DELDDS; } else if (strncmp(cmd, "dd ", 3) == 0) { cmd += 3; delcmd = CMD_DELDD; } if (delcmd != CMD_INVALID) { while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (delcmd); } } return (CMD_INVALID); } /* enable 0 */ if (strncmp(cmd, "enable ", 7) == 0) { cmd += 7; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_ENABLE); } return (CMD_INVALID); } /* disable 0 */ if (strncmp(cmd, "disable ", 8) == 0) { cmd += 8; while (*cmd == ' ') cmd ++; j = 0; while (*cmd >= '0' && *cmd <= '9') { tmp[j++] = *cmd ++; } tmp[j] = 0; while (*cmd == ' ') cmd ++; if (*cmd == 0 && j > 0) { argv[(*argc)++] = atoi(tmp); return (CMD_DISABLE); } return (CMD_INVALID); } /* file */ if (strncmp(cmd, "file ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd != 0) { j = strlen(cmd); } else { j = 0; } while (j > 0) { /* get rid of trail blank space */ if (cmd[j - 1] == ' ') { cmd[--j] = 0; } else { break; } } if (j > 0) { cmd[j] = 0; argv[(*argc)++] = (int)cmd; return (CMD_FILE); } return (CMD_INVALID); } /* pause */ if (strncmp(cmd, "pause ", 6) == 0) { cmd += 6; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_PAUSE); } return (CMD_INVALID); } /* help */ if (strncmp(cmd, "help ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_HELP); } return (CMD_INVALID); } /* verbose */ if (strncmp(cmd, "verbose ", 8) == 0) { cmd += 8; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_PARSER); } else if (*cmd == 'm') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_MEMORY); } } else if (*cmd == 'n') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_NET); } } else if (*cmd == 'p') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_PARSER); } } else if (*cmd == 't') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_TIME); } } else if (*cmd == 'l') { cmd ++; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_VERBOSE_LOCK); } } return (CMD_INVALID); } /* quit */ if (strncmp(cmd, "quit ", 5) == 0) { cmd += 5; while (*cmd == ' ') cmd ++; if (*cmd == 0) { return (CMD_QUIT); } return (CMD_INVALID); } return (CMD_INVALID); } static void print_entity( char *ident, isns_obj_t *obj ) { uint32_t uid; uchar_t *eid; uint32_t *cuid; int i, num; eid = obj->attrs[ ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)].value.ptr; uid = get_obj_uid(obj); if (ident != NULL) { printf("%s%d\t%s\n", ident, uid, (const char *)eid); } else { printf("%d\t%s\n", uid, (const char *)eid); } i = 0; while (i < NUM_OF_CHILD[obj->type]) { cuid = get_child_n(obj, i); if (ident != NULL) { printf("%s\t%s%d:", "child", i); } else { printf("\t%s%d:", "child", i); } if (cuid != NULL) { num = *cuid ++; } else { num = 0; } while (num > 0) { printf("\t%d", *cuid ++); num --; } printf("\n"); i ++; } } static void print_iscsi( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)] .value.ptr; uchar_t *alias = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)] .value.ptr; uint32_t type = obj->attrs[ ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); if (!alias) { alias = (uchar_t *)"-"; } if (ident != NULL) { printf("%s%d[%d]\t%s\n", ident, uid, puid, (const char *)name); printf("%s\t%s", ident, alias); } else { printf("%d[%d]\t%s\n", uid, puid, (const char *)name); printf("\t%s", alias); } if (IS_TYPE_TARGET(type)) { printf("\tTarget"); } if (IS_TYPE_INITIATOR(type)) { printf("\tInitiator"); } if (IS_TYPE_CONTROL(type)) { printf("\tControl"); } if (IS_TYPE_UNKNOWN(type)) { printf("\t-"); } printf("\n"); } static void print_portal( char *ident, isns_obj_t *obj ) { char pbuff[256] = { 0 }; in6_addr_t *ip = obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)].value.ip; uint32_t port = obj->attrs[ ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); if (ident != NULL) { printf("%s%d[%d]\t%s:%d", ident, uid, puid, pbuff, PORT_NUMBER(port)); } else { printf("%d[%d]\t%s:%d", uid, puid, pbuff, PORT_NUMBER(port)); } printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP"); } static void print_pg( char *ident, isns_obj_t *obj ) { uint32_t ref; int i; char pbuff[256] = { 0 }; uchar_t *name = obj->attrs[ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID)] .value.ptr; in6_addr_t *ip = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)].value.ip; uint32_t port = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID)].value.ui; uint32_t tag = obj->attrs[ ATTR_INDEX_PG(ISNS_PG_TAG_ATTR_ID)].value.ui; uint32_t uid = get_obj_uid(obj); uint32_t puid = get_parent_uid(obj); inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff)); if (ident != NULL) { printf("%s%d[%d]\t[%d] %s\n", ident, uid, puid, tag, (const char *)name); printf("%s\t%s:%d", ident, pbuff, PORT_NUMBER(port)); } else { printf("%d[%d]\t[%d] %s\n", uid, puid, tag, (const char *)name); printf("\t%s:%d", pbuff, PORT_NUMBER(port)); } printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP"); if (NUM_OF_REF[obj->type] > 0) { if (ident != NULL) { printf("%s\t%s:", "ref"); } else { printf("\t%s:", "ref"); } } i = 0; while (i < NUM_OF_REF[obj->type]) { ref = get_ref_n(obj, i); printf("\t%d", ref); i ++; } if (i > 0) { printf("\n"); } } static void print_dd( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)] .value.ptr; uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DD]].value.ui; if (ident != NULL) { printf("%s%d\t%s\n", ident, uid, (const char *)name); } else { printf("%d\t%s\n", uid, (const char *)name); } } static void print_dds( char *ident, isns_obj_t *obj ) { uchar_t *name = obj->attrs[ATTR_INDEX_DDS( ISNS_DD_SET_NAME_ATTR_ID)].value.ptr; uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DDS]].value.ui; uint32_t enabled = obj->attrs[ATTR_INDEX_DDS( ISNS_DD_SET_STATUS_ATTR_ID)].value.ui; if (ident != NULL) { printf("%s%d\t%s\t\t(%s)\n", ident, uid, (const char *)name, enabled ? "enabled" : "disabled"); } else { printf("%d\t%s\t\t(%s)\n", uid, (const char *)name, enabled ? "enabled" : "disabled"); } } void print_object( char *ident, isns_obj_t *obj ) { print_func[obj->type](ident, obj); } /*ARGSUSED*/ static int cb_print_obj_n( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; print_func[obj->type](NULL, obj); return (0); } static void list_pg( ) { cache_dump_htab(OBJ_PG); } static void list_portal( ) { cache_dump_htab(OBJ_PORTAL); } static void list_node( ) { cache_dump_htab(OBJ_ISCSI); } static void list_entity( ) { cache_dump_htab(OBJ_ENTITY); } static void list_dd( ) { cache_dump_htab(OBJ_DD); } static void list_ddn( uint32_t uid ) { lookup_ctrl_t lc; bmp_t *p; uint32_t n; if (uid != 0) { setup_ddid_lcp(&lc, uid); cache_lookup(&lc, &uid, cb_print_obj_n); } if (uid != 0) { printf("--------------------------------\n"); get_dd_matrix(uid, &p, &n); SET_UID_LCP(&lc, OBJ_ISCSI, 0); FOR_EACH_MEMBER(p, n, uid, { lc.data[0].ui = uid; cache_lookup(&lc, NULL, cb_print_obj_n); }); free(p); } else { printf("no such dd.\n"); } } static void list_ddsn( uint32_t uid ) { lookup_ctrl_t lc; bmp_t *p; uint32_t n; if (uid != 0) { setup_ddsid_lcp(&lc, uid); cache_lookup(&lc, &uid, cb_print_obj_n); } if (uid != 0) { printf("--------------------------------\n"); get_dds_matrix(uid, &p, &n); SET_UID_LCP(&lc, OBJ_DD, 0); FOR_EACH_MEMBER(p, n, uid, { lc.data[0].ui = uid; cache_lookup(&lc, NULL, cb_print_obj_n); }); free(p); } else { printf("no such dd-set.\n"); } } static void list_dds( ) { cache_dump_htab(OBJ_DDS); } static void new_dd_dds( int cmd_id, int argc, int *argv ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; int len = 0; uint32_t uid = 0; char *name; conn_arg_t conn; pdu->version = ISNSP_VERSION; /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload += 8 + 32; payload_len += 8 + 32; /* key attributes */ /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload += 8 + 0; payload_len += 8 + 0; /* operating attributes */ switch (cmd_id) { case CMD_NEWDD: pdu->func_id = ISNS_DD_REG; if (argc == 1) { name = (char *)argv[0]; len = strlen(name) + 1; len += 4 - (len % 4); } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; break; case CMD_NEWDDS: pdu->func_id = ISNS_DDS_REG; if (argc == 1) { name = (char *)argv[0]; len = strlen(name) + 1; len += 4 - (len % 4); } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; break; case CMD_NEWDDN: pdu->func_id = ISNS_DD_REG; switch (argc) { case 2: name = (char *)argv[1]; len = strlen(name) + 1; len += 4 - (len % 4); case 1: uid = argv[0]; } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload += 8 + len; payload_len += 8 + len; if (uid > 0) { tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; } break; case CMD_NEWDDSN: pdu->func_id = ISNS_DDS_REG; switch (argc) { case 2: name = (char *)argv[1]; len = strlen(name) + 1; len += 4 - (len % 4); case 1: uid = argv[0]; } tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID); tlv->attr_len = htonl(len); if (len > 0) { strcpy((char *)tlv->attr_value, name); } payload_len += 8 + len; payload += 8 + len; if (uid > 0) { tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; } break; default: break; } pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void del_dd_dds( int cmd_id, int uid ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; uint32_t tag; conn_arg_t conn; if (uid == 0) { return; } pdu->version = ISNSP_VERSION; if (cmd_id == CMD_DELDD) { tag = ISNS_DD_ID_ATTR_ID; pdu->func_id = ISNS_DD_DEREG; } else { tag = ISNS_DD_SET_ID_ATTR_ID; pdu->func_id = ISNS_DDS_DEREG; } /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(tag); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void update_dds( int cmd_id, int uid ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; conn_arg_t conn; if (uid == 0) { return; } pdu->version = ISNSP_VERSION; pdu->func_id = ISNS_DDS_REG; /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DD_SET_STATUS_ATTR_ID); tlv->attr_len = htonl(4); if (cmd_id == CMD_ENABLE) { *(uint32_t *)tlv->attr_value = htonl(1); } else { *(uint32_t *)tlv->attr_value = htonl(0); } payload_len += 8 + 4; pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void update_member( int cmd_id, int *argv ) { uint32_t buff[256]; isns_pdu_t *pdu = (isns_pdu_t *)buff; uint8_t *payload = &pdu->payload[0]; uint16_t payload_len = 0; isns_tlv_t *tlv; uint32_t key_tag, op_tag, op_len; uint32_t uid = argv[0]; uint32_t m_id; char *m_name; conn_arg_t conn; if (uid == 0) { printf("operation failed.\n"); return; } pdu->version = ISNSP_VERSION; switch (cmd_id) { case CMD_ADDDD: case CMD_ADDDDN: pdu->func_id = ISNS_DD_REG; break; case CMD_REMDD: case CMD_REMDDN: pdu->func_id = ISNS_DD_DEREG; break; case CMD_ADDDDSN: pdu->func_id = ISNS_DDS_REG; break; case CMD_REMDDSN: pdu->func_id = ISNS_DDS_DEREG; break; } switch (cmd_id) { case CMD_ADDDD: case CMD_REMDD: key_tag = ISNS_DD_ID_ATTR_ID; op_tag = ISNS_DD_ISCSI_NAME_ATTR_ID; m_name = (char *)argv[1]; op_len = strlen(m_name); op_len += 4 - (op_len % 4); break; case CMD_ADDDDN: case CMD_REMDDN: key_tag = ISNS_DD_ID_ATTR_ID; op_tag = ISNS_DD_ISCSI_INDEX_ATTR_ID; m_id = argv[1]; op_len = 4; break; case CMD_ADDDDSN: case CMD_REMDDSN: key_tag = ISNS_DD_SET_ID_ATTR_ID; op_tag = ISNS_DD_ID_ATTR_ID; m_id = argv[1]; op_len = 4; break; } /* source attribute */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID); tlv->attr_len = htonl(32); strcpy((char *)tlv->attr_value, "i am a control node."); payload_len += 8 + 32; payload += 8 + 32; /* key attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(key_tag); tlv->attr_len = htonl(4); *(uint32_t *)tlv->attr_value = htonl(uid); payload_len += 8 + 4; payload += 8 + 4; /* delimiter */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID); tlv->attr_len = htonl(0); payload_len += 8 + 0; payload += 8 + 0; /* operating attributes */ tlv = (isns_tlv_t *)payload; tlv->attr_id = htonl(op_tag); tlv->attr_len = htonl(op_len); switch (cmd_id) { case CMD_ADDDD: case CMD_REMDD: strcpy((char *)tlv->attr_value, m_name); break; case CMD_ADDDDN: case CMD_ADDDDSN: case CMD_REMDDN: case CMD_REMDDSN: *(uint32_t *)tlv->attr_value = htonl(m_id); break; } payload_len += 8 + op_len; pdu->payload_len = payload_len; dump_pdu1(pdu); conn.in_packet.pdu = pdu; conn.out_packet.pdu = NULL; conn.out_packet.sz = 0; if (packet_split_verify(&conn) == 0) { cache_lock(conn.lock); conn.handler(&conn); conn.ec = cache_unlock(conn.lock, conn.ec); } if (conn.out_packet.pdu != NULL) { pdu_update_code(conn.out_packet.pdu, &conn.out_packet.pl, conn.ec); dump_pdu2(conn.out_packet.pdu); free(conn.out_packet.pdu); } else if (conn.ec != 0) { printf("operation failed[%d].\n", conn.ec); } } static void cmd_file( char *file ) { char i = 0, ch, cmd[256]; FILE *f = fopen(file, "r"); if (f != NULL) { while ((ch = fgetc(f)) != 0 && ch != EOF) { if (ch == '\t') { cmd[i++] = ' '; } else if (ch != '\n') { cmd[i++] = ch; } else { cmd[i ++] = ' '; cmd[i] = 0; i = 0; printf("%s\n", cmd); if (run_cmd(cmd) != 0) { break; } } } fclose(f); } else { printf("Cannot open file %s.\n", file); } } static int run_cmd( char *cmd ) { int argc, argv[32]; int cmd_id; cmd_id = getcmd(&argc, argv, cmd); switch (cmd_id) { case CMD_LIST: list_node(); break; case CMD_LISTNE: list_entity(); break; case CMD_LISTP: list_portal(); break; case CMD_LISTPG: list_pg(); break; case CMD_LISTDD: list_dd(); break; case CMD_LISTDDS: list_dds(); break; case CMD_LISTDDN: list_ddn(argv[0]); break; case CMD_LISTDDSN: list_ddsn(argv[0]); break; case CMD_NEWDD: case CMD_NEWDDS: case CMD_NEWDDN: case CMD_NEWDDSN: new_dd_dds(cmd_id, argc, argv); break; case CMD_DELDD: case CMD_DELDDS: del_dd_dds(cmd_id, argv[0]); break; case CMD_ENABLE: case CMD_DISABLE: update_dds(cmd_id, argv[0]); break; case CMD_ADDDD: case CMD_ADDDDN: case CMD_ADDDDSN: case CMD_REMDD: case CMD_REMDDN: case CMD_REMDDSN: update_member(cmd_id, argv); break; case CMD_PAUSE: printf("Press enter to continue..."); getchar(); break; case CMD_FILE: cmd_file((char *)argv[0]); break; case CMD_HELP: test_cli_help(); break; case CMD_VERBOSE_MEMORY: verbose_mc = !verbose_mc; break; case CMD_VERBOSE_NET: verbose_net = !verbose_net; break; case CMD_VERBOSE_TIME: verbose_tc = !verbose_tc; break; case CMD_VERBOSE_LOCK: verbose_lock = !verbose_lock; break; case CMD_VERBOSE_PARSER: verbose_parser = !verbose_parser; break; case CMD_QUIT: /* clean up cli */ /* notify sys control */ shutdown_server(); return (1); case CMD_NONE: break; default: printf("invalid command\n"); break; } if (cmd_id != CMD_NONE) { printf("\n>"); } else { printf(">"); } return (0); } /*ARGSUSED*/ void *cli_test(void *arg) { char i = 0, ch, cmd[256]; printf("iSNS Server test CLI.\n"); printf("Copyright 2007 Sun Microsystems, Inc.\n"); printf("\n>"); while ((ch = getchar()) != 0 && ch != EOF) { if (ch == '\t') { cmd[i++] = ' '; } else if (ch != '\n') { cmd[i++] = ch; } else { cmd[i ++] = ' '; cmd[i] = 0; i = 0; if (run_cmd(cmd) != 0) { break; } } } return (NULL); } #endif