1 /* $OpenBSD: parser.c,v 1.25 2012/05/13 09:18:52 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/queue.h> 24 #include <sys/tree.h> 25 #include <sys/param.h> 26 27 #include <event.h> 28 #include <imsg.h> 29 30 #include <openssl/ssl.h> 31 32 #include "smtpd.h" 33 34 #include "parser.h" 35 36 enum token_type { 37 NOTOKEN, 38 ENDTOKEN, 39 KEYWORD, 40 VARIABLE 41 }; 42 43 struct token { 44 enum token_type type; 45 const char *keyword; 46 int value; 47 const struct token *next; 48 }; 49 50 static const struct token t_main[]; 51 static const struct token t_schedule_id[]; 52 static const struct token t_show[]; 53 static const struct token t_pause[]; 54 static const struct token t_remove[]; 55 static const struct token t_resume[]; 56 static const struct token t_log[]; 57 58 static const struct token t_main[] = { 59 {KEYWORD, "schedule-id", NONE, t_schedule_id}, 60 {KEYWORD, "schedule-all", SCHEDULE_ALL, NULL}, 61 {KEYWORD, "show", NONE, t_show}, 62 {KEYWORD, "monitor", MONITOR, NULL}, 63 {KEYWORD, "pause", NONE, t_pause}, 64 {KEYWORD, "remove", NONE, t_remove}, 65 {KEYWORD, "resume", NONE, t_resume}, 66 {KEYWORD, "stop", SHUTDOWN, NULL}, 67 {KEYWORD, "log", NONE, t_log}, 68 {ENDTOKEN, "", NONE, NULL} 69 }; 70 71 static const struct token t_remove[] = { 72 {VARIABLE, "evpid", REMOVE, NULL}, 73 {ENDTOKEN, "", NONE, NULL} 74 }; 75 76 static const struct token t_schedule_id[] = { 77 {VARIABLE, "msgid/evpid", SCHEDULE, NULL}, 78 {ENDTOKEN, "", NONE, NULL} 79 }; 80 81 static const struct token t_show[] = { 82 {KEYWORD, "queue", SHOW_QUEUE, NULL}, 83 {KEYWORD, "runqueue", SHOW_RUNQUEUE, NULL}, 84 {KEYWORD, "stats", SHOW_STATS, NULL}, 85 {ENDTOKEN, "", NONE, NULL} 86 }; 87 88 static const struct token t_pause[] = { 89 {KEYWORD, "mda", PAUSE_MDA, NULL}, 90 {KEYWORD, "mta", PAUSE_MTA, NULL}, 91 {KEYWORD, "smtp", PAUSE_SMTP, NULL}, 92 {ENDTOKEN, "", NONE, NULL} 93 }; 94 95 static const struct token t_resume[] = { 96 {KEYWORD, "mda", RESUME_MDA, NULL}, 97 {KEYWORD, "mta", RESUME_MTA, NULL}, 98 {KEYWORD, "smtp", RESUME_SMTP, NULL}, 99 {ENDTOKEN, "", NONE, NULL} 100 }; 101 102 static const struct token t_log[] = { 103 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 104 {KEYWORD, "brief", LOG_BRIEF, NULL}, 105 {ENDTOKEN, "", NONE, NULL} 106 }; 107 108 static const struct token *match_token(const char *, const struct token [], 109 struct parse_result *); 110 static void show_valid_args(const struct token []); 111 112 struct parse_result * 113 parse(int argc, char *argv[]) 114 { 115 static struct parse_result res; 116 const struct token *table = t_main; 117 const struct token *match; 118 119 bzero(&res, sizeof(res)); 120 121 while (argc >= 0) { 122 if ((match = match_token(argv[0], table, &res)) == NULL) { 123 fprintf(stderr, "valid commands/args:\n"); 124 show_valid_args(table); 125 return (NULL); 126 } 127 128 argc--; 129 argv++; 130 131 if (match->type == NOTOKEN || match->next == NULL) 132 break; 133 134 table = match->next; 135 } 136 137 if (argc > 0) { 138 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 139 return (NULL); 140 } 141 142 return (&res); 143 } 144 145 const struct token * 146 match_token(const char *word, const struct token table[], 147 struct parse_result *res) 148 { 149 u_int i, match; 150 const struct token *t = NULL; 151 152 match = 0; 153 154 for (i = 0; table[i].type != ENDTOKEN; i++) { 155 switch (table[i].type) { 156 case NOTOKEN: 157 if (word == NULL || strlen(word) == 0) { 158 match++; 159 t = &table[i]; 160 } 161 break; 162 case KEYWORD: 163 if (word != NULL && strncmp(word, table[i].keyword, 164 strlen(word)) == 0) { 165 match++; 166 t = &table[i]; 167 if (t->value) 168 res->action = t->value; 169 } 170 break; 171 case VARIABLE: 172 if (word != NULL && strlen(word) != 0) { 173 match++; 174 t = &table[i]; 175 if (t->value) { 176 res->action = t->value; 177 res->data = word; 178 } 179 } 180 break; 181 case ENDTOKEN: 182 break; 183 } 184 } 185 186 if (match != 1) { 187 if (word == NULL) 188 fprintf(stderr, "missing argument:\n"); 189 else if (match > 1) 190 fprintf(stderr, "ambiguous argument: %s\n", word); 191 else if (match < 1) 192 fprintf(stderr, "unknown argument: %s\n", word); 193 return (NULL); 194 } 195 196 return (t); 197 } 198 199 static void 200 show_valid_args(const struct token table[]) 201 { 202 int i; 203 204 for (i = 0; table[i].type != ENDTOKEN; i++) { 205 switch (table[i].type) { 206 case NOTOKEN: 207 fprintf(stderr, " <cr>\n"); 208 break; 209 case KEYWORD: 210 fprintf(stderr, " %s\n", table[i].keyword); 211 break; 212 case VARIABLE: 213 fprintf(stderr, " %s\n", table[i].keyword); 214 break; 215 case ENDTOKEN: 216 break; 217 } 218 } 219 } 220