]> git.sur5r.net Git - ngadmin/blob - cli/src/admin.c
Lib: add libtool version info
[ngadmin] / cli / src / admin.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include <stdio.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <setjmp.h>
10
11 #include <getopt.h>
12 #ifdef HAVE_LIBREADLINE
13 #include <readline/readline.h>
14 #include <readline/history.h>
15 #endif
16
17 #include "common.h"
18 #include "commands.h"
19
20
21 #define MAXCOM  32
22
23
24 int main_loop_continue;
25
26
27 static const struct TreeNode* getSubCom (char **com, int n, int *t)
28 {
29         int i;
30         const struct TreeNode *cur, *next;
31         
32         
33         cur = &commands;
34         for (i = 0; i < n; i++) {
35                 /* we have reached a terminal command, exit */
36                 if (cur->sub == NULL)
37                         break;
38                 
39                 /* search sub command in sub command array */
40                 for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
41                 
42                 /* sub command not found, exit */
43                 if (next->name == NULL)
44                         break;
45                 
46                 /* next command is now the current one */
47                 cur = next;
48         }
49         
50         *t = i;
51         
52         
53         return cur;
54 }
55
56
57 #ifdef HAVE_LIBREADLINE
58 static const struct TreeNode *compcur;
59
60
61 static char* my_generator (const char* text, int state)
62 {
63         static int len;
64         static const struct TreeNode *tn;
65         const char *name;
66         
67         
68         if (compcur == NULL) {
69                 /* sub command not found */
70                 return NULL;
71         } else if (state == 0) {
72                 tn = compcur->sub;
73                 len = strlen(text);
74         }
75         
76         if (tn == NULL) /* terminal command */
77                 return NULL;
78         
79         while ((name = tn++->name) != NULL) {
80                 if (strncmp(name, text, len) == 0)
81                         return strdup(name);
82         }
83         
84         
85         return NULL;
86 }
87
88
89 static char** my_completion (const char *text, int start, int end UNUSED)
90 {
91         char **matches = NULL;
92         char *line, *com[MAXCOM];
93         int i, n;
94         
95         
96         memset(com, 0, MAXCOM * sizeof(char*));
97         line = strdup(rl_line_buffer);
98         line[start] = '\0';
99         trim(line, start);
100         n = explode(line, com, MAXCOM);
101         free(line);
102         
103         compcur = getSubCom(com, n, &i);
104         
105         if (i < n)
106                 compcur = NULL;
107         matches = rl_completion_matches(text, my_generator);
108         
109         for (i = 0; com[i] != NULL; i++)
110                 free(com[i]);
111         
112         
113         return matches;
114 }
115 #endif /* HAVE_LIBREADLINE */
116
117
118 static struct ngadmin *nga;
119 static sigjmp_buf jmpbuf;
120 static struct termios orig_term;
121 struct termios current_term;
122 static bool batch;
123
124
125 NORET static void handler (int sig)
126 {
127         switch (sig) {
128         
129         case SIGTERM:
130         case SIGINT:
131                 printf("interrupt\n");
132                 
133                 current_term.c_lflag |= ECHO;
134                 tcsetattr(STDIN_FILENO, TCSANOW, &current_term);
135                 
136                 if (!batch)
137                         siglongjmp(jmpbuf, 1);
138         
139         default:
140                 ngadmin_close(nga);
141                 
142                 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
143                 
144                 exit(0);
145         }
146 }
147
148
149 static int pre_login (const struct ether_addr *mac, int retries)
150 {
151         const struct swi_attr *sa;
152         int i, n, err;
153         
154         
155         for (i = 1; retries <= 0 || i <= retries; i++) {
156                 /* scan */
157                 printf("scan... ");
158                 fflush(stdout);
159                 err = ngadmin_scan(nga);
160                 if (err < 0) {
161                         printErrCode(err);
162                         continue;
163                 }
164                 
165                 /* search switch with requested MAC */
166                 sa = ngadmin_getSwitchTab(nga, &n);
167                 while (--n >= 0) {
168                         if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
169                                 break;
170                 }
171         
172                 if (n < 0) {
173                         printf("no switch found\n");
174                 } else {
175                         printf("done\n");
176                         break;
177                 }
178         }
179         
180         if (n < 0)
181                 return 1;
182
183         /* login */
184         printf("login... ");
185         fflush(stdout);
186         err = ngadmin_login(nga, n);
187         if (err < 0)
188                 printErrCode(err);
189         else
190                 printf("done\n");
191         
192         return err;
193 }
194
195
196 int main (int argc, char **argv)
197 {
198         static const struct option opts[] = {
199                 {"batch", no_argument, NULL, 'a'},
200                 {"keep-broadcasting", no_argument, NULL, 'b'},
201                 {"force-interface", no_argument, NULL, 'f'},
202                 {"global-broadcast", no_argument, NULL, 'g'},
203                 {"help", no_argument, NULL, 'h'},
204                 {"interface", required_argument, NULL, 'i'},
205                 {"mac", required_argument, NULL, 'm'},
206                 {"password", required_argument, NULL, 'p'},
207                 {"retries", required_argument, NULL, 'r'},
208                 {"timeout", required_argument, NULL, 't'},
209                 {0, 0, 0, 0}
210         };
211         char *line, *com[MAXCOM];
212         const char *iface = "eth0", *password = NULL;
213         float timeout = 0.f;
214         bool kb = false, force = false, global = false;
215         struct timeval tv;
216         const struct TreeNode *cur, *next;
217         struct ether_addr *mac = NULL;
218         int i, n, retries = 3;
219         
220         
221         tcgetattr(STDIN_FILENO, &orig_term);
222         current_term = orig_term;
223 #ifdef HAVE_LIBREADLINE
224         batch = false;
225 #else
226         batch = true;
227 #endif
228         
229         opterr = 0;
230         
231         while ((n = getopt_long(argc, argv, "abfghi:m:p:r:t:", opts, NULL)) != -1) {
232                 switch (n) {
233                 
234                 case 'a':
235                         batch = true;
236                         break;
237                 
238                 case 'b':
239                         kb = true;
240                         break;
241                 
242                 case 'f':
243                         force = true;
244                         break;
245                 
246                 case 'g':
247                         global = true;
248                         break;
249                 
250                 case 'h':
251                         printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
252                         goto end;
253                 
254                 case 'i':
255                         iface = optarg;
256                         break;
257                 
258                 case 'm':
259                         mac = ether_aton(optarg);
260                         if (mac == NULL) {
261                                 printf("invalid MAC\n");
262                                 goto end;
263                         }
264                         break;
265                 
266                 case 'p':
267                         password = optarg;
268                         break;
269                 
270                 case 'r':
271                         retries = strtol(optarg, NULL, 0);
272                         break;
273                 
274                 case 't':
275                         timeout = strtof(optarg, NULL);
276                         break;
277                 
278                 case '?':
279                         printf("unknown option: \"%s\"\n", argv[optind - 1]);
280                         goto end;
281                 }
282         }
283         
284         argc -= optind;
285         argv += optind;
286         
287         if (argc != 0) {
288                 printf("unknown trailing options\n");
289                 goto end;
290         }
291         
292         
293         memset(com, 0, MAXCOM * sizeof(char*));
294         
295         nga = ngadmin_init(iface);
296         if (nga == NULL) {
297                 fprintf(stderr, "initialization error\n");
298                 goto end;
299         }
300         
301         /* set timeout */
302         if (timeout > 0.f) {
303                 tv.tv_sec = (int)timeout;
304                 tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
305                 ngadmin_setTimeout(nga, &tv);
306         }
307         
308         
309         if (kb && ngadmin_setKeepBroadcasting(nga, true) != ERR_OK)
310                 goto end;
311         
312         if (force && ngadmin_forceInterface(nga) != ERR_OK)
313                 goto end;
314         
315         if (global && ngadmin_useGlobalBroadcast(nga, true) != ERR_OK)
316                 goto end;
317         
318         /* non-TTY inputs are automatically set to batch mode */
319         if (!isatty(STDIN_FILENO))
320                 batch = true;
321         
322         if (password != NULL)
323                 ngadmin_setPassword(nga, password);
324         
325         signal(SIGTERM, handler);
326         signal(SIGINT, handler);
327         
328         /* automatic scan & login when switch MAC is specified on the command line */
329         if (mac != NULL && pre_login(mac, retries) != 0)
330                 goto end;
331         
332         if (!batch) {
333 #ifdef HAVE_LIBREADLINE
334                 /* initialize readline functions */
335                 rl_attempted_completion_function = my_completion;
336                 rl_completion_entry_function = my_generator;
337                 
338                 sigsetjmp(jmpbuf, 1);
339 #endif
340         }
341         
342         main_loop_continue = 1;
343         
344         while (main_loop_continue) {
345                 /* read user input */
346                 line = NULL;
347                 n = 0;
348                 if (batch)
349                         n = getline(&line, (size_t*)&i, stdin);
350 #ifdef HAVE_LIBREADLINE
351                 else
352                         line = readline("> ");
353 #endif
354                 if (n < 0 || line == NULL)
355                         goto end;
356                 
357                 /* split string into words */
358                 trim(line, strlen(line));
359                 n = explode(line, com, MAXCOM);
360                 
361                 if (n == 0) {
362                         free(line);
363                         continue;
364                 } else {
365 #ifdef HAVE_LIBREADLINE
366                         if (!batch)
367                                 add_history(line);
368 #endif
369                         free(line);
370                 }
371                 
372                 cur = getSubCom(com, n, &i);
373                 
374                 if (cur->sub != NULL) {
375                         /* not terminal command */
376                         if (i == 0) {
377                                 /* root command */
378                                 printf("unknown command: %s\n", com[i]);
379                         } else if (i < n) {
380                                 /* intermediate command, remaining string */
381                                 printf("unknown %s subcommand: %s\n", com[i - 1], com[i]);
382                         } else {
383                                 /* intermediate command, no remaining string */
384                                 /* print available subcommands */
385                                 for (next = cur->sub; next->name != NULL; next++)
386                                         printf("%s ", next->name);
387                                 putchar('\n');
388                         }
389                 } else if (cur->comfunc == NULL) {
390                         /* erroneous terminal command without function */
391                         printf("terminal command without function\n");
392                 } else {
393                         /* execute terminal command */
394                         cur->comfunc(n - i, (const char**)&com[i], nga);
395                 }
396                 
397                 for (i = 0; com[i] != NULL; i++) {
398                         free(com[i]);
399                         com[i] = NULL;
400                 }
401         }
402         
403 end:
404         handler(0);
405 }
406
407