1 /* $OpenBSD: parser.c,v 1.3 2014/04/21 17:44:47 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/socket.h> 23 #include <sys/uio.h> 24 #include <netinet/in.h> 25 #include <err.h> 26 #include <errno.h> 27 #include <event.h> 28 #include <limits.h> 29 #include <netdb.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "iscsid.h" 36 #include "iscsictl.h" 37 38 enum token_type { 39 NOTOKEN, 40 ENDTOKEN, 41 KEYWORD, 42 ADDRESS, 43 NAME, 44 FLAG 45 }; 46 47 struct token { 48 enum token_type type; 49 const char *keyword; 50 int value; 51 const struct token *next; 52 }; 53 54 static const struct token t_main[]; 55 static const struct token t_show[]; 56 static const struct token t_log[]; 57 static const struct token t_discovery[]; 58 static const struct token t_session[]; 59 static const struct token t_vscsi[]; 60 61 static const struct token t_main[] = { 62 {KEYWORD, "reload", RELOAD, NULL}, 63 {KEYWORD, "discover", DISCOVERY, t_discovery}, 64 {KEYWORD, "show", SHOW_SUM, t_show}, 65 {KEYWORD, "log", NONE, t_log}, 66 {ENDTOKEN, "", NONE, NULL} 67 }; 68 69 static const struct token t_show[] = { 70 {NOTOKEN, "", NONE, NULL}, 71 {KEYWORD, "summary", SHOW_SUM, NULL}, 72 {KEYWORD, "session", SHOW_SESS, t_session}, 73 {KEYWORD, "vscsi", NONE, t_vscsi}, 74 {ENDTOKEN, "", NONE, NULL} 75 }; 76 77 static const struct token t_log[] = { 78 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 79 {KEYWORD, "brief", LOG_BRIEF, NULL}, 80 {ENDTOKEN, "", NONE, NULL} 81 }; 82 83 static const struct token t_discovery[] = { 84 {ADDRESS, "", NONE, NULL}, 85 {ENDTOKEN, "", NONE, NULL} 86 }; 87 88 static const struct token t_session[] = { 89 {NAME, "", NONE, NULL}, 90 {ENDTOKEN, "", NONE, NULL} 91 }; 92 93 static const struct token t_vscsi[] = { 94 {KEYWORD, "stats", SHOW_VSCSI_STATS, NULL}, 95 {ENDTOKEN, "", NONE, NULL} 96 }; 97 98 static struct parse_result res; 99 100 struct parse_result * 101 parse(int argc, char *argv[]) 102 { 103 const struct token *table = t_main; 104 const struct token *match; 105 106 bzero(&res, sizeof(res)); 107 108 while (argc >= 0) { 109 if ((match = match_token(argv[0], table)) == NULL) { 110 fprintf(stderr, "valid commands/args:\n"); 111 show_valid_args(table); 112 return (NULL); 113 } 114 115 argc--; 116 argv++; 117 118 if (match->type == NOTOKEN || match->next == NULL) 119 break; 120 121 table = match->next; 122 } 123 124 if (argc > 0) { 125 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 126 return (NULL); 127 } 128 129 return (&res); 130 } 131 132 const struct token * 133 match_token(const char *word, const struct token *table) 134 { 135 u_int i, match; 136 const struct token *t = NULL; 137 138 match = 0; 139 140 for (i = 0; table[i].type != ENDTOKEN; i++) { 141 switch (table[i].type) { 142 case NOTOKEN: 143 if (word == NULL || strlen(word) == 0) { 144 match++; 145 t = &table[i]; 146 } 147 break; 148 case KEYWORD: 149 if (word != NULL && strncmp(word, table[i].keyword, 150 strlen(word)) == 0) { 151 match++; 152 t = &table[i]; 153 if (t->value) 154 res.action = t->value; 155 } 156 break; 157 case FLAG: 158 if (word != NULL && strncmp(word, table[i].keyword, 159 strlen(word)) == 0) { 160 match++; 161 t = &table[i]; 162 res.flags |= t->value; 163 } 164 break; 165 case ADDRESS: 166 if (!parse_addr(word, &res.addr)) { 167 match++; 168 t = &table[i]; 169 if (t->value) 170 res.action = t->value; 171 } 172 break; 173 case NAME: 174 if (word != NULL && strlen(word) > 0) { 175 if (strlcpy(res.name, word, sizeof(res.name)) >= 176 sizeof(res.name)) 177 errx(1, "name too long"); 178 match++; 179 t = &table[i]; 180 } 181 break; 182 case ENDTOKEN: 183 break; 184 } 185 } 186 187 if (match != 1) { 188 if (word == NULL) 189 fprintf(stderr, "missing argument:\n"); 190 else if (match > 1) 191 fprintf(stderr, "ambiguous argument: %s\n", word); 192 else if (match < 1) 193 fprintf(stderr, "unknown argument: %s\n", word); 194 return (NULL); 195 } 196 197 return (t); 198 } 199 200 void 201 show_valid_args(const struct token *table) 202 { 203 int i; 204 205 for (i = 0; table[i].type != ENDTOKEN; i++) { 206 switch (table[i].type) { 207 case NOTOKEN: 208 fprintf(stderr, " <cr>\n"); 209 break; 210 case KEYWORD: 211 case FLAG: 212 fprintf(stderr, " %s\n", table[i].keyword); 213 break; 214 case ADDRESS: 215 fprintf(stderr, " <address>\n"); 216 break; 217 case NAME: 218 fprintf(stderr, " <name>\n"); 219 break; 220 case ENDTOKEN: 221 break; 222 } 223 } 224 } 225 226 int 227 parse_addr(const char *word, struct sockaddr_storage *sa) 228 { 229 struct addrinfo hints, *addrs; 230 int rv; 231 232 bzero(&hints, sizeof(hints)); 233 hints.ai_family = PF_UNSPEC; 234 hints.ai_socktype = SOCK_STREAM; 235 hints.ai_protocol = IPPROTO_TCP; 236 237 if ((rv = getaddrinfo(word, "iscsi", &hints, &addrs)) == 0) { 238 if (sizeof(*sa) < addrs->ai_addrlen) 239 err(1, "parse_host: bork bork bork"); 240 bcopy(addrs->ai_addr, sa, addrs->ai_addrlen); 241 freeaddrinfo(addrs); 242 return (0); 243 } 244 245 errx(1, "parse_host: %s", gai_strerror(rv)); 246 } 247