Libecoli 0.11.1
Extensible COmmand LIne library
Loading...
Searching...
No Matches
pool-editline/main.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2025, Olivier MATZ <zer0@droids-corp.org>
3 */
4
33
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include <ecoli.h>
40
41#include "ip_pool.h"
42
43#define POOL_REGEXP "[A-Za-z][-_a-zA-Z0-9]+"
44#define IP_REGEXP \
45 "((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-" \
46 "9]|[1-9][0-9]|[0-9])"
47#define ID_POOL_NAME "id_pool_name"
48#define ID_ADDR "id_addr"
49
50/* stop program when true */
51static bool done;
52
53static struct ec_node *with_help(struct ec_node *node, const char *help)
54{
55 if (node == NULL)
56 return NULL;
57 if (ec_interact_set_help(node, help) < 0) {
58 ec_node_free(node);
59 return NULL;
60 }
61 return node;
62}
63
64static struct ec_node *with_cb(struct ec_node *node, ec_interact_command_cb_t cb)
65{
66 if (node == NULL)
67 return NULL;
68 if (ec_interact_set_callback(node, cb) < 0) {
69 ec_node_free(node);
70 return NULL;
71 }
72 return node;
73}
74
75static struct ec_node *with_desc(struct ec_node *node, const char *desc)
76{
77 if (node == NULL)
78 return NULL;
79 if (ec_interact_set_desc(node, desc) < 0) {
80 ec_node_free(node);
81 return NULL;
82 }
83 return node;
84}
85
86static int pool_list_cb(const struct ec_pnode *parse)
87{
88 struct ec_strvec *names = NULL;
89 size_t len;
90 size_t i;
91
92 (void)parse;
93
94 names = ip_pool_list();
95 if (names == NULL) {
96 fprintf(stderr, "Failed to list pools\n");
97 return -1;
98 }
99
100 len = ec_strvec_len(names);
101 if (len == 0) {
102 printf("No pool\n");
103 } else {
104 for (i = 0; i < len; i++)
105 printf("%s\n", ec_strvec_val(names, i));
106 }
107
108 ec_strvec_free(names);
109
110 return 0;
111}
112
113static int pool_add_cb(const struct ec_pnode *parse)
114{
115 const char *pool_name;
116
117 pool_name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_POOL_NAME)), 0);
118 if (ip_pool(pool_name) == NULL) {
119 fprintf(stderr, "Failed to add pool\n");
120 return -1;
121 }
122
123 return 0;
124}
125
126static int pool_del_cb(const struct ec_pnode *parse)
127{
128 const char *pool_name;
129
130 pool_name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_POOL_NAME)), 0);
131 ip_pool_free(pool_name);
132
133 return 0;
134}
135
136static int addr_list_cb(const struct ec_pnode *parse)
137{
138 struct ec_strvec *addrs = NULL;
139 const struct ip_pool *pool;
140 const char *pool_name;
141 size_t len;
142 size_t i;
143
144 pool_name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_POOL_NAME)), 0);
145 pool = ip_pool_lookup(pool_name);
146 addrs = ip_pool_addr_list(pool);
147 if (addrs == NULL) {
148 fprintf(stderr, "Failed to list pool addresses\n");
149 return -1;
150 }
151
152 len = ec_strvec_len(addrs);
153 if (len == 0) {
154 printf("No address\n");
155 } else {
156 for (i = 0; i < len; i++)
157 printf("%s\n", ec_strvec_val(addrs, i));
158 }
159
160 ec_strvec_free(addrs);
161
162 return 0;
163}
164
165static int addr_add_cb(const struct ec_pnode *parse)
166{
167 const char *pool_name;
168 struct ip_pool *pool;
169 const char *addr;
170
171 pool_name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_POOL_NAME)), 0);
172 pool = ip_pool_lookup(pool_name);
173 addr = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_ADDR)), 0);
174 if (ip_pool_addr_add(pool, addr) < 0) {
175 fprintf(stderr, "Failed to add address to pool\n");
176 return -1;
177 }
178
179 return 0;
180}
181
182static int addr_del_cb(const struct ec_pnode *parse)
183{
184 const char *pool_name;
185 struct ip_pool *pool;
186 const char *addr;
187
188 pool_name = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_POOL_NAME)), 0);
189 pool = ip_pool_lookup(pool_name);
190 addr = ec_strvec_val(ec_pnode_get_strvec(ec_pnode_find(parse, ID_ADDR)), 0);
191 if (ip_pool_addr_del(pool, addr) < 0) {
192 fprintf(stderr, "Failed to delete address from pool\n");
193 return -1;
194 }
195
196 return 0;
197}
198
199static int exit_cb(const struct ec_pnode *parse)
200{
201 (void)parse;
202
203 printf("Exit !\n");
204 done = true;
205
206 return 0;
207}
208
209static int check_exit(void *opaque)
210{
211 (void)opaque;
212 return done;
213}
214
215static struct ec_strvec *list_pools(struct ec_pnode *pstate, void *opaque)
216{
217 (void)pstate;
218 (void)opaque;
219
220 return ip_pool_list();
221}
222
223static struct ec_strvec *list_addrs(struct ec_pnode *pstate, void *opaque)
224{
225 const char *pool_name;
226 struct ip_pool *pool;
227
228 (void)opaque;
229
230 pool_name = ec_strvec_val(
231 ec_pnode_get_strvec(ec_pnode_find(ec_pnode_get_root(pstate), ID_POOL_NAME)), 0
232 );
233 if (pool_name == NULL)
234 return ec_strvec();
235 pool = ip_pool_lookup(pool_name);
236 if (pool == NULL)
237 return ec_strvec();
238
239 return ip_pool_addr_list(pool);
240}
241
242static struct ec_node *create_pool_commands(void)
243{
244 struct ec_node *cmdlist = NULL;
245
246 /* the list of pool subcommands */
247 cmdlist = EC_NODE_OR(
248 EC_NO_ID,
249 with_cb(with_help(ec_node_str(EC_NO_ID, "list"), "Display the list of IP pools"),
250 pool_list_cb),
251 with_cb(EC_NODE_SEQ(
252 EC_NO_ID,
253 with_help(ec_node_str(EC_NO_ID, "add"), "Create an IP pool"),
254 with_help(
255 with_desc(
257 ID_POOL_NAME,
258 list_pools,
259 NULL,
260 POOL_REGEXP,
262 ),
263 "<pool-name>"
264 ),
265 "The name of the pool to create"
266 )
267 ),
268 pool_add_cb),
269 with_cb(EC_NODE_SEQ(
270 EC_NO_ID,
271 with_help(ec_node_str(EC_NO_ID, "del"), "Delete an IP pool"),
272 with_help(
273 with_desc(
275 ID_POOL_NAME,
276 list_pools,
277 NULL,
278 POOL_REGEXP,
280 ),
281 "<pool-name>"
282 ),
283 "The name of the pool to delete"
284 )
285 ),
286 pool_del_cb)
287 );
288
289 /* the pool command */
290 return EC_NODE_SEQ(
291 EC_NO_ID,
292 with_help(ec_node_str(EC_NO_ID, "pool"), "Add, delete, or list pools"),
293 cmdlist
294 );
295}
296
297static struct ec_node *create_addr_commands(void)
298{
299 struct ec_node *cmdlist = NULL;
300
301 /* the list of addr subcommands */
302 cmdlist = EC_NODE_OR(
303 EC_NO_ID,
304 with_cb(with_help(
306 "Display the list of IP addresses in a pool"
307 ),
308 addr_list_cb),
310 EC_NO_ID,
311 with_cb(with_help(
312 ec_node_str(EC_NO_ID, "add"),
313 "Add an IP address into a pool"
314 ),
315 addr_add_cb),
316
317 with_help(
318 with_desc(
320 ID_ADDR,
321 list_addrs,
322 NULL,
323 IP_REGEXP,
325 ),
326 "<a.b.c.d>"
327 ),
328 "The IP to add"
329 )
330 ),
332 EC_NO_ID,
333 with_cb(with_help(
334 ec_node_str(EC_NO_ID, "del"),
335 "Delete an IP address from a pool"
336 ),
337 addr_del_cb),
338
339 with_help(
340 with_desc(
342 ID_ADDR,
343 list_addrs,
344 NULL,
345 IP_REGEXP,
347 ),
348 "<a.b.c.d>"
349 ),
350 "The existing IP to delete"
351 )
352 )
353
354 );
355
356 return EC_NODE_SEQ(
357 EC_NO_ID,
358 with_help(ec_node_str(EC_NO_ID, "addr"), "Add, delete, list addresses in pool"),
359 with_help(ec_node_str(EC_NO_ID, "pool"), "Specify the pool for this operation"),
360 with_help(
361 with_desc(
363 ID_POOL_NAME,
364 list_pools,
365 NULL,
366 POOL_REGEXP,
368 ),
369 "<pool-name>"
370 ),
371 "The name of the pool (must exist)"
372 ),
373 cmdlist
374 );
375}
376
377static struct ec_node *create_commands(void)
378{
379 struct ec_node *cmdlist = NULL;
380 struct ec_node *cmd = NULL;
381
382 /* the top node containing the list of commands */
383 cmdlist = ec_node("or", EC_NO_ID);
384 if (cmdlist == NULL)
385 goto fail;
386
387 /* the exit command */
388 cmd = ec_node_str(EC_NO_ID, "exit");
389 if (ec_interact_set_callback(cmd, exit_cb) < 0)
390 goto fail;
391 if (ec_interact_set_help(cmd, "Exit program") < 0)
392 goto fail;
393 if (ec_node_or_add(cmdlist, cmd) < 0)
394 goto fail;
395
396 /* the pool commands */
397 if (ec_node_or_add(cmdlist, create_pool_commands()) < 0)
398 goto fail;
399
400 /* the addr commands */
401 if (ec_node_or_add(cmdlist, create_addr_commands()) < 0)
402 goto fail;
403
404 /* the lexer, added above the command list */
405 cmdlist = ec_node_sh_lex(EC_NO_ID, cmdlist);
406 if (cmdlist == NULL)
407 goto fail;
408
409 return cmdlist;
410
411fail:
412 fprintf(stderr, "cannot initialize nodes\n");
413 ec_node_free(cmdlist);
414 return NULL;
415}
416
417int main(void)
418{
419 struct ec_editline *editline = NULL;
420 struct ec_node *node = NULL;
421
422 if (ip_pool_init() < 0) {
423 fprintf(stderr, "cannot init IP pools: %s\n", strerror(errno));
424 return 1;
425 }
426
427 if (ec_init() < 0) {
428 fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
429 return 1;
430 }
431
432 node = create_commands();
433 if (node == NULL) {
434 fprintf(stderr, "failed to create commands: %s\n", strerror(errno));
435 goto fail;
436 }
437
438 editline = ec_editline("pool-editline", stdin, stdout, stderr, 0);
439 if (editline == NULL) {
440 fprintf(stderr, "Failed to initialize editline\n");
441 goto fail;
442 }
443
444 if (ec_editline_set_prompt(editline, "pool> ") < 0) {
445 fprintf(stderr, "Failed to set prompt\n");
446 goto fail;
447 }
448 ec_editline_set_node(editline, node);
449
450 if (ec_editline_interact(editline, check_exit, NULL) < 0)
451 goto fail;
452
453 ec_editline_free(editline);
454 ec_node_free(node);
455 ip_pool_exit();
456
457 return 0;
458
459fail:
460 ec_editline_free(editline);
461 ec_node_free(node);
462 ip_pool_exit();
463 return 1;
464}
int ec_editline_set_prompt(struct ec_editline *editline, const char *prompt)
struct ec_editline * ec_editline(const char *prog, FILE *f_in, FILE *f_out, FILE *f_err, enum ec_editline_init_flags flags)
void ec_editline_free(struct ec_editline *editline)
int ec_editline_interact(struct ec_editline *editline, ec_editline_check_exit_cb_t check_exit_cb, void *opaque)
int ec_editline_set_node(struct ec_editline *editline, const struct ec_node *node)
int ec_init(void)
int(* ec_interact_command_cb_t)(const struct ec_pnode *)
Definition interact.h:49
int ec_interact_set_help(struct ec_node *node, const char *help)
int ec_interact_set_desc(struct ec_node *node, const char *desc)
int ec_interact_set_callback(struct ec_node *node, ec_interact_command_cb_t cb)
struct ec_node * ec_node_dynlist(const char *id, ec_node_dynlist_get_t get, void *opaque, const char *re_str, enum ec_node_dynlist_flags flags)
@ DYNLIST_MATCH_REGEXP
@ DYNLIST_MATCH_LIST
@ DYNLIST_EXCLUDE_LIST
int ec_node_or_add(struct ec_node *node, struct ec_node *child)
#define EC_NODE_OR(args...)
Definition node_or.h:23
#define EC_NODE_SEQ(args...)
Definition node_seq.h:29
struct ec_node * ec_node_sh_lex(const char *id, struct ec_node *child)
struct ec_node * ec_node_str(const char *id, const char *str)
struct ec_node * ec_node(const char *typename, const char *id)
#define EC_NO_ID
Definition node.h:64
void ec_node_free(struct ec_node *node)
const struct ec_strvec * ec_pnode_get_strvec(const struct ec_pnode *pnode)
const struct ec_pnode * ec_pnode_find(const struct ec_pnode *root, const char *id)
struct ec_pnode * ec_pnode_get_root(struct ec_pnode *pnode)
struct ec_pnode * ec_pnode(const struct ec_node *node)
void ec_strvec_free(struct ec_strvec *strvec)
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
struct ec_strvec * ec_strvec(void)
size_t ec_strvec_len(const struct ec_strvec *strvec)