8 #include <readline/readline.h>
9 #include <readline/history.h>
18 int main_loop_continue = 1;
21 static const struct TreeNode* getSubCom (char **com, int n, int *t)
24 const struct TreeNode *cur, *next;
28 for (i = 0; i < n; i++) {
29 /* we have reached a terminal command, exit */
33 /* search sub command in sub command array */
34 for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
36 /* sub command not found, exit */
37 if (next->name == NULL)
40 /* next command is now the current one */
51 static const struct TreeNode *compcur;
54 static char* my_generator (const char* text, int state)
57 static const struct TreeNode *tn;
61 if (compcur == NULL) {
62 /* sub command not found */
64 } else if (state == 0) {
69 if (tn == NULL) /* terminal command */
72 while ((name = tn++->name) != NULL) {
73 if (strncmp(name, text, len) == 0)
82 static char** my_completion (const char *text, int start, int end UNUSED)
84 char **matches = NULL;
85 char *line, *com[MAXCOM];
89 memset(com, 0, MAXCOM * sizeof(char*));
90 line = strdup(rl_line_buffer);
93 n = explode(line, com, MAXCOM);
96 compcur = getSubCom(com, n, &i);
100 matches = rl_completion_matches(text, my_generator);
102 for (i = 0; com[i] != NULL; i++)
110 static struct ngadmin *nga;
111 static sigjmp_buf jmpbuf;
112 static struct termios orig_term;
113 struct termios current_term;
117 NORET static void handler (int sig)
123 printf("interrupt\n");
125 current_term.c_lflag |= ECHO;
126 tcsetattr(STDIN_FILENO, TCSANOW, ¤t_term);
129 siglongjmp(jmpbuf, 1);
134 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
141 static int pre_login (const struct ether_addr *mac, int retries)
143 const struct swi_attr *sa;
147 for (i = 1; retries <= 0 || i <= retries; i++) {
151 err = ngadmin_scan(nga);
157 /* search switch with requested MAC */
158 sa = ngadmin_getSwitchTab(nga, &n);
160 if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
165 printf("no switch found\n");
178 err = ngadmin_login(nga, n);
188 int main (int argc, char **argv)
190 static const struct option opts[] = {
191 {"batch", no_argument, NULL, 'a'},
192 {"keep-broadcasting", no_argument, NULL, 'b'},
193 {"force-interface", no_argument, NULL, 'f'},
194 {"global-broadcast", no_argument, NULL, 'g'},
195 {"help", no_argument, NULL, 'h'},
196 {"interface", required_argument, NULL, 'i'},
197 {"mac", required_argument, NULL, 'm'},
198 {"password", required_argument, NULL, 'p'},
199 {"retries", required_argument, NULL, 'r'},
200 {"timeout", required_argument, NULL, 't'},
203 char *line, *com[MAXCOM];
204 const char *iface = "eth0", *password = NULL;
206 bool kb = false, force = false, global = false;
208 const struct TreeNode *cur, *next;
209 struct ether_addr *mac = NULL;
210 int i, n, retries = 3;
213 tcgetattr(STDIN_FILENO, &orig_term);
214 current_term = orig_term;
219 while ((n = getopt_long(argc, argv, "abfghi:m:p:r:t:", opts, NULL)) != -1) {
239 printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
247 mac = ether_aton(optarg);
249 printf("invalid MAC\n");
259 retries = strtol(optarg, NULL, 0);
263 timeout = strtof(optarg, NULL);
267 printf("unknown option: \"%s\"\n", argv[optind - 1]);
276 printf("unknown trailing options\n");
281 memset(com, 0, MAXCOM * sizeof(char*));
283 nga = ngadmin_init(iface);
285 fprintf(stderr, "initialization error\n");
291 tv.tv_sec = (int)timeout;
292 tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
293 ngadmin_setTimeout(nga, &tv);
297 if (kb && ngadmin_setKeepBroadcasting(nga, true) != ERR_OK)
300 if (force && ngadmin_forceInterface(nga) != ERR_OK)
303 if (global && ngadmin_useGlobalBroadcast(nga, true) != ERR_OK)
306 /* non-TTY inputs are automatically set to batch mode */
307 if (!isatty(STDIN_FILENO))
310 if (password != NULL)
311 ngadmin_setPassword(nga, password);
313 signal(SIGTERM, handler);
314 signal(SIGINT, handler);
316 /* automatic scan & login when switch MAC is specified on the command line */
317 if (mac != NULL && pre_login(mac, retries) != 0)
321 /* in batch mode, we must be logged to continue */
322 if (ngadmin_getCurrentSwitch(nga) == NULL) {
323 printf("must be logged\n");
327 /* initialize readline functions */
328 rl_attempted_completion_function = my_completion;
329 rl_completion_entry_function = my_generator;
331 sigsetjmp(jmpbuf, 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++) {