1 /*
2 *
3 ***** BEGIN LICENSE BLOCK *****
4
5 Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
6 Copyright (C) 2017-2019 Olof Hagsand
7 Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
8
9 This file is part of CLIXON.
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 Alternatively, the contents of this file may be used under the terms of
24 the GNU General Public License Version 3 or later (the "GPL"),
25 in which case the provisions of the GPL are applicable instead
26 of those above. If you wish to allow use of your version of this file only
27 under the terms of the GPL, and not to allow others to
28 use your version of this file under the terms of Apache License version 2, indicate
29 your decision by deleting the provisions above and replace them with the
30 notice and other provisions required by the GPL. If you do not delete
31 the provisions above, a recipient may use your version of this file under
32 the terms of any one of the Apache License version 2 or the GPL.
33
34 ***** END LICENSE BLOCK *****
35
36 *
37 * This file contains access functions for two types of clixon vars:
38 * - options, ie string based variables from Clixon configuration files.
39 * Accessed with clicon_options(h).
40 * @see clixon_data.[ch] for free-type runtime get/set
41 */
42 #ifdef HAVE_CONFIG_H
43 #include "clixon_config.h" /* generated by config & autoconf */
44 #endif
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <stdlib.h>
52 #include <stdint.h>
53 #include <dirent.h>
54 #include <libgen.h> /* dirname */
55 #include <syslog.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/param.h>
59 #include <sys/socket.h>
60
61 /* cligen */
62 #include <cligen/cligen.h>
63
64 /* clixon */
65 #include "clixon_err.h"
66 #include "clixon_string.h"
67 #include "clixon_queue.h"
68 #include "clixon_hash.h"
69 #include "clixon_handle.h"
70 #include "clixon_file.h"
71 #include "clixon_log.h"
72 #include "clixon_yang.h"
73 #include "clixon_xml.h"
74 #include "clixon_options.h"
75 #include "clixon_data.h"
76 #include "clixon_xpath_ctx.h"
77 #include "clixon_xpath.h"
78 #include "clixon_yang_parse_lib.h"
79 #include "clixon_netconf_lib.h"
80 #include "clixon_xml_nsctx.h"
81 #include "clixon_xml_io.h"
82 #include "clixon_validate.h"
83 #include "clixon_xml_map.h"
84
85 /* Mapping between Cli generation from Yang string <--> constants,
86 see clixon-config.yang type cli_genmodel_type */
87 static const map_str2int cli_genmodel_map[] = {
88 {"NONE", GT_NONE},
89 {"VARS", GT_VARS},
90 {"ALL", GT_ALL},
91 {"HIDE", GT_HIDE},
92 {NULL, -1}
93 };
94
95 /* Mapping between Clicon startup modes string <--> constants,
96 see clixon-config.yang type startup_mode */
97 static const map_str2int startup_mode_map[] = {
98 {"none", SM_NONE},
99 {"running", SM_RUNNING},
100 {"startup", SM_STARTUP},
101 {"init", SM_INIT},
102 {NULL, -1}
103 };
104
105 /* Mapping between Clicon privileges modes string <--> constants,
106 * see clixon-config.yang type priv_mode */
107 static const map_str2int priv_mode_map[] = {
108 {"none", PM_NONE},
109 {"drop_perm", PM_DROP_PERM},
110 {"drop_temp", PM_DROP_TEMP},
111 {NULL, -1}
112 };
113
114
115 /* Mapping between Clicon nacm user credential string <--> constants,
116 * see clixon-config.yang type nacm_cred_mode */
117 static const map_str2int nacm_credentials_map[] = {
118 {"none", NC_NONE},
119 {"exact", NC_EXACT},
120 {"except", NC_EXCEPT},
121 {NULL, -1}
122 };
123
124 /* Mapping between datastore cache string <--> constants,
125 * see clixon-config.yang type datastore_cache */
126 static const map_str2int datastore_cache_map[] = {
127 {"nocache", DATASTORE_NOCACHE},
128 {"cache", DATASTORE_CACHE},
129 {"cache-zerocopy", DATASTORE_CACHE_ZEROCOPY},
130 {NULL, -1}
131 };
132
133 /* Mapping between regular expression type string <--> constants,
134 * see clixon-config.yang type regexp_mode */
135 static const map_str2int yang_regexp_map[] = {
136 {"posix", REGEXP_POSIX},
137 {"libxml2", REGEXP_LIBXML2},
138 {NULL, -1}
139 };
140
141 /*! Print registry on file. For debugging.
142 * @param[in] h Clicon handle
143 * @param[in] dbglevel Debug level
144 * @retval 0 OK
145 * @retval -1 Error
146 * @note CLICON_FEATURE and CLICON_YANG_DIR are treated specially since they are lists
147 */
148 int
clicon_option_dump(clicon_handle h,int dbglevel)149 clicon_option_dump(clicon_handle h,
150 int dbglevel)
151 {
152 int retval = -1;
153 clicon_hash_t *hash = clicon_options(h);
154 int i;
155 char **keys = NULL;
156 void *val;
157 size_t klen;
158 size_t vlen;
159 cxobj *x = NULL;
160
161 if (clicon_hash_keys(hash, &keys, &klen) < 0)
162 goto done;
163 for(i = 0; i < klen; i++) {
164 val = clicon_hash_value(hash, keys[i], &vlen);
165 if (vlen){
166 if (((char*)val)[vlen-1]=='\0') /* assume string */
167 clicon_debug(dbglevel, "%s =\t \"%s\"", keys[i], (char*)val);
168 else
169 clicon_debug(dbglevel, "%s =\t 0x%p , length %zu", keys[i], val, vlen);
170 }
171 else
172 clicon_debug(dbglevel, "%s = NULL", keys[i]);
173 }
174 /* Next print CLICON_FEATURE and CLICON_YANG_DIR from config tree
175 * Since they are lists they are placed in the config tree.
176 */
177 x = NULL;
178 while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
179 if (strcmp(xml_name(x), "CLICON_YANG_DIR") != 0)
180 continue;
181 clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
182 }
183 x = NULL;
184 while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
185 if (strcmp(xml_name(x), "CLICON_FEATURE") != 0)
186 continue;
187 clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
188 }
189 retval = 0;
190 done:
191 if (keys)
192 free(keys);
193 return retval;
194 }
195
196 /*! Open and parse single config file
197 * @param[in] filename
198 * @param[in] yspec
199 * @param[out] xconfig Pointer to xml config tree. Should be freed by caller
200 */
201 static int
parse_configfile_one(const char * filename,yang_stmt * yspec,cxobj ** xconfig)202 parse_configfile_one(const char *filename,
203 yang_stmt *yspec,
204 cxobj **xconfig)
205 {
206 int retval = -1;
207 int fd = -1;
208 cxobj *xt = NULL;
209 cxobj *xerr = NULL;
210 cxobj *xa;
211 cbuf *cbret = NULL;
212 int ret;
213
214 if ((fd = open(filename, O_RDONLY)) < 0){
215 clicon_err(OE_UNIX, errno, "open configure file: %s", filename);
216 return -1;
217 }
218 clicon_debug(2, "%s: Reading config file %s", __FUNCTION__, filename);
219 if ((ret = clixon_xml_parse_file(fd, yspec?YB_MODULE:YB_NONE, yspec, NULL, &xt, &xerr)) < 0)
220 goto done;
221 if (ret == 0){
222 if ((cbret = cbuf_new()) ==NULL){
223 clicon_err(OE_XML, errno, "cbuf_new");
224 goto done;
225 }
226 if (netconf_err2cb(xerr, cbret) < 0)
227 goto done;
228 /* Here one could make it more relaxing to not quit on unrecognized option? */
229 clixon_netconf_error(xerr, NULL, NULL);
230 goto done;
231 }
232 /* Ensure a single root */
233 if (xt == NULL || xml_child_nr(xt) != 1){
234 clicon_err(OE_CFG, 0, "Config file %s: Lacks single top element", filename);
235 goto done;
236 }
237 if (xml_rootchild(xt, 0, &xt) < 0)
238 goto done;
239 /* Check well-formedness */
240 if (strcmp(xml_name(xt), "clixon-config") != 0 ||
241 (xa = xml_find_type(xt, NULL, "xmlns", CX_ATTR)) == NULL ||
242 strcmp(xml_value(xa), CLIXON_CONF_NS) != 0){
243 clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\">", filename, CLIXON_CONF_NS);
244 goto done;
245 }
246 *xconfig = xt;
247 xt = NULL;
248 retval = 0;
249 done:
250 if (xt)
251 xml_free(xt);
252 if (fd != -1)
253 close(fd);
254 if (cbret)
255 cbuf_free(cbret);
256 if (xerr)
257 xml_free(xerr);
258 return retval;
259 }
260
261 /*! Read filename and set values to global options registry. XML variant.
262 *
263 * @param[in] h Clixon handle
264 * @param[in] filename Main configuration file
265 * @param[in] extraconfig0 Override (if set use that, othewrwise get from main file)
266 * @param[in] yspec Yang spec
267 * @param[out] xconfig Pointer to xml config tree. Should be freed by caller
268 * @retval 0 OK
269 * @retval -1 Error
270 */
271 static int
parse_configfile(clicon_handle h,const char * filename,char * extraconfdir0,yang_stmt * yspec,cxobj ** xconfig)272 parse_configfile(clicon_handle h,
273 const char *filename,
274 char *extraconfdir0,
275 yang_stmt *yspec,
276 cxobj **xconfig)
277 {
278 int retval = -1;
279 struct stat st;
280 cxobj *xt = NULL;
281 cxobj *xc = NULL;
282 cxobj *x = NULL;
283 char *name;
284 char *body;
285 clicon_hash_t *copt = clicon_options(h);
286 cbuf *cbret = NULL;
287 cxobj *xerr = NULL;
288 int ret;
289 cvec *nsc = NULL;
290 int i;
291 int ndp;
292 struct dirent *dp = NULL;
293 char filename1[MAXPATHLEN];
294 char *extraconfdir = NULL;
295 cxobj *xe = NULL;
296 cxobj *xec;
297 DIR *dirp;
298
299 if (filename == NULL || !strlen(filename)){
300 clicon_err(OE_UNIX, 0, "Not specified");
301 goto done;
302 }
303 if (stat(filename, &st) < 0){
304 clicon_err(OE_UNIX, errno, "%s", filename);
305 goto done;
306 }
307 if (!S_ISREG(st.st_mode)){
308 clicon_err(OE_UNIX, 0, "%s is not a regular file", filename);
309 goto done;
310 }
311 /* Parse main config file */
312 if (parse_configfile_one(filename, yspec, &xt) < 0)
313 goto done;
314 /* xt is a single-rooted: <clixon-config>...</clixon-config>
315 * If no override (eg from command-line)
316 * Bootstrap: Shortcut to read extra confdir inline */
317 if ((extraconfdir = extraconfdir0) == NULL)
318 if ((xc = xpath_first(xt, 0, "CLICON_CONFIGDIR")) != NULL)
319 extraconfdir = xml_body(xc);
320 if (extraconfdir){ /* If extra dir, parse extra config files */
321 /* A check it exists (also done in clicon_file_dirent) */
322 if ((dirp = opendir(extraconfdir)) == NULL) {
323 clicon_err(OE_UNIX, errno, "CLICON_CONFIGDIR: %s opendir", extraconfdir);
324 goto done;
325 }
326 closedir(dirp);
327 if((ndp = clicon_file_dirent(extraconfdir, &dp, NULL, S_IFREG)) < 0) /* Read dir */
328 goto done;
329 /* Loop through files */
330 for (i = 0; i < ndp; i++){
331 snprintf(filename1, sizeof(filename1), "%s/%s", extraconfdir, dp[i].d_name);
332 if (parse_configfile_one(filename1, yspec, &xe) < 0)
333 goto done;
334 /* Drain objects from extrafile and replace/append to main */
335 while ((xec = xml_child_i_type(xe, 0, CX_ELMNT)) != NULL) {
336 name = xml_name(xec);
337 body = xml_body(xec);
338 /* Ignored from file due to bootstrapping */
339 if (strcmp(name,"CLICON_CONFIGFILE")==0)
340 continue;
341 /* List options for configure options that are leaf-lists: append to main */
342 if (strcmp(name,"CLICON_FEATURE")==0 ||
343 strcmp(name,"CLICON_YANG_DIR")==0){
344 if (xml_addsub(xt, xec) < 0)
345 goto done;
346 continue;
347 }
348 /* Remove existing in master if any */
349 if ((x = xml_find_type(xt, NULL, name, CX_ELMNT)) != NULL)
350 xml_purge(x);
351 /* Append to master (removed from xe) */
352 if (xml_addsub(xt, xec) < 0)
353 goto done;
354 }
355 if (xe)
356 xml_free(xe);
357 xe = NULL;
358 }
359 }
360 if (xml_default_recurse(xt, 0) < 0)
361 goto done;
362 if ((ret = xml_yang_validate_add(h, xt, &xerr)) < 0)
363 goto done;
364 if (ret == 0){
365 if ((cbret = cbuf_new()) ==NULL){
366 clicon_err(OE_XML, errno, "cbuf_new");
367 goto done;
368 }
369 if (netconf_err2cb(xerr, cbret) < 0)
370 goto done;
371 clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
372 goto done;
373 }
374 x = NULL;
375 while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
376 name = xml_name(x);
377 body = xml_body(x);
378 if (name == NULL || body == NULL){
379 clicon_log(LOG_WARNING, "%s option NULL: name:%s body:%s",
380 __FUNCTION__, name, body);
381 continue;
382 }
383 /* Ignored from file due to bootstrapping */
384 if (strcmp(name,"CLICON_CONFIGFILE")==0)
385 continue;
386 /* List options for configure options that are leaf-lists (not leaf)
387 * They must be accessed directly by looping over clicon_conf_xml(h)
388 */
389 if (strcmp(name,"CLICON_FEATURE")==0)
390 continue;
391 if (strcmp(name,"CLICON_YANG_DIR")==0)
392 continue;
393
394 if (clicon_hash_add(copt,
395 name,
396 body,
397 strlen(body)+1) == NULL)
398 goto done;
399 }
400 retval = 0;
401 *xconfig = xt;
402 xt = NULL;
403 done:
404 if (dp)
405 free(dp);
406 if (nsc)
407 xml_nsctx_free(nsc);
408 if (cbret)
409 cbuf_free(cbret);
410 if (xerr)
411 xml_free(xerr);
412 if (xt)
413 xml_free(xt);
414 return retval;
415 }
416
417 /*! Add configuration option overriding file setting
418 * Add to clicon_options hash, and to clicon_conf_xml tree
419 * Assumes clicon_conf_xml_set has been called
420 * @param[in] h Clicon handle
421 * @param[in] name Name of configuration option (see clixon-config.yang)
422 * @param[in] value String value
423 * @retval 0 OK
424 * @retval -1 Error
425 * @see clicon_options_main For loading options from file
426 */
427 int
clicon_option_add(clicon_handle h,const char * name,char * value)428 clicon_option_add(clicon_handle h,
429 const char *name,
430 char *value)
431 {
432 int retval = -1;
433 clicon_hash_t *copt = clicon_options(h);
434 cxobj *x;
435
436 if (strcmp(name, "CLICON_FEATURE")==0 ||
437 strcmp(name, "CLICON_YANG_DIR")==0){
438 if ((x = clicon_conf_xml(h)) == NULL){
439 clicon_err(OE_UNIX, ENOENT, "option %s not found (clicon_conf_xml_set has not been called?)", name);
440 goto done;
441 }
442 if (clixon_xml_parse_va(YB_NONE, NULL, &x, NULL, "<%s>%s</%s>",
443 name, value, name) < 0)
444 goto done;
445 }
446 if (clicon_hash_add(copt,
447 name,
448 value,
449 strlen(value)+1) == NULL)
450 goto done;
451 retval = 0;
452 done:
453 return retval;
454 }
455
456 /*! Parse clixon yang file. Parse XML config file. Initialize option values
457 *
458 * Set default options, Read config-file, Check that all values are set.
459 * Parse clixon yang file and save in yspec.
460 * Read clixon system config files
461 * @param[in] h clicon handle
462 * @param[in] yspec Yang spec of clixon config file
463 * @note Due to Bug: Top-level Yang symbol cannot be called "config" in any
464 * imported yang file, the config module needs to be isolated from all
465 * other yang modules.
466 */
467 int
clicon_options_main(clicon_handle h)468 clicon_options_main(clicon_handle h)
469 {
470 int retval = -1;
471 char *configfile;
472 clicon_hash_t *copt = clicon_options(h);
473 char *suffix;
474 char xml = 0; /* Configfile is xml, otherwise legacy */
475 cxobj *xconfig = NULL;
476 yang_stmt *yspec = NULL;
477 char *extraconfdir = NULL;
478
479 /* Create configure yang-spec */
480 if ((yspec = yspec_new()) == NULL)
481 goto done;
482 /*
483 * Set configure file if not set by command-line above
484 */
485 if (!clicon_hash_lookup(copt, "CLICON_CONFIGFILE")){
486 clicon_option_str_set(h, "CLICON_CONFIGFILE", CLIXON_DEFAULT_CONFIG);
487 }
488 configfile = clicon_hash_value(copt, "CLICON_CONFIGFILE", NULL);
489 clicon_debug(1, "CLICON_CONFIGFILE=%s", configfile);
490 /* File must end with .xml */
491 if ((suffix = rindex(configfile, '.')) != NULL){
492 suffix++;
493 xml = strcmp(suffix, "xml") == 0;
494 }
495 if (xml == 0){
496 clicon_err(OE_CFG, 0, "%s: suffix %s not recognized", configfile, suffix);
497 goto done;
498 }
499
500 /* Override extraconfdir */
501 if (clicon_option_str(h, "CLICON_CONFIGDIR") &&
502 (extraconfdir = strdup(clicon_option_str(h, "CLICON_CONFIGDIR"))) == NULL){
503 clicon_err(OE_UNIX, errno, "strdup");
504 goto done;
505 }
506
507 /* Read configfile first without yangspec, and without extra config dir for bootstrapping,
508 * see second time below with proper yangspec and extra config dir
509 * (You need to read the config-file to get the YANG_DIR to find the clixon yang-spec)
510 * Difference from parsing with yangspec is:
511 * - no default values
512 * - no sanity checks
513 * - no extra config dir
514 */
515 if (parse_configfile(h, configfile, extraconfdir, NULL, &xconfig) < 0)
516 goto done;
517
518 clicon_conf_xml_set(h, xconfig);
519
520 /* Parse clixon yang spec */
521 if (yang_spec_parse_module(h, "clixon-config", NULL, yspec) < 0)
522 goto done;
523 clicon_conf_xml_set(h, NULL);
524 if (xconfig){
525 xml_free(xconfig);
526 xconfig = NULL;
527 }
528
529 /* Read configfile second time now with check yang spec */
530 if (parse_configfile(h, configfile, extraconfdir, yspec, &xconfig) < 0)
531 goto done;
532 if (xml_spec(xconfig) == NULL){
533 clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"%s\"> or clixon-config.yang not found?", configfile, CLIXON_CONF_NS);
534 goto done;
535 }
536 /* Set yang config spec (must store to free at exit, since conf_xml below uses it) */
537 if (clicon_config_yang_set(h, yspec) < 0)
538 goto done;
539 yspec = NULL;
540 /* Set clixon_conf pointer to handle */
541 if (clicon_conf_xml_set(h, xconfig) < 0)
542 goto done;
543
544 retval = 0;
545 done:
546 if (yspec)
547 ys_free(yspec);
548 if (extraconfdir)
549 free(extraconfdir);
550 return retval;
551 }
552
553 /*! Check if a clicon option has a value
554 * @param[in] h clicon_handle
555 * @param[in] name option name
556 * @retval !=0 option exists
557 * @retval 0 option does not exist
558 */
559 int
clicon_option_exists(clicon_handle h,const char * name)560 clicon_option_exists(clicon_handle h,
561 const char *name)
562 {
563 clicon_hash_t *copt = clicon_options(h);
564
565 return (clicon_hash_lookup(copt, (char*)name) != NULL);
566 }
567
568 /*! Get a single string option string via handle
569 *
570 * @param[in] h clicon_handle
571 * @param[in] name option name
572 * @retval NULL If option not found, or value of option is NULL
573 * @retval string value of option if found
574 * clicon options should be strings.
575 * @note To differentiate the two reasons why NULL may be returned, use function
576 * clicon_option_exists() before the call
577 */
578 char *
clicon_option_str(clicon_handle h,const char * name)579 clicon_option_str(clicon_handle h,
580 const char *name)
581 {
582 clicon_hash_t *copt = clicon_options(h);
583
584 if (clicon_hash_lookup(copt, (char*)name) == NULL)
585 return NULL;
586 return clicon_hash_value(copt, (char*)name, NULL);
587 }
588
589 /*! Set a single string option via handle
590 * @param[in] h clicon_handle
591 * @param[in] name option name
592 * @param[in] val option value, must be null-terminated string
593 * @retval 0 OK
594 * @retval -1 Error
595 */
596 int
clicon_option_str_set(clicon_handle h,const char * name,char * val)597 clicon_option_str_set(clicon_handle h,
598 const char *name,
599 char *val)
600 {
601 clicon_hash_t *copt = clicon_options(h);
602
603 return clicon_hash_add(copt, (char*)name, val, strlen(val)+1)==NULL?-1:0;
604 }
605
606 /*! Get options as integer but stored as string
607 *
608 * @param[in] h clicon handle
609 * @param[in] name name of option
610 * @retval int An integer as a result of atoi
611 * @retval -1 If option does not exist
612 * @code
613 * if (clicon_option_exists(h, "X"))
614 * return clicon_option_int(h, "X");
615 * else
616 * return 0;
617 * @endcode
618 * Note that -1 can be both error and value.
619 * This means that it should be used together with clicon_option_exists() and
620 * supply a default value as shown in the example.
621 */
622 int
clicon_option_int(clicon_handle h,const char * name)623 clicon_option_int(clicon_handle h,
624 const char *name)
625 {
626 char *s;
627
628 if ((s = clicon_option_str(h, name)) == NULL)
629 return -1;
630 return atoi(s);
631 }
632
633 /*! Set option given as int.
634 * @param[in] h Clicon handle
635 * @param[in] name Name of option to set
636 * @param[in] val Integer value
637 */
638 int
clicon_option_int_set(clicon_handle h,const char * name,int val)639 clicon_option_int_set(clicon_handle h,
640 const char *name,
641 int val)
642 {
643 char s[64];
644
645 if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
646 return -1;
647 return clicon_option_str_set(h, name, s);
648 }
649
650 /*! Get options as bool but stored as string
651 *
652 * @param[in] h Clicon handle
653 * @param[in] name name of option
654 * @retval 0 false, or does not exist, or does not have a boolean value
655 * @retval 1 true
656 * @code
657 * if (clicon_option_exists(h, "X")
658 * return clicon_option_bool(h, "X");
659 * else
660 * return 0; # default false?
661 * @endcode
662 * Note that 0 can be both error and false.
663 * This means that it should be used together with clicon_option_exists() and
664 * supply a default value as shown in the example.
665 */
666 int
clicon_option_bool(clicon_handle h,const char * name)667 clicon_option_bool(clicon_handle h,
668 const char *name)
669 {
670 char *s;
671
672 if ((s = clicon_option_str(h, name)) == NULL)
673 return 0;
674 if (strcmp(s,"true")==0)
675 return 1;
676 if (strcmp(s,"1")==0)
677 return 1;
678 return 0; /* Hopefully false, but anything else than "true" or "one" */
679 }
680
681 /*! Set option given as bool
682 * @param[in] h Clicon handle
683 * @param[in] name Name of option to set
684 * @param[in] val Boolean value, 0 or 1
685 */
686 int
clicon_option_bool_set(clicon_handle h,const char * name,int val)687 clicon_option_bool_set(clicon_handle h,
688 const char *name,
689 int val)
690 {
691 char s[64];
692
693 if (val != 0 && val != 1){
694 clicon_err(OE_CFG, EINVAL, "val is %d, 0 or 1 expected", val);
695 return -1;
696 }
697 if (snprintf(s, sizeof(s)-1, "%s", val?"true":"false") < 0){
698 clicon_err(OE_CFG, errno, "snprintf");
699 return -1;
700 }
701 return clicon_option_str_set(h, name, s);
702 }
703
704 /*! Delete option
705 * @param[in] h Clicon handle
706 * @param[in] name Name of option to delete
707 */
708 int
clicon_option_del(clicon_handle h,const char * name)709 clicon_option_del(clicon_handle h,
710 const char *name)
711 {
712 clicon_hash_t *copt = clicon_options(h);
713
714 return clicon_hash_del(copt, (char*)name);
715 }
716
717 /*-----------------------------------------------------------------
718 * Specific option access functions for YANG configuration variables.
719 * Sometimes overridden by command-line options,
720 * such as -f for CLICON_CONFIGFILE
721 * @see yang/clixon-config@<date>.yang
722 * You can always use the basic access functions, such as
723 * clicon_option_str[_set]
724 * But sometimes there are type conversions, etc which makes it more
725 * convenient to make wrapper functions. Or not?
726 *-----------------------------------------------------------------*/
727 /*! Whether to generate CLIgen syntax from datamodel or not (0, 1 or 2)
728 * Must be used with a previous clicon_option_exists().
729 * @param[in] h Clicon handle
730 * @retval flag If set, generate CLI code from yang model, otherwise not
731 * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL
732 */
733 int
clicon_cli_genmodel(clicon_handle h)734 clicon_cli_genmodel(clicon_handle h)
735 {
736 char const *opt = "CLICON_CLI_GENMODEL";
737
738 if (clicon_option_exists(h, opt))
739 return clicon_option_int(h, opt);
740 else
741 return 0;
742 }
743
744 /*! Generate code for CLI completion of existing db symbols
745 * @param[in] h Clicon handle
746 * @retval flag If set, generate auto-complete CLI specs
747 * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_COMPLETION
748 */
749 int
clicon_cli_genmodel_completion(clicon_handle h)750 clicon_cli_genmodel_completion(clicon_handle h)
751 {
752 char const *opt = "CLICON_CLI_GENMODEL_COMPLETION";
753
754 if (clicon_option_exists(h, opt))
755 return clicon_option_int(h, opt);
756 else
757 return 0;
758 }
759
760 /*! How to generate and show CLI syntax: VARS|ALL
761 * @param[in] h Clicon handle
762 * @retval mode
763 * @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_TYPE
764 */
765 enum genmodel_type
clicon_cli_genmodel_type(clicon_handle h)766 clicon_cli_genmodel_type(clicon_handle h)
767 {
768 char *str;
769
770 if ((str = clicon_option_str(h, "CLICON_CLI_GENMODEL_TYPE")) == NULL)
771 return GT_VARS;
772 else
773 return clicon_str2int(cli_genmodel_map, str);
774 }
775
776 /*! Get "do not include keys in cvec" in cli vars callbacks
777 * @param[in] h Clicon handle
778 * @retval flag If set, get only vars
779 * @see clixon-config@<date>.yang CLICON_CLI_VARONLY
780 */
781 int
clicon_cli_varonly(clicon_handle h)782 clicon_cli_varonly(clicon_handle h)
783 {
784 char const *opt = "CLICON_CLI_VARONLY";
785
786 if (clicon_option_exists(h, opt))
787 return clicon_option_int(h, opt);
788 else
789 return 0;
790 }
791
792 /*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6
793 * @see clixon-config@<date>.yang CLICON_SOCK_FAMILY
794 * @param[in] h Clicon handle
795 * @retval fam Socket family
796 */
797 int
clicon_sock_family(clicon_handle h)798 clicon_sock_family(clicon_handle h)
799 {
800 char *s;
801
802 if ((s = clicon_option_str(h, "CLICON_SOCK_FAMILY")) == NULL)
803 return AF_UNIX;
804 else if (strcmp(s, "IPv4")==0)
805 return AF_INET;
806 else if (strcmp(s, "IPv6")==0)
807 return AF_INET6;
808 else
809 return AF_UNIX; /* default */
810 }
811
812 /*! Get port for backend socket in case of AF_INET or AF_INET6
813 * @param[in] h Clicon handle
814 * @retval port Socket port
815 * @see clixon-config@<date>.yang CLICON_SOCK_PORT
816 */
817 int
clicon_sock_port(clicon_handle h)818 clicon_sock_port(clicon_handle h)
819 {
820 char *s;
821
822 if ((s = clicon_option_str(h, "CLICON_SOCK_PORT")) == NULL)
823 return -1;
824 return atoi(s);
825 }
826
827 /*! Set if all configuration changes are committed automatically
828 * @param[in] h Clicon handle
829 * @retval flag Autocommit (or not)
830 */
831 int
clicon_autocommit(clicon_handle h)832 clicon_autocommit(clicon_handle h)
833 {
834 char const *opt = "CLICON_AUTOCOMMIT";
835
836 if (clicon_option_exists(h, opt))
837 return clicon_option_int(h, opt);
838 else
839 return 0;
840 }
841
842 /*! Which method to boot/start clicon backend
843 * @param[in] h Clicon handle
844 * @retval mode Startup mode
845 */
846 int
clicon_startup_mode(clicon_handle h)847 clicon_startup_mode(clicon_handle h)
848 {
849 char *mode;
850
851 if ((mode = clicon_option_str(h, "CLICON_STARTUP_MODE")) == NULL)
852 return -1;
853 return clicon_str2int(startup_mode_map, mode);
854 }
855
856 /*! Which privileges drop method to use
857 * @param[in] h Clicon handle
858 * @retval mode Privileges mode
859 */
860 enum priv_mode_t
clicon_backend_privileges_mode(clicon_handle h)861 clicon_backend_privileges_mode(clicon_handle h)
862 {
863 char *mode;
864
865 if ((mode = clicon_option_str(h, "CLICON_BACKEND_PRIVILEGES")) == NULL)
866 return -1;
867 return clicon_str2int(priv_mode_map, mode);
868 }
869
870 /*! Which privileges drop method to use
871 * @param[in] h Clicon handle
872 * @retval mode Privileges mode
873 */
874 enum nacm_credentials_t
clicon_nacm_credentials(clicon_handle h)875 clicon_nacm_credentials(clicon_handle h)
876 {
877 char *mode;
878
879 if ((mode = clicon_option_str(h, "CLICON_NACM_CREDENTIALS")) == NULL)
880 return -1;
881 return clicon_str2int(nacm_credentials_map, mode);
882 }
883
884 /*! Which datastore cache method to use
885 * @param[in] h Clicon handle
886 * @retval method Datastore cache method
887 * @see clixon-config@<date>.yang CLICON_DATASTORE_CACHE
888 */
889 enum datastore_cache
clicon_datastore_cache(clicon_handle h)890 clicon_datastore_cache(clicon_handle h)
891 {
892 char *str;
893
894 if ((str = clicon_option_str(h, "CLICON_DATASTORE_CACHE")) == NULL)
895 return DATASTORE_CACHE;
896 else
897 return clicon_str2int(datastore_cache_map, str);
898 }
899
900 /*! Which Yang regexp/pattern engine to use
901 * @param[in] h Clicon handle
902 * @retval mode Regexp engine to use
903 * @see clixon-config@<date>.yang CLICON_YANG_REGEXP
904 */
905 enum regexp_mode
clicon_yang_regexp(clicon_handle h)906 clicon_yang_regexp(clicon_handle h)
907 {
908 char *str;
909
910 if ((str = clicon_option_str(h, "CLICON_YANG_REGEXP")) == NULL)
911 return REGEXP_POSIX;
912 else
913 return clicon_str2int(yang_regexp_map, str);
914 }
915
916 /*---------------------------------------------------------------------
917 * Specific option access functions for non-yang options
918 * Typically dynamic values and more complex datatypes,
919 * Such as handles to plugins, API:s and parsed structures
920 *--------------------------------------------------------------------*/
921
922 /*! Get quiet mode eg -q option, do not print notifications on stdout
923 * @param[in] h Clicon handle
924 * @retval flag quiet mode on or off
925 */
926 int
clicon_quiet_mode(clicon_handle h)927 clicon_quiet_mode(clicon_handle h)
928 {
929 char *s;
930 if ((s = clicon_option_str(h, "CLICON_QUIET")) == NULL)
931 return 0; /* default */
932 return atoi(s);
933 }
934
935 /*! Set quiet mode
936 * @param[in] h Clicon handle
937 * @param[in] val Flag value
938 */
939 int
clicon_quiet_mode_set(clicon_handle h,int val)940 clicon_quiet_mode_set(clicon_handle h,
941 int val)
942 {
943 return clicon_option_int_set(h, "CLICON_QUIET", val);
944 }
945
946