]> git.sur5r.net Git - ngadmin/blobdiff - cli/admin.c
Cli: fix infinite loop in automatic login in case of network errors
[ngadmin] / cli / admin.c
index e3fbec65e89bb37577796a6f4449cb8b579b946a..f5b691b305fd555e9ec0054fc3f08c401e0918fc 100644 (file)
@@ -1,6 +1,7 @@
 
 #include <stdio.h>
 #include <signal.h>
+#include <unistd.h>
 #include <setjmp.h>
 
 #include <getopt.h>
@@ -14,7 +15,7 @@
 #define MAXCOM 32
 
 
-int cont = 1;
+int main_loop_continue = 1;
 
 
 static const struct TreeNode* getSubCom (char **com, int n, int *t)
@@ -23,7 +24,7 @@ static const struct TreeNode* getSubCom (char **com, int n, int *t)
        const struct TreeNode *cur, *next;
        
        
-       cur = &coms;
+       cur = &commands;
        for (i = 0; i < n; i++) {
                /* we have reached a terminal command, exit */
                if (cur->sub == NULL)
@@ -110,6 +111,7 @@ static struct ngadmin *nga;
 static sigjmp_buf jmpbuf;
 static struct termios orig_term;
 struct termios current_term;
+static bool batch;
 
 
 NORET static void handler (int sig)
@@ -120,10 +122,11 @@ NORET static void handler (int sig)
        case SIGINT:
                printf("interrupt\n");
                
-               current_term.c_lflag|=ECHO;
+               current_term.c_lflag |= ECHO;
                tcsetattr(STDIN_FILENO, TCSANOW, &current_term);
                
-               siglongjmp(jmpbuf, 1);
+               if (!batch)
+                       siglongjmp(jmpbuf, 1);
        
        default:
                ngadmin_close(nga);
@@ -135,34 +138,91 @@ NORET static void handler (int sig)
 }
 
 
+static int pre_login (const struct ether_addr *mac, int retries)
+{
+       const struct swi_attr *sa;
+       int i, n, err;
+       
+       
+       for (i = 1; retries <= 0 || i <= retries; i++) {
+               /* scan */
+               printf("scan... ");
+               fflush(stdout);
+               err = ngadmin_scan(nga);
+               if (err < 0) {
+                       printErrCode(err);
+                       return err;
+               }
+               
+               /* search switch with requested MAC */
+               sa = ngadmin_getSwitchTab(nga, &n);
+               while (--n >= 0) {
+                       if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
+                               break;
+               }
+       
+               if (n < 0) {
+                       printf("no switch found\n");
+               } else {
+                       printf("done\n");
+                       break;
+               }
+       }
+       
+       if (n < 0)
+               return 1;
+
+       /* login */
+       printf("login... ");
+       fflush(stdout);
+       err = ngadmin_login(nga, n);
+       if (err < 0)
+               printErrCode(err);
+       else
+               printf("done\n");
+       
+       return err;
+}
+
+
 int main (int argc, char **argv)
 {
        static const struct option opts[] = {
+               {"batch", no_argument, NULL, 'a'},
                {"keep-broadcasting", no_argument, NULL, 'b'},
                {"force-interface", no_argument, NULL, 'f'},
-               {"global-broadcast", no_argument, NULL, 'g'},
-               {"interface", required_argument, NULL, 'i'},
                {"help", no_argument, NULL, 'h'},
+               {"interface", required_argument, NULL, 'i'},
+               {"local-broadcast", no_argument, NULL, 'l'},
+               {"mac", required_argument, NULL, 'm'},
+               {"password", required_argument, NULL, 'p'},
+               {"retries", required_argument, NULL, 'r'},
                {"timeout", required_argument, NULL, 't'},
                {0, 0, 0, 0}
        };
        char *line, *com[MAXCOM];
-       const char *iface = "eth0";
+       const char *iface = "eth0", *password = NULL;
        float timeout = 0.f;
-       bool kb = false, force = false, global = false;
+       bool kb = false, force = false, global = true;
        struct timeval tv;
        const struct TreeNode *cur, *next;
-       int i, n;
+       struct ether_addr *mac = NULL;
+       int i, n, retries = 3;
        
        
        tcgetattr(STDIN_FILENO, &orig_term);
        current_term = orig_term;
+       batch = false;
        
        opterr = 0;
        
-       while ((n = getopt_long(argc, argv, "bfgi:ht:", opts, NULL)) != -1) {
+       while ((n = getopt_long(argc, argv, "abfhi:lm:p:r:t:", opts, NULL)) != -1) {
                switch (n) {
                
+               case 'a':
+                       batch = true;
+                       break;
+               
                case 'b':
                        kb = true;
                        break;
@@ -171,24 +231,40 @@ int main (int argc, char **argv)
                        force = true;
                        break;
                
-               case 'g':
-                       global = true;
-                       break;
+               case 'h':
+                       printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
+                       goto end;
                
                case 'i':
                        iface = optarg;
                        break;
                
-               case 'h':
-                       printf("Usage: %s [-b] [-f] [-g] [-i <interface>]\n", argv[0]);
-                       goto end;
+               case 'l':
+                       global = false;
+                       break;
+               
+               case 'm':
+                       mac = ether_aton(optarg);
+                       if (mac == NULL) {
+                               printf("invalid MAC\n");
+                               goto end;
+                       }
+                       break;
+               
+               case 'p':
+                       password = optarg;
+                       break;
+               
+               case 'r':
+                       retries = strtol(optarg, NULL, 0);
+                       break;
                
                case 't':
                        timeout = strtof(optarg, NULL);
                        break;
                
                case '?':
-                       printf("Unknown option: \"%s\"\n", argv[optind - 1]);
+                       printf("unknown option: \"%s\"\n", argv[optind - 1]);
                        goto end;
                }
        }
@@ -197,7 +273,7 @@ int main (int argc, char **argv)
        argv += optind;
        
        if (argc != 0) {
-               printf("Unknown trailing options\n");
+               printf("unknown trailing options\n");
                goto end;
        }
        
@@ -206,7 +282,7 @@ int main (int argc, char **argv)
        
        nga = ngadmin_init(iface);
        if (nga == NULL) {
-               fprintf(stderr, "Initialization error\n");
+               fprintf(stderr, "initialization error\n");
                goto end;
        }
        
@@ -218,27 +294,55 @@ int main (int argc, char **argv)
        }
        
        
-       if (kb && ngadmin_setKeepBroadcasting(nga, true) != ERR_OK)
+       if (ngadmin_setKeepBroadcasting(nga, kb) != ERR_OK)
                goto end;
        
        if (force && ngadmin_forceInterface(nga) != ERR_OK)
                goto end;
        
-       if (global && ngadmin_useGlobalBroadcast(nga, true) != ERR_OK)
+       if (ngadmin_useGlobalBroadcast(nga, global) != ERR_OK)
                goto end;
        
-       rl_attempted_completion_function = my_completion;
-       rl_completion_entry_function = my_generator;
+       /* non-TTY inputs are automatically set to batch mode */
+       if (!isatty(STDIN_FILENO))
+               batch = true;
+       
+       if (password != NULL)
+               ngadmin_setPassword(nga, password);
        
        signal(SIGTERM, handler);
        signal(SIGINT, handler);
        
-       sigsetjmp(jmpbuf, 1);
+       /* automatic scan & login when switch MAC is specified on the command line */
+       if (mac != NULL && pre_login(mac, retries) != 0)
+               goto end;
+       
+       if (batch) {
+               /* in batch mode, we must be logged to continue */
+               if (ngadmin_getCurrentSwitch(nga) == NULL) {
+                       printf("must be logged\n");
+                       goto end;
+               }
+       } else {
+               /* initialize readline functions */
+               rl_attempted_completion_function = my_completion;
+               rl_completion_entry_function = my_generator;
+               
+               sigsetjmp(jmpbuf, 1);
+       }
        
-       while (cont) {
-               line = readline("> ");
-               if (line == NULL)
+       while (main_loop_continue) {
+               /* read user input */
+               line = NULL;
+               n = 0;
+               if (batch)
+                       n = getline(&line, (size_t*)&i, stdin);
+               else
+                       line = readline("> ");
+               if (n < 0 || line == NULL)
                        goto end;
+               
+               /* split string into words */
                trim(line, strlen(line));
                n = explode(line, com, MAXCOM);
                
@@ -246,35 +350,34 @@ int main (int argc, char **argv)
                        free(line);
                        continue;
                } else {
-                       add_history(line);
+                       if (!batch)
+                               add_history(line);
                        free(line);
                }
                
                cur = getSubCom(com, n, &i);
                
-               if (i < n) { /* commands left unchecked */
-                       if (i == 0) { /* root command */
-                               printf("unknown command\n");
-                       } else if (cur->sub != NULL) { /* intermediate command */
-                               printf("unknown %s subcommand\n", com[i - 1]);
-                       } else if (!cur->hasArgs) { /* terminal command without arguments */
-                               printf("%s as no subcommand and takes no parameter\n", com[i - 1]);
-                       } else if (cur->comfunc == NULL) { /* erroneous terminal command without function */
-                               printf("terminal command without function\n");
-                       } else { /* terminal command with arguments, left "commands" are in fact parameters */
-                               cur->comfunc(n - i, (const char**)&com[i], nga);
-                       }
-               } else { /* no command left */
-                       if (cur->sub != NULL) { /* intermediate command */
+               if (cur->sub != NULL) {
+                       /* not terminal command */
+                       if (i == 0) {
+                               /* root command */
+                               printf("unknown command: %s\n", com[i]);
+                       } else if (i < n) {
+                               /* intermediate command, remaining string */
+                               printf("unknown %s subcommand: %s\n", com[i - 1], com[i]);
+                       } else {
+                               /* intermediate command, no remaining string */
                                /* print available subcommands */
                                for (next = cur->sub; next->name != NULL; next++)
                                        printf("%s ", next->name);
-                               printf("\n");
-                       } else if (cur->comfunc == NULL) { /* erroneous terminal command without function */
-                               printf("terminal command without function\n");
-                       } else { /* terminal command without arguments */
-                               cur->comfunc(0, NULL, nga); 
+                               putchar('\n');
                        }
+               } else if (cur->comfunc == NULL) {
+                       /* erroneous terminal command without function */
+                       printf("terminal command without function\n");
+               } else {
+                       /* execute terminal command */
+                       cur->comfunc(n - i, (const char**)&com[i], nga);
                }
                
                for (i = 0; com[i] != NULL; i++) {