4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 * This file contains routines to read/write formatted entries from/to
27 * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
28 * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
32 * The 'name' determines how to interpret 'value'. The supported names are:
34 * IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
35 * converted to nvlist, will contain nvpairs for local and remote
36 * addresses. These nvpairs are of type DATA_TYPE_STRING
38 * IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
39 * converted to nvlist, will contain nvpairs for local and remote
40 * addresses. These nvpairs are of type DATA_TYPE_STRING
42 * IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
43 * info and when converted to nvlist, will contain following nvpairs
44 * interface_id: DATA_TYPE_UINT8_ARRAY
45 * prefixlen: DATA_TYPE_UINT32
46 * stateless: DATA_TYPE_STRING
47 * stateful: DATA_TYPE_STRING
49 * IPADM_NVP_DHCP - value holds wait time and primary info and when converted
50 * to nvlist, will contain following nvpairs
51 * wait: DATA_TYPE_INT32
52 * primary: DATA_TYPE_BOOLEAN
54 * default - value is a single entity and when converted to nvlist, will
55 * contain nvpair of type DATA_TYPE_STRING. nvpairs private to
56 * ipadm are of this type. Further the property name and property
57 * values are stored as nvpairs of this type.
59 * The syntax for each line is described above the respective functions below.
66 #include <sys/types.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
76 #include <sys/sockio.h>
77 #include "libipadm_impl.h"
79 #define MAXLINELEN 1024
80 #define IPADM_NVPAIR_SEP ";"
81 #define IPADM_NAME_SEP ","
83 static char ipadm_rootdir
[MAXPATHLEN
] = "/";
85 static int ipadm_process_db_line(db_wfunc_t
*, void *, FILE *fp
, FILE *nfp
,
89 * convert nvpair to a "name=value" string for writing to the DB.
91 typedef size_t ipadm_wfunc_t(nvpair_t
*, char *, size_t);
94 * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
95 * nvpair to the nvlist.
97 typedef void ipadm_rfunc_t(nvlist_t
*, char *name
, char *value
);
99 static ipadm_rfunc_t i_ipadm_str_dbline2nvl
, i_ipadm_ip4_dbline2nvl
,
100 i_ipadm_ip6_dbline2nvl
, i_ipadm_intfid_dbline2nvl
,
101 i_ipadm_dhcp_dbline2nvl
;
103 static ipadm_wfunc_t i_ipadm_str_nvp2dbline
, i_ipadm_ip4_nvp2dbline
,
104 i_ipadm_ip6_nvp2dbline
, i_ipadm_intfid_nvp2dbline
,
105 i_ipadm_dhcp_nvp2dbline
;
108 * table of function pointers to read/write formatted entries from/to
111 typedef struct ipadm_conf_ent_s
{
112 const char *ipent_type_name
;
113 ipadm_wfunc_t
*ipent_wfunc
;
114 ipadm_rfunc_t
*ipent_rfunc
;
117 static ipadm_conf_ent_t ipadm_conf_ent
[] = {
118 { IPADM_NVP_IPV6ADDR
, i_ipadm_ip6_nvp2dbline
, i_ipadm_ip6_dbline2nvl
},
119 { IPADM_NVP_IPV4ADDR
, i_ipadm_ip4_nvp2dbline
, i_ipadm_ip4_dbline2nvl
},
120 { IPADM_NVP_INTFID
, i_ipadm_intfid_nvp2dbline
,
121 i_ipadm_intfid_dbline2nvl
},
122 { IPADM_NVP_DHCP
, i_ipadm_dhcp_nvp2dbline
, i_ipadm_dhcp_dbline2nvl
},
123 { NULL
, i_ipadm_str_nvp2dbline
, i_ipadm_str_dbline2nvl
}
126 static ipadm_conf_ent_t
*
127 i_ipadm_find_conf_type(const char *type
)
131 for (i
= 0; ipadm_conf_ent
[i
].ipent_type_name
!= NULL
; i
++)
132 if (strcmp(type
, ipadm_conf_ent
[i
].ipent_type_name
) == 0)
134 return (&ipadm_conf_ent
[i
]);
138 * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
139 * the given nvlist `nvl' and adds the strings to `buf'.
142 i_ipadm_ip_addhostname2dbline(nvlist_t
*nvl
, char *buf
, size_t buflen
)
145 char tmpbuf
[IPADM_STRSIZE
];
147 /* Add the local hostname */
148 if (nvlist_lookup_string(nvl
, IPADM_NVP_IPADDRHNAME
, &cp
) != 0)
150 (void) strlcat(buf
, cp
, buflen
); /* local hostname */
152 /* Add the dst hostname */
153 if (nvlist_lookup_string(nvl
, IPADM_NVP_IPDADDRHNAME
, &cp
) != 0) {
154 /* no dst addr. just add a NULL character */
155 (void) snprintf(tmpbuf
, sizeof (tmpbuf
), ",");
157 (void) snprintf(tmpbuf
, sizeof (tmpbuf
), ",%s", cp
);
159 return (strlcat(buf
, tmpbuf
, buflen
));
163 * Converts IPADM_NVP_IPV4ADDR nvpair to a string representation for writing to
164 * the DB. The converted string format:
165 * ipv4addr=<local numeric IP string or hostname,remote numeric IP
166 * string or hostname>
169 i_ipadm_ip4_nvp2dbline(nvpair_t
*nvp
, char *buf
, size_t buflen
)
174 assert(nvpair_type(nvp
) == DATA_TYPE_NVLIST
&&
175 strcmp(nvpair_name(nvp
), IPADM_NVP_IPV4ADDR
) == 0);
177 (void) snprintf(buf
, buflen
, "%s=", IPADM_NVP_IPV4ADDR
);
178 if (nvpair_value_nvlist(nvp
, &v
) != 0)
180 nbytes
= i_ipadm_ip_addhostname2dbline(v
, buf
, buflen
);
189 * Converts IPADM_NVP_IPV6ADDR nvpair to a string representation for writing to
190 * the DB. The converted string format:
191 * ipv6addr=<local numeric IP string or hostname,remote numeric IP
192 * string or hostname>
195 i_ipadm_ip6_nvp2dbline(nvpair_t
*nvp
, char *buf
, size_t buflen
)
200 assert(nvpair_type(nvp
) == DATA_TYPE_NVLIST
&&
201 strcmp(nvpair_name(nvp
), IPADM_NVP_IPV6ADDR
) == 0);
203 (void) snprintf(buf
, buflen
, "%s=", IPADM_NVP_IPV6ADDR
);
204 if (nvpair_value_nvlist(nvp
, &v
) != 0)
206 nbytes
= i_ipadm_ip_addhostname2dbline(v
, buf
, buflen
);
215 * Converts IPADM_NVP_INTFID nvpair to a string representation for writing to
216 * the DB. The converted string format:
217 * IPADM_NVP_INTFID=<intfid/prefixlen>,{yes|no},{yes|no}
220 i_ipadm_intfid_nvp2dbline(nvpair_t
*nvp
, char *buf
, size_t buflen
)
222 char addrbuf
[IPADM_STRSIZE
];
225 struct in6_addr in6addr
;
229 assert(nvpair_type(nvp
) == DATA_TYPE_NVLIST
&&
230 strcmp(nvpair_name(nvp
), IPADM_NVP_INTFID
) == 0);
232 (void) snprintf(buf
, buflen
, "%s=", IPADM_NVP_INTFID
);
233 if (nvpair_value_nvlist(nvp
, &v
) != 0)
235 if (i_ipadm_nvl2in6_addr(v
, IPADM_NVP_IPNUMADDR
, &in6addr
) !=
238 (void) inet_ntop(AF_INET6
, &in6addr
, addrbuf
,
240 (void) strlcat(buf
, addrbuf
, buflen
);
241 if (nvlist_lookup_uint32(v
, IPADM_NVP_PREFIXLEN
, &prefixlen
) != 0 ||
242 nvlist_lookup_string(v
, IPADM_NVP_STATELESS
, &stateless
) != 0 ||
243 nvlist_lookup_string(v
, IPADM_NVP_STATEFUL
, &stateful
) != 0)
245 (void) snprintf(addrbuf
, sizeof (addrbuf
), "/%d,%s,%s",
246 prefixlen
, stateless
, stateful
);
247 return (strlcat(buf
, addrbuf
, buflen
));
254 * Converts IPADM_NVP_DHCP nvpair to a string representation for writing to the
255 * DB. The converted string format:
256 * IPADM_NVP_DHCP=<wait_time>,{yes|no}
259 i_ipadm_dhcp_nvp2dbline(nvpair_t
*nvp
, char *buf
, size_t buflen
)
261 char addrbuf
[IPADM_STRSIZE
];
266 assert(nvpair_type(nvp
) == DATA_TYPE_NVLIST
&&
267 strcmp(nvpair_name(nvp
), IPADM_NVP_DHCP
) == 0);
269 if (nvpair_value_nvlist(nvp
, &v
) != 0 ||
270 nvlist_lookup_int32(v
, IPADM_NVP_WAIT
, &wait
) != 0 ||
271 nvlist_lookup_boolean_value(v
, IPADM_NVP_PRIMARY
, &primary
) != 0) {
274 (void) snprintf(buf
, buflen
, "%s=", IPADM_NVP_DHCP
);
275 (void) snprintf(addrbuf
, sizeof (addrbuf
), "%d,%s", wait
,
276 (primary
? "yes" : "no"));
277 return (strlcat(buf
, addrbuf
, buflen
));
281 * Constructs a "<name>=<value>" string from the nvpair, whose type must
285 i_ipadm_str_nvp2dbline(nvpair_t
*nvp
, char *buf
, size_t buflen
)
289 assert(nvpair_type(nvp
) == DATA_TYPE_STRING
);
290 if (nvpair_value_string(nvp
, &str
) != 0)
292 return (snprintf(buf
, buflen
, "%s=%s", nvpair_name(nvp
), str
));
296 * Converts a nvlist to string of the form:
297 * <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
300 ipadm_nvlist2str(nvlist_t
*nvl
, char *buf
, size_t buflen
)
302 nvpair_t
*nvp
= NULL
;
303 uint_t nbytes
= 0, tbytes
= 0;
304 ipadm_conf_ent_t
*ipent
;
305 size_t bufsize
= buflen
;
307 for (nvp
= nvlist_next_nvpair(nvl
, NULL
); nvp
!= NULL
;
308 nvp
= nvlist_next_nvpair(nvl
, nvp
)) {
309 ipent
= i_ipadm_find_conf_type(nvpair_name(nvp
));
310 nbytes
= (*ipent
->ipent_wfunc
)(nvp
, buf
, buflen
);
311 /* add nvpair separator */
312 nbytes
+= snprintf(buf
+ nbytes
, buflen
- nbytes
, "%s",
317 if (tbytes
>= bufsize
) /* buffer overflow */
320 nbytes
= snprintf(buf
, buflen
, "%c%c", '\n', '\0');
322 if (tbytes
>= bufsize
)
328 * Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
329 * The value will be interpreted as explained at the top of this file.
332 i_ipadm_add_nvpair(nvlist_t
*nvl
, char *name
, char *value
)
334 ipadm_conf_ent_t
*ipent
;
336 ipent
= i_ipadm_find_conf_type(name
);
337 (*ipent
->ipent_rfunc
)(nvl
, name
, value
);
341 * Adds an nvpair for IPv4 addr to the nvlist. The "name" is the string in
342 * IPADM_NVP_IPV4ADDR. The "value" for IPADM_NVP_IPV4ADDR is another nvlist.
343 * Allocate the value nvlist for IPADM_NVP_IPV4ADDR if necessary, and add
344 * the address and hostnames from the address object `ipaddr' to it.
345 * Then add the allocated nvlist to `nvl'.
348 i_ipadm_add_ipaddr2nvl(nvlist_t
*nvl
, ipadm_addrobj_t ipaddr
)
350 nvlist_t
*nvl_addr
= NULL
;
353 sa_family_t af
= ipaddr
->ipadm_af
;
356 name
= IPADM_NVP_IPV4ADDR
;
358 assert(af
== AF_INET6
);
359 name
= IPADM_NVP_IPV6ADDR
;
362 if (!nvlist_exists(nvl
, name
)) {
363 if ((err
= nvlist_alloc(&nvl_addr
, NV_UNIQUE_NAME
, 0)) != 0)
364 return (ipadm_errno2status(err
));
365 if ((err
= nvlist_add_nvlist(nvl
, name
, nvl_addr
)) != 0) {
366 nvlist_free(nvl_addr
);
367 return (ipadm_errno2status(err
));
369 nvlist_free(nvl_addr
);
371 if ((err
= nvlist_lookup_nvlist(nvl
, name
, &nvl_addr
)) != 0 ||
372 (err
= nvlist_add_string(nvl_addr
, IPADM_NVP_IPADDRHNAME
,
373 ipaddr
->ipadm_static_aname
)) != 0)
374 return (ipadm_errno2status(err
));
375 if (ipaddr
->ipadm_static_dname
[0] != '\0') {
376 if ((err
= nvlist_add_string(nvl_addr
, IPADM_NVP_IPDADDRHNAME
,
377 ipaddr
->ipadm_static_dname
)) != 0)
378 return (ipadm_errno2status(err
));
381 return (IPADM_SUCCESS
);
385 * Adds an nvpair for IPv6 interface id to the nvlist. The "name" is
386 * the string in IPADM_NVP_INTFID. The "value" for IPADM_NVP_INTFID is another
387 * nvlist. Allocate the value nvlist for IPADM_NVP_INTFID if necessary, and add
388 * the interface id and its prefixlen from the address object `ipaddr' to it.
389 * Then add the allocated nvlist to `nvl'.
392 i_ipadm_add_intfid2nvl(nvlist_t
*nvl
, ipadm_addrobj_t addr
)
394 nvlist_t
*nvl_addr
= NULL
;
395 struct in6_addr addr6
;
398 if (!nvlist_exists(nvl
, IPADM_NVP_INTFID
)) {
399 if ((err
= nvlist_alloc(&nvl_addr
, NV_UNIQUE_NAME
, 0)) != 0)
400 return (ipadm_errno2status(err
));
401 if ((err
= nvlist_add_nvlist(nvl
, IPADM_NVP_INTFID
,
403 nvlist_free(nvl_addr
);
404 return (ipadm_errno2status(err
));
406 nvlist_free(nvl_addr
);
408 if ((err
= nvlist_lookup_nvlist(nvl
, IPADM_NVP_INTFID
,
409 &nvl_addr
)) != 0 || (err
= nvlist_add_uint32(nvl_addr
,
410 IPADM_NVP_PREFIXLEN
, addr
->ipadm_intfidlen
)) != 0) {
411 return (ipadm_errno2status(err
));
413 addr6
= addr
->ipadm_intfid
.sin6_addr
;
414 if ((err
= nvlist_add_uint8_array(nvl_addr
, IPADM_NVP_IPNUMADDR
,
415 addr6
.s6_addr
, 16)) != 0) {
416 return (ipadm_errno2status(err
));
418 if (addr
->ipadm_stateless
)
419 err
= nvlist_add_string(nvl_addr
, IPADM_NVP_STATELESS
, "yes");
421 err
= nvlist_add_string(nvl_addr
, IPADM_NVP_STATELESS
, "no");
423 return (ipadm_errno2status(err
));
424 if (addr
->ipadm_stateful
)
425 err
= nvlist_add_string(nvl_addr
, IPADM_NVP_STATEFUL
, "yes");
427 err
= nvlist_add_string(nvl_addr
, IPADM_NVP_STATEFUL
, "no");
429 return (ipadm_errno2status(err
));
431 return (IPADM_SUCCESS
);
435 * Adds an nvpair for a dhcp address object to the nvlist. The "name" is
436 * the string in IPADM_NVP_DHCP. The "value" for IPADM_NVP_DHCP is another
437 * nvlist. Allocate the value nvlist for IPADM_NVP_DHCP if necessary, and add
438 * the parameters from the arguments `primary' and `wait'.
439 * Then add the allocated nvlist to `nvl'.
442 i_ipadm_add_dhcp2nvl(nvlist_t
*nvl
, boolean_t primary
, int32_t wait
)
444 nvlist_t
*nvl_dhcp
= NULL
;
447 if (!nvlist_exists(nvl
, IPADM_NVP_DHCP
)) {
448 if ((err
= nvlist_alloc(&nvl_dhcp
, NV_UNIQUE_NAME
, 0)) != 0)
449 return (ipadm_errno2status(err
));
450 if ((err
= nvlist_add_nvlist(nvl
, IPADM_NVP_DHCP
,
452 nvlist_free(nvl_dhcp
);
453 return (ipadm_errno2status(err
));
455 nvlist_free(nvl_dhcp
);
457 if ((err
= nvlist_lookup_nvlist(nvl
, IPADM_NVP_DHCP
, &nvl_dhcp
)) != 0 ||
458 (err
= nvlist_add_int32(nvl_dhcp
, IPADM_NVP_WAIT
, wait
)) != 0 ||
459 (err
= nvlist_add_boolean_value(nvl_dhcp
, IPADM_NVP_PRIMARY
,
461 return (ipadm_errno2status(err
));
464 return (IPADM_SUCCESS
);
468 * Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
471 i_ipadm_str_dbline2nvl(nvlist_t
*nvl
, char *name
, char *value
)
473 /* if value is NULL create an empty node */
475 (void) nvlist_add_string(nvl
, name
, "");
477 (void) nvlist_add_string(nvl
, name
, value
);
481 * `name' = IPADM_NVP_IPV4ADDR and
482 * `value' = <local numeric IP string or hostname,remote numeric IP string or
484 * This function will add an nvlist with the hostname information in
485 * nvpairs to the nvlist in `nvl'.
488 i_ipadm_ip4_dbline2nvl(nvlist_t
*nvl
, char *name
, char *value
)
491 struct ipadm_addrobj_s ipaddr
;
493 assert(strcmp(name
, IPADM_NVP_IPV4ADDR
) == 0 && value
!= NULL
);
495 bzero(&ipaddr
, sizeof (ipaddr
));
496 ipaddr
.ipadm_af
= AF_INET
;
498 hname
= value
; /* local hostname */
499 cp
= strchr(hname
, ',');
502 (void) strlcpy(ipaddr
.ipadm_static_aname
, hname
,
503 sizeof (ipaddr
.ipadm_static_aname
));
506 /* we have a dst hostname */
507 (void) strlcpy(ipaddr
.ipadm_static_dname
, cp
,
508 sizeof (ipaddr
.ipadm_static_dname
));
510 (void) i_ipadm_add_ipaddr2nvl(nvl
, &ipaddr
);
514 * `name' = IPADM_NVP_IPV6ADDR and
515 * `value' = <local numeric IP string or hostname,remote numeric IP string or
517 * This function will add an nvlist with the hostname information in
518 * nvpairs to the nvlist in `nvl'.
521 i_ipadm_ip6_dbline2nvl(nvlist_t
*nvl
, char *name
, char *value
)
524 struct ipadm_addrobj_s ipaddr
;
526 assert(strcmp(name
, IPADM_NVP_IPV6ADDR
) == 0 && value
!= NULL
);
528 bzero(&ipaddr
, sizeof (ipaddr
));
529 ipaddr
.ipadm_af
= AF_INET6
;
531 hname
= value
; /* local hostname */
532 cp
= strchr(hname
, ',');
535 (void) strlcpy(ipaddr
.ipadm_static_aname
, hname
,
536 sizeof (ipaddr
.ipadm_static_aname
));
539 /* we have a dst hostname */
540 (void) strlcpy(ipaddr
.ipadm_static_dname
, cp
,
541 sizeof (ipaddr
.ipadm_static_dname
));
543 (void) i_ipadm_add_ipaddr2nvl(nvl
, &ipaddr
);
547 * `name' = IPADM_NVP_INTFID and `value' = <intfid/prefixlen>,{yes,no},{yes|no}
548 * This function will add an nvlist with the address object information in
549 * nvpairs to the nvlist in `nvl'.
552 i_ipadm_intfid_dbline2nvl(nvlist_t
*nvl
, char *name
, char *value
)
555 struct ipadm_addrobj_s ipaddr
;
561 assert(strcmp(name
, IPADM_NVP_INTFID
) == 0 && value
!= NULL
);
563 bzero(&ipaddr
, sizeof (ipaddr
));
565 cp
= strchr(value
, '/');
569 ipaddr
.ipadm_intfid
.sin6_family
= AF_INET6
;
570 (void) inet_pton(AF_INET6
, value
, &ipaddr
.ipadm_intfid
.sin6_addr
);
573 cp
= strchr(cp
, ',');
578 ipaddr
.ipadm_intfidlen
= (uint32_t)strtoul(prefixlen
, &endp
, 10);
579 if (*endp
!= '\0' || errno
!= 0)
583 stateful
= strchr(stateless
, ',');
584 assert(stateful
!= NULL
);
586 ipaddr
.ipadm_stateless
= (strcmp(stateless
, "yes") == 0);
587 ipaddr
.ipadm_stateful
= (strcmp(stateful
, "yes") == 0);
589 /* Add all of it to the given nvlist */
590 (void) i_ipadm_add_intfid2nvl(nvl
, &ipaddr
);
594 * `name' = IPADM_NVP_DHCP and `value' = <wait_time>,{yes|no}
595 * This function will add an nvlist with the dhcp address object information in
596 * nvpairs to the nvlist in `nvl'.
599 i_ipadm_dhcp_dbline2nvl(nvlist_t
*nvl
, char *name
, char *value
)
606 assert(strcmp(name
, IPADM_NVP_DHCP
) == 0 && value
!= NULL
);
607 cp
= strchr(value
, ',');
611 wait_time
= strtol(value
, &endp
, 10);
612 if (*endp
!= '\0' || errno
!= 0)
614 primary
= (strcmp(cp
, "yes") == 0);
615 (void) i_ipadm_add_dhcp2nvl(nvl
, primary
, (int32_t)wait_time
);
619 * Parses the buffer, for name-value pairs and creates nvlist. The value
620 * is always considered to be a string.
623 ipadm_str2nvlist(const char *inbuf
, nvlist_t
**ipnvl
, uint_t flags
)
625 char *nv
, *name
, *val
, *buf
, *cp
, *sep
;
628 if (inbuf
== NULL
|| inbuf
[0] == '\0' || ipnvl
== NULL
)
633 * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
635 if ((flags
& IPADM_NORVAL
) && strchr(inbuf
, '=') != NULL
)
638 if ((cp
= buf
= strdup(inbuf
)) == NULL
)
641 while (isspace(*buf
))
651 * work on one nvpair at a time and extract the name and value
653 sep
= ((flags
& IPADM_NORVAL
) ? IPADM_NAME_SEP
: IPADM_NVPAIR_SEP
);
654 while ((nv
= strsep(&buf
, sep
)) != NULL
) {
658 if ((val
= strchr(nv
, '=')) != NULL
)
660 if (*ipnvl
== NULL
&&
661 (err
= nvlist_alloc(ipnvl
, NV_UNIQUE_NAME
, 0)) != 0)
663 if (nvlist_exists(*ipnvl
, name
)) {
667 /* Add the extracted nvpair to the nvlist `ipnvl'. */
668 (void) i_ipadm_add_nvpair(*ipnvl
, name
, val
);
680 * Opens the data store for read/write operation. For write operation we open
681 * another file and scribble the changes to it and copy the new file back to
685 ipadm_rw_db(db_wfunc_t
*db_walk_func
, void *arg
, const char *db_file
,
686 mode_t db_perms
, ipadm_db_op_t db_op
)
688 FILE *fp
, *nfp
= NULL
;
689 char file
[MAXPATHLEN
];
690 char newfile
[MAXPATHLEN
];
695 writeop
= (db_op
!= IPADM_DB_READ
);
697 (void) snprintf(file
, MAXPATHLEN
, "%s/%s", ipadm_rootdir
, db_file
);
699 /* open the data store */
700 if ((fp
= fopen(file
, (writeop
? "r+" : "r"))) == NULL
)
704 (void) snprintf(newfile
, MAXPATHLEN
, "%s/%s.new",
705 ipadm_rootdir
, db_file
);
706 if ((nfd
= open(newfile
, O_WRONLY
| O_CREAT
| O_TRUNC
,
713 if ((nfp
= fdopen(nfd
, "w")) == NULL
) {
717 (void) unlink(newfile
);
721 err
= ipadm_process_db_line(db_walk_func
, arg
, fp
, nfp
, db_op
);
724 if (err
!= 0 && err
!= ENOENT
)
727 if (fflush(nfp
) == EOF
) {
734 if (rename(newfile
, file
) < 0) {
736 (void) unlink(newfile
);
743 (void) unlink(newfile
);
750 * Processes each line of the configuration file, skipping lines with
751 * leading spaces, blank lines and comments. The line form the DB
752 * is converted to nvlist and the callback function is called to process
753 * the list. The buf could be modified by the callback function and
754 * if this is a write operation and buf is not truncated, buf will
755 * be written to disk.
757 * Further if cont is set to B_FALSE, the remainder of the file will
758 * continue to be read (however callback function will not be called) and,
759 * if necessary, written to disk as well.
762 ipadm_process_db_line(db_wfunc_t
*db_walk_func
, void *arg
, FILE *fp
, FILE *nfp
,
766 char buf
[MAXLINELEN
];
767 boolean_t cont
= B_TRUE
;
769 nvlist_t
*db_nvl
= NULL
;
770 boolean_t line_deleted
= B_FALSE
;
772 while (fgets(buf
, MAXLINELEN
, fp
) != NULL
) {
774 * Skip leading spaces, blank lines, and comments.
776 len
= strnlen(buf
, MAXLINELEN
);
777 for (i
= 0; i
< len
; i
++) {
778 if (!isspace(buf
[i
]))
782 if (i
!= len
&& buf
[i
] != '#' && cont
) {
783 if (ipadm_str2nvlist(buf
, &db_nvl
, 0) == 0) {
784 cont
= db_walk_func(arg
, db_nvl
, buf
,
787 /* Delete corrupted line. */
795 if (nfp
!= NULL
&& buf
[0] == '\0')
796 line_deleted
= B_TRUE
;
797 if (nfp
!= NULL
&& buf
[0] != '\0' && fputs(buf
, nfp
) == EOF
) {
803 if (err
!= 0 || !cont
)
806 if (db_op
== IPADM_DB_WRITE
) {
810 * `arg' will be NULL when we are doing in-line update of
814 nvl
= ((ipadm_dbwrite_cbarg_t
*)arg
)->dbw_nvl
;
816 * If the specified entry is not found above, we add
817 * the entry to the configuration file, here.
819 (void) memset(buf
, 0, MAXLINELEN
);
820 if (ipadm_nvlist2str(nvl
, buf
, MAXLINELEN
) == 0)
822 else if (fputs(buf
, nfp
) == EOF
)
828 if (db_op
== IPADM_DB_DELETE
&& line_deleted
)
831 /* if we have come this far, then we didn't find any match */