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