X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=cli%2Fadmin.c;h=40f5431ba8df0a95eb9af189cd2483888f02e9ff;hb=5b6cf83fc4d11e65d212975bb1e2504dbf9125cb;hp=beb40f22192c9c8768735fb36028c0890279626c;hpb=25c375ef21fa0c0d46b6d7a45acd4d613f1fe907;p=ngadmin diff --git a/cli/admin.c b/cli/admin.c index beb40f2..40f5431 100644 --- a/cli/admin.c +++ b/cli/admin.c @@ -1,5 +1,8 @@ #include +#include +#include +#include #include #include @@ -9,276 +12,382 @@ #include "commands.h" - - #define MAXCOM 32 -int cont=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; +} +static const struct TreeNode *compcur; -const struct TreeNode* getSubCom (char **com, int n, int *t) { - - int i; - const struct TreeNode *cur, *next; - - - cur=&coms; - for (i=0; isub==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; - -} +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; +} +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; +} -const struct TreeNode *compcur; +int main_loop_continue; +static struct ngadmin *nga; +static sigjmp_buf jmpbuf; +static struct termios orig_term; +struct termios current_term; +static bool batch; -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 ) { - ++tn; - - if ( strncmp(name, text, len)==0 ) { - return strdup(name); - } - - } - - - return NULL; - +NORET static void handler (int sig) +{ + switch (sig) { + + case SIGTERM: + case SIGINT: + printf("interrupt\n"); + + current_term.c_lflag |= ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, ¤t_term); + + if (!batch && main_loop_continue) + siglongjmp(jmpbuf, 1); + + default: + ngadmin_close(nga); + + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); + + exit(0); + } } +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; -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", 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*)); - - if ( (nga=ngadmin_init(iface))==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_bind_key('\t', rl_abort); // disable auto completion - //rl_bind_key('\t', rl_complete); // enable auto-complete - rl_attempted_completion_function=my_completion; - rl_completion_entry_function=my_generator; - - - while ( cont ) { - - if ( (line=readline("> "))==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 ( isub!=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 - // 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); - } - - } - - - for (i=0; com[i]!=NULL; ++i) { - free(com[i]); - com[i]=NULL; - } - - } - - - end: - ngadmin_close(nga); - - - return 0; - +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'}, + {"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", *password = NULL; + float timeout = 0.f; + bool kb = false, force = false, global = true; + struct timeval tv; + const struct TreeNode *cur, *next; + 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, "abfhi:lm:p:r:t:", opts, NULL)) != -1) { + switch (n) { + + case 'a': + batch = true; + break; + + case 'b': + kb = true; + break; + + case 'f': + force = true; + break; + + case 'h': + printf("usage: %s [-a] [-b] [-f] [-g] [-i ] [-m ] [-p ]\n", argv[0]); + goto end; + + case 'i': + iface = optarg; + break; + + 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]); + 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 (ngadmin_setKeepBroadcasting(nga, kb) != ERR_OK) + goto end; + + if (force && ngadmin_forceInterface(nga) != ERR_OK) + goto end; + + if (ngadmin_useGlobalBroadcast(nga, global) != ERR_OK) + goto end; + + /* 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); + + /* 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); + } + + main_loop_continue = 1; + 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); + + if (n == 0) { + free(line); + continue; + } else { + if (!batch) + 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); }