11 #ifdef HAVE_LIBREADLINE
13 #include <readline/readline.h>
14 #include <readline/history.h>
25 static const struct TreeNode* getSubCom (char **com, int n, int *t)
28 const struct TreeNode *cur, *next;
32 for (i = 0; i < n; i++) {
33 /* we have reached a terminal command, exit */
37 /* search sub command in sub command array */
38 for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
40 /* sub command not found, exit */
41 if (next->name == NULL)
44 /* next command is now the current one */
55 #ifdef HAVE_LIBREADLINE
56 static const struct TreeNode *compcur;
57 static sigjmp_buf jmpbuf;
61 static char* my_generator (const char* text, int state)
64 static const struct TreeNode *tn;
68 if (compcur == NULL) {
69 /* sub command not found */
71 } else if (state == 0) {
76 if (tn == NULL) /* terminal command */
79 while ((name = tn++->name) != NULL) {
80 if (strncmp(name, text, len) == 0)
89 static char** my_completion (const char *text, int start, int end UNUSED)
91 char *line, *com[MAXCOM];
95 memset(com, 0, MAXCOM * sizeof(char*));
96 line = strdup(rl_line_buffer);
99 n = explode(line, com, MAXCOM);
102 compcur = getSubCom(com, n, &i);
103 for (i = 0; com[i] != NULL; i++)
106 if (i < n) /* unknown command */
108 else if (compcur->sub == NULL) /* terminal command */
109 return rl_completion_matches(text, rl_filename_completion_function);
110 else /* intermediate command */
111 return rl_completion_matches(text, my_generator);
113 #endif /* HAVE_LIBREADLINE */
116 int main_loop_continue;
117 static struct ngadmin *nga;
118 static struct termios orig_term;
119 struct termios current_term;
122 NORET static void handler (int sig)
128 printf("interrupt\n");
130 #ifdef HAVE_LIBREADLINE
131 current_term.c_lflag |= ECHO;
132 tcsetattr(STDIN_FILENO, TCSANOW, ¤t_term);
134 if (!batch && main_loop_continue)
135 siglongjmp(jmpbuf, 1);
141 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
148 static int pre_login (const struct ether_addr *mac, int retries)
150 const struct swi_attr *sa;
154 for (i = 1; retries <= 0 || i <= retries; i++) {
158 err = ngadmin_scan(nga);
164 /* search switch with requested MAC */
165 sa = ngadmin_getSwitchTab(nga, &n);
167 if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
172 printf("no switch found\n");
185 err = ngadmin_login(nga, n);
195 int main (int argc, char **argv)
197 static const struct option opts[] = {
198 {"batch", no_argument, NULL, 'a'},
199 {"keep-broadcasting", no_argument, NULL, 'b'},
200 {"force-interface", no_argument, NULL, 'f'},
201 {"help", no_argument, NULL, 'h'},
202 {"interface", required_argument, NULL, 'i'},
203 {"local-broadcast", no_argument, NULL, 'l'},
204 {"mac", required_argument, NULL, 'm'},
205 {"password", required_argument, NULL, 'p'},
206 {"retries", required_argument, NULL, 'r'},
207 {"timeout", required_argument, NULL, 't'},
210 char *line, *com[MAXCOM];
211 const char *iface = NULL, *password = NULL;
213 bool kb = false, force = false, global = true;
215 const struct TreeNode *cur, *next;
216 struct ether_addr *mac = NULL;
217 int i, n, retries = 3;
220 tcgetattr(STDIN_FILENO, &orig_term);
221 current_term = orig_term;
222 #ifdef HAVE_LIBREADLINE
228 while ((n = getopt_long(argc, argv, "abfhi:lm:p:r:t:", opts, NULL)) != -1) {
232 #ifdef HAVE_LIBREADLINE
246 printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
258 mac = ether_aton(optarg);
260 printf("invalid MAC\n");
270 retries = strtol(optarg, NULL, 0);
274 timeout = strtof(optarg, NULL);
278 printf("unknown option: \"%s\"\n", argv[optind - 1]);
287 printf("unknown trailing options\n");
293 fprintf(stderr, "no interface specified (-i), defaulting to eth0\n");
297 memset(com, 0, MAXCOM * sizeof(char*));
299 nga = ngadmin_init(iface);
301 fprintf(stderr, "initialization error (bad interface ?)\n");
307 tv.tv_sec = (int)timeout;
308 tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
309 ngadmin_setTimeout(nga, &tv);
313 if (ngadmin_setKeepBroadcasting(nga, kb) != ERR_OK)
316 if (force && ngadmin_forceInterface(nga) != ERR_OK)
319 if (ngadmin_useGlobalBroadcast(nga, global) != ERR_OK)
322 #ifdef HAVE_LIBREADLINE
323 /* non-TTY inputs are automatically set to batch mode */
324 if (!isatty(STDIN_FILENO))
328 if (password != NULL)
329 ngadmin_setPassword(nga, password);
331 signal(SIGTERM, handler);
332 signal(SIGINT, handler);
334 /* automatic scan & login when switch MAC is specified on the command line */
335 if (mac != NULL && pre_login(mac, retries) != 0)
338 #ifdef HAVE_LIBREADLINE
340 /* initialize readline functions */
341 rl_attempted_completion_function = my_completion;
342 rl_completion_entry_function = my_generator;
344 sigsetjmp(jmpbuf, 1);
348 main_loop_continue = 1;
349 while (main_loop_continue) {
350 /* read user input */
353 #ifdef HAVE_LIBREADLINE
355 n = getline(&line, (size_t*)&i, stdin);
357 line = readline("> ");
359 n = getline(&line, (size_t*)&i, stdin);
361 if (n < 0 || line == NULL)
364 /* split string into words */
365 trim(line, strlen(line));
366 n = explode(line, com, MAXCOM);
372 #ifdef HAVE_LIBREADLINE
379 cur = getSubCom(com, n, &i);
381 if (cur->sub != NULL) {
382 /* not terminal command */
385 printf("unknown command: %s\n", com[i]);
387 /* intermediate command, remaining string */
388 printf("unknown %s subcommand: %s\n", com[i - 1], com[i]);
390 /* intermediate command, no remaining string */
391 /* print available subcommands */
392 for (next = cur->sub; next->name != NULL; next++)
393 printf("%s ", next->name);
396 } else if (cur->comfunc == NULL) {
397 /* erroneous terminal command without function */
398 printf("terminal command without function\n");
400 /* execute terminal command */
401 cur->comfunc(n - i, (const char**)&com[i], nga);
404 for (i = 0; com[i] != NULL; i++) {