8 #include <readline/readline.h>
9 #include <readline/history.h>
19 static const struct TreeNode* getSubCom (char **com, int n, int *t)
22 const struct TreeNode *cur, *next;
26 for (i = 0; i < n; i++) {
27 /* we have reached a terminal command, exit */
31 /* search sub command in sub command array */
32 for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
34 /* sub command not found, exit */
35 if (next->name == NULL)
38 /* next command is now the current one */
49 static const struct TreeNode *compcur;
52 static char* my_generator (const char* text, int state)
55 static const struct TreeNode *tn;
59 if (compcur == NULL) {
60 /* sub command not found */
62 } else if (state == 0) {
67 if (tn == NULL) /* terminal command */
70 while ((name = tn++->name) != NULL) {
71 if (strncmp(name, text, len) == 0)
80 static char** my_completion (const char *text, int start, int end UNUSED)
82 char **matches = NULL;
83 char *line, *com[MAXCOM];
87 memset(com, 0, MAXCOM * sizeof(char*));
88 line = strdup(rl_line_buffer);
91 n = explode(line, com, MAXCOM);
94 compcur = getSubCom(com, n, &i);
98 matches = rl_completion_matches(text, my_generator);
100 for (i = 0; com[i] != NULL; i++)
108 int main_loop_continue;
109 static struct ngadmin *nga;
110 static sigjmp_buf jmpbuf;
111 static struct termios orig_term;
112 struct termios current_term;
116 NORET static void handler (int sig)
122 printf("interrupt\n");
124 current_term.c_lflag |= ECHO;
125 tcsetattr(STDIN_FILENO, TCSANOW, ¤t_term);
127 if (!batch && main_loop_continue)
128 siglongjmp(jmpbuf, 1);
133 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
140 static int pre_login (const struct ether_addr *mac, int retries)
142 const struct swi_attr *sa;
146 for (i = 1; retries <= 0 || i <= retries; i++) {
150 err = ngadmin_scan(nga);
156 /* search switch with requested MAC */
157 sa = ngadmin_getSwitchTab(nga, &n);
159 if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
164 printf("no switch found\n");
177 err = ngadmin_login(nga, n);
187 int main (int argc, char **argv)
189 static const struct option opts[] = {
190 {"batch", no_argument, NULL, 'a'},
191 {"keep-broadcasting", no_argument, NULL, 'b'},
192 {"force-interface", no_argument, NULL, 'f'},
193 {"help", no_argument, NULL, 'h'},
194 {"interface", required_argument, NULL, 'i'},
195 {"local-broadcast", no_argument, NULL, 'l'},
196 {"mac", required_argument, NULL, 'm'},
197 {"password", required_argument, NULL, 'p'},
198 {"retries", required_argument, NULL, 'r'},
199 {"timeout", required_argument, NULL, 't'},
202 char *line, *com[MAXCOM];
203 const char *iface = "eth0", *password = NULL;
205 bool kb = false, force = false, global = true;
207 const struct TreeNode *cur, *next;
208 struct ether_addr *mac = NULL;
209 int i, n, retries = 3;
212 tcgetattr(STDIN_FILENO, &orig_term);
213 current_term = orig_term;
218 while ((n = getopt_long(argc, argv, "abfhi:lm:p:r:t:", opts, NULL)) != -1) {
234 printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
246 mac = ether_aton(optarg);
248 printf("invalid MAC\n");
258 retries = strtol(optarg, NULL, 0);
262 timeout = strtof(optarg, NULL);
266 printf("unknown option: \"%s\"\n", argv[optind - 1]);
275 printf("unknown trailing options\n");
280 memset(com, 0, MAXCOM * sizeof(char*));
282 nga = ngadmin_init(iface);
284 fprintf(stderr, "initialization error\n");
290 tv.tv_sec = (int)timeout;
291 tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
292 ngadmin_setTimeout(nga, &tv);
296 if (ngadmin_setKeepBroadcasting(nga, kb) != ERR_OK)
299 if (force && ngadmin_forceInterface(nga) != ERR_OK)
302 if (ngadmin_useGlobalBroadcast(nga, global) != ERR_OK)
305 /* non-TTY inputs are automatically set to batch mode */
306 if (!isatty(STDIN_FILENO))
309 if (password != NULL)
310 ngadmin_setPassword(nga, password);
312 signal(SIGTERM, handler);
313 signal(SIGINT, handler);
315 /* automatic scan & login when switch MAC is specified on the command line */
316 if (mac != NULL && pre_login(mac, retries) != 0)
320 /* in batch mode, we must be logged to continue */
321 if (ngadmin_getCurrentSwitch(nga) == NULL) {
322 printf("must be logged\n");
326 /* initialize readline functions */
327 rl_attempted_completion_function = my_completion;
328 rl_completion_entry_function = my_generator;
330 sigsetjmp(jmpbuf, 1);
333 main_loop_continue = 1;
334 while (main_loop_continue) {
335 /* read user input */
339 n = getline(&line, (size_t*)&i, stdin);
341 line = readline("> ");
342 if (n < 0 || line == NULL)
345 /* split string into words */
346 trim(line, strlen(line));
347 n = explode(line, com, MAXCOM);
358 cur = getSubCom(com, n, &i);
360 if (cur->sub != NULL) {
361 /* not terminal command */
364 printf("unknown command: %s\n", com[i]);
366 /* intermediate command, remaining string */
367 printf("unknown %s subcommand: %s\n", com[i - 1], com[i]);
369 /* intermediate command, no remaining string */
370 /* print available subcommands */
371 for (next = cur->sub; next->name != NULL; next++)
372 printf("%s ", next->name);
375 } else if (cur->comfunc == NULL) {
376 /* erroneous terminal command without function */
377 printf("terminal command without function\n");
379 /* execute terminal command */
380 cur->comfunc(n - i, (const char**)&com[i], nga);
383 for (i = 0; com[i] != NULL; i++) {