xref: /titanic_51/usr/src/lib/libipadm/common/ipadm_persist.c (revision 8887b57dc579de11464fc6c74163d2595ce073af)
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.
236e91bba0SGirish Moodalbail  */
246e91bba0SGirish Moodalbail 
256e91bba0SGirish Moodalbail /*
266e91bba0SGirish Moodalbail  * This file contains routines to read/write formatted entries from/to
276e91bba0SGirish Moodalbail  * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
286e91bba0SGirish Moodalbail  * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
296e91bba0SGirish Moodalbail  * below:
306e91bba0SGirish Moodalbail  *		name=value[;...]
316e91bba0SGirish Moodalbail  *
326e91bba0SGirish Moodalbail  * The 'name' determines how to interpret 'value'. The supported names are:
336e91bba0SGirish Moodalbail  *
346e91bba0SGirish Moodalbail  *  IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
356e91bba0SGirish Moodalbail  *	       converted to nvlist, will contain nvpairs for local and remote
366e91bba0SGirish Moodalbail  *	       addresses. These nvpairs are of type DATA_TYPE_STRING
376e91bba0SGirish Moodalbail  *
386e91bba0SGirish Moodalbail  *  IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
396e91bba0SGirish Moodalbail  *	       converted to nvlist, will contain nvpairs for local and remote
406e91bba0SGirish Moodalbail  *	       addresses. These nvpairs are of type DATA_TYPE_STRING
416e91bba0SGirish Moodalbail  *
426e91bba0SGirish Moodalbail  *  IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
436e91bba0SGirish Moodalbail  *	       info and when converted to nvlist, will contain following nvpairs
446e91bba0SGirish Moodalbail  *			interface_id: DATA_TYPE_UINT8_ARRAY
456e91bba0SGirish Moodalbail  *			prefixlen: DATA_TYPE_UINT32
466e91bba0SGirish Moodalbail  *			stateless: DATA_TYPE_STRING
476e91bba0SGirish Moodalbail  *			stateful: DATA_TYPE_STRING
486e91bba0SGirish Moodalbail  *
496e91bba0SGirish Moodalbail  *  IPADM_NVP_DHCP - value holds wait time and primary info and when converted
506e91bba0SGirish Moodalbail  *	       to nvlist, will contain following nvpairs
516e91bba0SGirish Moodalbail  *			wait:	DATA_TYPE_INT32
526e91bba0SGirish Moodalbail  *			primary: DATA_TYPE_BOOLEAN
536e91bba0SGirish Moodalbail  *
546e91bba0SGirish Moodalbail  *  default  - value is a single entity and when converted to nvlist, will
556e91bba0SGirish Moodalbail  *	       contain nvpair of type DATA_TYPE_STRING. nvpairs private to
566e91bba0SGirish Moodalbail  *	       ipadm are of this type. Further the property name and property
576e91bba0SGirish Moodalbail  *	       values are stored as nvpairs of this type.
586e91bba0SGirish Moodalbail  *
596e91bba0SGirish Moodalbail  * The syntax for each line is described above the respective functions below.
606e91bba0SGirish Moodalbail  */
616e91bba0SGirish Moodalbail 
626e91bba0SGirish Moodalbail #include <stdlib.h>
636e91bba0SGirish Moodalbail #include <strings.h>
646e91bba0SGirish Moodalbail #include <errno.h>
656e91bba0SGirish Moodalbail #include <ctype.h>
666e91bba0SGirish Moodalbail #include <sys/types.h>
676e91bba0SGirish Moodalbail #include <sys/stat.h>
686e91bba0SGirish Moodalbail #include <sys/dld.h>
696e91bba0SGirish Moodalbail #include <fcntl.h>
706e91bba0SGirish Moodalbail #include <dirent.h>
716e91bba0SGirish Moodalbail #include <unistd.h>
726e91bba0SGirish Moodalbail #include <assert.h>
736e91bba0SGirish Moodalbail #include <sys/socket.h>
746e91bba0SGirish Moodalbail #include <netinet/in.h>
756e91bba0SGirish Moodalbail #include <arpa/inet.h>
766e91bba0SGirish Moodalbail #include <sys/sockio.h>
776e91bba0SGirish Moodalbail #include "libipadm_impl.h"
786e91bba0SGirish Moodalbail 
796e91bba0SGirish Moodalbail #define	MAXLINELEN		1024
806e91bba0SGirish Moodalbail #define	IPADM_NVPAIR_SEP	";"
816e91bba0SGirish Moodalbail #define	IPADM_NAME_SEP		","
826e91bba0SGirish Moodalbail 
836e91bba0SGirish Moodalbail static char ipadm_rootdir[MAXPATHLEN] = "/";
846e91bba0SGirish Moodalbail 
856e91bba0SGirish Moodalbail static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
866e91bba0SGirish Moodalbail     ipadm_db_op_t);
876e91bba0SGirish Moodalbail 
886e91bba0SGirish Moodalbail /*
896e91bba0SGirish Moodalbail  * convert nvpair to a "name=value" string for writing to the DB.
906e91bba0SGirish Moodalbail  */
916e91bba0SGirish Moodalbail typedef size_t  ipadm_wfunc_t(nvpair_t *, char *, size_t);
926e91bba0SGirish Moodalbail 
936e91bba0SGirish Moodalbail /*
946e91bba0SGirish Moodalbail  * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
956e91bba0SGirish Moodalbail  * nvpair to the nvlist.
966e91bba0SGirish Moodalbail  */
976e91bba0SGirish Moodalbail typedef void  ipadm_rfunc_t(nvlist_t *, char *name, char *value);
986e91bba0SGirish Moodalbail 
996e91bba0SGirish Moodalbail static ipadm_rfunc_t	i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
1006e91bba0SGirish Moodalbail 			i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
1016e91bba0SGirish Moodalbail 			i_ipadm_dhcp_dbline2nvl;
1026e91bba0SGirish Moodalbail 
1036e91bba0SGirish Moodalbail static ipadm_wfunc_t	i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
1046e91bba0SGirish Moodalbail 			i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
1056e91bba0SGirish Moodalbail 			i_ipadm_dhcp_nvp2dbline;
1066e91bba0SGirish Moodalbail 
1076e91bba0SGirish Moodalbail /*
1086e91bba0SGirish Moodalbail  * table of function pointers to read/write formatted entries from/to
1096e91bba0SGirish Moodalbail  * ipadm.conf.
1106e91bba0SGirish Moodalbail  */
1116e91bba0SGirish Moodalbail typedef struct ipadm_conf_ent_s {
1126e91bba0SGirish Moodalbail 	const char		*ipent_type_name;
1136e91bba0SGirish Moodalbail 	ipadm_wfunc_t		*ipent_wfunc;
1146e91bba0SGirish Moodalbail 	ipadm_rfunc_t		*ipent_rfunc;
1156e91bba0SGirish Moodalbail } ipadm_conf_ent_t;
1166e91bba0SGirish Moodalbail 
1176e91bba0SGirish Moodalbail static ipadm_conf_ent_t ipadm_conf_ent[] = {
1186e91bba0SGirish Moodalbail 	{ IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
1196e91bba0SGirish Moodalbail 	{ IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
1206e91bba0SGirish Moodalbail 	{ IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
1216e91bba0SGirish Moodalbail 	    i_ipadm_intfid_dbline2nvl },
1226e91bba0SGirish Moodalbail 	{ IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
1236e91bba0SGirish Moodalbail 	{ NULL,	i_ipadm_str_nvp2dbline,	i_ipadm_str_dbline2nvl }
1246e91bba0SGirish Moodalbail };
1256e91bba0SGirish Moodalbail 
1266e91bba0SGirish Moodalbail static ipadm_conf_ent_t *
1276e91bba0SGirish Moodalbail i_ipadm_find_conf_type(const char *type)
1286e91bba0SGirish Moodalbail {
1296e91bba0SGirish Moodalbail 	int	i;
1306e91bba0SGirish Moodalbail 
1316e91bba0SGirish Moodalbail 	for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
1326e91bba0SGirish Moodalbail 		if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
1336e91bba0SGirish Moodalbail 			break;
1346e91bba0SGirish Moodalbail 	return (&ipadm_conf_ent[i]);
1356e91bba0SGirish Moodalbail }
1366e91bba0SGirish Moodalbail 
1376e91bba0SGirish Moodalbail /*
1386e91bba0SGirish Moodalbail  * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
1396e91bba0SGirish Moodalbail  * the given nvlist `nvl' and adds the strings to `buf'.
1406e91bba0SGirish Moodalbail  */
1416e91bba0SGirish Moodalbail size_t
1426e91bba0SGirish Moodalbail i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
1436e91bba0SGirish Moodalbail {
1446e91bba0SGirish Moodalbail 	char	*cp;
1456e91bba0SGirish Moodalbail 	char	tmpbuf[IPADM_STRSIZE];
1466e91bba0SGirish Moodalbail 
1476e91bba0SGirish Moodalbail 	/* Add the local hostname */
1486e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(nvl, IPADM_NVP_IPADDRHNAME, &cp) != 0)
1496e91bba0SGirish Moodalbail 		return (0);
1506e91bba0SGirish Moodalbail 	(void) strlcat(buf, cp, buflen); /* local hostname */
1516e91bba0SGirish Moodalbail 
1526e91bba0SGirish Moodalbail 	/* Add the dst hostname */
1536e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(nvl, IPADM_NVP_IPDADDRHNAME, &cp) != 0) {
1546e91bba0SGirish Moodalbail 		/* no dst addr. just add a NULL character */
1556e91bba0SGirish Moodalbail 		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",");
1566e91bba0SGirish Moodalbail 	} else {
1576e91bba0SGirish Moodalbail 		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",%s", cp);
1586e91bba0SGirish Moodalbail 	}
1596e91bba0SGirish Moodalbail 	return (strlcat(buf, tmpbuf, buflen));
1606e91bba0SGirish Moodalbail }
1616e91bba0SGirish Moodalbail 
1626e91bba0SGirish Moodalbail /*
1636e91bba0SGirish Moodalbail  * Converts IPADM_NVP_IPV4ADDR nvpair to a string representation for writing to
1646e91bba0SGirish Moodalbail  * the DB. The converted string format:
1656e91bba0SGirish Moodalbail  *	ipv4addr=<local numeric IP string or hostname,remote numeric IP
1666e91bba0SGirish Moodalbail  *          string or hostname>
1676e91bba0SGirish Moodalbail  */
1686e91bba0SGirish Moodalbail static size_t
1696e91bba0SGirish Moodalbail i_ipadm_ip4_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
1706e91bba0SGirish Moodalbail {
1716e91bba0SGirish Moodalbail 	nvlist_t	*v;
1726e91bba0SGirish Moodalbail 	int		nbytes;
1736e91bba0SGirish Moodalbail 
1746e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
1756e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV4ADDR) == 0);
1766e91bba0SGirish Moodalbail 
1776e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV4ADDR);
1786e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
1796e91bba0SGirish Moodalbail 		goto fail;
1806e91bba0SGirish Moodalbail 	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
1816e91bba0SGirish Moodalbail 	if (nbytes != 0)
1826e91bba0SGirish Moodalbail 		return (nbytes);
1836e91bba0SGirish Moodalbail fail:
1846e91bba0SGirish Moodalbail 	buf[0] = '\0';
1856e91bba0SGirish Moodalbail 	return (0);
1866e91bba0SGirish Moodalbail }
1876e91bba0SGirish Moodalbail 
1886e91bba0SGirish Moodalbail /*
1896e91bba0SGirish Moodalbail  * Converts IPADM_NVP_IPV6ADDR nvpair to a string representation for writing to
1906e91bba0SGirish Moodalbail  * the DB. The converted string format:
1916e91bba0SGirish Moodalbail  *	ipv6addr=<local numeric IP string or hostname,remote numeric IP
1926e91bba0SGirish Moodalbail  *          string or hostname>
1936e91bba0SGirish Moodalbail  */
1946e91bba0SGirish Moodalbail static size_t
1956e91bba0SGirish Moodalbail i_ipadm_ip6_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
1966e91bba0SGirish Moodalbail {
1976e91bba0SGirish Moodalbail 	nvlist_t	*v;
1986e91bba0SGirish Moodalbail 	int		nbytes;
1996e91bba0SGirish Moodalbail 
2006e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2016e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV6ADDR) == 0);
2026e91bba0SGirish Moodalbail 
2036e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV6ADDR);
2046e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
2056e91bba0SGirish Moodalbail 		goto fail;
2066e91bba0SGirish Moodalbail 	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
2076e91bba0SGirish Moodalbail 	if (nbytes != 0)
2086e91bba0SGirish Moodalbail 		return (nbytes);
2096e91bba0SGirish Moodalbail fail:
2106e91bba0SGirish Moodalbail 	buf[0] = '\0';
2116e91bba0SGirish Moodalbail 	return (0);
2126e91bba0SGirish Moodalbail }
2136e91bba0SGirish Moodalbail 
2146e91bba0SGirish Moodalbail /*
2156e91bba0SGirish Moodalbail  * Converts IPADM_NVP_INTFID nvpair to a string representation for writing to
2166e91bba0SGirish Moodalbail  * the DB. The converted string format:
2176e91bba0SGirish Moodalbail  *	IPADM_NVP_INTFID=<intfid/prefixlen>,{yes|no},{yes|no}
2186e91bba0SGirish Moodalbail  */
2196e91bba0SGirish Moodalbail static size_t
2206e91bba0SGirish Moodalbail i_ipadm_intfid_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2216e91bba0SGirish Moodalbail {
2226e91bba0SGirish Moodalbail 	char		addrbuf[IPADM_STRSIZE];
2236e91bba0SGirish Moodalbail 	nvlist_t	*v;
2246e91bba0SGirish Moodalbail 	uint32_t	prefixlen;
2256e91bba0SGirish Moodalbail 	struct in6_addr	in6addr;
2266e91bba0SGirish Moodalbail 	char		*stateless;
2276e91bba0SGirish Moodalbail 	char		*stateful;
2286e91bba0SGirish Moodalbail 
2296e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2306e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_INTFID) == 0);
2316e91bba0SGirish Moodalbail 
2326e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_INTFID);
2336e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0)
2346e91bba0SGirish Moodalbail 		goto fail;
2356e91bba0SGirish Moodalbail 	if (i_ipadm_nvl2in6_addr(v, IPADM_NVP_IPNUMADDR, &in6addr) !=
2366e91bba0SGirish Moodalbail 	    IPADM_SUCCESS)
2376e91bba0SGirish Moodalbail 		goto fail;
2386e91bba0SGirish Moodalbail 	(void) inet_ntop(AF_INET6, &in6addr, addrbuf,
2396e91bba0SGirish Moodalbail 	    sizeof (addrbuf));
2406e91bba0SGirish Moodalbail 	(void) strlcat(buf, addrbuf, buflen);
2416e91bba0SGirish Moodalbail 	if (nvlist_lookup_uint32(v, IPADM_NVP_PREFIXLEN, &prefixlen) != 0 ||
2426e91bba0SGirish Moodalbail 	    nvlist_lookup_string(v, IPADM_NVP_STATELESS, &stateless) != 0 ||
2436e91bba0SGirish Moodalbail 	    nvlist_lookup_string(v, IPADM_NVP_STATEFUL, &stateful) != 0)
2446e91bba0SGirish Moodalbail 		goto fail;
2456e91bba0SGirish Moodalbail 	(void) snprintf(addrbuf, sizeof (addrbuf), "/%d,%s,%s",
2466e91bba0SGirish Moodalbail 	    prefixlen, stateless, stateful);
2476e91bba0SGirish Moodalbail 	return (strlcat(buf, addrbuf, buflen));
2486e91bba0SGirish Moodalbail fail:
2496e91bba0SGirish Moodalbail 	buf[0] = '\0';
2506e91bba0SGirish Moodalbail 	return (0);
2516e91bba0SGirish Moodalbail }
2526e91bba0SGirish Moodalbail 
2536e91bba0SGirish Moodalbail /*
2546e91bba0SGirish Moodalbail  * Converts IPADM_NVP_DHCP nvpair to a string representation for writing to the
2556e91bba0SGirish Moodalbail  * DB. The converted string format:
2566e91bba0SGirish Moodalbail  *	IPADM_NVP_DHCP=<wait_time>,{yes|no}
2576e91bba0SGirish Moodalbail  */
2586e91bba0SGirish Moodalbail static size_t
2596e91bba0SGirish Moodalbail i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2606e91bba0SGirish Moodalbail {
2616e91bba0SGirish Moodalbail 	char		addrbuf[IPADM_STRSIZE];
2626e91bba0SGirish Moodalbail 	int32_t 	wait;
2636e91bba0SGirish Moodalbail 	boolean_t	primary;
2646e91bba0SGirish Moodalbail 	nvlist_t	*v;
2656e91bba0SGirish Moodalbail 
2666e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
2676e91bba0SGirish Moodalbail 	    strcmp(nvpair_name(nvp), IPADM_NVP_DHCP) == 0);
2686e91bba0SGirish Moodalbail 
2696e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &v) != 0 ||
2706e91bba0SGirish Moodalbail 	    nvlist_lookup_int32(v, IPADM_NVP_WAIT, &wait) != 0 ||
2716e91bba0SGirish Moodalbail 	    nvlist_lookup_boolean_value(v, IPADM_NVP_PRIMARY, &primary) != 0) {
2726e91bba0SGirish Moodalbail 		return (0);
2736e91bba0SGirish Moodalbail 	}
2746e91bba0SGirish Moodalbail 	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_DHCP);
2756e91bba0SGirish Moodalbail 	(void) snprintf(addrbuf, sizeof (addrbuf), "%d,%s", wait,
2766e91bba0SGirish Moodalbail 	    (primary ? "yes" : "no"));
2776e91bba0SGirish Moodalbail 	return (strlcat(buf, addrbuf, buflen));
2786e91bba0SGirish Moodalbail }
2796e91bba0SGirish Moodalbail 
2806e91bba0SGirish Moodalbail /*
2816e91bba0SGirish Moodalbail  * Constructs a "<name>=<value>" string from the nvpair, whose type must
2826e91bba0SGirish Moodalbail  * be STRING.
2836e91bba0SGirish Moodalbail  */
2846e91bba0SGirish Moodalbail static size_t
2856e91bba0SGirish Moodalbail i_ipadm_str_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
2866e91bba0SGirish Moodalbail {
2876e91bba0SGirish Moodalbail 	char	*str = NULL;
2886e91bba0SGirish Moodalbail 
2896e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
2906e91bba0SGirish Moodalbail 	if (nvpair_value_string(nvp, &str) != 0)
2916e91bba0SGirish Moodalbail 		return (0);
2926e91bba0SGirish Moodalbail 	return (snprintf(buf, buflen, "%s=%s", nvpair_name(nvp), str));
2936e91bba0SGirish Moodalbail }
2946e91bba0SGirish Moodalbail 
2956e91bba0SGirish Moodalbail /*
2966e91bba0SGirish Moodalbail  * Converts a nvlist to string of the form:
2976e91bba0SGirish Moodalbail  *  <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
2986e91bba0SGirish Moodalbail  */
2996e91bba0SGirish Moodalbail size_t
3006e91bba0SGirish Moodalbail ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
3016e91bba0SGirish Moodalbail {
3026e91bba0SGirish Moodalbail 	nvpair_t	*nvp = NULL;
3036e91bba0SGirish Moodalbail 	uint_t		nbytes = 0, tbytes = 0;
3046e91bba0SGirish Moodalbail 	ipadm_conf_ent_t *ipent;
3056e91bba0SGirish Moodalbail 	size_t		bufsize = buflen;
3066e91bba0SGirish Moodalbail 
3076e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
3086e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
3096e91bba0SGirish Moodalbail 		ipent = i_ipadm_find_conf_type(nvpair_name(nvp));
3106e91bba0SGirish Moodalbail 		nbytes = (*ipent->ipent_wfunc)(nvp, buf, buflen);
3116e91bba0SGirish Moodalbail 		/* add nvpair separator */
3126e91bba0SGirish Moodalbail 		nbytes += snprintf(buf + nbytes, buflen - nbytes, "%s",
3136e91bba0SGirish Moodalbail 		    IPADM_NVPAIR_SEP);
3146e91bba0SGirish Moodalbail 		buflen -= nbytes;
3156e91bba0SGirish Moodalbail 		buf += nbytes;
3166e91bba0SGirish Moodalbail 		tbytes += nbytes;
3176e91bba0SGirish Moodalbail 		if (tbytes >= bufsize)	/* buffer overflow */
3186e91bba0SGirish Moodalbail 			return (0);
3196e91bba0SGirish Moodalbail 	}
3206e91bba0SGirish Moodalbail 	nbytes = snprintf(buf, buflen, "%c%c", '\n', '\0');
3216e91bba0SGirish Moodalbail 	tbytes += nbytes;
3226e91bba0SGirish Moodalbail 	if (tbytes >= bufsize)
3236e91bba0SGirish Moodalbail 		return (0);
3246e91bba0SGirish Moodalbail 	return (tbytes);
3256e91bba0SGirish Moodalbail }
3266e91bba0SGirish Moodalbail 
3276e91bba0SGirish Moodalbail /*
3286e91bba0SGirish Moodalbail  * Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
3296e91bba0SGirish Moodalbail  * The value will be interpreted as explained at the top of this file.
3306e91bba0SGirish Moodalbail  */
3316e91bba0SGirish Moodalbail static void
3326e91bba0SGirish Moodalbail i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
3336e91bba0SGirish Moodalbail {
3346e91bba0SGirish Moodalbail 	ipadm_conf_ent_t	*ipent;
3356e91bba0SGirish Moodalbail 
3366e91bba0SGirish Moodalbail 	ipent = i_ipadm_find_conf_type(name);
3376e91bba0SGirish Moodalbail 	(*ipent->ipent_rfunc)(nvl, name, value);
3386e91bba0SGirish Moodalbail }
3396e91bba0SGirish Moodalbail 
3406e91bba0SGirish Moodalbail /*
3416e91bba0SGirish Moodalbail  * Adds an nvpair for IPv4 addr to the nvlist. The "name" is the string in
3426e91bba0SGirish Moodalbail  * IPADM_NVP_IPV4ADDR. The "value" for IPADM_NVP_IPV4ADDR is another nvlist.
3436e91bba0SGirish Moodalbail  * Allocate the value nvlist for IPADM_NVP_IPV4ADDR if necessary, and add
3446e91bba0SGirish Moodalbail  * the address and hostnames from the address object `ipaddr' to it.
3456e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
3466e91bba0SGirish Moodalbail  */
3476e91bba0SGirish Moodalbail ipadm_status_t
3486e91bba0SGirish Moodalbail i_ipadm_add_ipaddr2nvl(nvlist_t *nvl, ipadm_addrobj_t ipaddr)
3496e91bba0SGirish Moodalbail {
3506e91bba0SGirish Moodalbail 	nvlist_t		*nvl_addr = NULL;
3516e91bba0SGirish Moodalbail 	int			err;
3526e91bba0SGirish Moodalbail 	char			*name;
3536e91bba0SGirish Moodalbail 	sa_family_t		af = ipaddr->ipadm_af;
3546e91bba0SGirish Moodalbail 
3556e91bba0SGirish Moodalbail 	if (af == AF_INET) {
3566e91bba0SGirish Moodalbail 		name = IPADM_NVP_IPV4ADDR;
3576e91bba0SGirish Moodalbail 	} else {
3586e91bba0SGirish Moodalbail 		assert(af == AF_INET6);
3596e91bba0SGirish Moodalbail 		name = IPADM_NVP_IPV6ADDR;
3606e91bba0SGirish Moodalbail 	}
3616e91bba0SGirish Moodalbail 
3626e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, name)) {
3636e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
3646e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3656e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, name, nvl_addr)) != 0) {
3666e91bba0SGirish Moodalbail 			nvlist_free(nvl_addr);
3676e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3686e91bba0SGirish Moodalbail 		}
3696e91bba0SGirish Moodalbail 		nvlist_free(nvl_addr);
3706e91bba0SGirish Moodalbail 	}
3716e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, name, &nvl_addr)) != 0 ||
3726e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl_addr, IPADM_NVP_IPADDRHNAME,
3736e91bba0SGirish Moodalbail 	    ipaddr->ipadm_static_aname)) != 0)
3746e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
375ec3706caSVasumathi Sundaram 	if (ipaddr->ipadm_static_dname[0] != '\0') {
3766e91bba0SGirish Moodalbail 		if ((err = nvlist_add_string(nvl_addr, IPADM_NVP_IPDADDRHNAME,
3776e91bba0SGirish Moodalbail 		    ipaddr->ipadm_static_dname)) != 0)
3786e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
3796e91bba0SGirish Moodalbail 	}
3806e91bba0SGirish Moodalbail 
3816e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
3826e91bba0SGirish Moodalbail }
3836e91bba0SGirish Moodalbail 
3846e91bba0SGirish Moodalbail /*
3856e91bba0SGirish Moodalbail  * Adds an nvpair for IPv6 interface id to the nvlist. The "name" is
3866e91bba0SGirish Moodalbail  * the string in IPADM_NVP_INTFID. The "value" for IPADM_NVP_INTFID is another
3876e91bba0SGirish Moodalbail  * nvlist. Allocate the value nvlist for IPADM_NVP_INTFID if necessary, and add
3886e91bba0SGirish Moodalbail  * the interface id and its prefixlen from the address object `ipaddr' to it.
3896e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
3906e91bba0SGirish Moodalbail  */
3916e91bba0SGirish Moodalbail ipadm_status_t
3926e91bba0SGirish Moodalbail i_ipadm_add_intfid2nvl(nvlist_t *nvl, ipadm_addrobj_t addr)
3936e91bba0SGirish Moodalbail {
3946e91bba0SGirish Moodalbail 	nvlist_t	*nvl_addr = NULL;
3956e91bba0SGirish Moodalbail 	struct in6_addr	addr6;
3966e91bba0SGirish Moodalbail 	int		err;
3976e91bba0SGirish Moodalbail 
3986e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, IPADM_NVP_INTFID)) {
3996e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
4006e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4016e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_INTFID,
4026e91bba0SGirish Moodalbail 		    nvl_addr)) != 0) {
4036e91bba0SGirish Moodalbail 			nvlist_free(nvl_addr);
4046e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4056e91bba0SGirish Moodalbail 		}
4066e91bba0SGirish Moodalbail 		nvlist_free(nvl_addr);
4076e91bba0SGirish Moodalbail 	}
4086e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID,
4096e91bba0SGirish Moodalbail 	    &nvl_addr)) != 0 || (err = nvlist_add_uint32(nvl_addr,
4106e91bba0SGirish Moodalbail 	    IPADM_NVP_PREFIXLEN, addr->ipadm_intfidlen)) != 0) {
4116e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4126e91bba0SGirish Moodalbail 	}
4136e91bba0SGirish Moodalbail 	addr6 = addr->ipadm_intfid.sin6_addr;
4146e91bba0SGirish Moodalbail 	if ((err = nvlist_add_uint8_array(nvl_addr, IPADM_NVP_IPNUMADDR,
4156e91bba0SGirish Moodalbail 	    addr6.s6_addr, 16)) != 0) {
4166e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4176e91bba0SGirish Moodalbail 	}
4186e91bba0SGirish Moodalbail 	if (addr->ipadm_stateless)
4196e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "yes");
4206e91bba0SGirish Moodalbail 	else
4216e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "no");
4226e91bba0SGirish Moodalbail 	if (err != 0)
4236e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4246e91bba0SGirish Moodalbail 	if (addr->ipadm_stateful)
4256e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "yes");
4266e91bba0SGirish Moodalbail 	else
4276e91bba0SGirish Moodalbail 		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "no");
4286e91bba0SGirish Moodalbail 	if (err != 0)
4296e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4306e91bba0SGirish Moodalbail 
4316e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
4326e91bba0SGirish Moodalbail }
4336e91bba0SGirish Moodalbail 
4346e91bba0SGirish Moodalbail /*
4356e91bba0SGirish Moodalbail  * Adds an nvpair for a dhcp address object to the nvlist. The "name" is
4366e91bba0SGirish Moodalbail  * the string in IPADM_NVP_DHCP. The "value" for IPADM_NVP_DHCP is another
4376e91bba0SGirish Moodalbail  * nvlist. Allocate the value nvlist for IPADM_NVP_DHCP if necessary, and add
4386e91bba0SGirish Moodalbail  * the parameters from the arguments `primary' and `wait'.
4396e91bba0SGirish Moodalbail  * Then add the allocated nvlist to `nvl'.
4406e91bba0SGirish Moodalbail  */
4416e91bba0SGirish Moodalbail ipadm_status_t
4426e91bba0SGirish Moodalbail i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
4436e91bba0SGirish Moodalbail {
4446e91bba0SGirish Moodalbail 	nvlist_t	*nvl_dhcp = NULL;
4456e91bba0SGirish Moodalbail 	int		err;
4466e91bba0SGirish Moodalbail 
4476e91bba0SGirish Moodalbail 	if (!nvlist_exists(nvl, IPADM_NVP_DHCP)) {
4486e91bba0SGirish Moodalbail 		if ((err = nvlist_alloc(&nvl_dhcp, NV_UNIQUE_NAME, 0)) != 0)
4496e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4506e91bba0SGirish Moodalbail 		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_DHCP,
4516e91bba0SGirish Moodalbail 		    nvl_dhcp)) != 0) {
4526e91bba0SGirish Moodalbail 			nvlist_free(nvl_dhcp);
4536e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
4546e91bba0SGirish Moodalbail 		}
4556e91bba0SGirish Moodalbail 		nvlist_free(nvl_dhcp);
4566e91bba0SGirish Moodalbail 	}
4576e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvl_dhcp)) != 0 ||
4586e91bba0SGirish Moodalbail 	    (err = nvlist_add_int32(nvl_dhcp, IPADM_NVP_WAIT, wait)) != 0 ||
4596e91bba0SGirish Moodalbail 	    (err = nvlist_add_boolean_value(nvl_dhcp, IPADM_NVP_PRIMARY,
4606e91bba0SGirish Moodalbail 	    primary)) != 0) {
4616e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
4626e91bba0SGirish Moodalbail 	}
4636e91bba0SGirish Moodalbail 
4646e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
4656e91bba0SGirish Moodalbail }
4666e91bba0SGirish Moodalbail 
4676e91bba0SGirish Moodalbail /*
4686e91bba0SGirish Moodalbail  * Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
4696e91bba0SGirish Moodalbail  */
4706e91bba0SGirish Moodalbail static void
4716e91bba0SGirish Moodalbail i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
4726e91bba0SGirish Moodalbail {
4736e91bba0SGirish Moodalbail 	/* if value is NULL create an empty node */
4746e91bba0SGirish Moodalbail 	if (value == NULL)
4756e91bba0SGirish Moodalbail 		(void) nvlist_add_string(nvl, name, "");
4766e91bba0SGirish Moodalbail 	else
4776e91bba0SGirish Moodalbail 		(void) nvlist_add_string(nvl, name, value);
4786e91bba0SGirish Moodalbail }
4796e91bba0SGirish Moodalbail 
4806e91bba0SGirish Moodalbail /*
4816e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_IPV4ADDR and
4826e91bba0SGirish Moodalbail  * `value' = <local numeric IP string or hostname,remote numeric IP string or
4836e91bba0SGirish Moodalbail  *     hostname>
4846e91bba0SGirish Moodalbail  * This function will add an nvlist with the hostname information in
4856e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
4866e91bba0SGirish Moodalbail  */
4876e91bba0SGirish Moodalbail static void
4886e91bba0SGirish Moodalbail i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
4896e91bba0SGirish Moodalbail {
4906e91bba0SGirish Moodalbail 	char			*cp, *hname;
4916e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
4926e91bba0SGirish Moodalbail 
4936e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_IPV4ADDR) == 0 && value != NULL);
4946e91bba0SGirish Moodalbail 
4956e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
4966e91bba0SGirish Moodalbail 	ipaddr.ipadm_af = AF_INET;
4976e91bba0SGirish Moodalbail 
4986e91bba0SGirish Moodalbail 	hname = value; /* local hostname */
4996e91bba0SGirish Moodalbail 	cp = strchr(hname, ',');
5006e91bba0SGirish Moodalbail 	assert(cp != NULL);
5016e91bba0SGirish Moodalbail 	*cp++ = '\0';
5026e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
5036e91bba0SGirish Moodalbail 	    sizeof (ipaddr.ipadm_static_aname));
5046e91bba0SGirish Moodalbail 
5056e91bba0SGirish Moodalbail 	if (*cp != '\0') {
5066e91bba0SGirish Moodalbail 		/* we have a dst hostname */
5076e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
5086e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_static_dname));
5096e91bba0SGirish Moodalbail 	}
5106e91bba0SGirish Moodalbail 	(void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
5116e91bba0SGirish Moodalbail }
5126e91bba0SGirish Moodalbail 
5136e91bba0SGirish Moodalbail /*
5146e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_IPV6ADDR and
5156e91bba0SGirish Moodalbail  * `value' = <local numeric IP string or hostname,remote numeric IP string or
5166e91bba0SGirish Moodalbail  *     hostname>
5176e91bba0SGirish Moodalbail  * This function will add an nvlist with the hostname information in
5186e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5196e91bba0SGirish Moodalbail  */
5206e91bba0SGirish Moodalbail static void
5216e91bba0SGirish Moodalbail i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
5226e91bba0SGirish Moodalbail {
5236e91bba0SGirish Moodalbail 	char			*cp, *hname;
5246e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
5256e91bba0SGirish Moodalbail 
5266e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_IPV6ADDR) == 0 && value != NULL);
5276e91bba0SGirish Moodalbail 
5286e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
5296e91bba0SGirish Moodalbail 	ipaddr.ipadm_af = AF_INET6;
5306e91bba0SGirish Moodalbail 
5316e91bba0SGirish Moodalbail 	hname = value; /* local hostname */
5326e91bba0SGirish Moodalbail 	cp = strchr(hname, ',');
5336e91bba0SGirish Moodalbail 	assert(cp != NULL);
5346e91bba0SGirish Moodalbail 	*cp++ = '\0';
5356e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
5366e91bba0SGirish Moodalbail 	    sizeof (ipaddr.ipadm_static_aname));
5376e91bba0SGirish Moodalbail 
5386e91bba0SGirish Moodalbail 	if (*cp != '\0') {
5396e91bba0SGirish Moodalbail 		/* we have a dst hostname */
5406e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
5416e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_static_dname));
5426e91bba0SGirish Moodalbail 	}
5436e91bba0SGirish Moodalbail 	(void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
5446e91bba0SGirish Moodalbail }
5456e91bba0SGirish Moodalbail 
5466e91bba0SGirish Moodalbail /*
5476e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_INTFID and `value' = <intfid/prefixlen>,{yes,no},{yes|no}
5486e91bba0SGirish Moodalbail  * This function will add an nvlist with the address object information in
5496e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5506e91bba0SGirish Moodalbail  */
5516e91bba0SGirish Moodalbail static void
5526e91bba0SGirish Moodalbail i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
5536e91bba0SGirish Moodalbail {
5546e91bba0SGirish Moodalbail 	char			*cp;
5556e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
5566e91bba0SGirish Moodalbail 	char			*endp;
5576e91bba0SGirish Moodalbail 	char			*prefixlen;
5586e91bba0SGirish Moodalbail 	char			*stateless;
5596e91bba0SGirish Moodalbail 	char			*stateful;
5606e91bba0SGirish Moodalbail 
5616e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_INTFID) == 0 && value != NULL);
5626e91bba0SGirish Moodalbail 
5636e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
5646e91bba0SGirish Moodalbail 
5656e91bba0SGirish Moodalbail 	cp = strchr(value, '/');
5666e91bba0SGirish Moodalbail 	assert(cp != NULL);
5676e91bba0SGirish Moodalbail 
5686e91bba0SGirish Moodalbail 	*cp++ = '\0';
5696e91bba0SGirish Moodalbail 	ipaddr.ipadm_intfid.sin6_family = AF_INET6;
5706e91bba0SGirish Moodalbail 	(void) inet_pton(AF_INET6, value, &ipaddr.ipadm_intfid.sin6_addr);
5716e91bba0SGirish Moodalbail 
5726e91bba0SGirish Moodalbail 	prefixlen = cp;
5736e91bba0SGirish Moodalbail 	cp = strchr(cp, ',');
5746e91bba0SGirish Moodalbail 	assert(cp != NULL);
5756e91bba0SGirish Moodalbail 	*cp++ = '\0';
5766e91bba0SGirish Moodalbail 
5776e91bba0SGirish Moodalbail 	errno = 0;
5786e91bba0SGirish Moodalbail 	ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
5796e91bba0SGirish Moodalbail 	if (*endp != '\0' || errno != 0)
5806e91bba0SGirish Moodalbail 		return;
5816e91bba0SGirish Moodalbail 
5826e91bba0SGirish Moodalbail 	stateless = cp;
5836e91bba0SGirish Moodalbail 	stateful = strchr(stateless, ',');
5846e91bba0SGirish Moodalbail 	assert(stateful != NULL);
5856e91bba0SGirish Moodalbail 	*stateful++ = '\0';
5866e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
5876e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
5886e91bba0SGirish Moodalbail 
5896e91bba0SGirish Moodalbail 	/* Add all of it to the given nvlist */
5906e91bba0SGirish Moodalbail 	(void) i_ipadm_add_intfid2nvl(nvl, &ipaddr);
5916e91bba0SGirish Moodalbail }
5926e91bba0SGirish Moodalbail 
5936e91bba0SGirish Moodalbail /*
5946e91bba0SGirish Moodalbail  * `name' = IPADM_NVP_DHCP and `value' = <wait_time>,{yes|no}
5956e91bba0SGirish Moodalbail  * This function will add an nvlist with the dhcp address object information in
5966e91bba0SGirish Moodalbail  * nvpairs to the nvlist in `nvl'.
5976e91bba0SGirish Moodalbail  */
5986e91bba0SGirish Moodalbail static void
5996e91bba0SGirish Moodalbail i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
6006e91bba0SGirish Moodalbail {
6016e91bba0SGirish Moodalbail 	char		*cp;
6026e91bba0SGirish Moodalbail 	char		*endp;
6036e91bba0SGirish Moodalbail 	long		wait_time;
6046e91bba0SGirish Moodalbail 	boolean_t	primary;
6056e91bba0SGirish Moodalbail 
6066e91bba0SGirish Moodalbail 	assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
6076e91bba0SGirish Moodalbail 	cp = strchr(value, ',');
6086e91bba0SGirish Moodalbail 	assert(cp != NULL);
6096e91bba0SGirish Moodalbail 	*cp++ = '\0';
6106e91bba0SGirish Moodalbail 	errno = 0;
6116e91bba0SGirish Moodalbail 	wait_time = strtol(value, &endp, 10);
6126e91bba0SGirish Moodalbail 	if (*endp != '\0' || errno != 0)
6136e91bba0SGirish Moodalbail 		return;
6146e91bba0SGirish Moodalbail 	primary = (strcmp(cp, "yes") == 0);
6156e91bba0SGirish Moodalbail 	(void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
6166e91bba0SGirish Moodalbail }
6176e91bba0SGirish Moodalbail 
6186e91bba0SGirish Moodalbail /*
6196e91bba0SGirish Moodalbail  * Parses the buffer, for name-value pairs and creates nvlist. The value
6206e91bba0SGirish Moodalbail  * is always considered to be a string.
6216e91bba0SGirish Moodalbail  */
6226e91bba0SGirish Moodalbail int
6236e91bba0SGirish Moodalbail ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
6246e91bba0SGirish Moodalbail {
6256e91bba0SGirish Moodalbail 	char	*nv, *name, *val, *buf, *cp, *sep;
6266e91bba0SGirish Moodalbail 	int	err;
6276e91bba0SGirish Moodalbail 
6286e91bba0SGirish Moodalbail 	if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
6296e91bba0SGirish Moodalbail 		return (EINVAL);
6306e91bba0SGirish Moodalbail 	*ipnvl = NULL;
6316e91bba0SGirish Moodalbail 
6326e91bba0SGirish Moodalbail 	/*
6336e91bba0SGirish Moodalbail 	 * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
6346e91bba0SGirish Moodalbail 	 */
6356e91bba0SGirish Moodalbail 	if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
6366e91bba0SGirish Moodalbail 		return (EINVAL);
6376e91bba0SGirish Moodalbail 
6386e91bba0SGirish Moodalbail 	if ((cp = buf = strdup(inbuf)) == NULL)
6396e91bba0SGirish Moodalbail 		return (errno);
6406e91bba0SGirish Moodalbail 
6416e91bba0SGirish Moodalbail 	while (isspace(*buf))
6426e91bba0SGirish Moodalbail 		buf++;
6436e91bba0SGirish Moodalbail 
6446e91bba0SGirish Moodalbail 	if (*buf == '\0') {
6456e91bba0SGirish Moodalbail 		err = EINVAL;
6466e91bba0SGirish Moodalbail 		goto fail;
6476e91bba0SGirish Moodalbail 	}
6486e91bba0SGirish Moodalbail 
6496e91bba0SGirish Moodalbail 	nv = buf;
6506e91bba0SGirish Moodalbail 	/*
6516e91bba0SGirish Moodalbail 	 * work on one nvpair at a time and extract the name and value
6526e91bba0SGirish Moodalbail 	 */
6536e91bba0SGirish Moodalbail 	sep = ((flags & IPADM_NORVAL) ? IPADM_NAME_SEP : IPADM_NVPAIR_SEP);
6546e91bba0SGirish Moodalbail 	while ((nv = strsep(&buf, sep)) != NULL) {
6556e91bba0SGirish Moodalbail 		if (*nv == '\n')
6566e91bba0SGirish Moodalbail 			continue;
6576e91bba0SGirish Moodalbail 		name = nv;
6586e91bba0SGirish Moodalbail 		if ((val = strchr(nv, '=')) != NULL)
6596e91bba0SGirish Moodalbail 			*val++ = '\0';
6606e91bba0SGirish Moodalbail 		if (*ipnvl == NULL &&
6616e91bba0SGirish Moodalbail 		    (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0)
6626e91bba0SGirish Moodalbail 			goto fail;
6636e91bba0SGirish Moodalbail 		if (nvlist_exists(*ipnvl, name)) {
6646e91bba0SGirish Moodalbail 			err = EEXIST;
6656e91bba0SGirish Moodalbail 			goto fail;
6666e91bba0SGirish Moodalbail 		}
6676e91bba0SGirish Moodalbail 		/* Add the extracted nvpair to the nvlist `ipnvl'. */
6686e91bba0SGirish Moodalbail 		(void) i_ipadm_add_nvpair(*ipnvl, name, val);
6696e91bba0SGirish Moodalbail 	}
6706e91bba0SGirish Moodalbail 	free(cp);
6716e91bba0SGirish Moodalbail 	return (0);
6726e91bba0SGirish Moodalbail fail:
6736e91bba0SGirish Moodalbail 	free(cp);
6746e91bba0SGirish Moodalbail 	nvlist_free(*ipnvl);
6756e91bba0SGirish Moodalbail 	*ipnvl = NULL;
6766e91bba0SGirish Moodalbail 	return (err);
6776e91bba0SGirish Moodalbail }
6786e91bba0SGirish Moodalbail 
6796e91bba0SGirish Moodalbail /*
6806e91bba0SGirish Moodalbail  * Opens the data store for read/write operation. For write operation we open
6816e91bba0SGirish Moodalbail  * another file and scribble the changes to it and copy the new file back to
6826e91bba0SGirish Moodalbail  * old file.
6836e91bba0SGirish Moodalbail  */
6846e91bba0SGirish Moodalbail int
6856e91bba0SGirish Moodalbail ipadm_rw_db(db_wfunc_t *db_walk_func, void *arg, const char *db_file,
6866e91bba0SGirish Moodalbail     mode_t db_perms, ipadm_db_op_t db_op)
6876e91bba0SGirish Moodalbail {
6886e91bba0SGirish Moodalbail 	FILE		*fp, *nfp = NULL;
6896e91bba0SGirish Moodalbail 	char		file[MAXPATHLEN];
6906e91bba0SGirish Moodalbail 	char		newfile[MAXPATHLEN];
6916e91bba0SGirish Moodalbail 	int		nfd;
6926e91bba0SGirish Moodalbail 	boolean_t	writeop;
6936e91bba0SGirish Moodalbail 	int		err = 0;
6946e91bba0SGirish Moodalbail 
6956e91bba0SGirish Moodalbail 	writeop = (db_op != IPADM_DB_READ);
6966e91bba0SGirish Moodalbail 
6976e91bba0SGirish Moodalbail 	(void) snprintf(file, MAXPATHLEN, "%s/%s", ipadm_rootdir, db_file);
6986e91bba0SGirish Moodalbail 
6996e91bba0SGirish Moodalbail 	/* open the data store */
7006e91bba0SGirish Moodalbail 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL)
7016e91bba0SGirish Moodalbail 		return (errno);
7026e91bba0SGirish Moodalbail 
7036e91bba0SGirish Moodalbail 	if (writeop) {
7046e91bba0SGirish Moodalbail 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
7056e91bba0SGirish Moodalbail 		    ipadm_rootdir, db_file);
7066e91bba0SGirish Moodalbail 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
7076e91bba0SGirish Moodalbail 		    db_perms)) < 0) {
7086e91bba0SGirish Moodalbail 			err = errno;
7096e91bba0SGirish Moodalbail 			(void) fclose(fp);
7106e91bba0SGirish Moodalbail 			return (err);
7116e91bba0SGirish Moodalbail 		}
7126e91bba0SGirish Moodalbail 
7136e91bba0SGirish Moodalbail 		if ((nfp = fdopen(nfd, "w")) == NULL) {
7146e91bba0SGirish Moodalbail 			err = errno;
7156e91bba0SGirish Moodalbail 			(void) close(nfd);
7166e91bba0SGirish Moodalbail 			(void) fclose(fp);
7176e91bba0SGirish Moodalbail 			(void) unlink(newfile);
7186e91bba0SGirish Moodalbail 			return (err);
7196e91bba0SGirish Moodalbail 		}
7206e91bba0SGirish Moodalbail 	}
7216e91bba0SGirish Moodalbail 	err = ipadm_process_db_line(db_walk_func, arg, fp, nfp, db_op);
7226e91bba0SGirish Moodalbail 	if (!writeop)
7236e91bba0SGirish Moodalbail 		goto done;
7246e91bba0SGirish Moodalbail 	if (err != 0 && err != ENOENT)
7256e91bba0SGirish Moodalbail 		goto done;
7266e91bba0SGirish Moodalbail 
7276e91bba0SGirish Moodalbail 	if (fflush(nfp) == EOF) {
7286e91bba0SGirish Moodalbail 		err = errno;
7296e91bba0SGirish Moodalbail 		goto done;
7306e91bba0SGirish Moodalbail 	}
7316e91bba0SGirish Moodalbail 	(void) fclose(fp);
7326e91bba0SGirish Moodalbail 	(void) fclose(nfp);
7336e91bba0SGirish Moodalbail 
7346e91bba0SGirish Moodalbail 	if (rename(newfile, file) < 0) {
7356e91bba0SGirish Moodalbail 		err = errno;
7366e91bba0SGirish Moodalbail 		(void) unlink(newfile);
7376e91bba0SGirish Moodalbail 	}
7386e91bba0SGirish Moodalbail 	return (err);
7396e91bba0SGirish Moodalbail done:
7406e91bba0SGirish Moodalbail 	if (nfp != NULL) {
7416e91bba0SGirish Moodalbail 		(void) fclose(nfp);
7426e91bba0SGirish Moodalbail 		if (err != 0)
7436e91bba0SGirish Moodalbail 			(void) unlink(newfile);
7446e91bba0SGirish Moodalbail 	}
7456e91bba0SGirish Moodalbail 	(void) fclose(fp);
7466e91bba0SGirish Moodalbail 	return (err);
7476e91bba0SGirish Moodalbail }
7486e91bba0SGirish Moodalbail 
7496e91bba0SGirish Moodalbail /*
7506e91bba0SGirish Moodalbail  * Processes each line of the configuration file, skipping lines with
7516e91bba0SGirish Moodalbail  * leading spaces, blank lines and comments. The line form the DB
7526e91bba0SGirish Moodalbail  * is converted to nvlist and the callback function is called to process
7536e91bba0SGirish Moodalbail  * the list. The buf could be modified by the callback function and
7546e91bba0SGirish Moodalbail  * if this is a write operation and buf is not truncated, buf will
7556e91bba0SGirish Moodalbail  * be written to disk.
7566e91bba0SGirish Moodalbail  *
7576e91bba0SGirish Moodalbail  * Further if cont is set to B_FALSE,  the remainder of the file will
7586e91bba0SGirish Moodalbail  * continue to be read (however callback function will not be called) and,
7596e91bba0SGirish Moodalbail  * if necessary, written to disk as well.
7606e91bba0SGirish Moodalbail  */
7616e91bba0SGirish Moodalbail static int
7626e91bba0SGirish Moodalbail ipadm_process_db_line(db_wfunc_t *db_walk_func, void *arg, FILE *fp, FILE *nfp,
7636e91bba0SGirish Moodalbail     ipadm_db_op_t db_op)
7646e91bba0SGirish Moodalbail {
7656e91bba0SGirish Moodalbail 	int		err = 0;
7666e91bba0SGirish Moodalbail 	char		buf[MAXLINELEN];
7676e91bba0SGirish Moodalbail 	boolean_t	cont = B_TRUE;
7686e91bba0SGirish Moodalbail 	int		i, len;
7696e91bba0SGirish Moodalbail 	nvlist_t	*db_nvl = NULL;
7706e91bba0SGirish Moodalbail 	boolean_t	line_deleted = B_FALSE;
7716e91bba0SGirish Moodalbail 
7726e91bba0SGirish Moodalbail 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
7736e91bba0SGirish Moodalbail 		/*
7746e91bba0SGirish Moodalbail 		 * Skip leading spaces, blank lines, and comments.
7756e91bba0SGirish Moodalbail 		 */
7766e91bba0SGirish Moodalbail 		len = strnlen(buf, MAXLINELEN);
7776e91bba0SGirish Moodalbail 		for (i = 0; i < len; i++) {
7786e91bba0SGirish Moodalbail 			if (!isspace(buf[i]))
7796e91bba0SGirish Moodalbail 				break;
7806e91bba0SGirish Moodalbail 		}
7816e91bba0SGirish Moodalbail 
7826e91bba0SGirish Moodalbail 		if (i != len && buf[i] != '#' && cont) {
7836e91bba0SGirish Moodalbail 			if (ipadm_str2nvlist(buf, &db_nvl, 0) == 0) {
7846e91bba0SGirish Moodalbail 				cont = db_walk_func(arg, db_nvl, buf,
7856e91bba0SGirish Moodalbail 				    MAXLINELEN, &err);
7866e91bba0SGirish Moodalbail 			} else {
7876e91bba0SGirish Moodalbail 				/* Delete corrupted line. */
7886e91bba0SGirish Moodalbail 				buf[0] = '\0';
7896e91bba0SGirish Moodalbail 			}
7906e91bba0SGirish Moodalbail 			nvlist_free(db_nvl);
7916e91bba0SGirish Moodalbail 			db_nvl = NULL;
7926e91bba0SGirish Moodalbail 		}
7936e91bba0SGirish Moodalbail 		if (err != 0)
7946e91bba0SGirish Moodalbail 			break;
7956e91bba0SGirish Moodalbail 		if (nfp != NULL && buf[0] == '\0')
7966e91bba0SGirish Moodalbail 			line_deleted = B_TRUE;
7976e91bba0SGirish Moodalbail 		if (nfp != NULL	&& buf[0] != '\0' && fputs(buf, nfp) == EOF) {
7986e91bba0SGirish Moodalbail 			err = errno;
7996e91bba0SGirish Moodalbail 			break;
8006e91bba0SGirish Moodalbail 		}
8016e91bba0SGirish Moodalbail 	}
8026e91bba0SGirish Moodalbail 
8036e91bba0SGirish Moodalbail 	if (err != 0 || !cont)
8046e91bba0SGirish Moodalbail 		return (err);
8056e91bba0SGirish Moodalbail 
8066e91bba0SGirish Moodalbail 	if (db_op == IPADM_DB_WRITE) {
807*8887b57dSGirish Moodalbail 		nvlist_t	*nvl;
8086e91bba0SGirish Moodalbail 
8096e91bba0SGirish Moodalbail 		/*
810*8887b57dSGirish Moodalbail 		 * `arg' will be NULL when we are doing in-line update of
811*8887b57dSGirish Moodalbail 		 * entries.
812*8887b57dSGirish Moodalbail 		 */
813*8887b57dSGirish Moodalbail 		if (arg != NULL) {
814*8887b57dSGirish Moodalbail 			nvl = ((ipadm_dbwrite_cbarg_t *)arg)->dbw_nvl;
815*8887b57dSGirish Moodalbail 			/*
8166e91bba0SGirish Moodalbail 			 * If the specified entry is not found above, we add
8176e91bba0SGirish Moodalbail 			 * the entry to the configuration file, here.
8186e91bba0SGirish Moodalbail 			 */
8196e91bba0SGirish Moodalbail 			(void) memset(buf, 0, MAXLINELEN);
8206e91bba0SGirish Moodalbail 			if (ipadm_nvlist2str(nvl, buf, MAXLINELEN) == 0)
8216e91bba0SGirish Moodalbail 				err = ENOBUFS;
8226e91bba0SGirish Moodalbail 			else if (fputs(buf, nfp) == EOF)
8236e91bba0SGirish Moodalbail 				err = errno;
824*8887b57dSGirish Moodalbail 		}
8256e91bba0SGirish Moodalbail 		return (err);
8266e91bba0SGirish Moodalbail 	}
8276e91bba0SGirish Moodalbail 
8286e91bba0SGirish Moodalbail 	if (db_op == IPADM_DB_DELETE && line_deleted)
8296e91bba0SGirish Moodalbail 		return (0);
8306e91bba0SGirish Moodalbail 
8316e91bba0SGirish Moodalbail 	/* if we have come this far, then we didn't find any match */
8326e91bba0SGirish Moodalbail 	return (ENOENT);
8336e91bba0SGirish Moodalbail }
834