]> git.sur5r.net Git - ngadmin/blobdiff - cli/admin.c
Let commands handle themselves absence of arguments
[ngadmin] / cli / admin.c
index 523a96c188a6430d073ce3752fcafc1f506cc5fe..14ad11cf9ce1bc413f98be4baface91bd27b0ce4 100644 (file)
 
 #include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
 
+#include <getopt.h>
 #include <readline/readline.h>
 #include <readline/history.h>
 
-#include "command.h"
 #include "common.h"
+#include "commands.h"
 
 
+#define MAXCOM 32
 
 
-#define MAXCOM 8
-
-
+int main_loop_continue = 1;
 
 
+static const struct TreeNode* getSubCom (char **com, int n, int *t)
+{
+       int i;
+       const struct TreeNode *cur, *next;
+       
+       
+       cur = &commands;
+       for (i = 0; i < n; i++) {
+               /* we have reached a terminal command, exit */
+               if (cur->sub == NULL)
+                       break;
+               
+               /* search sub command in sub command array */
+               for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
+               
+               /* sub command not found, exit */
+               if (next->name == NULL)
+                       break;
+               
+               /* next command is now the current one */
+               cur = next;
+       }
+       
+       *t = i;
+       
+       
+       return cur;
+}
 
-int cont=1;
 
+static const struct TreeNode *compcur;
 
-static const struct TreeNode rootNode={.sub={
- &com_quit,
- &com_login, 
- &com_scan, 
- &com_ports, 
- &com_password, 
- &com_list, 
- &com_firmware, 
- &com_name, 
- NULL
-}};
 
+static char* my_generator (const char* text, int state)
+{
+       static int len;
+       static const struct TreeNode *tn;
+       const char *name;
+       
+       
+       if (compcur == NULL) {
+               /* sub command not found */
+               return NULL;
+       } else if (state == 0) {
+               tn = compcur->sub;
+               len = strlen(text);
+       }
+       
+       if (tn == NULL) /* terminal command */
+               return NULL;
+       
+       while ((name = tn++->name) != NULL) {
+               if (strncmp(name, text, len) == 0)
+                       return strdup(name);
+       }
+       
+       
+       return NULL;
+}
 
 
-void printErrCode (int err) {
- switch ( err ) {
-  case ERR_OK: /*printf("ok\n");*/ break;
-  case ERR_NET: printf("network error\n"); break;
-  case ERR_NOTLOG: printf("no switch selected\n"); break;
-  case ERR_BADPASS: printf("wrong password\n"); break;
-  case ERR_BADID: printf("bad switch id\n"); break;
-  case ERR_INVARG: printf("invalid argument\n"); break;
-  case ERR_TIMEOUT: printf("timeout\n"); break;
-  default: printf("unknown status code (%i)\n", err);
- }
+static char** my_completion (const char *text, int start, int end UNUSED)
+{
+       char **matches = NULL;
+       char *line, *com[MAXCOM];
+       int i, n;
+       
+       
+       memset(com, 0, MAXCOM * sizeof(char*));
+       line = strdup(rl_line_buffer);
+       line[start] = '\0';
+       trim(line, start);
+       n = explode(line, com, MAXCOM);
+       free(line);
+       
+       compcur = getSubCom(com, n, &i);
+       
+       if (i < n)
+               compcur = NULL;
+       matches = rl_completion_matches(text, my_generator);
+       
+       for (i = 0; com[i] != NULL; i++)
+               free(com[i]);
+       
+       
+       return matches;
 }
 
 
-
-void displaySwitchTab (const struct swi_attr *sa, int nb) {
- int i=0;
- if ( nb==0 ) {
-  printf("no switch found\n");
-  return;
- }
- printf("Num\tMac\t\t\tProduct\t\tName\t\t\tIP/mask\t\t\t\tDHCP\tPorts\tFirmware\n");
- for (i=0; i<nb; ++i) {
-  printf("%i\t%s\t%s\t\t%s\t%s/", i, ether_ntoa(&sa[i].mac), sa[i].product, sa[i].name, inet_ntoa(sa[i].nc.ip));
-  printf("%s\t%s\t%i\t%s\n", inet_ntoa(sa[i].nc.netmask), ( sa[i].nc.dhcp ? "Yes" : "No" ), sa[i].ports, sa[i].firmware);
- }
- printf("\nfound %i switch(es)\n", nb);
-}
+static struct ngadmin *nga;
+static sigjmp_buf jmpbuf;
+static struct termios orig_term;
+struct termios current_term;
 
 
+NORET static void handler (int sig)
+{
+       switch (sig) {
+       
+       case SIGTERM:
+       case SIGINT:
+               printf("interrupt\n");
+               
+               current_term.c_lflag|=ECHO;
+               tcsetattr(STDIN_FILENO, TCSANOW, &current_term);
+               
+               siglongjmp(jmpbuf, 1);
+       
+       default:
+               ngadmin_close(nga);
+               
+               tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+               
+               exit(0);
+       }
+}
 
 
-int main (int argc, char **argv) {
- char *line, *com[MAXCOM];
- struct ngadmin *nga=NULL;
- struct timeval tv;
- const struct TreeNode *cur, *next, **tab;
- int i, n;
- if ( argc<2 ) {
-  printf("Usage: %s <interface>\n", argv[0]);
-  return 1;
- }
- memset(com, 0, MAXCOM*sizeof(char*));
- if ( (nga=ngadmin_init(argv[1]))==NULL ) {
-  fprintf(stderr, "Initialization error\n");
-  goto end;
- }
- // set timeout
- tv.tv_sec=3;
- tv.tv_usec=0;
- ngadmin_setTimeout(nga, &tv);
- rl_bind_key('\t', rl_abort); // disable auto completion
- while ( cont ) {
-  
-  if ( (line=readline("> "))==NULL ) goto end;
-  trim(line, strlen(line));
-  if ( *line!=0 ) add_history(line);
-  n=explode(line, com, MAXCOM);
-  free(line);
-  
-  
-  i=0;
-  for (next=&rootNode; i<n; ++i) {
-   cur=next;
-   for (tab=cur->sub; (next=*tab)!=NULL && strcmp(next->name, com[i])!=0; ++tab);
-   if ( next==NULL ) break;
-  }
-  
-  
-  if ( i<n ) { // commands left uncompared
-   
-   if ( cur->hasArgs ) { // left "commands" are in fact parameters
-    cur->comfunc(cur, n-i, (const char**)&com[i], nga);
-   } else {
-    if ( i==0 ) {
-     printf("unknown command\n");
-    } else {
-     printf("unknown %s subcommand\n", com[i-1]);
-    }
-   }
-   
-  } else {
-   
-   cur=next;
-   if ( cur->comfunc==NULL ) {
-    // print available subcommands
-    for (tab=cur->sub; (next=*tab)!=NULL; ++tab) {
-     printf("%s ", next->name);
-    }
-    printf("\n");
-    
-   } else { // terminal command
-   
-    cur->comfunc(cur, 0, NULL, nga);
-    
-   }
-  }
-  
-  /*
-  if ( n==0 ) {
-   // nothing: do nothing
-   
-  } else if ( strcmp(com[0], "timeout")==0 ) {
-   // 
-   
-  }
-  */
-  
-  for (i=0; i<MAXCOM; i++) {
-   if ( com[i]!=NULL ) {
-    free(com[i]);
-    com[i]=NULL;
-   }
-  }
-  
- }
- end:
- ngadmin_close(nga);
- return 0;
+int main (int argc, char **argv)
+{
+       static const struct option opts[] = {
+               {"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'},
+               {"timeout", required_argument, NULL, 't'},
+               {0, 0, 0, 0}
+       };
+       char *line, *com[MAXCOM];
+       const char *iface = "eth0";
+       float timeout = 0.f;
+       bool kb = false, force = false, global = false;
+       struct timeval tv;
+       const struct TreeNode *cur, *next;
+       int i, n;
+       
+       
+       tcgetattr(STDIN_FILENO, &orig_term);
+       current_term = orig_term;
+       
+       opterr = 0;
+       
+       while ((n = getopt_long(argc, argv, "bfgi:ht:", opts, NULL)) != -1) {
+               switch (n) {
+               
+               case 'b':
+                       kb = true;
+                       break;
+               
+               case 'f':
+                       force = true;
+                       break;
+               
+               case 'g':
+                       global = true;
+                       break;
+               
+               case 'i':
+                       iface = optarg;
+                       break;
+               
+               case 'h':
+                       printf("usage: %s [-b] [-f] [-g] [-i <interface>]\n", argv[0]);
+                       goto end;
+               
+               case 't':
+                       timeout = strtof(optarg, NULL);
+                       break;
+               
+               case '?':
+                       printf("Unknown option: \"%s\"\n", argv[optind - 1]);
+                       goto end;
+               }
+       }
+       
+       argc -= optind;
+       argv += optind;
+       
+       if (argc != 0) {
+               printf("Unknown trailing options\n");
+               goto end;
+       }
+       
+       
+       memset(com, 0, MAXCOM * sizeof(char*));
+       
+       nga = ngadmin_init(iface);
+       if (nga == NULL) {
+               fprintf(stderr, "Initialization error\n");
+               goto end;
+       }
+       
+       /* set timeout */
+       if (timeout > 0.f) {
+               tv.tv_sec = (int)timeout;
+               tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
+               ngadmin_setTimeout(nga, &tv);
+       }
+       
+       
+       if (kb && ngadmin_setKeepBroadcasting(nga, true) != ERR_OK)
+               goto end;
+       
+       if (force && ngadmin_forceInterface(nga) != ERR_OK)
+               goto end;
+       
+       if (global && ngadmin_useGlobalBroadcast(nga, true) != ERR_OK)
+               goto end;
+       
+       rl_attempted_completion_function = my_completion;
+       rl_completion_entry_function = my_generator;
+       
+       signal(SIGTERM, handler);
+       signal(SIGINT, handler);
+       
+       sigsetjmp(jmpbuf, 1);
+       
+       while (main_loop_continue) {
+               line = readline("> ");
+               if (line == NULL)
+                       goto end;
+               trim(line, strlen(line));
+               n = explode(line, com, MAXCOM);
+               
+               if (n == 0) {
+                       free(line);
+                       continue;
+               } else {
+                       add_history(line);
+                       free(line);
+               }
+               
+               cur = getSubCom(com, n, &i);
+               
+               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);
+                               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++) {
+                       free(com[i]);
+                       com[i] = NULL;
+               }
+       }
+       
+end:
+       handler(0);
 }