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