make multipathd disable queue_without_daemon by default
[multipath-tools/.git] / multipathd / cli.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <memory.h>
5 #include <vector.h>
6 #include <parser.h>
7 #include <util.h>
8 #include <version.h>
9 #include <readline/readline.h>
10
11 #include "cli.h"
12
13 static vector keys;
14 static vector handlers;
15
16 static struct key *
17 alloc_key (void)
18 {
19         return (struct key *)MALLOC(sizeof(struct key));
20 }
21
22 static struct handler *
23 alloc_handler (void)
24 {
25         return (struct handler *)MALLOC(sizeof(struct handler));
26 }
27
28 static int
29 add_key (vector vec, char * str, unsigned long code, int has_param)
30 {
31         struct key * kw;
32
33         kw = alloc_key();
34
35         if (!kw)
36                 return 1;
37
38         kw->code = code;
39         kw->has_param = has_param;
40         kw->str = STRDUP(str);
41
42         if (!kw->str)
43                 goto out;
44
45         if (!vector_alloc_slot(vec))
46                 goto out1;
47
48         vector_set_slot(vec, kw);
49
50         return 0;
51
52 out1:
53         FREE(kw->str);
54 out:
55         FREE(kw);
56         return 1;
57 }
58
59 int
60 add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *))
61 {
62         struct handler * h;
63
64         h = alloc_handler();
65
66         if (!h)
67                 return 1;
68
69         if (!vector_alloc_slot(handlers)) {
70                 FREE(h);
71                 return 1;
72         }
73
74         vector_set_slot(handlers, h);
75         h->fingerprint = fp;
76         h->fn = fn;
77
78         return 0;
79 }
80
81 static struct handler *
82 find_handler (unsigned long fp)
83 {
84         int i;
85         struct handler *h;
86
87         vector_foreach_slot (handlers, h, i)
88                 if (h->fingerprint == fp)
89                         return h;
90
91         return NULL;
92 }
93
94 int
95 set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *))
96 {
97         struct handler * h = find_handler(fp);
98
99         if (!h)
100                 return 1;
101         h->fn = fn;
102         return 0;
103 }
104
105 static void
106 free_key (struct key * kw)
107 {
108         if (kw->str)
109                 FREE(kw->str);
110
111         if (kw->param)
112                 FREE(kw->param);
113
114         FREE(kw);
115 }
116
117 void
118 free_keys (vector vec)
119 {
120         int i;
121         struct key * kw;
122
123         vector_foreach_slot (vec, kw, i)
124                 free_key(kw);
125
126         vector_free(vec);
127 }
128
129 void
130 free_handlers (void)
131 {
132         int i;
133         struct handler * h;
134
135         vector_foreach_slot (handlers, h, i)
136                 FREE(h);
137
138         vector_free(handlers);
139         handlers = NULL;
140 }
141
142 int
143 load_keys (void)
144 {
145         int r = 0;
146         keys = vector_alloc();
147
148         if (!keys)
149                 return 1;
150
151         r += add_key(keys, "list", LIST, 0);
152         r += add_key(keys, "show", LIST, 0);
153         r += add_key(keys, "add", ADD, 0);
154         r += add_key(keys, "remove", DEL, 0);
155         r += add_key(keys, "del", DEL, 0);
156         r += add_key(keys, "switch", SWITCH, 0);
157         r += add_key(keys, "switchgroup", SWITCH, 0);
158         r += add_key(keys, "suspend", SUSPEND, 0);
159         r += add_key(keys, "resume", RESUME, 0);
160         r += add_key(keys, "reinstate", REINSTATE, 0);
161         r += add_key(keys, "fail", FAIL, 0);
162         r += add_key(keys, "resize", RESIZE, 0);
163         r += add_key(keys, "reset", RESET, 0);
164         r += add_key(keys, "reload", RELOAD, 0);
165         r += add_key(keys, "forcequeueing", FORCEQ, 0);
166         r += add_key(keys, "disablequeueing", DISABLEQ, 0);
167         r += add_key(keys, "restorequeueing", RESTOREQ, 0);
168         r += add_key(keys, "paths", PATHS, 0);
169         r += add_key(keys, "maps", MAPS, 0);
170         r += add_key(keys, "multipaths", MAPS, 0);
171         r += add_key(keys, "path", PATH, 1);
172         r += add_key(keys, "map", MAP, 1);
173         r += add_key(keys, "multipath", MAP, 1);
174         r += add_key(keys, "group", GROUP, 1);
175         r += add_key(keys, "reconfigure", RECONFIGURE, 0);
176         r += add_key(keys, "daemon", DAEMON, 0);
177         r += add_key(keys, "status", STATUS, 0);
178         r += add_key(keys, "stats", STATS, 0);
179         r += add_key(keys, "topology", TOPOLOGY, 0);
180         r += add_key(keys, "config", CONFIG, 0);
181         r += add_key(keys, "blacklist", BLACKLIST, 0);
182         r += add_key(keys, "devices", DEVICES, 0);
183         r += add_key(keys, "format", FMT, 1);
184         r += add_key(keys, "wildcards", WILDCARDS, 0);
185         r += add_key(keys, "quit", QUIT, 0);
186         r += add_key(keys, "exit", QUIT, 0);
187         r += add_key(keys, "shutdown", SHUTDOWN, 0);
188         r += add_key(keys, "getprstatus", GETPRSTATUS, 0);
189         r += add_key(keys, "setprstatus", SETPRSTATUS, 0);
190         r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0);
191
192         if (r) {
193                 free_keys(keys);
194                 keys = NULL;
195                 return 1;
196         }
197         return 0;
198 }
199
200 static struct key *
201 find_key (const char * str)
202 {
203         int i;
204         int len, klen;
205         struct key * kw = NULL;
206         struct key * foundkw = NULL;
207
208         len = strlen(str);
209
210         vector_foreach_slot (keys, kw, i) {
211                 if (strncmp(kw->str, str, len))
212                         continue;
213                 klen = strlen(kw->str);
214                 if (len == klen)
215                         return kw; /* exact match */
216                 if (len < klen) {
217                         if (!foundkw)
218                                 foundkw = kw; /* shortcut match */
219                         else
220                                 return NULL; /* ambiguous word */
221                 }
222         }
223         return foundkw;
224 }
225
226 #define E_SYNTAX        1
227 #define E_NOPARM        2
228 #define E_NOMEM         3
229
230 static int
231 get_cmdvec (char * cmd, vector *v)
232 {
233         int i;
234         int r = 0;
235         int get_param = 0;
236         char * buff;
237         struct key * kw = NULL;
238         struct key * cmdkw = NULL;
239         vector cmdvec, strvec;
240
241         strvec = alloc_strvec(cmd);
242         if (!strvec)
243                 return E_NOMEM;
244
245         cmdvec = vector_alloc();
246
247         if (!cmdvec) {
248                 free_strvec(strvec);
249                 return E_NOMEM;
250         }
251
252         vector_foreach_slot(strvec, buff, i) {
253                 if (*buff == '"')
254                         continue;
255                 if (get_param) {
256                         get_param = 0;
257                         cmdkw->param = strdup(buff);
258                         continue;
259                 }
260                 kw = find_key(buff);
261                 if (!kw) {
262                         r = E_SYNTAX;
263                         goto out;
264                 }
265                 cmdkw = alloc_key();
266                 if (!cmdkw) {
267                         r = E_NOMEM;
268                         goto out;
269                 }
270                 if (!vector_alloc_slot(cmdvec)) {
271                         FREE(cmdkw);
272                         r = E_NOMEM;
273                         goto out;
274                 }
275                 vector_set_slot(cmdvec, cmdkw);
276                 cmdkw->code = kw->code;
277                 cmdkw->has_param = kw->has_param;
278                 if (kw->has_param)
279                         get_param = 1;
280         }
281         if (get_param) {
282                 r = E_NOPARM;
283                 goto out;
284         }
285         *v = cmdvec;
286         free_strvec(strvec);
287         return 0;
288
289 out:
290         free_strvec(strvec);
291         free_keys(cmdvec);
292         return r;
293 }
294
295 static unsigned long 
296 fingerprint(vector vec)
297 {
298         int i;
299         unsigned long fp = 0;
300         struct key * kw;
301
302         if (!vec)
303                 return 0;
304
305         vector_foreach_slot(vec, kw, i)
306                 fp += kw->code;
307
308         return fp;
309 }
310
311 int
312 alloc_handlers (void)
313 {
314         handlers = vector_alloc();
315
316         if (!handlers)
317                 return 1;
318
319         return 0;
320 }
321
322 static int
323 genhelp_sprint_aliases (char * reply, vector keys, struct key * refkw)
324 {
325         int i, fwd = 0;
326         struct key * kw;
327
328         vector_foreach_slot (keys, kw, i)
329                 if (kw->code == refkw->code && kw != refkw)
330                         fwd += sprintf(reply, "|%s", kw->str);
331
332         return fwd;
333 }
334
335 static char *
336 genhelp_handler (void)
337 {
338         int i, j;
339         unsigned long fp;
340         struct handler * h;
341         struct key * kw;
342         char * reply;
343         char * p;
344
345         reply = MALLOC(INITIAL_REPLY_LEN);
346
347         if (!reply)
348                 return NULL;
349
350         p = reply;
351         p += sprintf(p, VERSION_STRING);
352         p += sprintf(p, "CLI commands reference:\n");
353
354         vector_foreach_slot (handlers, h, i) {
355                 fp = h->fingerprint;
356                 vector_foreach_slot (keys, kw, j) {
357                         if ((kw->code & fp)) {
358                                 fp -= kw->code;
359                                 p += sprintf(p, " %s", kw->str);
360                                 p += genhelp_sprint_aliases(p, keys, kw);
361
362                                 if (kw->has_param)
363                                         p += sprintf(p, " $%s", kw->str);
364                         }
365                 }
366                 p += sprintf(p, "\n");
367         }
368
369         return reply;
370 }
371
372 int
373 parse_cmd (char * cmd, char ** reply, int * len, void * data)
374 {
375         int r;
376         struct handler * h;
377         vector cmdvec = NULL;
378
379         r = get_cmdvec(cmd, &cmdvec);
380
381         if (r) {
382                 *reply = genhelp_handler();
383                 *len = strlen(*reply) + 1;
384                 return 0;
385         }
386
387         h = find_handler(fingerprint(cmdvec));
388
389         if (!h || !h->fn) {
390                 *reply = genhelp_handler();
391                 *len = strlen(*reply) + 1;
392                 free_keys(cmdvec);
393                 return 0;
394         }
395
396         /*
397          * execute handler
398          */
399         r = h->fn(cmdvec, reply, len, data);
400         free_keys(cmdvec);
401
402         return r;
403 }
404
405 char *
406 get_keyparam (vector v, unsigned long code)
407 {
408         struct key * kw;
409         int i;
410
411         vector_foreach_slot(v, kw, i)
412                 if (kw->code == code)
413                         return kw->param;
414
415         return NULL;
416 }
417
418 int
419 cli_init (void) {
420         if (load_keys())
421                 return 1;
422
423         if (alloc_handlers())
424                 return 1;
425
426         add_handler(LIST+PATHS, NULL);
427         add_handler(LIST+PATHS+FMT, NULL);
428         add_handler(LIST+STATUS, NULL);
429         add_handler(LIST+DAEMON, NULL);
430         add_handler(LIST+MAPS, NULL);
431         add_handler(LIST+MAPS+STATUS, NULL);
432         add_handler(LIST+MAPS+STATS, NULL);
433         add_handler(LIST+MAPS+FMT, NULL);
434         add_handler(LIST+MAPS+TOPOLOGY, NULL);
435         add_handler(LIST+TOPOLOGY, NULL);
436         add_handler(LIST+MAP+TOPOLOGY, NULL);
437         add_handler(LIST+CONFIG, NULL);
438         add_handler(LIST+BLACKLIST, NULL);
439         add_handler(LIST+DEVICES, NULL);
440         add_handler(LIST+WILDCARDS, NULL);
441         add_handler(ADD+PATH, NULL);
442         add_handler(DEL+PATH, NULL);
443         add_handler(ADD+MAP, NULL);
444         add_handler(DEL+MAP, NULL);
445         add_handler(SWITCH+MAP+GROUP, NULL);
446         add_handler(RECONFIGURE, NULL);
447         add_handler(SUSPEND+MAP, NULL);
448         add_handler(RESUME+MAP, NULL);
449         add_handler(RESIZE+MAP, NULL);
450         add_handler(RESET+MAP, NULL);
451         add_handler(RELOAD+MAP, NULL);
452         add_handler(DISABLEQ+MAP, NULL);
453         add_handler(RESTOREQ+MAP, NULL);
454         add_handler(DISABLEQ+MAPS, NULL);
455         add_handler(RESTOREQ+MAPS, NULL);
456         add_handler(REINSTATE+PATH, NULL);
457         add_handler(FAIL+PATH, NULL);
458         add_handler(QUIT, NULL);
459         add_handler(SHUTDOWN, NULL);
460         add_handler(GETPRSTATUS+MAP, NULL);
461         add_handler(SETPRSTATUS+MAP, NULL);
462         add_handler(UNSETPRSTATUS+MAP, NULL);
463         add_handler(FORCEQ+DAEMON, NULL);
464         add_handler(RESTOREQ+DAEMON, NULL);
465
466         return 0;
467 }
468
469 void cli_exit(void)
470 {
471         free_handlers();
472         free_keys(keys);
473         keys = NULL;
474 }
475
476 static int
477 key_match_fingerprint (struct key * kw, unsigned long fp)
478 {
479         if (!fp)
480                 return 0;
481
482         return ((fp & kw->code) == kw->code);
483 }
484
485 /*
486  * This is the readline completion handler
487  */
488 char *
489 key_generator (const char * str, int state)
490 {
491         static int index, len, has_param;
492         static unsigned long rlfp;      
493         struct key * kw;
494         int i;
495         struct handler *h;
496         vector v = NULL;
497
498         if (!state) {
499                 index = 0;
500                 has_param = 0;
501                 rlfp = 0;
502                 len = strlen(str);
503                 int r = get_cmdvec(rl_line_buffer, &v);
504                 /*
505                  * If a word completion is in progess, we don't want
506                  * to take an exact keyword match in the fingerprint.
507                  * For ex "show map[tab]" would validate "map" and discard
508                  * "maps" as a valid candidate.
509                  */
510                 if (v && len)
511                         vector_del_slot(v, VECTOR_SIZE(v) - 1);
512                 /*
513                  * Clean up the mess if we dropped the last slot of a 1-slot
514                  * vector
515                  */
516                 if (v && !VECTOR_SIZE(v)) {
517                         vector_free(v);
518                         v = NULL;
519                 }
520                 /*
521                  * If last keyword takes a param, don't even try to guess
522                  */
523                 if (r == E_NOPARM) {
524                         has_param = 1;
525                         return (strdup("(value)"));
526                 }
527                 /*
528                  * Compute a command fingerprint to find out possible completions.
529                  * Once done, the vector is useless. Free it.
530                  */
531                 if (v) {
532                         rlfp = fingerprint(v);
533                         free_keys(v);
534                 }
535         }
536         /*
537          * No more completions for parameter placeholder.
538          * Brave souls might try to add parameter completion by walking paths and
539          * multipaths vectors.
540          */
541         if (has_param)
542                 return ((char *)NULL);
543         /*
544          * Loop through keywords for completion candidates
545          */
546         vector_foreach_slot_after (keys, kw, index) {
547                 if (!strncmp(kw->str, str, len)) {
548                         /*
549                          * Discard keywords already in the command line
550                          */
551                         if (key_match_fingerprint(kw, rlfp)) {
552                                 struct key * curkw = find_key(str);
553                                 if (!curkw || (curkw != kw))
554                                         continue;
555                         }
556                         /*
557                          * Discard keywords making syntax errors.
558                          *
559                          * nfp is the candidate fingerprint we try to
560                          * validate against all known command fingerprints.
561                          */
562                         unsigned long nfp = rlfp | kw->code;
563                         vector_foreach_slot(handlers, h, i) {
564                                 if (!rlfp || ((h->fingerprint & nfp) == nfp)) {
565                                         /*
566                                          * At least one full command is
567                                          * possible with this keyword :
568                                          * Consider it validated
569                                          */
570                                         index++;
571                                         return (strdup(kw->str));
572                                 }
573                         }
574                 }
575         }
576         /*
577          * No more candidates
578          */
579         return ((char *)NULL);
580 }
581