Libecoli  0.11.3
Extensible COmmand LIne library
pool-editline/main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2025, Olivier MATZ <zer0@droids-corp.org>
3  */
4 
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 */
51 static bool done;
52 
53 static 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 
64 static 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 
75 static 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 
86 static 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 
113 static 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 
126 static 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 
136 static 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 
165 static 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 
182 static 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 
199 static 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 
209 static int check_exit(void *opaque)
210 {
211  (void)opaque;
212  return done;
213 }
214 
215 static 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 
223 static 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 
242 static 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 
297 static 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),
309  EC_NODE_SEQ(
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  ),
331  EC_NODE_SEQ(
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 
377 static 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 
411 fail:
412  fprintf(stderr, "cannot initialize nodes\n");
413  ec_node_free(cmdlist);
414  return NULL;
415 }
416 
417 int 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 
459 fail:
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)
void ec_editline_free(struct ec_editline *editline)
struct ec_editline * ec_editline(const char *prog, FILE *f_in, FILE *f_out, FILE *f_err, enum ec_editline_init_flags flags)
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
Definition: node_dynlist.h:51
@ DYNLIST_MATCH_LIST
Definition: node_dynlist.h:46
@ DYNLIST_EXCLUDE_LIST
Definition: node_dynlist.h:57
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)
#define EC_NO_ID
Definition: node.h:64
struct ec_node * ec_node(const char *typename, const char *id)
void ec_node_free(struct ec_node *node)
struct ec_pnode * ec_pnode_get_root(struct ec_pnode *pnode)
const struct ec_pnode * ec_pnode_find(const struct ec_pnode *root, const char *id)
struct ec_pnode * ec_pnode(const struct ec_node *node)
const struct ec_strvec * ec_pnode_get_strvec(const struct ec_pnode *pnode)
void ec_strvec_free(struct ec_strvec *strvec)
struct ec_strvec * ec_strvec(void)
size_t ec_strvec_len(const struct ec_strvec *strvec)
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)