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  * Access functions for clixon data.
38  * Free-typed values for runtime getting and setting.
39  *            Accessed with clicon_data(h).
40  * @see clixon_option.[ch] for clixon options
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 <syslog.h>
54 #include <assert.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 
60 /* cligen */
61 #include <cligen/cligen.h>
62 
63 /* clicon */
64 #include "clixon_err.h"
65 #include "clixon_string.h"
66 #include "clixon_queue.h"
67 #include "clixon_hash.h"
68 #include "clixon_handle.h"
69 #include "clixon_log.h"
70 #include "clixon_yang.h"
71 #include "clixon_xml.h"
72 #include "clixon_xml_sort.h"
73 #include "clixon_yang_module.h"
74 #include "clixon_options.h"
75 #include "clixon_yang_module.h"
76 #include "clixon_plugin.h"
77 #include "clixon_xpath_ctx.h"
78 #include "clixon_xpath.h"
79 #include "clixon_data.h"
80 
81 /*! Get generic clixon data on the form <name>=<val> where <val> is string
82  * @param[in]  h    Clicon handle
83  * @param[in]  name Data name
84  * @param[out] val  Data value as string
85  * @retval     0    OK
86  * @retval    -1    Not found (or error)
87  * @see clicon_option_str
88  */
89 int
clicon_data_get(clicon_handle h,const char * name,char ** val)90 clicon_data_get(clicon_handle h,
91 		const char   *name,
92 		char        **val)
93 {
94     clicon_hash_t *cdat = clicon_data(h);
95 
96     if (clicon_hash_lookup(cdat, (char*)name) == NULL)
97 	return -1;
98     if (val)
99 	*val = clicon_hash_value(cdat, (char*)name, NULL);
100     return 0;
101 }
102 
103 /*! Set generic clixon data on the form <name>=<val> where <val> is string
104  * @param[in]  h    Clicon handle
105  * @param[in]  name Data name
106  * @param[in]  val  Data value as null-terminated string
107  * @retval     0    OK
108  * @retval    -1    Error
109  * @see clicon_option_str_set
110  */
111 int
clicon_data_set(clicon_handle h,const char * name,char * val)112 clicon_data_set(clicon_handle h,
113 		const char   *name,
114 		char         *val)
115 {
116     clicon_hash_t  *cdat = clicon_data(h);
117 
118     return clicon_hash_add(cdat, (char*)name, val, strlen(val)+1)==NULL?-1:0;
119 }
120 
121 /*! Delete generic clixon data
122  * @param[in]  h    Clicon handle
123  * @param[in]  name Data name
124  * @retval     0    OK
125  * @retval    -1    Error
126  * @see clicon_option_del
127  */
128 int
clicon_data_del(clicon_handle h,const char * name)129 clicon_data_del(clicon_handle h,
130 		const char   *name)
131 {
132     clicon_hash_t  *cdat = clicon_data(h);
133 
134     return clicon_hash_del(cdat, (char*)name);
135 }
136 
137 /*! Get generic cligen varaibel vector (cvv) on the form <name>=<val> where <val> is cvv
138  *
139  * @param[in]  h     Clicon handle
140  * @param[in]  name  Data name
141  * @retval     cvv   Data value as cvv
142  * @retval     NULL  Not found (or error)
143  * @code
144  *   cvec *cvv = NULL;
145  *   if (clicon_data_cvec_get(h, "mycvv", &cvv) < 0)
146  *     err;
147  * @endcode
148  */
149 cvec *
clicon_data_cvec_get(clicon_handle h,const char * name)150 clicon_data_cvec_get(clicon_handle h,
151 		     const char   *name)
152 {
153     clicon_hash_t  *cdat = clicon_data(h);
154     size_t          len = 0;
155     void           *p;
156 
157     if ((p = clicon_hash_value(cdat, (char*)name, &len)) != NULL)
158 	return *(cvec **)p;
159     return NULL;
160 }
161 
162 /*! Set generic cligen varaibel vector (cvv) on the form <name>=<val> where <val> is cvv
163  * @param[in]  h     Clicon handle
164  * @param[in]  name  Name
165  * @param[in]  cvv   CLIgen variable vector (cvv) (malloced)
166  */
167 int
clicon_data_cvec_set(clicon_handle h,const char * name,cvec * cvv)168 clicon_data_cvec_set(clicon_handle h,
169 		     const char   *name,
170 		     cvec         *cvv)
171 {
172     clicon_hash_t *cdat = clicon_data(h);
173     cvec          *cvv0;
174 
175     /* It is the pointer to cvec that should be copied by hash,
176        so we send a ptr to the ptr to indicate what to copy.
177      */
178     if ((cvv0 = clicon_data_cvec_get(h, name)) != NULL)
179 	cvec_free(cvv0);
180     if (clicon_hash_add(cdat, (char*)name, &cvv, sizeof(cvv)) == NULL)
181 	return -1;
182     return 0;
183 }
184 
185 /*! Delete generic cligen varaibel vector (cvv)
186  * @param[in]  h     Clicon handle
187  * @param[in]  name  Name
188  */
189 int
clicon_data_cvec_del(clicon_handle h,const char * name)190 clicon_data_cvec_del(clicon_handle h,
191 		     const char   *name)
192 {
193     clicon_hash_t *cdat = clicon_data(h);
194     cvec          *cvv0;
195 
196     /* It is the pointer to cvec that should be copied by hash,
197        so we send a ptr to the ptr to indicate what to copy.
198      */
199     if ((cvv0 = clicon_data_cvec_get(h, name)) != NULL)
200 	cvec_free(cvv0);
201     return clicon_hash_del(cdat, (char*)name);
202 }
203 
204 /*!
205  * @param[in]  h     Clicon handle
206  * @retval     yspec Yang spec
207  * @see clicon_config_yang  for the configuration yang
208  */
209 yang_stmt *
clicon_dbspec_yang(clicon_handle h)210 clicon_dbspec_yang(clicon_handle h)
211 {
212     clicon_hash_t  *cdat = clicon_data(h);
213     size_t          len;
214     void           *p;
215 
216     if ((p = clicon_hash_value(cdat, "dbspec_yang", &len)) != NULL)
217 	return *(yang_stmt **)p;
218     return NULL;
219 }
220 
221 /*! Set yang specification for application specifications
222  * @param[in]  h     Clicon handle
223  * @param[in]  yspec Yang spec (malloced pointer)
224  * @see clicon_config_yang_set  for the configuration yang
225  */
226 int
clicon_dbspec_yang_set(clicon_handle h,yang_stmt * ys)227 clicon_dbspec_yang_set(clicon_handle h,
228 		       yang_stmt    *ys)
229 {
230     clicon_hash_t  *cdat = clicon_data(h);
231 
232     /* It is the pointer to ys that should be copied by hash,
233        so we send a ptr to the ptr to indicate what to copy.
234      */
235     if (clicon_hash_add(cdat, "dbspec_yang", &ys, sizeof(ys)) == NULL)
236 	return -1;
237     return 0;
238 }
239 
240 /*! Get YANG specification for clixon config (separate from application yangs)
241  * @param[in]  h     Clicon handle
242  * @retval     yspec Yang spec
243  * @see clicon_dbspec_yang  for the application specs
244  */
245 yang_stmt *
clicon_config_yang(clicon_handle h)246 clicon_config_yang(clicon_handle h)
247 {
248     clicon_hash_t  *cdat = clicon_data(h);
249     size_t          len;
250     void           *p;
251 
252     if ((p = clicon_hash_value(cdat, "control_yang", &len)) != NULL)
253 	return *(yang_stmt **)p;
254     return NULL;
255 }
256 
257 /*! Set yang specification for configuration
258  * @param[in]  h     Clicon handle
259  * @param[in]  yspec Yang spec (malloced pointer)
260  * @see clicon_dbspec_yang_set  for the application specs
261  */
262 int
clicon_config_yang_set(clicon_handle h,yang_stmt * ys)263 clicon_config_yang_set(clicon_handle   h,
264 		       yang_stmt      *ys)
265 {
266     clicon_hash_t  *cdat = clicon_data(h);
267 
268     /* It is the pointer to ys that should be copied by hash,
269        so we send a ptr to the ptr to indicate what to copy.
270      */
271     if (clicon_hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL)
272 	return -1;
273     return 0;
274 }
275 
276 /*! Get YANG specification for external NACM (separate from application yangs)
277  * @param[in]  h     Clicon handle
278  * @retval     yspec Yang spec
279  * @see clicon_nacm_ext  for external NACM XML
280  */
281 yang_stmt *
clicon_nacm_ext_yang(clicon_handle h)282 clicon_nacm_ext_yang(clicon_handle h)
283 {
284     clicon_hash_t  *cdat = clicon_data(h);
285     size_t          len;
286     void           *p;
287 
288     if ((p = clicon_hash_value(cdat, "nacm_ext_yang", &len)) != NULL)
289 	return *(yang_stmt **)p;
290     return NULL;
291 }
292 
293 /*! Set yang specification for external NACM
294  * @param[in]  h     Clicon handle
295  * @param[in]  yspec Yang spec (malloced pointer)
296  * @see clicon_nacm_ext_set  for external NACM XML
297  */
298 int
clicon_nacm_ext_yang_set(clicon_handle h,yang_stmt * ys)299 clicon_nacm_ext_yang_set(clicon_handle   h,
300 			 yang_stmt      *ys)
301 {
302     clicon_hash_t  *cdat = clicon_data(h);
303 
304     /* It is the pointer to ys that should be copied by hash,
305        so we send a ptr to the ptr to indicate what to copy.
306      */
307     if (clicon_hash_add(cdat, "nacm_ext_yang", &ys, sizeof(ys)) == NULL)
308 	return -1;
309     return 0;
310 }
311 
312 /*! Get Global "canonical" namespace context
313  * Canonical: use prefix and namespace specified in the yang modules.
314  * @param[in]  h     Clicon handle
315  * @retval     nsctx Namespace context (malloced)
316  * @code
317  *   cvec *nsctx;
318  *   nsctx = clicon_nsctx_global_get(h);
319  * @endcode
320  */
321 cvec *
clicon_nsctx_global_get(clicon_handle h)322 clicon_nsctx_global_get(clicon_handle h)
323 {
324     clicon_hash_t  *cdat = clicon_data(h);
325     size_t          len;
326     void           *p;
327 
328     if ((p = clicon_hash_value(cdat, "nsctx_global", &len)) != NULL)
329 	return *(cvec **)p;
330     return NULL;
331 }
332 
333 /*! Set global "canonical" namespace context
334  * Canonical: use prefix and namespace specified in the yang modules.
335  * @param[in]  h     Clicon handle
336  * @param[in]  nsctx Namespace context (malloced)
337  */
338 int
clicon_nsctx_global_set(clicon_handle h,cvec * nsctx)339 clicon_nsctx_global_set(clicon_handle h,
340 			cvec         *nsctx)
341 {
342     clicon_hash_t  *cdat = clicon_data(h);
343 
344     /* It is the pointer to cvec that should be copied by hash,
345        so we send a ptr to the ptr to indicate what to copy.
346      */
347     if (clicon_hash_add(cdat, "nsctx_global", &nsctx, sizeof(nsctx)) == NULL)
348 	return -1;
349     return 0;
350 }
351 
352 /*! Get NACM (rfc 8341) XML parse tree if external not in std xml config
353  * @param[in]  h    Clicon handle
354  * @retval     xn   XML NACM tree, or NULL
355  * @note only used if config option CLICON_NACM_MODE is external
356  * @see clicon_nacm_ext_set
357  */
358 cxobj *
clicon_nacm_ext(clicon_handle h)359 clicon_nacm_ext(clicon_handle h)
360 {
361     clicon_hash_t *cdat = clicon_data(h);
362     size_t         len;
363     void          *p;
364 
365     if ((p = clicon_hash_value(cdat, "nacm_xml", &len)) != NULL)
366 	return *(cxobj **)p;
367     return NULL;
368 }
369 
370 /*! Set NACM (rfc 8341) external XML parse tree, free old if any
371  * @param[in]  h   Clicon handle
372  * @param[in]  xn  XML Nacm tree
373  * @note only used if config option CLICON_NACM_MODE is external
374  * @see clicon_nacm_ext
375  */
376 int
clicon_nacm_ext_set(clicon_handle h,cxobj * xn)377 clicon_nacm_ext_set(clicon_handle h,
378 		     cxobj        *xn)
379 {
380     clicon_hash_t *cdat = clicon_data(h);
381     cxobj         *xo;
382 
383     if ((xo = clicon_nacm_ext(h)) != NULL)
384 	xml_free(xo);
385     /* It is the pointer to xn that should be copied by hash,
386        so we send a ptr to the ptr to indicate what to copy.
387      */
388     if (clicon_hash_add(cdat, "nacm_xml", &xn, sizeof(xn)) == NULL)
389 	return -1;
390     return 0;
391 }
392 
393 /*! Get NACM (rfc 8341) XML parse tree cache
394  * @param[in]  h    Clicon handle
395  * @retval     xn   XML NACM tree, or NULL. Direct pointer, no copying
396  * @note  Use with caution, only valid on a stack, direct pointer freed on function return
397  * @see from_client_msg
398  */
399 cxobj *
clicon_nacm_cache(clicon_handle h)400 clicon_nacm_cache(clicon_handle h)
401 {
402     clicon_hash_t *cdat = clicon_data(h);
403     size_t         len;
404     void          *p;
405 
406     if ((p = clicon_hash_value(cdat, "nacm_cache", &len)) != NULL)
407 	return *(cxobj **)p;
408     return NULL;
409 }
410 
411 /*! Set NACM (rfc 8341) external XML parse tree cache
412  * @param[in]  h   Clicon handle
413  * @param[in]  xn  XML Nacm tree direct pointer, no copying
414  * @note  Use with caution, only valid on a stack, direct pointer freed on function return
415  * @see from_client_msg
416  */
417 int
clicon_nacm_cache_set(clicon_handle h,cxobj * xn)418 clicon_nacm_cache_set(clicon_handle h,
419 		      cxobj        *xn)
420 {
421     clicon_hash_t *cdat = clicon_data(h);
422 
423     /* It is the pointer to xn that should be copied by hash,
424        so we send a ptr to the ptr to indicate what to copy.
425      */
426     if (clicon_hash_add(cdat, "nacm_cache", &xn, sizeof(xn)) == NULL)
427 	return -1;
428     return 0;
429 }
430 
431 /*! Get YANG specification for Clixon system options and features
432  * Must use hash functions directly since they are not strings.
433  * Example: features are typically accessed directly in the config tree.
434  */
435 cxobj *
clicon_conf_xml(clicon_handle h)436 clicon_conf_xml(clicon_handle h)
437 {
438     clicon_hash_t *cdat = clicon_data(h);
439     size_t         len;
440     void          *p;
441 
442     if ((p = clicon_hash_value(cdat, "clixon_conf", &len)) != NULL)
443 	return *(cxobj **)p;
444     return NULL;
445 }
446 
447 /*! Set YANG specification for Clixon system options and features
448  * ys must be a malloced pointer
449  */
450 int
clicon_conf_xml_set(clicon_handle h,cxobj * x)451 clicon_conf_xml_set(clicon_handle h,
452 		    cxobj        *x)
453 {
454     clicon_hash_t  *cdat = clicon_data(h);
455 
456     /* It is the pointer to x that should be copied by hash,
457      * so we send a ptr to the ptr to indicate what to copy.
458      */
459     if (clicon_hash_add(cdat, "clixon_conf", &x, sizeof(x)) == NULL)
460 	return -1;
461     return 0;
462 }
463 
464 /*! Get authorized user name
465  * @param[in]  h   Clicon handle
466  * @retval     username
467  */
468 char *
clicon_username_get(clicon_handle h)469 clicon_username_get(clicon_handle h)
470 {
471     clicon_hash_t  *cdat = clicon_data(h);
472 
473     return (char*)clicon_hash_value(cdat, "username", NULL);
474 }
475 
476 /*! Set authorized user name
477  * @param[in]  h   Clicon handle
478  * @param[in]  username
479  * @note Just keep note of it, dont allocate it or so.
480  */
481 int
clicon_username_set(clicon_handle h,void * username)482 clicon_username_set(clicon_handle h,
483 		    void         *username)
484 {
485     clicon_hash_t  *cdat = clicon_data(h);
486 
487     if (username == NULL)
488 	return clicon_hash_del(cdat, "username");
489     return clicon_hash_add(cdat, "username", username, strlen(username)+1)==NULL?-1:0;
490 }
491 
492 /*! Get backend daemon startup status
493  * @param[in]  h      Clicon handle
494  * @retval     status Startup status
495  */
496 enum startup_status
clicon_startup_status_get(clicon_handle h)497 clicon_startup_status_get(clicon_handle h)
498 {
499     clicon_hash_t *cdat = clicon_data(h);
500     void           *p;
501 
502     if ((p = clicon_hash_value(cdat, "startup_status", NULL)) != NULL)
503         return *(enum startup_status *)p;
504     return STARTUP_ERR;
505 }
506 
507 /*! Set backend daemon startup status
508  * @param[in]  h      Clicon handle
509  * @param[in]  status Startup status
510  * @retval     0      OK
511  * @retval    -1      Error (when setting value)
512  */
513 int
clicon_startup_status_set(clicon_handle h,enum startup_status status)514 clicon_startup_status_set(clicon_handle       h,
515 			  enum startup_status status)
516 {
517     clicon_hash_t  *cdat = clicon_data(h);
518     if (clicon_hash_add(cdat, "startup_status", &status, sizeof(status))==NULL)
519         return -1;
520     return 0;
521 }
522 
523 /*! Get socket fd (ie backend server socket / restconf fcgx socket)
524  * @param[in]  h   Clicon handle
525  * @retval    -1   No open socket
526  * @retval     s   Socket
527  */
528 int
clicon_socket_get(clicon_handle h)529 clicon_socket_get(clicon_handle h)
530 {
531     clicon_hash_t *cdat = clicon_data(h);
532     void           *p;
533 
534     if ((p = clicon_hash_value(cdat, "socket", NULL)) == NULL)
535 	return -1;
536     return *(int*)p;
537 }
538 
539 /*! Set socket fd (ie backend server socket / restconf fcgx socket)
540  * @param[in]  h   Clicon handle
541  * @param[in]  s   Open socket (or -1 to close)
542  * @retval    0       OK
543  * @retval   -1       Error
544  */
545 int
clicon_socket_set(clicon_handle h,int s)546 clicon_socket_set(clicon_handle h,
547 		  int           s)
548 {
549     clicon_hash_t  *cdat = clicon_data(h);
550 
551     if (s == -1)
552 	return clicon_hash_del(cdat, "socket");
553     return clicon_hash_add(cdat, "socket", &s, sizeof(int))==NULL?-1:0;
554 }
555 
556 /*! Get module state cache
557  * @param[in]  h     Clicon handle
558  * @param[in]  brief 0: Full module state tree, 1: Brief tree (datastore)
559  * @retval     xms   Module state cache XML tree
560  * xms is on the form: <modules-state>...
561  */
562 cxobj *
clicon_modst_cache_get(clicon_handle h,int brief)563 clicon_modst_cache_get(clicon_handle h,
564 		       int           brief)
565 {
566     clicon_hash_t *cdat = clicon_data(h);
567     void           *p;
568 
569     if ((p = clicon_hash_value(cdat, brief?"modst_brief":"modst_full", NULL)) != NULL)
570 	return *(cxobj **)p;
571     return NULL;
572 }
573 
574 /*! Set module state cache
575  * @param[in]  h     Clicon handle
576  * @param[in]  brief 0: Full module state tree, 1: Brief tree (datastore)
577  * @param[in]  xms   Module state cache XML tree
578  * @retval    0       OK
579  * @retval   -1       Error
580  */
581 int
clicon_modst_cache_set(clicon_handle h,int brief,cxobj * xms)582 clicon_modst_cache_set(clicon_handle h,
583 		       int           brief,
584 			cxobj        *xms)
585 {
586     clicon_hash_t  *cdat = clicon_data(h);
587     cxobj          *x;
588 
589     if ((x = clicon_modst_cache_get(h, brief)) != NULL)
590 	xml_free(x);
591     if (xms == NULL)
592 	goto ok;
593     assert(strcmp(xml_name(xms),"modules-state")==0);
594     if ((x = xml_dup(xms)) == NULL)
595 	return -1;
596     if (clicon_hash_add(cdat, brief?"modst_brief":"modst_full", &x, sizeof(x))==NULL)
597 	return -1;
598  ok:
599     return 0;
600 }
601 
602 /*! Get yang module changelog
603  * @param[in]  h    Clicon handle
604  * @retval     xch  Module revision changelog XML tree
605  * @see draft-wang-netmod-module-revision-management-01
606  */
607 cxobj *
clicon_xml_changelog_get(clicon_handle h)608 clicon_xml_changelog_get(clicon_handle h)
609 {
610     clicon_hash_t *cdat = clicon_data(h);
611     void          *p;
612 
613     if ((p = clicon_hash_value(cdat, "xml-changelog", NULL)) != NULL)
614 	return *(cxobj **)p;
615     return NULL;
616 }
617 
618 /*! Set xml module changelog
619  * @param[in] h   Clicon handle
620  * @param[in] s   Module revision changelog XML tree
621  * @retval    0   OK
622  * @retval   -1   Error
623  * @see draft-wang-netmod-module-revision-management-01
624  */
625 int
clicon_xml_changelog_set(clicon_handle h,cxobj * xchlog)626 clicon_xml_changelog_set(clicon_handle h,
627 			 cxobj        *xchlog)
628 {
629     clicon_hash_t  *cdat = clicon_data(h);
630 
631     if (clicon_hash_add(cdat, "xml-changelog", &xchlog, sizeof(xchlog))==NULL)
632 	return -1;
633     return 0;
634 }
635 
636 /*! Get user clicon command-line options argv, argc (after --)
637  * @param[in]  h    Clicon handle
638  * @param[out] argc
639  * @param[out] argv
640  * @retval     0    OK
641  * @retval    -1    Error
642  */
643 int
clicon_argv_get(clicon_handle h,int * argc,char *** argv)644 clicon_argv_get(clicon_handle h,
645 		int          *argc,
646 		char       ***argv)
647 
648 {
649     clicon_hash_t *cdat = clicon_data(h);
650     void          *p;
651 
652     if (argc){
653 	if ((p = clicon_hash_value(cdat, "argc", NULL)) == NULL)
654 	    return -1;
655 	*argc = *(int*)p;
656     }
657     if (argv){
658 	if ((p = clicon_hash_value(cdat, "argv", NULL)) == NULL)
659 	    return -1;
660 	*argv = (char**)p;
661     }
662     return 0;
663 }
664 
665 /*! Set clicon user command-line options argv, argc (after --)
666  * @param[in] h     Clicon handle
667  * @param[in] prog  argv[0] - the program name
668  * @param[in] argc  Length of argv
669  * @param[in] argv  Array of command-line options or NULL
670  * @retval    0     OK
671  * @retval   -1     Error
672  * @note If argv=NULL deallocate allocated argv vector if exists.
673  */
674 int
clicon_argv_set(clicon_handle h,char * prgm,int argc,char ** argv)675 clicon_argv_set(clicon_handle h,
676 		char         *prgm,
677 		int           argc,
678 		char        **argv)
679 {
680     int             retval = -1;
681     clicon_hash_t  *cdat = clicon_data(h);
682     char          **argvv = NULL;
683     size_t          len;
684 
685     /* add space for null-termination and argv[0] program name */
686     len = argc+2;
687     if ((argvv = calloc(len, sizeof(char*))) == NULL){
688 	clicon_err(OE_UNIX, errno, "calloc");
689 	goto done;
690     }
691     memcpy(argvv+1, argv, argc*sizeof(char*));
692     argvv[0] = prgm;
693     /* Note the value is the argv vector (which is copied) */
694     if (clicon_hash_add(cdat, "argv", argvv, len*sizeof(char*))==NULL)
695 	goto done;
696     argc += 1;
697     if (clicon_hash_add(cdat, "argc", &argc, sizeof(argc))==NULL)
698 	goto done;
699     retval = 0;
700  done:
701     if (argvv)
702 	free(argvv);
703     return retval;
704 }
705 
706 /*! Get xml database element including id, xml cache, empty on startup and dirty bit
707  * @param[in]  h    Clicon handle
708  * @param[in]  db   Name of database
709  * @retval     de   Database element
710  * @retval     NULL None found
711  */
712 db_elmnt *
clicon_db_elmnt_get(clicon_handle h,const char * db)713 clicon_db_elmnt_get(clicon_handle h,
714 		    const char   *db)
715 {
716     clicon_hash_t *cdat = clicon_db_elmnt(h);
717     void          *p;
718 
719     if ((p = clicon_hash_value(cdat, db, NULL)) != NULL)
720 	return (db_elmnt *)p;
721     return NULL;
722 }
723 
724 /*! Set xml database element including id, xml cache, empty on startup and dirty bit
725  * @param[in] h   Clicon handle
726  * @param[in] db  Name of database
727  * @param[in] de  Database element
728  * @retval    0   OK
729  * @retval   -1   Error
730  * @see xmldb_disconnect
731 */
732 int
clicon_db_elmnt_set(clicon_handle h,const char * db,db_elmnt * de)733 clicon_db_elmnt_set(clicon_handle h,
734 		    const char   *db,
735 		    db_elmnt     *de)
736 {
737     clicon_hash_t  *cdat = clicon_db_elmnt(h);
738 
739     if (clicon_hash_add(cdat, db, de, sizeof(*de))==NULL)
740 	return -1;
741     return 0;
742 }
743 
744 /*! Get session id
745  * @param[in]  h    Clicon handle
746  * @param[out] sid  Session identifier
747  * @retval     0    OK
748  * @retval    -1    Session id not set
749  * Session-ids survive TCP sessions that are created for each message sent to the backend.
750  * The backend assigns session-id for clients: backend assigns, clients get it from backend.
751  */
752 int
clicon_session_id_get(clicon_handle h,uint32_t * id)753 clicon_session_id_get(clicon_handle h,
754 		      uint32_t     *id)
755 {
756     clicon_hash_t *cdat = clicon_data(h);
757     void           *p;
758 
759     if ((p = clicon_hash_value(cdat, "session-id", NULL)) == NULL)
760 	return -1;
761     *id = *(uint32_t*)p;
762     return 0;
763 }
764 
765 /*! Set session id
766  * @param[in]  h   Clicon handle
767  * @param[in]  id  Session id
768  * @retval     0   OK
769  * @retval    -1   Error
770  * Session-ids survive TCP sessions that are created for each message sent to the backend.
771  */
772 int
clicon_session_id_set(clicon_handle h,uint32_t id)773 clicon_session_id_set(clicon_handle h,
774 		      uint32_t      id)
775 {
776     clicon_hash_t  *cdat = clicon_data(h);
777 
778     clicon_hash_add(cdat, "session-id", &id, sizeof(uint32_t));
779     return 0;
780 }
781 
782 /*! Get quit-after-upgrade flag
783  * @param[in]  h    Clicon handle
784  * @retval     1    Flag set: quit startup directly after upgrade
785  * @retval     0    Flag not set
786  * If set, quit startup directly after upgrade
787  */
788 int
clicon_quit_upgrade_get(clicon_handle h)789 clicon_quit_upgrade_get(clicon_handle h)
790 {
791     clicon_hash_t *cdat = clicon_data(h);
792     void           *p;
793 
794     if ((p = clicon_hash_value(cdat, "quit-after-upgrade", NULL)) == NULL)
795 	return 0;
796     return *(int*)p;
797 }
798 
799 /*! Set quit-after-upgrade flag
800  * @param[in]  h   Clicon handle
801  * @param[in]  val  Set or reset flag
802  * @retval     0   OK
803  * @retval    -1   Error
804  * If set, quit startup directly after upgrade
805  */
806 int
clicon_quit_upgrade_set(clicon_handle h,int val)807 clicon_quit_upgrade_set(clicon_handle h,
808 			int           val)
809 {
810     clicon_hash_t  *cdat = clicon_data(h);
811 
812     clicon_hash_add(cdat, "quit-after-upgrade", &val, sizeof(int));
813     return 0;
814 }
815