#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dld.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include "libipadm_impl.h"
#define MAXLINELEN 1024
#define IPADM_NVPAIR_SEP ";"
#define IPADM_NAME_SEP ","
static char ipadm_rootdir[MAXPATHLEN] = "/";
static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
ipadm_db_op_t);
typedef size_t ipadm_wfunc_t(nvpair_t *, char *, size_t);
typedef ipadm_status_t ipadm_rfunc_t(nvlist_t *, char *, char *);
static ipadm_rfunc_t i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
i_ipadm_dhcp_dbline2nvl, i_ipadm_families_dbline2nvl,
i_ipadm_groupmembers_dbline2nvl;
static ipadm_wfunc_t i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
i_ipadm_dhcp_nvp2dbline, i_ipadm_families_nvp2dbline,
i_ipadm_groupmembers_nvp2dbline;
typedef struct ipadm_conf_ent_s {
const char *ipent_type_name;
ipadm_wfunc_t *ipent_wfunc;
ipadm_rfunc_t *ipent_rfunc;
} ipadm_conf_ent_t;
static ipadm_conf_ent_t ipadm_conf_ent[] = {
{ IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
{ IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
{ IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
i_ipadm_intfid_dbline2nvl },
{ IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
{ IPADM_NVP_FAMILIES, i_ipadm_families_nvp2dbline,
i_ipadm_families_dbline2nvl },
{ IPADM_NVP_MIFNAMES, i_ipadm_groupmembers_nvp2dbline,
i_ipadm_groupmembers_dbline2nvl},
{ NULL, i_ipadm_str_nvp2dbline, i_ipadm_str_dbline2nvl }
};
static ipadm_conf_ent_t *
i_ipadm_find_conf_type(const char *type)
{
int i;
for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
break;
return (&ipadm_conf_ent[i]);
}
size_t
i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
{
char *cp;
char tmpbuf[IPADM_STRSIZE];
if (nvlist_lookup_string(nvl, IPADM_NVP_IPADDRHNAME, &cp) != 0)
return (0);
(void) strlcat(buf, cp, buflen);
if (nvlist_lookup_string(nvl, IPADM_NVP_IPDADDRHNAME, &cp) != 0) {
(void) snprintf(tmpbuf, sizeof (tmpbuf), ",");
} else {
(void) snprintf(tmpbuf, sizeof (tmpbuf), ",%s", cp);
}
return (strlcat(buf, tmpbuf, buflen));
}
static size_t
i_ipadm_ip4_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
nvlist_t *v;
int nbytes;
assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
strcmp(nvpair_name(nvp), IPADM_NVP_IPV4ADDR) == 0);
(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV4ADDR);
if (nvpair_value_nvlist(nvp, &v) != 0)
goto fail;
nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
if (nbytes != 0)
return (nbytes);
fail:
buf[0] = '\0';
return (0);
}
static size_t
i_ipadm_ip6_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
nvlist_t *v;
int nbytes;
assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
strcmp(nvpair_name(nvp), IPADM_NVP_IPV6ADDR) == 0);
(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV6ADDR);
if (nvpair_value_nvlist(nvp, &v) != 0)
goto fail;
nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
if (nbytes != 0)
return (nbytes);
fail:
buf[0] = '\0';
return (0);
}
static size_t
i_ipadm_intfid_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
char addrbuf[IPADM_STRSIZE];
nvlist_t *v;
uint32_t prefixlen;
struct in6_addr in6addr;
char *stateless;
char *stateful;
assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
strcmp(nvpair_name(nvp), IPADM_NVP_INTFID) == 0);
(void) snprintf(buf, buflen, "%s=", IPADM_NVP_INTFID);
if (nvpair_value_nvlist(nvp, &v) != 0)
goto fail;
if (i_ipadm_nvl2in6_addr(v, IPADM_NVP_IPNUMADDR, &in6addr) !=
IPADM_SUCCESS)
goto fail;
(void) inet_ntop(AF_INET6, &in6addr, addrbuf,
sizeof (addrbuf));
(void) strlcat(buf, addrbuf, buflen);
if (nvlist_lookup_uint32(v, IPADM_NVP_PREFIXLEN, &prefixlen) != 0 ||
nvlist_lookup_string(v, IPADM_NVP_STATELESS, &stateless) != 0 ||
nvlist_lookup_string(v, IPADM_NVP_STATEFUL, &stateful) != 0)
goto fail;
(void) snprintf(addrbuf, sizeof (addrbuf), "/%d,%s,%s",
prefixlen, stateless, stateful);
return (strlcat(buf, addrbuf, buflen));
fail:
buf[0] = '\0';
return (0);
}
static size_t
i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
char addrbuf[IPADM_STRSIZE];
int32_t wait;
boolean_t primary;
nvlist_t *v;
assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
strcmp(nvpair_name(nvp), IPADM_NVP_DHCP) == 0);
if (nvpair_value_nvlist(nvp, &v) != 0 ||
nvlist_lookup_int32(v, IPADM_NVP_WAIT, &wait) != 0 ||
nvlist_lookup_boolean_value(v, IPADM_NVP_PRIMARY, &primary) != 0) {
return (0);
}
(void) snprintf(buf, buflen, "%s=", IPADM_NVP_DHCP);
(void) snprintf(addrbuf, sizeof (addrbuf), "%d,%s", wait,
(primary ? "yes" : "no"));
return (strlcat(buf, addrbuf, buflen));
}
static size_t
i_ipadm_str_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
char *str = NULL;
assert(nvpair_type(nvp) == DATA_TYPE_STRING);
if (nvpair_value_string(nvp, &str) != 0)
return (0);
return (snprintf(buf, buflen, "%s=%s", nvpair_name(nvp), str));
}
size_t
ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
{
nvpair_t *nvp = NULL;
uint_t nbytes = 0, tbytes = 0;
ipadm_conf_ent_t *ipent;
size_t bufsize = buflen;
for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(nvl, nvp)) {
ipent = i_ipadm_find_conf_type(nvpair_name(nvp));
nbytes = (*ipent->ipent_wfunc)(nvp, buf, buflen);
nbytes += snprintf(buf + nbytes, buflen - nbytes, "%s",
IPADM_NVPAIR_SEP);
buflen -= nbytes;
buf += nbytes;
tbytes += nbytes;
if (tbytes >= bufsize)
return (0);
}
nbytes = snprintf(buf, buflen, "%c%c", '\n', '\0');
tbytes += nbytes;
if (tbytes >= bufsize)
return (0);
return (tbytes);
}
static ipadm_status_t
i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
{
ipadm_conf_ent_t *ipent;
ipent = i_ipadm_find_conf_type(name);
return ((*ipent->ipent_rfunc)(nvl, name, value));
}
ipadm_status_t
i_ipadm_add_ipaddr2nvl(nvlist_t *nvl, ipadm_addrobj_t ipaddr)
{
nvlist_t *nvl_addr = NULL;
int err;
char *name;
sa_family_t af = ipaddr->ipadm_af;
if (af == AF_INET) {
name = IPADM_NVP_IPV4ADDR;
} else {
assert(af == AF_INET6);
name = IPADM_NVP_IPV6ADDR;
}
if (!nvlist_exists(nvl, name)) {
if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
return (ipadm_errno2status(err));
if ((err = nvlist_add_nvlist(nvl, name, nvl_addr)) != 0) {
nvlist_free(nvl_addr);
return (ipadm_errno2status(err));
}
nvlist_free(nvl_addr);
}
if ((err = nvlist_lookup_nvlist(nvl, name, &nvl_addr)) != 0 ||
(err = nvlist_add_string(nvl_addr, IPADM_NVP_IPADDRHNAME,
ipaddr->ipadm_static_aname)) != 0)
return (ipadm_errno2status(err));
if (ipaddr->ipadm_static_dname[0] != '\0') {
if ((err = nvlist_add_string(nvl_addr, IPADM_NVP_IPDADDRHNAME,
ipaddr->ipadm_static_dname)) != 0)
return (ipadm_errno2status(err));
}
return (IPADM_SUCCESS);
}
ipadm_status_t
i_ipadm_add_intfid2nvl(nvlist_t *nvl, ipadm_addrobj_t addr)
{
nvlist_t *nvl_addr = NULL;
struct in6_addr addr6;
int err;
if (!nvlist_exists(nvl, IPADM_NVP_INTFID)) {
if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
return (ipadm_errno2status(err));
if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_INTFID,
nvl_addr)) != 0) {
nvlist_free(nvl_addr);
return (ipadm_errno2status(err));
}
nvlist_free(nvl_addr);
}
if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID,
&nvl_addr)) != 0 || (err = nvlist_add_uint32(nvl_addr,
IPADM_NVP_PREFIXLEN, addr->ipadm_intfidlen)) != 0) {
return (ipadm_errno2status(err));
}
addr6 = addr->ipadm_intfid.sin6_addr;
if ((err = nvlist_add_uint8_array(nvl_addr, IPADM_NVP_IPNUMADDR,
addr6.s6_addr, 16)) != 0) {
return (ipadm_errno2status(err));
}
if (addr->ipadm_stateless)
err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "yes");
else
err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "no");
if (err != 0)
return (ipadm_errno2status(err));
if (addr->ipadm_stateful)
err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "yes");
else
err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "no");
if (err != 0)
return (ipadm_errno2status(err));
return (IPADM_SUCCESS);
}
ipadm_status_t
i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
{
nvlist_t *nvl_dhcp = NULL;
int err;
if (!nvlist_exists(nvl, IPADM_NVP_DHCP)) {
if ((err = nvlist_alloc(&nvl_dhcp, NV_UNIQUE_NAME, 0)) != 0)
return (ipadm_errno2status(err));
if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_DHCP,
nvl_dhcp)) != 0) {
nvlist_free(nvl_dhcp);
return (ipadm_errno2status(err));
}
nvlist_free(nvl_dhcp);
}
if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvl_dhcp)) != 0 ||
(err = nvlist_add_int32(nvl_dhcp, IPADM_NVP_WAIT, wait)) != 0 ||
(err = nvlist_add_boolean_value(nvl_dhcp, IPADM_NVP_PRIMARY,
primary)) != 0) {
return (ipadm_errno2status(err));
}
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
int err;
if (value == NULL)
err = nvlist_add_string(nvl, name, "");
else
err = nvlist_add_string(nvl, name, value);
return (ipadm_errno2status(err));
}
static ipadm_status_t
i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp, *hname;
struct ipadm_addrobj_s ipaddr;
assert(strcmp(name, IPADM_NVP_IPV4ADDR) == 0 && value != NULL);
bzero(&ipaddr, sizeof (ipaddr));
ipaddr.ipadm_af = AF_INET;
hname = value;
cp = strchr(hname, ',');
assert(cp != NULL);
*cp++ = '\0';
(void) strlcpy(ipaddr.ipadm_static_aname, hname,
sizeof (ipaddr.ipadm_static_aname));
if (*cp != '\0') {
(void) strlcpy(ipaddr.ipadm_static_dname, cp,
sizeof (ipaddr.ipadm_static_dname));
}
return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
}
static ipadm_status_t
i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp, *hname;
struct ipadm_addrobj_s ipaddr;
assert(strcmp(name, IPADM_NVP_IPV6ADDR) == 0 && value != NULL);
bzero(&ipaddr, sizeof (ipaddr));
ipaddr.ipadm_af = AF_INET6;
hname = value;
cp = strchr(hname, ',');
assert(cp != NULL);
*cp++ = '\0';
(void) strlcpy(ipaddr.ipadm_static_aname, hname,
sizeof (ipaddr.ipadm_static_aname));
if (*cp != '\0') {
(void) strlcpy(ipaddr.ipadm_static_dname, cp,
sizeof (ipaddr.ipadm_static_dname));
}
return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
}
static ipadm_status_t
i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp;
struct ipadm_addrobj_s ipaddr;
char *endp;
char *prefixlen;
char *stateless;
char *stateful;
assert(strcmp(name, IPADM_NVP_INTFID) == 0 && value != NULL);
bzero(&ipaddr, sizeof (ipaddr));
cp = strchr(value, '/');
assert(cp != NULL);
*cp++ = '\0';
ipaddr.ipadm_intfid.sin6_family = AF_INET6;
(void) inet_pton(AF_INET6, value, &ipaddr.ipadm_intfid.sin6_addr);
prefixlen = cp;
cp = strchr(cp, ',');
assert(cp != NULL);
*cp++ = '\0';
errno = 0;
ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
if (*endp != '\0' || errno != 0)
return (ipadm_errno2status(errno));
stateless = cp;
stateful = strchr(stateless, ',');
assert(stateful != NULL);
*stateful++ = '\0';
ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
return (i_ipadm_add_intfid2nvl(nvl, &ipaddr));
}
static ipadm_status_t
i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp;
char *endp;
long wait_time;
boolean_t primary;
assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
cp = strchr(value, ',');
assert(cp != NULL);
*cp++ = '\0';
errno = 0;
wait_time = strtol(value, &endp, 10);
if (*endp != '\0' || errno != 0)
return (ipadm_errno2status(errno));
primary = (strcmp(cp, "yes") == 0);
return (i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time));
}
static size_t
i_ipadm_families_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
uint_t nelem = 0;
uint16_t *elem;
assert(nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY);
if (nvpair_value_uint16_array(nvp,
&elem, &nelem) != 0) {
buf[0] = '\0';
return (0);
}
assert(nelem != 0 || nelem > 2);
if (nelem == 1) {
return (snprintf(buf, buflen, "%s=%d",
nvpair_name(nvp), elem[0]));
} else {
return (snprintf(buf, buflen, "%s=%d,%d",
nvpair_name(nvp), elem[0], elem[1]));
}
}
static ipadm_status_t
i_ipadm_families_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
uint16_t families[2];
uint_t nelem = 0;
char *val, *lasts;
if ((val = strtok_r(value,
",", &lasts)) != NULL) {
families[0] = atoi(val);
nelem++;
if ((val = strtok_r(NULL,
",", &lasts)) != NULL) {
families[1] = atoi(val);
nelem++;
}
return (ipadm_errno2status(nvlist_add_uint16_array(nvl,
IPADM_NVP_FAMILIES, families, nelem)));
}
return (IPADM_INVALID_ARG);
}
static size_t
i_ipadm_groupmembers_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
uint_t nelem = 0;
char **elem;
size_t n;
assert(nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY);
if (nvpair_value_string_array(nvp,
&elem, &nelem) != 0) {
buf[0] = '\0';
return (0);
}
assert(nelem != 0);
n = snprintf(buf, buflen, "%s=", IPADM_NVP_MIFNAMES);
if (n >= buflen)
return (n);
while (nelem-- > 0) {
n = strlcat(buf, elem[nelem], buflen);
if (nelem > 0)
n = strlcat(buf, ",", buflen);
if (n > buflen)
return (n);
}
return (n);
}
static ipadm_status_t
i_ipadm_groupmembers_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char **members = NULL;
char *member = NULL;
char *val, *lasts;
uint_t m_cnt = 0;
ipadm_status_t ret = IPADM_SUCCESS;
assert(strcmp(name, IPADM_NVP_MIFNAMES) == 0 && value != NULL);
for (val = strtok_r(value, ",", &lasts);
val != NULL;
val = strtok_r(NULL, ",", &lasts)) {
if ((m_cnt % 4) == 0) {
char **tmp = recallocarray(members, m_cnt, m_cnt + 4,
sizeof (char *));
if (tmp == NULL) {
ret = IPADM_NO_MEMORY;
goto fail;
}
members = tmp;
}
member = calloc(1, LIFNAMSIZ);
if (member == NULL) {
ret = IPADM_NO_MEMORY;
goto fail;
}
(void) strlcpy(member, val, LIFNAMSIZ);
members[m_cnt++] = member;
}
if ((ret = ipadm_errno2status(nvlist_add_string_array(nvl,
IPADM_NVP_MIFNAMES, members, m_cnt))) != IPADM_SUCCESS)
goto fail;
fail:
while (m_cnt-- > 0) {
free(members[m_cnt]);
}
free(members);
return (ret);
}
ipadm_status_t
ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
{
ipadm_status_t status;
char *nv, *name, *val, *buf, *cp, *sep;
int err;
if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
return (IPADM_INVALID_ARG);
*ipnvl = NULL;
if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
return (IPADM_INVALID_ARG);
if ((cp = buf = strdup(inbuf)) == NULL)
return (ipadm_errno2status(errno));
while (isspace(*buf))
buf++;
if (*buf == '\0') {
status = IPADM_INVALID_ARG;
goto fail;
}
nv = buf;
sep = ((flags & IPADM_NORVAL) ? IPADM_NAME_SEP : IPADM_NVPAIR_SEP);
while ((nv = strsep(&buf, sep)) != NULL) {
if (*nv == '\n')
continue;
name = nv;
if ((val = strchr(nv, '=')) != NULL)
*val++ = '\0';
if (*ipnvl == NULL &&
(err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0) {
status = ipadm_errno2status(err);
goto fail;
}
if (nvlist_exists(*ipnvl, name)) {
status = IPADM_EXISTS;
goto fail;
}
status = i_ipadm_add_nvpair(*ipnvl, name, val);
if (status != IPADM_SUCCESS)
goto fail;
}
free(cp);
return (IPADM_SUCCESS);
fail:
free(cp);
nvlist_free(*ipnvl);
*ipnvl = NULL;
return (status);
}
int
ipadm_rw_db(db_wfunc_t *db_walk_func, void *arg, const char *db_file,
mode_t db_perms, ipadm_db_op_t db_op)
{
FILE *fp, *nfp = NULL;
char file[MAXPATHLEN];
char newfile[MAXPATHLEN];
int nfd;
boolean_t writeop;
int err = 0;
writeop = (db_op != IPADM_DB_READ);
(void) snprintf(file, MAXPATHLEN, "%s/%s", ipadm_rootdir, db_file);
if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL)
return (errno);
if (writeop) {
(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
ipadm_rootdir, db_file);
if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
db_perms)) < 0) {
err = errno;
(void) fclose(fp);
return (err);
}
if ((nfp = fdopen(nfd, "w")) == NULL) {
err = errno;
(void) close(nfd);
(void) fclose(fp);
(void) unlink(newfile);
return (err);
}
}
err = ipadm_process_db_line(db_walk_func, arg, fp, nfp, db_op);
if (!writeop)
goto done;
if (err != 0 && err != ENOENT)
goto done;
if (fflush(nfp) == EOF) {
err = errno;
goto done;
}
(void) fclose(fp);
(void) fclose(nfp);
if (rename(newfile, file) < 0) {
err = errno;
(void) unlink(newfile);
}
return (err);
done:
if (nfp != NULL) {
(void) fclose(nfp);
if (err != 0)
(void) unlink(newfile);
}
(void) fclose(fp);
return (err);
}
static int
ipadm_process_db_line(db_wfunc_t *db_walk_func, void *arg, FILE *fp, FILE *nfp,
ipadm_db_op_t db_op)
{
int err = 0;
char buf[MAXLINELEN];
boolean_t cont = B_TRUE;
int i, len;
nvlist_t *db_nvl = NULL;
boolean_t line_deleted = B_FALSE;
while (fgets(buf, MAXLINELEN, fp) != NULL) {
len = strnlen(buf, MAXLINELEN);
for (i = 0; i < len; i++) {
if (!isspace(buf[i]))
break;
}
if (i != len && buf[i] != '#' && cont) {
if (ipadm_str2nvlist(buf, &db_nvl, 0) == 0) {
cont = db_walk_func(arg, db_nvl, buf,
MAXLINELEN, &err);
} else {
buf[0] = '\0';
}
nvlist_free(db_nvl);
db_nvl = NULL;
}
if (err != 0)
break;
if (nfp != NULL && buf[0] == '\0')
line_deleted = B_TRUE;
if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
err = errno;
break;
}
}
if (err != 0 || !cont)
return (err);
if (db_op == IPADM_DB_WRITE) {
nvlist_t *nvl;
if (arg != NULL) {
nvl = ((ipadm_dbwrite_cbarg_t *)arg)->dbw_nvl;
(void) memset(buf, 0, MAXLINELEN);
if (ipadm_nvlist2str(nvl, buf, MAXLINELEN) == 0)
err = ENOBUFS;
else if (fputs(buf, nfp) == EOF)
err = errno;
}
return (err);
}
if (db_op == IPADM_DB_DELETE && line_deleted)
return (0);
return (ENOENT);
}