xref: /illumos-gate/usr/src/lib/libipadm/common/ipadm_persist.c (revision a73be61a80f7331c35adfa540bcf8f1546ff1e33)
16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail /*
22ec3706caSVasumathi Sundaram  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23*a73be61aSHans Rosenfeld  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
246e91bba0SGirish Moodalbail  */
256e91bba0SGirish Moodalbail 
266e91bba0SGirish Moodalbail /*
276e91bba0SGirish Moodalbail  * This file contains routines to read/write formatted entries from/to
286e91bba0SGirish Moodalbail  * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
296e91bba0SGirish Moodalbail  * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
306e91bba0SGirish Moodalbail  * below:
316e91bba0SGirish Moodalbail  *		name=value[;...]
326e91bba0SGirish Moodalbail  *
336e91bba0SGirish Moodalbail  * The 'name' determines how to interpret 'value'. The supported names are:
346e91bba0SGirish Moodalbail  *
356e91bba0SGirish Moodalbail  *  IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
366e91bba0SGirish Moodalbail  *	       converted to nvlist, will contain nvpairs for local and remote
376e91bba0SGirish Moodalbail  *	       addresses. These nvpairs are of type DATA_TYPE_STRING
386e91bba0SGirish Moodalbail  *
396e91bba0SGirish Moodalbail  *  IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
406e91bba0SGirish Moodalbail  *	       converted to nvlist, will contain nvpairs for local and remote
416e91bba0SGirish Moodalbail  *	       addresses. These nvpairs are of type DATA_TYPE_STRING
426e91bba0SGirish Moodalbail  *
436e91bba0SGirish Moodalbail  *  IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
446e91bba0SGirish Moodalbail  *	       info and when converted to nvlist, will contain following nvpairs
456e91bba0SGirish Moodalbail  *			interface_id: DATA_TYPE_UINT8_ARRAY
466e91bba0SGirish Moodalbail  *			prefixlen: DATA_TYPE_UINT32
476e91bba0SGirish Moodalbail  *			stateless: DATA_TYPE_STRING
486e91bba0SGirish Moodalbail  *			stateful: DATA_TYPE_STRING
496e91bba0SGirish Moodalbail  *
506e91bba0SGirish Moodalbail  *  IPADM_NVP_DHCP - value holds wait time and primary info and when converted
516e91bba0SGirish Moodalbail  *	       to nvlist, will contain following nvpairs
526e91bba0SGirish Moodalbail  *			wait:	DATA_TYPE_INT32
536e91bba0SGirish Moodalbail  *			primary: DATA_TYPE_BOOLEAN
546e91bba0SGirish Moodalbail  *
55*a73be61aSHans Rosenfeld  *  IPADM_NVP_FAMILIES - value holds interface families and when converted
56*a73be61aSHans Rosenfeld  *	       to nvlist, will be a DATA_TYPE_UINT16_ARRAY
57*a73be61aSHans Rosenfeld  *
58*a73be61aSHans Rosenfeld  *  IPADM_NVP_MIFNAMES - value holds IPMP group members and when converted
59*a73be61aSHans Rosenfeld  *	       to nvlist, will be a DATA_TYPE_STRING_ARRAY
60*a73be61aSHans Rosenfeld  *
616e91bba0SGirish Moodalbail  *  default  - value is a single entity and when converted to nvlist, will
626e91bba0SGirish Moodalbail  *	       contain nvpair of type DATA_TYPE_STRING. nvpairs private to
636e91bba0SGirish Moodalbail  *	       ipadm are of this type. Further the property name and property
646e91bba0SGirish Moodalbail  *	       values are stored as nvpairs of this type.
656e91bba0SGirish Moodalbail  *
666e91bba0SGirish Moodalbail  * The syntax for each line is described above the respective functions below.
676e91bba0SGirish Moodalbail  */
686e91bba0SGirish Moodalbail 
696e91bba0SGirish Moodalbail #include <stdlib.h>
706e91bba0SGirish Moodalbail #include <strings.h>
716e91bba0SGirish Moodalbail #include <errno.h>
726e91bba0SGirish Moodalbail #include <ctype.h>
736e91bba0SGirish Moodalbail #include <sys/types.h>
746e91bba0SGirish Moodalbail #include <sys/stat.h>
756e91bba0SGirish Moodalbail #include <sys/dld.h>
766e91bba0SGirish Moodalbail #include <fcntl.h>
776e91bba0SGirish Moodalbail #include <dirent.h>
786e91bba0SGirish Moodalbail #include <unistd.h>
796e91bba0SGirish Moodalbail #include <assert.h>
806e91bba0SGirish Moodalbail #include <sys/socket.h>
816e91bba0SGirish Moodalbail #include <netinet/in.h>
826e91bba0SGirish Moodalbail #include <arpa/inet.h>
836e91bba0SGirish Moodalbail #include <sys/sockio.h>
846e91bba0SGirish Moodalbail #include "libipadm_impl.h"
856e91bba0SGirish Moodalbail 
866e91bba0SGirish Moodalbail #define	MAXLINELEN		1024
876e91bba0SGirish Moodalbail #define	IPADM_NVPAIR_SEP	";"
886e91bba0SGirish Moodalbail #define	IPADM_NAME_SEP		","
896e91bba0SGirish Moodalbail 
906e91bba0SGirish Moodalbail static char ipadm_rootdir[MAXPATHLEN] = "/";
916e91bba0SGirish Moodalbail 
926e91bba0SGirish Moodalbail static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
936e91bba0SGirish Moodalbail     ipadm_db_op_t);
946e91bba0SGirish Moodalbail 
956e91bba0SGirish Moodalbail /*
966e91bba0SGirish Moodalbail  * convert nvpair to a "name=value" string for writing to the DB.
976e91bba0SGirish Moodalbail  */
986e91bba0SGirish Moodalbail typedef size_t ipadm_wfunc_t(nvpair_t *, char *, size_t);
996e91bba0SGirish Moodalbail 
1006e91bba0SGirish Moodalbail /*
1016e91bba0SGirish Moodalbail  * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
1026e91bba0SGirish Moodalbail  * nvpair to the nvlist.
1036e91bba0SGirish Moodalbail  */
104*a73be61aSHans Rosenfeld typedef ipadm_status_t ipadm_rfunc_t(nvlist_t *, char *, char *);
1056e91bba0SGirish Moodalbail 
1066e91bba0SGirish Moodalbail static ipadm_rfunc_t	i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
1076e91bba0SGirish Moodalbail 			i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
108*a73be61aSHans Rosenfeld 			i_ipadm_dhcp_dbline2nvl, i_ipadm_families_dbline2nvl,
109*a73be61aSHans Rosenfeld 			i_ipadm_groupmembers_dbline2nvl;
1106e91bba0SGirish Moodalbail 
1116e91bba0SGirish Moodalbail static ipadm_wfunc_t	i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
1126e91bba0SGirish Moodalbail 			i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
113*a73be61aSHans Rosenfeld 			i_ipadm_dhcp_nvp2dbline, i_ipadm_families_nvp2dbline,
114*a73be61aSHans Rosenfeld 			i_ipadm_groupmembers_nvp2dbline;
1156e91bba0SGirish Moodalbail 
1166e91bba0SGirish Moodalbail /*
1176e91bba0SGirish Moodalbail  * table of function pointers to read/write formatted entries from/to
1186e91bba0SGirish Moodalbail  * ipadm.conf.
1196e91bba0SGirish Moodalbail  */
1206e91bba0SGirish Moodalbail typedef struct ipadm_conf_ent_s {
1216e91bba0SGirish Moodalbail 	const char		*ipent_type_name;
1226e91bba0SGirish Moodalbail 	ipadm_wfunc_t		*ipent_wfunc;
1236e91bba0SGirish Moodalbail 	ipadm_rfunc_t		*ipent_rfunc;
1246e91bba0SGirish Moodalbail } ipadm_conf_ent_t;
1256e91bba0SGirish Moodalbail 
1266e91bba0SGirish Moodalbail static ipadm_conf_ent_t ipadm_conf_ent[] = {
1276e91bba0SGirish Moodalbail 	{ IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
1286e91bba0SGirish Moodalbail 	{ IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
1296e91bba0SGirish Moodalbail 	{ IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
1306e91bba0SGirish Moodalbail 	    i_ipadm_intfid_dbline2nvl },
1316e91bba0SGirish Moodalbail 	{ IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
132*a73be61aSHans Rosenfeld 	{ IPADM_NVP_FAMILIES, i_ipadm_families_nvp2dbline,
133*a73be61aSHans Rosenfeld 	    i_ipadm_families_dbline2nvl },
134*a73be61aSHans Rosenfeld 	{ IPADM_NVP_MIFNAMES, i_ipadm_groupmembers_nvp2dbline,
135*a73be61aSHans Rosenfeld 	    i_ipadm_groupmembers_dbline2nvl},
1366e91bba0SGirish Moodalbail 	{ NULL,	i_ipadm_str_nvp2dbline,	i_ipadm_str_dbline2nvl }
1376e91bba0SGirish Moodalbail };
1386e91bba0SGirish Moodalbail 
1396e91bba0SGirish Moodalbail static ipadm_conf_ent_t *
i_ipadm_find_conf_type(const char * type)1406e91bba0SGirish Moodalbail i_ipadm_find_conf_type(const char *type)
1416e91bba0SGirish Moodalbail {
1426e91bba0SGirish Moodalbail 	int	i;
1436e91bba0SGirish Moodalbail 
1446e91bba0SGirish Moodalbail 	for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
1456e91bba0SGirish Moodalbail 		if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
1466e91bba0SGirish Moodalbail 			break;
1476e91bba0SGirish Moodalbail 	return (&ipadm_conf_ent[i]);
1486e91bba0SGirish Moodalbail }
1496e91bba0SGirish Moodalbail 
1506e91bba0SGirish Moodalbail /*
1516e91bba0SGirish Moodalbail  * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
1526e91bba0SGirish Moodalbail  * the given nvlist `nvl' and adds the strings to `buf'.
1536e91bba0SGirish Moodalbail  */
1546e91bba0SGirish Moodalbail size_t
i_ipadm_ip_addhostname2dbline(nvlist_t * nvl,char * buf,size_t buflen)1556e91bba0SGirish Moodalbail i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
1566e91bba0SGirish Moodalbail {
1576e91bba0SGirish Moodalbail 	char	*cp;
1586e91bba0SGirish Moodalbail 	char	tmpbuf[IPADM_STRSIZE];
1596e91bba0SGirish Moodalbail 
1606e91bba0SGirish Moodalbail 	/* Add the local hostname */
1616e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(nvl, IPADM_NVP_IPADDRHNAME, &cp) != 0)
1626e91bba0SGirish Moodalbail 		return (0);
1636e91bba0SGirish Moodalbail 	(void) strlcat(buf, cp, buflen); /* local hostname */
1646e91bba0SGirish Moodalbail 
1656e91bba0SGirish Moodalbail 	/* Add the dst hostname */
1666e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(nvl, IPADM_NVP_IPDADDRHNAME, &cp) != 0) {
1676e91bba0SGirish Moodalbail 		/* no dst addr. just add a NULL character */
1686e91bba0SGirish Moodalbail 		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",");
1696e91bba0SGirish Moodalbail 	} else {
1706e91bba0SGirish Moodalbail 		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",%s", cp);
1716e91bba0SGirish Moodalbail 	}
1726e91bba0SGirish Moodalbail 	return (strlcat(buf, tmpbuf, buflen));
1736e91bba0SGirish Moodalbail }
1746e91bba0SGirish Moodalbail 
1756e91bba0SGirish Moodalbail /*
1766e91bba0SGirish Moodalbail  * Converts IPADM_NVP_IPV4ADDR nvpair to a string representation for writing to
1776e91bba0SGirish Moodalbail  * the DB. The converted string format:
1786e91bba0SGirish Moodalbail  *	ipv4addr=<local numeric IP string or hostname,remote numeric IP
1796e91bba0SGirish Moodalbail  *          string or hostname>
1806e91bba0SGirish Moodalbail  */
1816e91bba0SGirish Moodalbail static size_t
i_ipadm_ip4_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)1826e91bba0SGirish Moodalbail i_ipadm_ip4_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
1836e91bba0SGirish Moodalbail {
1846e91bba0SGirish Moodalbail 	nvlist_t	*v;
1856e91bba0SGirish Moodalbail 	int		nbytes;
1866e91bba0SGirish Moodalbail 
1876e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
1886e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV4ADDR) == 0);
1896e91bba0SGirish Moodalbail 
1906e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV4ADDR);
1916e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
1926e91bba0SGirish Moodalbail 		goto fail;
1936e91bba0SGirish Moodalbail 	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
1946e91bba0SGirish Moodalbail 	if (nbytes != 0)
1956e91bba0SGirish Moodalbail 		return (nbytes);
1966e91bba0SGirish Moodalbail fail:
1976e91bba0SGirish Moodalbail 	buf[0] = '\0';
1986e91bba0SGirish Moodalbail 	return (0);
1996e91bba0SGirish Moodalbail }
2006e91bba0SGirish Moodalbail 
2016e91bba0SGirish Moodalbail /*
2026e91bba0SGirish Moodalbail  * Converts IPADM_NVP_IPV6ADDR nvpair to a string representation for writing to
2036e91bba0SGirish Moodalbail  * the DB. The converted string format:
2046e91bba0SGirish Moodalbail  *	ipv6addr=<local numeric IP string or hostname,remote numeric IP
2056e91bba0SGirish Moodalbail  *          string or hostname>
2066e91bba0SGirish Moodalbail  */
2076e91bba0SGirish Moodalbail static size_t
i_ipadm_ip6_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)2086e91bba0SGirish Moodalbail i_ipadm_ip6_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2096e91bba0SGirish Moodalbail {
2106e91bba0SGirish Moodalbail 	nvlist_t	*v;
2116e91bba0SGirish Moodalbail 	int		nbytes;
2126e91bba0SGirish Moodalbail 
2136e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2146e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV6ADDR) == 0);
2156e91bba0SGirish Moodalbail 
2166e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV6ADDR);
2176e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
2186e91bba0SGirish Moodalbail 		goto fail;
2196e91bba0SGirish Moodalbail 	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
2206e91bba0SGirish Moodalbail 	if (nbytes != 0)
2216e91bba0SGirish Moodalbail 		return (nbytes);
2226e91bba0SGirish Moodalbail fail:
2236e91bba0SGirish Moodalbail 	buf[0] = '\0';
2246e91bba0SGirish Moodalbail 	return (0);
2256e91bba0SGirish Moodalbail }
2266e91bba0SGirish Moodalbail 
2276e91bba0SGirish Moodalbail /*
2286e91bba0SGirish Moodalbail  * Converts IPADM_NVP_INTFID nvpair to a string representation for writing to
2296e91bba0SGirish Moodalbail  * the DB. The converted string format:
2306e91bba0SGirish Moodalbail  *	IPADM_NVP_INTFID=<intfid/prefixlen>,{yes|no},{yes|no}
2316e91bba0SGirish Moodalbail  */
2326e91bba0SGirish Moodalbail static size_t
i_ipadm_intfid_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)2336e91bba0SGirish Moodalbail i_ipadm_intfid_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2346e91bba0SGirish Moodalbail {
2356e91bba0SGirish Moodalbail 	char		addrbuf[IPADM_STRSIZE];
2366e91bba0SGirish Moodalbail 	nvlist_t	*v;
2376e91bba0SGirish Moodalbail 	uint32_t	prefixlen;
2386e91bba0SGirish Moodalbail 	struct in6_addr	in6addr;
2396e91bba0SGirish Moodalbail 	char		*stateless;
2406e91bba0SGirish Moodalbail 	char		*stateful;
2416e91bba0SGirish Moodalbail 
2426e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2436e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_INTFID) == 0);
2446e91bba0SGirish Moodalbail 
2456e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_INTFID);
2466e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
2476e91bba0SGirish Moodalbail 		goto fail;
2486e91bba0SGirish Moodalbail 	if (i_ipadm_nvl2in6_addr(v, IPADM_NVP_IPNUMADDR, &in6addr) !=
2496e91bba0SGirish Moodalbail 	    IPADM_SUCCESS)
2506e91bba0SGirish Moodalbail 		goto fail;
2516e91bba0SGirish Moodalbail 	(void) inet_ntop(AF_INET6, &in6addr, addrbuf,
2526e91bba0SGirish Moodalbail 	    sizeof (addrbuf));
2536e91bba0SGirish Moodalbail 	(void) strlcat(buf, addrbuf, buflen);
2546e91bba0SGirish Moodalbail 	if (nvlist_lookup_uint32(v, IPADM_NVP_PREFIXLEN, &prefixlen) != 0 ||
2556e91bba0SGirish Moodalbail 	    nvlist_lookup_string(v, IPADM_NVP_STATELESS, &stateless) != 0 ||
2566e91bba0SGirish Moodalbail 	    nvlist_lookup_string(v, IPADM_NVP_STATEFUL, &stateful) != 0)
2576e91bba0SGirish Moodalbail 		goto fail;
2586e91bba0SGirish Moodalbail 	(void) snprintf(addrbuf, sizeof (addrbuf), "/%d,%s,%s",
2596e91bba0SGirish Moodalbail 	    prefixlen, stateless, stateful);
2606e91bba0SGirish Moodalbail 	return (strlcat(buf, addrbuf, buflen));
2616e91bba0SGirish Moodalbail fail:
2626e91bba0SGirish Moodalbail 	buf[0] = '\0';
2636e91bba0SGirish Moodalbail 	return (0);
2646e91bba0SGirish Moodalbail }
2656e91bba0SGirish Moodalbail 
2666e91bba0SGirish Moodalbail /*
2676e91bba0SGirish Moodalbail  * Converts IPADM_NVP_DHCP nvpair to a string representation for writing to the
2686e91bba0SGirish Moodalbail  * DB. The converted string format:
2696e91bba0SGirish Moodalbail  *	IPADM_NVP_DHCP=<wait_time>,{yes|no}
2706e91bba0SGirish Moodalbail  */
2716e91bba0SGirish Moodalbail static size_t
i_ipadm_dhcp_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)2726e91bba0SGirish Moodalbail i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2736e91bba0SGirish Moodalbail {
2746e91bba0SGirish Moodalbail 	char		addrbuf[IPADM_STRSIZE];
2756e91bba0SGirish Moodalbail 	int32_t		wait;
2766e91bba0SGirish Moodalbail 	boolean_t	primary;
2776e91bba0SGirish Moodalbail 	nvlist_t	*v;
2786e91bba0SGirish Moodalbail 
2796e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2806e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_DHCP) == 0);
2816e91bba0SGirish Moodalbail 
2826e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0 ||
2836e91bba0SGirish Moodalbail 	    nvlist_lookup_int32(v, IPADM_NVP_WAIT, &wait) != 0 ||
2846e91bba0SGirish Moodalbail 	    nvlist_lookup_boolean_value(v, IPADM_NVP_PRIMARY, &primary) != 0) {
2856e91bba0SGirish Moodalbail 		return (0);
2866e91bba0SGirish Moodalbail 	}
2876e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_DHCP);
2886e91bba0SGirish Moodalbail 	(void) snprintf(addrbuf, sizeof (addrbuf), "%d,%s", wait,
2896e91bba0SGirish Moodalbail 	    (primary ? "yes" : "no"));
2906e91bba0SGirish Moodalbail 	return (strlcat(buf, addrbuf, buflen));
2916e91bba0SGirish Moodalbail }
2926e91bba0SGirish Moodalbail 
2936e91bba0SGirish Moodalbail /*
2946e91bba0SGirish Moodalbail  * Constructs a "<name>=<value>" string from the nvpair, whose type must
2956e91bba0SGirish Moodalbail  * be STRING.
2966e91bba0SGirish Moodalbail  */
2976e91bba0SGirish Moodalbail static size_t
i_ipadm_str_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)2986e91bba0SGirish Moodalbail i_ipadm_str_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2996e91bba0SGirish Moodalbail {
3006e91bba0SGirish Moodalbail 	char	*str = NULL;
3016e91bba0SGirish Moodalbail 
3026e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
3036e91bba0SGirish Moodalbail 	if (nvpair_value_string(nvp, &str) != 0)
3046e91bba0SGirish Moodalbail 		return (0);
3056e91bba0SGirish Moodalbail 	return (snprintf(buf, buflen, "%s=%s", nvpair_name(nvp), str));
3066e91bba0SGirish Moodalbail }
3076e91bba0SGirish Moodalbail 
3086e91bba0SGirish Moodalbail /*
3096e91bba0SGirish Moodalbail  * Converts a nvlist to string of the form:
3106e91bba0SGirish Moodalbail  *  <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
3116e91bba0SGirish Moodalbail  */
3126e91bba0SGirish Moodalbail size_t
ipadm_nvlist2str(nvlist_t * nvl,char * buf,size_t buflen)3136e91bba0SGirish Moodalbail ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
3146e91bba0SGirish Moodalbail {
3156e91bba0SGirish Moodalbail 	nvpair_t	*nvp = NULL;
3166e91bba0SGirish Moodalbail 	uint_t		nbytes = 0, tbytes = 0;
3176e91bba0SGirish Moodalbail 	ipadm_conf_ent_t *ipent;
3186e91bba0SGirish Moodalbail 	size_t		bufsize = buflen;
3196e91bba0SGirish Moodalbail 
3206e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
3216e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
3226e91bba0SGirish Moodalbail 		ipent = i_ipadm_find_conf_type(nvpair_name(nvp));
3236e91bba0SGirish Moodalbail 		nbytes = (*ipent->ipent_wfunc)(nvp, buf, buflen);
3246e91bba0SGirish Moodalbail 		/* add nvpair separator */
3256e91bba0SGirish Moodalbail 		nbytes += snprintf(buf + nbytes, buflen - nbytes, "%s",
3266e91bba0SGirish Moodalbail 		    IPADM_NVPAIR_SEP);
3276e91bba0SGirish Moodalbail 		buflen -= nbytes;
3286e91bba0SGirish Moodalbail 		buf += nbytes;
3296e91bba0SGirish Moodalbail 		tbytes += nbytes;
3306e91bba0SGirish Moodalbail 		if (tbytes >= bufsize)	/* buffer overflow */
3316e91bba0SGirish Moodalbail 			return (0);
3326e91bba0SGirish Moodalbail 	}
3336e91bba0SGirish Moodalbail 	nbytes = snprintf(buf, buflen, "%c%c", '\n', '\0');
3346e91bba0SGirish Moodalbail 	tbytes += nbytes;
3356e91bba0SGirish Moodalbail 	if (tbytes >= bufsize)
3366e91bba0SGirish Moodalbail 		return (0);
3376e91bba0SGirish Moodalbail 	return (tbytes);
3386e91bba0SGirish Moodalbail }
3396e91bba0SGirish Moodalbail 
3406e91bba0SGirish Moodalbail /*
3416e91bba0SGirish Moodalbail  * Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
3426e91bba0SGirish Moodalbail  * The value will be interpreted as explained at the top of this file.
3436e91bba0SGirish Moodalbail  */
344*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_add_nvpair(nvlist_t * nvl,char * name,char * value)3456e91bba0SGirish Moodalbail i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
3466e91bba0SGirish Moodalbail {
3476e91bba0SGirish Moodalbail 	ipadm_conf_ent_t	*ipent;
3486e91bba0SGirish Moodalbail 
3496e91bba0SGirish Moodalbail 	ipent = i_ipadm_find_conf_type(name);
350*a73be61aSHans Rosenfeld 	return ((*ipent->ipent_rfunc)(nvl, name, value));
3516e91bba0SGirish Moodalbail }
3526e91bba0SGirish Moodalbail 
3536e91bba0SGirish Moodalbail /*
3546e91bba0SGirish Moodalbail  * Adds an nvpair for IPv4 addr to the nvlist. The "name" is the string in
3556e91bba0SGirish Moodalbail  * IPADM_NVP_IPV4ADDR. The "value" for IPADM_NVP_IPV4ADDR is another nvlist.
3566e91bba0SGirish Moodalbail  * Allocate the value nvlist for IPADM_NVP_IPV4ADDR if necessary, and add
3576e91bba0SGirish Moodalbail  * the address and hostnames from the address object `ipaddr' to it.
3586e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
3596e91bba0SGirish Moodalbail  */
3606e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_add_ipaddr2nvl(nvlist_t * nvl,ipadm_addrobj_t ipaddr)3616e91bba0SGirish Moodalbail i_ipadm_add_ipaddr2nvl(nvlist_t *nvl, ipadm_addrobj_t ipaddr)
3626e91bba0SGirish Moodalbail {
3636e91bba0SGirish Moodalbail 	nvlist_t		*nvl_addr = NULL;
3646e91bba0SGirish Moodalbail 	int			err;
3656e91bba0SGirish Moodalbail 	char			*name;
3666e91bba0SGirish Moodalbail 	sa_family_t		af = ipaddr->ipadm_af;
3676e91bba0SGirish Moodalbail 
3686e91bba0SGirish Moodalbail 	if (af == AF_INET) {
3696e91bba0SGirish Moodalbail 		name = IPADM_NVP_IPV4ADDR;
3706e91bba0SGirish Moodalbail 	} else {
3716e91bba0SGirish Moodalbail 		assert(af == AF_INET6);
3726e91bba0SGirish Moodalbail 		name = IPADM_NVP_IPV6ADDR;
3736e91bba0SGirish Moodalbail 	}
3746e91bba0SGirish Moodalbail 
3756e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, name)) {
3766e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
3776e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3786e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, name, nvl_addr)) != 0) {
3796e91bba0SGirish Moodalbail 			nvlist_free(nvl_addr);
3806e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3816e91bba0SGirish Moodalbail 		}
3826e91bba0SGirish Moodalbail 		nvlist_free(nvl_addr);
3836e91bba0SGirish Moodalbail 	}
3846e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, name, &nvl_addr)) != 0 ||
3856e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl_addr, IPADM_NVP_IPADDRHNAME,
3866e91bba0SGirish Moodalbail 	    ipaddr->ipadm_static_aname)) != 0)
3876e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
388ec3706caSVasumathi Sundaram 	if (ipaddr->ipadm_static_dname[0] != '\0') {
3896e91bba0SGirish Moodalbail 		if ((err = nvlist_add_string(nvl_addr, IPADM_NVP_IPDADDRHNAME,
3906e91bba0SGirish Moodalbail 		    ipaddr->ipadm_static_dname)) != 0)
3916e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3926e91bba0SGirish Moodalbail 	}
3936e91bba0SGirish Moodalbail 
3946e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
3956e91bba0SGirish Moodalbail }
3966e91bba0SGirish Moodalbail 
3976e91bba0SGirish Moodalbail /*
3986e91bba0SGirish Moodalbail  * Adds an nvpair for IPv6 interface id to the nvlist. The "name" is
3996e91bba0SGirish Moodalbail  * the string in IPADM_NVP_INTFID. The "value" for IPADM_NVP_INTFID is another
4006e91bba0SGirish Moodalbail  * nvlist. Allocate the value nvlist for IPADM_NVP_INTFID if necessary, and add
4016e91bba0SGirish Moodalbail  * the interface id and its prefixlen from the address object `ipaddr' to it.
4026e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
4036e91bba0SGirish Moodalbail  */
4046e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_add_intfid2nvl(nvlist_t * nvl,ipadm_addrobj_t addr)4056e91bba0SGirish Moodalbail i_ipadm_add_intfid2nvl(nvlist_t *nvl, ipadm_addrobj_t addr)
4066e91bba0SGirish Moodalbail {
4076e91bba0SGirish Moodalbail 	nvlist_t	*nvl_addr = NULL;
4086e91bba0SGirish Moodalbail 	struct in6_addr	addr6;
4096e91bba0SGirish Moodalbail 	int		err;
4106e91bba0SGirish Moodalbail 
4116e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, IPADM_NVP_INTFID)) {
4126e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
4136e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4146e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_INTFID,
4156e91bba0SGirish Moodalbail 		    nvl_addr)) != 0) {
4166e91bba0SGirish Moodalbail 			nvlist_free(nvl_addr);
4176e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4186e91bba0SGirish Moodalbail 		}
4196e91bba0SGirish Moodalbail 		nvlist_free(nvl_addr);
4206e91bba0SGirish Moodalbail 	}
4216e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID,
4226e91bba0SGirish Moodalbail 	    &nvl_addr)) != 0 || (err = nvlist_add_uint32(nvl_addr,
4236e91bba0SGirish Moodalbail 	    IPADM_NVP_PREFIXLEN, addr->ipadm_intfidlen)) != 0) {
4246e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4256e91bba0SGirish Moodalbail 	}
4266e91bba0SGirish Moodalbail 	addr6 = addr->ipadm_intfid.sin6_addr;
4276e91bba0SGirish Moodalbail 	if ((err = nvlist_add_uint8_array(nvl_addr, IPADM_NVP_IPNUMADDR,
4286e91bba0SGirish Moodalbail 	    addr6.s6_addr, 16)) != 0) {
4296e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4306e91bba0SGirish Moodalbail 	}
4316e91bba0SGirish Moodalbail 	if (addr->ipadm_stateless)
4326e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "yes");
4336e91bba0SGirish Moodalbail 	else
4346e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "no");
4356e91bba0SGirish Moodalbail 	if (err != 0)
4366e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4376e91bba0SGirish Moodalbail 	if (addr->ipadm_stateful)
4386e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "yes");
4396e91bba0SGirish Moodalbail 	else
4406e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "no");
4416e91bba0SGirish Moodalbail 	if (err != 0)
4426e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4436e91bba0SGirish Moodalbail 
4446e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
4456e91bba0SGirish Moodalbail }
4466e91bba0SGirish Moodalbail 
4476e91bba0SGirish Moodalbail /*
4486e91bba0SGirish Moodalbail  * Adds an nvpair for a dhcp address object to the nvlist. The "name" is
4496e91bba0SGirish Moodalbail  * the string in IPADM_NVP_DHCP. The "value" for IPADM_NVP_DHCP is another
4506e91bba0SGirish Moodalbail  * nvlist. Allocate the value nvlist for IPADM_NVP_DHCP if necessary, and add
4516e91bba0SGirish Moodalbail  * the parameters from the arguments `primary' and `wait'.
4526e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
4536e91bba0SGirish Moodalbail  */
4546e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_add_dhcp2nvl(nvlist_t * nvl,boolean_t primary,int32_t wait)4556e91bba0SGirish Moodalbail i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
4566e91bba0SGirish Moodalbail {
4576e91bba0SGirish Moodalbail 	nvlist_t	*nvl_dhcp = NULL;
4586e91bba0SGirish Moodalbail 	int		err;
4596e91bba0SGirish Moodalbail 
4606e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, IPADM_NVP_DHCP)) {
4616e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_dhcp, NV_UNIQUE_NAME, 0)) != 0)
4626e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4636e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_DHCP,
4646e91bba0SGirish Moodalbail 		    nvl_dhcp)) != 0) {
4656e91bba0SGirish Moodalbail 			nvlist_free(nvl_dhcp);
4666e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4676e91bba0SGirish Moodalbail 		}
4686e91bba0SGirish Moodalbail 		nvlist_free(nvl_dhcp);
4696e91bba0SGirish Moodalbail 	}
4706e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvl_dhcp)) != 0 ||
4716e91bba0SGirish Moodalbail 	    (err = nvlist_add_int32(nvl_dhcp, IPADM_NVP_WAIT, wait)) != 0 ||
4726e91bba0SGirish Moodalbail 	    (err = nvlist_add_boolean_value(nvl_dhcp, IPADM_NVP_PRIMARY,
4736e91bba0SGirish Moodalbail 	    primary)) != 0) {
4746e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4756e91bba0SGirish Moodalbail 	}
4766e91bba0SGirish Moodalbail 
4776e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
4786e91bba0SGirish Moodalbail }
4796e91bba0SGirish Moodalbail 
4806e91bba0SGirish Moodalbail /*
4816e91bba0SGirish Moodalbail  * Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
4826e91bba0SGirish Moodalbail  */
483*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_str_dbline2nvl(nvlist_t * nvl,char * name,char * value)4846e91bba0SGirish Moodalbail i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
4856e91bba0SGirish Moodalbail {
486*a73be61aSHans Rosenfeld 	int err;
487*a73be61aSHans Rosenfeld 
4886e91bba0SGirish Moodalbail 	/* if value is NULL create an empty node */
4896e91bba0SGirish Moodalbail 	if (value == NULL)
490*a73be61aSHans Rosenfeld 		err = nvlist_add_string(nvl, name, "");
4916e91bba0SGirish Moodalbail 	else
492*a73be61aSHans Rosenfeld 		err = nvlist_add_string(nvl, name, value);
493*a73be61aSHans Rosenfeld 
494*a73be61aSHans Rosenfeld 	return (ipadm_errno2status(err));
4956e91bba0SGirish Moodalbail }
4966e91bba0SGirish Moodalbail 
4976e91bba0SGirish Moodalbail /*
4986e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_IPV4ADDR and
4996e91bba0SGirish Moodalbail  * `value' = <local numeric IP string or hostname,remote numeric IP string or
5006e91bba0SGirish Moodalbail  *     hostname>
5016e91bba0SGirish Moodalbail  * This function will add an nvlist with the hostname information in
5026e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5036e91bba0SGirish Moodalbail  */
504*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_ip4_dbline2nvl(nvlist_t * nvl,char * name,char * value)5056e91bba0SGirish Moodalbail i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
5066e91bba0SGirish Moodalbail {
5076e91bba0SGirish Moodalbail 	char			*cp, *hname;
5086e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
5096e91bba0SGirish Moodalbail 
5106e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_IPV4ADDR) == 0 && value != NULL);
5116e91bba0SGirish Moodalbail 
5126e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
5136e91bba0SGirish Moodalbail 	ipaddr.ipadm_af = AF_INET;
5146e91bba0SGirish Moodalbail 
5156e91bba0SGirish Moodalbail 	hname = value; /* local hostname */
5166e91bba0SGirish Moodalbail 	cp = strchr(hname, ',');
5176e91bba0SGirish Moodalbail 	assert(cp != NULL);
5186e91bba0SGirish Moodalbail 	*cp++ = '\0';
5196e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
5206e91bba0SGirish Moodalbail 	    sizeof (ipaddr.ipadm_static_aname));
5216e91bba0SGirish Moodalbail 
5226e91bba0SGirish Moodalbail 	if (*cp != '\0') {
5236e91bba0SGirish Moodalbail 		/* we have a dst hostname */
5246e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
5256e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_static_dname));
5266e91bba0SGirish Moodalbail 	}
527*a73be61aSHans Rosenfeld 	return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
5286e91bba0SGirish Moodalbail }
5296e91bba0SGirish Moodalbail 
5306e91bba0SGirish Moodalbail /*
5316e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_IPV6ADDR and
5326e91bba0SGirish Moodalbail  * `value' = <local numeric IP string or hostname,remote numeric IP string or
5336e91bba0SGirish Moodalbail  *     hostname>
5346e91bba0SGirish Moodalbail  * This function will add an nvlist with the hostname information in
5356e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5366e91bba0SGirish Moodalbail  */
537*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_ip6_dbline2nvl(nvlist_t * nvl,char * name,char * value)5386e91bba0SGirish Moodalbail i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
5396e91bba0SGirish Moodalbail {
5406e91bba0SGirish Moodalbail 	char			*cp, *hname;
5416e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
5426e91bba0SGirish Moodalbail 
5436e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_IPV6ADDR) == 0 && value != NULL);
5446e91bba0SGirish Moodalbail 
5456e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
5466e91bba0SGirish Moodalbail 	ipaddr.ipadm_af = AF_INET6;
5476e91bba0SGirish Moodalbail 
5486e91bba0SGirish Moodalbail 	hname = value; /* local hostname */
5496e91bba0SGirish Moodalbail 	cp = strchr(hname, ',');
5506e91bba0SGirish Moodalbail 	assert(cp != NULL);
5516e91bba0SGirish Moodalbail 	*cp++ = '\0';
5526e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
5536e91bba0SGirish Moodalbail 	    sizeof (ipaddr.ipadm_static_aname));
5546e91bba0SGirish Moodalbail 
5556e91bba0SGirish Moodalbail 	if (*cp != '\0') {
5566e91bba0SGirish Moodalbail 		/* we have a dst hostname */
5576e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
5586e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_static_dname));
5596e91bba0SGirish Moodalbail 	}
560*a73be61aSHans Rosenfeld 	return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
5616e91bba0SGirish Moodalbail }
5626e91bba0SGirish Moodalbail 
5636e91bba0SGirish Moodalbail /*
5646e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_INTFID and `value' = <intfid/prefixlen>,{yes,no},{yes|no}
5656e91bba0SGirish Moodalbail  * This function will add an nvlist with the address object information in
5666e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5676e91bba0SGirish Moodalbail  */
568*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_intfid_dbline2nvl(nvlist_t * nvl,char * name,char * value)5696e91bba0SGirish Moodalbail i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
5706e91bba0SGirish Moodalbail {
5716e91bba0SGirish Moodalbail 	char			*cp;
5726e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
5736e91bba0SGirish Moodalbail 	char			*endp;
5746e91bba0SGirish Moodalbail 	char			*prefixlen;
5756e91bba0SGirish Moodalbail 	char			*stateless;
5766e91bba0SGirish Moodalbail 	char			*stateful;
5776e91bba0SGirish Moodalbail 
5786e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_INTFID) == 0 && value != NULL);
5796e91bba0SGirish Moodalbail 
5806e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
5816e91bba0SGirish Moodalbail 
5826e91bba0SGirish Moodalbail 	cp = strchr(value, '/');
5836e91bba0SGirish Moodalbail 	assert(cp != NULL);
5846e91bba0SGirish Moodalbail 
5856e91bba0SGirish Moodalbail 	*cp++ = '\0';
5866e91bba0SGirish Moodalbail 	ipaddr.ipadm_intfid.sin6_family = AF_INET6;
5876e91bba0SGirish Moodalbail 	(void) inet_pton(AF_INET6, value, &ipaddr.ipadm_intfid.sin6_addr);
5886e91bba0SGirish Moodalbail 
5896e91bba0SGirish Moodalbail 	prefixlen = cp;
5906e91bba0SGirish Moodalbail 	cp = strchr(cp, ',');
5916e91bba0SGirish Moodalbail 	assert(cp != NULL);
5926e91bba0SGirish Moodalbail 	*cp++ = '\0';
5936e91bba0SGirish Moodalbail 
5946e91bba0SGirish Moodalbail 	errno = 0;
5956e91bba0SGirish Moodalbail 	ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
5966e91bba0SGirish Moodalbail 	if (*endp != '\0' || errno != 0)
597*a73be61aSHans Rosenfeld 		return (ipadm_errno2status(errno));
5986e91bba0SGirish Moodalbail 
5996e91bba0SGirish Moodalbail 	stateless = cp;
6006e91bba0SGirish Moodalbail 	stateful = strchr(stateless, ',');
6016e91bba0SGirish Moodalbail 	assert(stateful != NULL);
6026e91bba0SGirish Moodalbail 	*stateful++ = '\0';
6036e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
6046e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
6056e91bba0SGirish Moodalbail 
6066e91bba0SGirish Moodalbail 	/* Add all of it to the given nvlist */
607*a73be61aSHans Rosenfeld 	return (i_ipadm_add_intfid2nvl(nvl, &ipaddr));
6086e91bba0SGirish Moodalbail }
6096e91bba0SGirish Moodalbail 
6106e91bba0SGirish Moodalbail /*
6116e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_DHCP and `value' = <wait_time>,{yes|no}
6126e91bba0SGirish Moodalbail  * This function will add an nvlist with the dhcp address object information in
6136e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
6146e91bba0SGirish Moodalbail  */
615*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_dhcp_dbline2nvl(nvlist_t * nvl,char * name,char * value)6166e91bba0SGirish Moodalbail i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
6176e91bba0SGirish Moodalbail {
6186e91bba0SGirish Moodalbail 	char		*cp;
6196e91bba0SGirish Moodalbail 	char		*endp;
6206e91bba0SGirish Moodalbail 	long		wait_time;
6216e91bba0SGirish Moodalbail 	boolean_t	primary;
6226e91bba0SGirish Moodalbail 
6236e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
6246e91bba0SGirish Moodalbail 	cp = strchr(value, ',');
6256e91bba0SGirish Moodalbail 	assert(cp != NULL);
6266e91bba0SGirish Moodalbail 	*cp++ = '\0';
6276e91bba0SGirish Moodalbail 	errno = 0;
6286e91bba0SGirish Moodalbail 	wait_time = strtol(value, &endp, 10);
6296e91bba0SGirish Moodalbail 	if (*endp != '\0' || errno != 0)
630*a73be61aSHans Rosenfeld 		return (ipadm_errno2status(errno));
6316e91bba0SGirish Moodalbail 	primary = (strcmp(cp, "yes") == 0);
632*a73be61aSHans Rosenfeld 	return (i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time));
633*a73be61aSHans Rosenfeld }
634*a73be61aSHans Rosenfeld 
635*a73be61aSHans Rosenfeld /*
636*a73be61aSHans Rosenfeld  * Input 'nvp': name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
637*a73be61aSHans Rosenfeld  *
638*a73be61aSHans Rosenfeld  *
639*a73be61aSHans Rosenfeld  */
640*a73be61aSHans Rosenfeld static size_t
i_ipadm_families_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)641*a73be61aSHans Rosenfeld i_ipadm_families_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
642*a73be61aSHans Rosenfeld {
643*a73be61aSHans Rosenfeld 	uint_t nelem = 0;
644*a73be61aSHans Rosenfeld 	uint16_t *elem;
645*a73be61aSHans Rosenfeld 
646*a73be61aSHans Rosenfeld 	assert(nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY);
647*a73be61aSHans Rosenfeld 
648*a73be61aSHans Rosenfeld 	if (nvpair_value_uint16_array(nvp,
649*a73be61aSHans Rosenfeld 	    &elem, &nelem) != 0) {
650*a73be61aSHans Rosenfeld 		buf[0] = '\0';
651*a73be61aSHans Rosenfeld 		return (0);
652*a73be61aSHans Rosenfeld 	}
653*a73be61aSHans Rosenfeld 
654*a73be61aSHans Rosenfeld 	assert(nelem != 0 || nelem > 2);
655*a73be61aSHans Rosenfeld 
656*a73be61aSHans Rosenfeld 	if (nelem == 1) {
657*a73be61aSHans Rosenfeld 		return (snprintf(buf, buflen, "%s=%d",
658*a73be61aSHans Rosenfeld 		    nvpair_name(nvp), elem[0]));
659*a73be61aSHans Rosenfeld 	} else {
660*a73be61aSHans Rosenfeld 		return (snprintf(buf, buflen, "%s=%d,%d",
661*a73be61aSHans Rosenfeld 		    nvpair_name(nvp), elem[0], elem[1]));
662*a73be61aSHans Rosenfeld 	}
663*a73be61aSHans Rosenfeld }
664*a73be61aSHans Rosenfeld 
665*a73be61aSHans Rosenfeld /*
666*a73be61aSHans Rosenfeld  * name = IPADM_NVP_FAMILIES and value = <FAMILY>[,FAMILY]
667*a73be61aSHans Rosenfeld  *
668*a73be61aSHans Rosenfeld  * output nvp: name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
669*a73be61aSHans Rosenfeld  *
670*a73be61aSHans Rosenfeld  */
671*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_families_dbline2nvl(nvlist_t * nvl,char * name,char * value)672*a73be61aSHans Rosenfeld i_ipadm_families_dbline2nvl(nvlist_t *nvl, char *name, char *value)
673*a73be61aSHans Rosenfeld {
674*a73be61aSHans Rosenfeld 	uint16_t	families[2];
675*a73be61aSHans Rosenfeld 	uint_t	nelem = 0;
676*a73be61aSHans Rosenfeld 	char	*val, *lasts;
677*a73be61aSHans Rosenfeld 
678*a73be61aSHans Rosenfeld 	if ((val = strtok_r(value,
679*a73be61aSHans Rosenfeld 	    ",", &lasts)) != NULL) {
680*a73be61aSHans Rosenfeld 		families[0] = atoi(val);
681*a73be61aSHans Rosenfeld 		nelem++;
682*a73be61aSHans Rosenfeld 		if ((val = strtok_r(NULL,
683*a73be61aSHans Rosenfeld 		    ",", &lasts)) != NULL) {
684*a73be61aSHans Rosenfeld 			families[1] = atoi(val);
685*a73be61aSHans Rosenfeld 			nelem++;
686*a73be61aSHans Rosenfeld 		}
687*a73be61aSHans Rosenfeld 		return (ipadm_errno2status(nvlist_add_uint16_array(nvl,
688*a73be61aSHans Rosenfeld 		    IPADM_NVP_FAMILIES, families, nelem)));
689*a73be61aSHans Rosenfeld 	}
690*a73be61aSHans Rosenfeld 
691*a73be61aSHans Rosenfeld 	return (IPADM_INVALID_ARG);
692*a73be61aSHans Rosenfeld }
693*a73be61aSHans Rosenfeld 
694*a73be61aSHans Rosenfeld /*
695*a73be61aSHans Rosenfeld  * input nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
696*a73be61aSHans Rosenfeld  *
697*a73be61aSHans Rosenfeld  *
698*a73be61aSHans Rosenfeld  */
699*a73be61aSHans Rosenfeld static size_t
i_ipadm_groupmembers_nvp2dbline(nvpair_t * nvp,char * buf,size_t buflen)700*a73be61aSHans Rosenfeld i_ipadm_groupmembers_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
701*a73be61aSHans Rosenfeld {
702*a73be61aSHans Rosenfeld 	uint_t nelem = 0;
703*a73be61aSHans Rosenfeld 	char **elem;
704*a73be61aSHans Rosenfeld 	size_t n;
705*a73be61aSHans Rosenfeld 
706*a73be61aSHans Rosenfeld 	assert(nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY);
707*a73be61aSHans Rosenfeld 
708*a73be61aSHans Rosenfeld 	if (nvpair_value_string_array(nvp,
709*a73be61aSHans Rosenfeld 	    &elem, &nelem) != 0) {
710*a73be61aSHans Rosenfeld 		buf[0] = '\0';
711*a73be61aSHans Rosenfeld 		return (0);
712*a73be61aSHans Rosenfeld 	}
713*a73be61aSHans Rosenfeld 
714*a73be61aSHans Rosenfeld 	assert(nelem != 0);
715*a73be61aSHans Rosenfeld 
716*a73be61aSHans Rosenfeld 	n = snprintf(buf, buflen, "%s=", IPADM_NVP_MIFNAMES);
717*a73be61aSHans Rosenfeld 	if (n >= buflen)
718*a73be61aSHans Rosenfeld 		return (n);
719*a73be61aSHans Rosenfeld 
720*a73be61aSHans Rosenfeld 	while (nelem-- > 0) {
721*a73be61aSHans Rosenfeld 		n = strlcat(buf, elem[nelem], buflen);
722*a73be61aSHans Rosenfeld 		if (nelem > 0)
723*a73be61aSHans Rosenfeld 			n = strlcat(buf, ",", buflen);
724*a73be61aSHans Rosenfeld 
725*a73be61aSHans Rosenfeld 		if (n > buflen)
726*a73be61aSHans Rosenfeld 			return (n);
727*a73be61aSHans Rosenfeld 	}
728*a73be61aSHans Rosenfeld 
729*a73be61aSHans Rosenfeld 	return (n);
730*a73be61aSHans Rosenfeld }
731*a73be61aSHans Rosenfeld 
732*a73be61aSHans Rosenfeld /*
733*a73be61aSHans Rosenfeld  * name = IPADM_NVP_MIFNAMES and value = <if_name>[,if_name]
734*a73be61aSHans Rosenfeld  *
735*a73be61aSHans Rosenfeld  * output nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
736*a73be61aSHans Rosenfeld  */
737*a73be61aSHans Rosenfeld static ipadm_status_t
i_ipadm_groupmembers_dbline2nvl(nvlist_t * nvl,char * name,char * value)738*a73be61aSHans Rosenfeld i_ipadm_groupmembers_dbline2nvl(nvlist_t *nvl, char *name, char *value)
739*a73be61aSHans Rosenfeld {
740*a73be61aSHans Rosenfeld 	char	**members = NULL;
741*a73be61aSHans Rosenfeld 	char	*member = NULL;
742*a73be61aSHans Rosenfeld 	char	*val, *lasts;
743*a73be61aSHans Rosenfeld 	uint_t	m_cnt = 0;
744*a73be61aSHans Rosenfeld 	ipadm_status_t	ret = IPADM_SUCCESS;
745*a73be61aSHans Rosenfeld 
746*a73be61aSHans Rosenfeld 	assert(strcmp(name, IPADM_NVP_MIFNAMES) == 0 && value != NULL);
747*a73be61aSHans Rosenfeld 
748*a73be61aSHans Rosenfeld 	for (val = strtok_r(value, ",", &lasts);
749*a73be61aSHans Rosenfeld 	    val != NULL;
750*a73be61aSHans Rosenfeld 	    val = strtok_r(NULL, ",", &lasts)) {
751*a73be61aSHans Rosenfeld 		if ((m_cnt % 4) == 0) {
752*a73be61aSHans Rosenfeld 			char **tmp = recallocarray(members, m_cnt, m_cnt + 4,
753*a73be61aSHans Rosenfeld 			    sizeof (char *));
754*a73be61aSHans Rosenfeld 
755*a73be61aSHans Rosenfeld 			if (tmp == NULL) {
756*a73be61aSHans Rosenfeld 				ret = IPADM_NO_MEMORY;
757*a73be61aSHans Rosenfeld 				goto fail;
758*a73be61aSHans Rosenfeld 			}
759*a73be61aSHans Rosenfeld 
760*a73be61aSHans Rosenfeld 			members = tmp;
761*a73be61aSHans Rosenfeld 		}
762*a73be61aSHans Rosenfeld 
763*a73be61aSHans Rosenfeld 		member = calloc(1, LIFNAMSIZ);
764*a73be61aSHans Rosenfeld 
765*a73be61aSHans Rosenfeld 		if (member == NULL) {
766*a73be61aSHans Rosenfeld 			ret = IPADM_NO_MEMORY;
767*a73be61aSHans Rosenfeld 			goto fail;
768*a73be61aSHans Rosenfeld 		}
769*a73be61aSHans Rosenfeld 
770*a73be61aSHans Rosenfeld 		(void) strlcpy(member, val, LIFNAMSIZ);
771*a73be61aSHans Rosenfeld 		members[m_cnt++] = member;
772*a73be61aSHans Rosenfeld 
773*a73be61aSHans Rosenfeld 	}
774*a73be61aSHans Rosenfeld 
775*a73be61aSHans Rosenfeld 	if ((ret = ipadm_errno2status(nvlist_add_string_array(nvl,
776*a73be61aSHans Rosenfeld 	    IPADM_NVP_MIFNAMES, members, m_cnt))) != IPADM_SUCCESS)
777*a73be61aSHans Rosenfeld 		goto fail;
778*a73be61aSHans Rosenfeld 
779*a73be61aSHans Rosenfeld fail:
780*a73be61aSHans Rosenfeld 	while (m_cnt-- > 0) {
781*a73be61aSHans Rosenfeld 		free(members[m_cnt]);
782*a73be61aSHans Rosenfeld 	}
783*a73be61aSHans Rosenfeld 
784*a73be61aSHans Rosenfeld 	free(members);
785*a73be61aSHans Rosenfeld 
786*a73be61aSHans Rosenfeld 	return (ret);
7876e91bba0SGirish Moodalbail }
7886e91bba0SGirish Moodalbail 
7896e91bba0SGirish Moodalbail /*
7906e91bba0SGirish Moodalbail  * Parses the buffer, for name-value pairs and creates nvlist. The value
7916e91bba0SGirish Moodalbail  * is always considered to be a string.
7926e91bba0SGirish Moodalbail  */
793*a73be61aSHans Rosenfeld ipadm_status_t
ipadm_str2nvlist(const char * inbuf,nvlist_t ** ipnvl,uint_t flags)7946e91bba0SGirish Moodalbail ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
7956e91bba0SGirish Moodalbail {
796*a73be61aSHans Rosenfeld 	ipadm_status_t	status;
7976e91bba0SGirish Moodalbail 	char	*nv, *name, *val, *buf, *cp, *sep;
7986e91bba0SGirish Moodalbail 	int	err;
7996e91bba0SGirish Moodalbail 
8006e91bba0SGirish Moodalbail 	if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
801*a73be61aSHans Rosenfeld 		return (IPADM_INVALID_ARG);
8026e91bba0SGirish Moodalbail 	*ipnvl = NULL;
8036e91bba0SGirish Moodalbail 
8046e91bba0SGirish Moodalbail 	/*
8056e91bba0SGirish Moodalbail 	 * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
8066e91bba0SGirish Moodalbail 	 */
8076e91bba0SGirish Moodalbail 	if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
808*a73be61aSHans Rosenfeld 		return (IPADM_INVALID_ARG);
8096e91bba0SGirish Moodalbail 
8106e91bba0SGirish Moodalbail 	if ((cp = buf = strdup(inbuf)) == NULL)
811*a73be61aSHans Rosenfeld 		return (ipadm_errno2status(errno));
8126e91bba0SGirish Moodalbail 
8136e91bba0SGirish Moodalbail 	while (isspace(*buf))
8146e91bba0SGirish Moodalbail 		buf++;
8156e91bba0SGirish Moodalbail 
8166e91bba0SGirish Moodalbail 	if (*buf == '\0') {
817*a73be61aSHans Rosenfeld 		status = IPADM_INVALID_ARG;
8186e91bba0SGirish Moodalbail 		goto fail;
8196e91bba0SGirish Moodalbail 	}
8206e91bba0SGirish Moodalbail 
8216e91bba0SGirish Moodalbail 	nv = buf;
8226e91bba0SGirish Moodalbail 	/*
8236e91bba0SGirish Moodalbail 	 * work on one nvpair at a time and extract the name and value
8246e91bba0SGirish Moodalbail 	 */
8256e91bba0SGirish Moodalbail 	sep = ((flags & IPADM_NORVAL) ? IPADM_NAME_SEP : IPADM_NVPAIR_SEP);
8266e91bba0SGirish Moodalbail 	while ((nv = strsep(&buf, sep)) != NULL) {
8276e91bba0SGirish Moodalbail 		if (*nv == '\n')
8286e91bba0SGirish Moodalbail 			continue;
8296e91bba0SGirish Moodalbail 		name = nv;
8306e91bba0SGirish Moodalbail 		if ((val = strchr(nv, '=')) != NULL)
8316e91bba0SGirish Moodalbail 			*val++ = '\0';
8326e91bba0SGirish Moodalbail 		if (*ipnvl == NULL &&
833*a73be61aSHans Rosenfeld 		    (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0) {
834*a73be61aSHans Rosenfeld 			status = ipadm_errno2status(err);
8356e91bba0SGirish Moodalbail 			goto fail;
836*a73be61aSHans Rosenfeld 		}
8376e91bba0SGirish Moodalbail 		if (nvlist_exists(*ipnvl, name)) {
838*a73be61aSHans Rosenfeld 			status = IPADM_EXISTS;
8396e91bba0SGirish Moodalbail 			goto fail;
8406e91bba0SGirish Moodalbail 		}
8416e91bba0SGirish Moodalbail 		/* Add the extracted nvpair to the nvlist `ipnvl'. */
842*a73be61aSHans Rosenfeld 		status = i_ipadm_add_nvpair(*ipnvl, name, val);
843*a73be61aSHans Rosenfeld 		if (status != IPADM_SUCCESS)
844*a73be61aSHans Rosenfeld 			goto fail;
8456e91bba0SGirish Moodalbail 	}
8466e91bba0SGirish Moodalbail 	free(cp);
847*a73be61aSHans Rosenfeld 	return (IPADM_SUCCESS);
8486e91bba0SGirish Moodalbail fail:
8496e91bba0SGirish Moodalbail 	free(cp);
8506e91bba0SGirish Moodalbail 	nvlist_free(*ipnvl);
8516e91bba0SGirish Moodalbail 	*ipnvl = NULL;
852*a73be61aSHans Rosenfeld 	return (status);
8536e91bba0SGirish Moodalbail }
8546e91bba0SGirish Moodalbail 
8556e91bba0SGirish Moodalbail /*
8566e91bba0SGirish Moodalbail  * Opens the data store for read/write operation. For write operation we open
8576e91bba0SGirish Moodalbail  * another file and scribble the changes to it and copy the new file back to
8586e91bba0SGirish Moodalbail  * old file.
8596e91bba0SGirish Moodalbail  */
8606e91bba0SGirish Moodalbail int
ipadm_rw_db(db_wfunc_t * db_walk_func,void * arg,const char * db_file,mode_t db_perms,ipadm_db_op_t db_op)8616e91bba0SGirish Moodalbail ipadm_rw_db(db_wfunc_t *db_walk_func, void *arg, const char *db_file,
8626e91bba0SGirish Moodalbail     mode_t db_perms, ipadm_db_op_t db_op)
8636e91bba0SGirish Moodalbail {
8646e91bba0SGirish Moodalbail 	FILE		*fp, *nfp = NULL;
8656e91bba0SGirish Moodalbail 	char		file[MAXPATHLEN];
8666e91bba0SGirish Moodalbail 	char		newfile[MAXPATHLEN];
8676e91bba0SGirish Moodalbail 	int		nfd;
8686e91bba0SGirish Moodalbail 	boolean_t	writeop;
8696e91bba0SGirish Moodalbail 	int		err = 0;
8706e91bba0SGirish Moodalbail 
8716e91bba0SGirish Moodalbail 	writeop = (db_op != IPADM_DB_READ);
8726e91bba0SGirish Moodalbail 
8736e91bba0SGirish Moodalbail 	(void) snprintf(file, MAXPATHLEN, "%s/%s", ipadm_rootdir, db_file);
8746e91bba0SGirish Moodalbail 
8756e91bba0SGirish Moodalbail 	/* open the data store */
8766e91bba0SGirish Moodalbail 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL)
8776e91bba0SGirish Moodalbail 		return (errno);
8786e91bba0SGirish Moodalbail 
8796e91bba0SGirish Moodalbail 	if (writeop) {
8806e91bba0SGirish Moodalbail 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
8816e91bba0SGirish Moodalbail 		    ipadm_rootdir, db_file);
8826e91bba0SGirish Moodalbail 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
8836e91bba0SGirish Moodalbail 		    db_perms)) < 0) {
8846e91bba0SGirish Moodalbail 			err = errno;
8856e91bba0SGirish Moodalbail 			(void) fclose(fp);
8866e91bba0SGirish Moodalbail 			return (err);
8876e91bba0SGirish Moodalbail 		}
8886e91bba0SGirish Moodalbail 
8896e91bba0SGirish Moodalbail 		if ((nfp = fdopen(nfd, "w")) == NULL) {
8906e91bba0SGirish Moodalbail 			err = errno;
8916e91bba0SGirish Moodalbail 			(void) close(nfd);
8926e91bba0SGirish Moodalbail 			(void) fclose(fp);
8936e91bba0SGirish Moodalbail 			(void) unlink(newfile);
8946e91bba0SGirish Moodalbail 			return (err);
8956e91bba0SGirish Moodalbail 		}
8966e91bba0SGirish Moodalbail 	}
8976e91bba0SGirish Moodalbail 	err = ipadm_process_db_line(db_walk_func, arg, fp, nfp, db_op);
8986e91bba0SGirish Moodalbail 	if (!writeop)
8996e91bba0SGirish Moodalbail 		goto done;
9006e91bba0SGirish Moodalbail 	if (err != 0 && err != ENOENT)
9016e91bba0SGirish Moodalbail 		goto done;
9026e91bba0SGirish Moodalbail 
9036e91bba0SGirish Moodalbail 	if (fflush(nfp) == EOF) {
9046e91bba0SGirish Moodalbail 		err = errno;
9056e91bba0SGirish Moodalbail 		goto done;
9066e91bba0SGirish Moodalbail 	}
9076e91bba0SGirish Moodalbail 	(void) fclose(fp);
9086e91bba0SGirish Moodalbail 	(void) fclose(nfp);
9096e91bba0SGirish Moodalbail 
9106e91bba0SGirish Moodalbail 	if (rename(newfile, file) < 0) {
9116e91bba0SGirish Moodalbail 		err = errno;
9126e91bba0SGirish Moodalbail 		(void) unlink(newfile);
9136e91bba0SGirish Moodalbail 	}
9146e91bba0SGirish Moodalbail 	return (err);
9156e91bba0SGirish Moodalbail done:
9166e91bba0SGirish Moodalbail 	if (nfp != NULL) {
9176e91bba0SGirish Moodalbail 		(void) fclose(nfp);
9186e91bba0SGirish Moodalbail 		if (err != 0)
9196e91bba0SGirish Moodalbail 			(void) unlink(newfile);
9206e91bba0SGirish Moodalbail 	}
9216e91bba0SGirish Moodalbail 	(void) fclose(fp);
9226e91bba0SGirish Moodalbail 	return (err);
9236e91bba0SGirish Moodalbail }
9246e91bba0SGirish Moodalbail 
9256e91bba0SGirish Moodalbail /*
9266e91bba0SGirish Moodalbail  * Processes each line of the configuration file, skipping lines with
9276e91bba0SGirish Moodalbail  * leading spaces, blank lines and comments. The line form the DB
9286e91bba0SGirish Moodalbail  * is converted to nvlist and the callback function is called to process
9296e91bba0SGirish Moodalbail  * the list. The buf could be modified by the callback function and
9306e91bba0SGirish Moodalbail  * if this is a write operation and buf is not truncated, buf will
9316e91bba0SGirish Moodalbail  * be written to disk.
9326e91bba0SGirish Moodalbail  *
9336e91bba0SGirish Moodalbail  * Further if cont is set to B_FALSE,  the remainder of the file will
9346e91bba0SGirish Moodalbail  * continue to be read (however callback function will not be called) and,
9356e91bba0SGirish Moodalbail  * if necessary, written to disk as well.
9366e91bba0SGirish Moodalbail  */
9376e91bba0SGirish Moodalbail static int
ipadm_process_db_line(db_wfunc_t * db_walk_func,void * arg,FILE * fp,FILE * nfp,ipadm_db_op_t db_op)9386e91bba0SGirish Moodalbail ipadm_process_db_line(db_wfunc_t *db_walk_func, void *arg, FILE *fp, FILE *nfp,
9396e91bba0SGirish Moodalbail     ipadm_db_op_t db_op)
9406e91bba0SGirish Moodalbail {
9416e91bba0SGirish Moodalbail 	int		err = 0;
9426e91bba0SGirish Moodalbail 	char		buf[MAXLINELEN];
9436e91bba0SGirish Moodalbail 	boolean_t	cont = B_TRUE;
9446e91bba0SGirish Moodalbail 	int		i, len;
9456e91bba0SGirish Moodalbail 	nvlist_t	*db_nvl = NULL;
9466e91bba0SGirish Moodalbail 	boolean_t	line_deleted = B_FALSE;
9476e91bba0SGirish Moodalbail 
9486e91bba0SGirish Moodalbail 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
9496e91bba0SGirish Moodalbail 		/*
9506e91bba0SGirish Moodalbail 		 * Skip leading spaces, blank lines, and comments.
9516e91bba0SGirish Moodalbail 		 */
9526e91bba0SGirish Moodalbail 		len = strnlen(buf, MAXLINELEN);
9536e91bba0SGirish Moodalbail 		for (i = 0; i < len; i++) {
9546e91bba0SGirish Moodalbail 			if (!isspace(buf[i]))
9556e91bba0SGirish Moodalbail 				break;
9566e91bba0SGirish Moodalbail 		}
9576e91bba0SGirish Moodalbail 
9586e91bba0SGirish Moodalbail 		if (i != len && buf[i] != '#' && cont) {
9596e91bba0SGirish Moodalbail 			if (ipadm_str2nvlist(buf, &db_nvl, 0) == 0) {
9606e91bba0SGirish Moodalbail 				cont = db_walk_func(arg, db_nvl, buf,
9616e91bba0SGirish Moodalbail 				    MAXLINELEN, &err);
9626e91bba0SGirish Moodalbail 			} else {
9636e91bba0SGirish Moodalbail 				/* Delete corrupted line. */
9646e91bba0SGirish Moodalbail 				buf[0] = '\0';
9656e91bba0SGirish Moodalbail 			}
9666e91bba0SGirish Moodalbail 			nvlist_free(db_nvl);
9676e91bba0SGirish Moodalbail 			db_nvl = NULL;
9686e91bba0SGirish Moodalbail 		}
9696e91bba0SGirish Moodalbail 		if (err != 0)
9706e91bba0SGirish Moodalbail 			break;
9716e91bba0SGirish Moodalbail 		if (nfp != NULL && buf[0] == '\0')
9726e91bba0SGirish Moodalbail 			line_deleted = B_TRUE;
9736e91bba0SGirish Moodalbail 		if (nfp != NULL	&& buf[0] != '\0' && fputs(buf, nfp) == EOF) {
9746e91bba0SGirish Moodalbail 			err = errno;
9756e91bba0SGirish Moodalbail 			break;
9766e91bba0SGirish Moodalbail 		}
9776e91bba0SGirish Moodalbail 	}
9786e91bba0SGirish Moodalbail 
9796e91bba0SGirish Moodalbail 	if (err != 0 || !cont)
9806e91bba0SGirish Moodalbail 		return (err);
9816e91bba0SGirish Moodalbail 
9826e91bba0SGirish Moodalbail 	if (db_op == IPADM_DB_WRITE) {
9838887b57dSGirish Moodalbail 		nvlist_t	*nvl;
9846e91bba0SGirish Moodalbail 
9856e91bba0SGirish Moodalbail 		/*
9868887b57dSGirish Moodalbail 		 * `arg' will be NULL when we are doing in-line update of
9878887b57dSGirish Moodalbail 		 * entries.
9888887b57dSGirish Moodalbail 		 */
9898887b57dSGirish Moodalbail 		if (arg != NULL) {
9908887b57dSGirish Moodalbail 			nvl = ((ipadm_dbwrite_cbarg_t *)arg)->dbw_nvl;
9918887b57dSGirish Moodalbail 			/*
9926e91bba0SGirish Moodalbail 			 * If the specified entry is not found above, we add
9936e91bba0SGirish Moodalbail 			 * the entry to the configuration file, here.
9946e91bba0SGirish Moodalbail 			 */
9956e91bba0SGirish Moodalbail 			(void) memset(buf, 0, MAXLINELEN);
9966e91bba0SGirish Moodalbail 			if (ipadm_nvlist2str(nvl, buf, MAXLINELEN) == 0)
9976e91bba0SGirish Moodalbail 				err = ENOBUFS;
9986e91bba0SGirish Moodalbail 			else if (fputs(buf, nfp) == EOF)
9996e91bba0SGirish Moodalbail 				err = errno;
10008887b57dSGirish Moodalbail 		}
10016e91bba0SGirish Moodalbail 		return (err);
10026e91bba0SGirish Moodalbail 	}
10036e91bba0SGirish Moodalbail 
10046e91bba0SGirish Moodalbail 	if (db_op == IPADM_DB_DELETE && line_deleted)
10056e91bba0SGirish Moodalbail 		return (0);
10066e91bba0SGirish Moodalbail 
10076e91bba0SGirish Moodalbail 	/* if we have come this far, then we didn't find any match */
10086e91bba0SGirish Moodalbail 	return (ENOENT);
10096e91bba0SGirish Moodalbail }
1010