]> git.sur5r.net Git - ngadmin/blob - cli/admin.c
b23018d25b5f3c1ff0717914b0c127b41534c58c
[ngadmin] / cli / admin.c
1
2 #include <stdio.h>
3 #include <signal.h>
4 #include <setjmp.h>
5
6 #include <getopt.h>
7 #include <readline/readline.h>
8 #include <readline/history.h>
9
10 #include "common.h"
11 #include "commands.h"
12
13
14
15
16 #define MAXCOM  32
17
18
19 int cont=1;
20
21
22
23
24 const struct TreeNode* getSubCom (char **com, int n, int *t) {
25  
26  int i;
27  const struct TreeNode *cur, *next;
28  
29  
30  cur=&coms;
31  for (i=0; i<n; ++i) {
32   
33   // we have reached a terminal command, exit
34   if ( cur->sub==NULL ) break;
35   
36   // search sub command in sub command array
37   for (next=cur->sub; next->name!=NULL && strcmp(next->name, com[i])!=0; ++next);
38   
39   // sub command not found, exit
40   if ( next->name==NULL ) break;
41   
42   // next command is now the current one
43   cur=next;
44   
45  }
46  
47  *t=i;
48  
49  
50  return cur;
51  
52 }
53
54
55
56
57 const struct TreeNode *compcur;
58
59
60
61 char* my_generator (const char* text, int state) {
62  
63  static int len;
64  static const struct TreeNode *tn;
65  const char *name;
66  
67  
68  if ( compcur==NULL ) { // sub command not found
69   return NULL;
70  } else if ( state==0 ) {
71   tn=compcur->sub;
72   len=strlen(text);
73  }
74  
75  if ( tn==NULL ) { // terminal command
76   return NULL;
77  }
78  
79  
80  while ( (name=tn++->name)!=NULL )
81   if ( strncmp(name, text, len)==0 )
82    return strdup(name);
83  
84  
85  return NULL;
86  
87 }
88
89
90
91 char** my_completion (const char *text, int start, int end UNUSED) {
92  
93  char **matches=NULL;
94  char *line, *com[MAXCOM];
95  int i, n;
96  
97  
98  memset(com, 0, MAXCOM*sizeof(char*));
99  line=strdup(rl_line_buffer);
100  line[start]=0;
101  trim(line, start);
102  n=explode(line, com, MAXCOM);
103  free(line);
104  
105  compcur=getSubCom(com, n, &i);
106  
107  if ( i<n ) compcur=NULL;
108  matches=rl_completion_matches(text, my_generator);
109  
110  for (i=0; com[i]!=NULL; ++i) {
111   free(com[i]);
112  }
113  
114  
115  return matches;
116  
117 }
118
119
120
121 static struct ngadmin *nga=NULL;
122 static sigjmp_buf jmpbuf;
123 struct termios orig_term, current_term;
124
125
126
127 NORET static void handler (int sig) {
128  
129  
130  switch ( sig ) {
131   
132   case SIGTERM:
133   case SIGINT:
134    printf("interrupt\n");
135   
136    current_term.c_lflag|=ECHO;
137    tcsetattr(STDIN_FILENO, TCSANOW, &current_term);
138    
139    siglongjmp(jmpbuf, 1);
140   
141   default:
142    ngadmin_close(nga);
143    
144    tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
145    
146    exit(0);
147   
148  }
149  
150  
151 }
152
153
154
155 int main (int argc, char **argv) {
156  
157  static const struct option opts[]={
158   {"keep-broadcasting", no_argument, NULL, 'b'}, 
159   {"force-interface", no_argument, NULL, 'f'}, 
160   {"global-broadcast", no_argument, NULL, 'g'}, 
161   {"interface", required_argument, NULL, 'i'}, 
162   {"help", no_argument, NULL, 'h'}, 
163   {"timeout", required_argument, NULL, 't'}, 
164   {0, 0, 0, 0}
165  };
166  char *line, *com[MAXCOM];
167  const char *iface="eth0";
168  float timeout=0.f;
169  bool kb=false, force=false, global=false;
170  struct timeval tv;
171  const struct TreeNode *cur, *next;
172  int i, n;
173  
174  
175  
176  tcgetattr(STDIN_FILENO, &orig_term);
177  current_term=orig_term;
178  /*
179  current_term.c_lflag&=~ECHOCTL;
180  tcsetattr(STDIN_FILENO, TCSANOW, &current_term);
181  */
182  
183  
184  opterr=0;
185  
186  while ( (n=getopt_long(argc, argv, "bfgi:ht:", opts, NULL))!=-1 ) {
187   switch ( n ) {
188    
189    case 'b':
190     kb=true;
191    break;
192    
193    case 'f':
194     force=true;
195    break;
196    
197    case 'g':
198     global=true;
199    break;
200    
201    case 'i':
202     iface=optarg;
203    break;
204    
205    case 'h':
206     printf("Usage: %s [-b] [-f] [-g] [-i <interface>]\n", argv[0]);
207     goto end;
208    
209    case 't':
210     timeout=strtof(optarg, NULL);
211    break;
212    
213    case '?':
214     printf("Unknown option: \"%s\"\n", argv[optind-1]);
215     goto end;
216    
217   }
218  }
219  
220  argc-=optind;
221  argv+=optind;
222  
223  
224  if ( argc!=0 ) {
225   printf("Unknown trailing options\n");
226   goto end;
227  }
228  
229  
230  memset(com, 0, MAXCOM*sizeof(char*));
231  
232  if ( (nga=ngadmin_init(iface))==NULL ) {
233   fprintf(stderr, "Initialization error\n");
234   goto end;
235  }
236  
237  // set timeout
238  if ( timeout>0.f ) {
239   tv.tv_sec=(int)timeout;
240   tv.tv_usec=(int)((timeout-(float)tv.tv_sec)*1.e6f);
241   ngadmin_setTimeout(nga, &tv);
242  }
243  
244  
245  if ( kb && ngadmin_setKeepBroadcasting(nga, true)!=ERR_OK ) goto end;
246  
247  if ( force && ngadmin_forceInterface(nga)!=ERR_OK ) goto end;
248  
249  if ( global && ngadmin_useGlobalBroadcast(nga, true)!=ERR_OK ) goto end;
250  
251  
252  
253  //rl_bind_key('\t', rl_abort); // disable auto completion
254  //rl_bind_key('\t', rl_complete); // enable auto-complete
255  rl_attempted_completion_function=my_completion;
256  rl_completion_entry_function=my_generator;
257  
258  
259  
260  signal(SIGTERM, handler);
261  signal(SIGINT, handler);
262  
263  sigsetjmp(jmpbuf, 1);
264  
265  
266  while ( cont ) {
267   
268   if ( (line=readline("> "))==NULL ) goto end;
269   trim(line, strlen(line));
270   n=explode(line, com, MAXCOM);
271   
272   if ( n==0 ) {
273    free(line);
274    continue;
275   } else {
276    add_history(line);
277    free(line);
278   }
279   
280   cur=getSubCom(com, n, &i);
281   
282   if ( i<n ) { // commands left unchecked
283    
284    if ( i==0 ) { // root command
285     printf("unknown command\n");
286    } else if ( cur->sub!=NULL ) { // intermediate command
287     printf("unknown %s subcommand\n", com[i-1]);
288    } else if ( !cur->hasArgs ) { // terminal command without arguments
289     printf("%s as no subcommand and takes no parameter\n", com[i-1]);
290    } else if ( cur->comfunc==NULL ) { // erroneous terminal command without function
291     printf("terminal command without function\n");
292    } else { // terminal command with arguments, left "commands" are in fact parameters
293     cur->comfunc(n-i, (const char**)&com[i], nga);
294    }
295    
296   } else { // no command left
297    
298    if ( cur->sub!=NULL ) { // intermediate command
299     // print available subcommands
300     for (next=cur->sub; next->name!=NULL; ++next) {
301      printf("%s ", next->name);
302     }
303     printf("\n");
304    } else if ( cur->comfunc==NULL ) { // erroneous terminal command without function
305     printf("terminal command without function\n");
306    } else { // terminal command without arguments
307     cur->comfunc(0, NULL, nga); 
308    }
309    
310   }
311   
312   
313   for (i=0; com[i]!=NULL; ++i) {
314    free(com[i]);
315    com[i]=NULL;
316   }
317   
318  }
319  
320  
321  end:
322  handler(0);
323  
324 }
325
326