comparison usr/src/lib/libipadm/common/ipadm_persist.c @ 12016:0248e987199b

PSARC 2009/306 Brussels II - ipadm and libipadm PSARC 2010/080 Brussels II addendum 6827318 Brussels Phase II aka ipadm(1m) 6731945 need BSD getifaddrs() API 6909065 explicitly disallow non-contiguous netmasks in the next minor release 6853922 ifconfig dumps core when ether address is non-hexadecimal. 6815806 ipReasmTimeout value should be variable 6567083 nd_getset has some dead and confusing code. 6884466 remove unused tcp/sctp ndd tunables 6928813 Comments at odds with default value of tcp_time_wait_interval 6236982 ifconfig usesrc lets adapter use itself as source address 6936855 modifying the ip6_strict_src_multihoming to non-zero value will unbind V4 IREs
author Girish Moodalbail <Girish.Moodalbail@Sun.COM>
date Fri, 26 Mar 2010 17:53:11 -0400
parents
children 9b5ab8584c21
comparison
equal deleted inserted replaced
12015:63716a810520 12016:0248e987199b
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This file contains routines to read/write formatted entries from/to
28 * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
29 * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
30 * below:
31 * name=value[;...]
32 *
33 * The 'name' determines how to interpret 'value'. The supported names are:
34 *
35 * IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
36 * converted to nvlist, will contain nvpairs for local and remote
37 * addresses. These nvpairs are of type DATA_TYPE_STRING
38 *
39 * IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
40 * converted to nvlist, will contain nvpairs for local and remote
41 * addresses. These nvpairs are of type DATA_TYPE_STRING
42 *
43 * IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
44 * info and when converted to nvlist, will contain following nvpairs
45 * interface_id: DATA_TYPE_UINT8_ARRAY
46 * prefixlen: DATA_TYPE_UINT32
47 * stateless: DATA_TYPE_STRING
48 * stateful: DATA_TYPE_STRING
49 *
50 * IPADM_NVP_DHCP - value holds wait time and primary info and when converted
51 * to nvlist, will contain following nvpairs
52 * wait: DATA_TYPE_INT32
53 * primary: DATA_TYPE_BOOLEAN
54 *
55 * default - value is a single entity and when converted to nvlist, will
56 * contain nvpair of type DATA_TYPE_STRING. nvpairs private to
57 * ipadm are of this type. Further the property name and property
58 * values are stored as nvpairs of this type.
59 *
60 * The syntax for each line is described above the respective functions below.
61 */
62
63 #include <stdlib.h>
64 #include <strings.h>
65 #include <errno.h>
66 #include <ctype.h>
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <sys/dld.h>
70 #include <fcntl.h>
71 #include <dirent.h>
72 #include <unistd.h>
73 #include <assert.h>
74 #include <sys/socket.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <sys/sockio.h>
78 #include "libipadm_impl.h"
79
80 #define MAXLINELEN 1024
81 #define IPADM_NVPAIR_SEP ";"
82 #define IPADM_NAME_SEP ","
83
84 static char ipadm_rootdir[MAXPATHLEN] = "/";
85
86 static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
87 ipadm_db_op_t);
88
89 /*
90 * convert nvpair to a "name=value" string for writing to the DB.
91 */
92 typedef size_t ipadm_wfunc_t(nvpair_t *, char *, size_t);
93
94 /*
95 * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
96 * nvpair to the nvlist.
97 */
98 typedef void ipadm_rfunc_t(nvlist_t *, char *name, char *value);
99
100 static ipadm_rfunc_t i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
101 i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
102 i_ipadm_dhcp_dbline2nvl;
103
104 static ipadm_wfunc_t i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
105 i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
106 i_ipadm_dhcp_nvp2dbline;
107
108 /*
109 * table of function pointers to read/write formatted entries from/to
110 * ipadm.conf.
111 */
112 typedef struct ipadm_conf_ent_s {
113 const char *ipent_type_name;
114 ipadm_wfunc_t *ipent_wfunc;
115 ipadm_rfunc_t *ipent_rfunc;
116 } ipadm_conf_ent_t;
117
118 static ipadm_conf_ent_t ipadm_conf_ent[] = {
119 { IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
120 { IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
121 { IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
122 i_ipadm_intfid_dbline2nvl },
123 { IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
124 { NULL, i_ipadm_str_nvp2dbline, i_ipadm_str_dbline2nvl }
125 };
126
127 static ipadm_conf_ent_t *
128 i_ipadm_find_conf_type(const char *type)
129 {
130 int i;
131
132 for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
133 if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
134 break;
135 return (&ipadm_conf_ent[i]);
136 }
137
138 /*
139 * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
140 * the given nvlist `nvl' and adds the strings to `buf'.
141 */
142 size_t
143 i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
144 {
145 char *cp;
146 char tmpbuf[IPADM_STRSIZE];
147
148 /* Add the local hostname */
149 if (nvlist_lookup_string(nvl, IPADM_NVP_IPADDRHNAME, &cp) != 0)
150 return (0);
151 (void) strlcat(buf, cp, buflen); /* local hostname */
152
153 /* Add the dst hostname */
154 if (nvlist_lookup_string(nvl, IPADM_NVP_IPDADDRHNAME, &cp) != 0) {
155 /* no dst addr. just add a NULL character */
156 (void) snprintf(tmpbuf, sizeof (tmpbuf), ",");
157 } else {
158 (void) snprintf(tmpbuf, sizeof (tmpbuf), ",%s", cp);
159 }
160 return (strlcat(buf, tmpbuf, buflen));
161 }
162
163 /*
164 * Converts IPADM_NVP_IPV4ADDR nvpair to a string representation for writing to
165 * the DB. The converted string format:
166 * ipv4addr=<local numeric IP string or hostname,remote numeric IP
167 * string or hostname>
168 */
169 static size_t
170 i_ipadm_ip4_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
171 {
172 nvlist_t *v;
173 int nbytes;
174
175 assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
176 strcmp(nvpair_name(nvp), IPADM_NVP_IPV4ADDR) == 0);
177
178 (void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV4ADDR);
179 if (nvpair_value_nvlist(nvp, &v) != 0)
180 goto fail;
181 nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
182 if (nbytes != 0)
183 return (nbytes);
184 fail:
185 buf[0] = '\0';
186 return (0);
187 }
188
189 /*
190 * Converts IPADM_NVP_IPV6ADDR nvpair to a string representation for writing to
191 * the DB. The converted string format:
192 * ipv6addr=<local numeric IP string or hostname,remote numeric IP
193 * string or hostname>
194 */
195 static size_t
196 i_ipadm_ip6_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
197 {
198 nvlist_t *v;
199 int nbytes;
200
201 assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
202 strcmp(nvpair_name(nvp), IPADM_NVP_IPV6ADDR) == 0);
203
204 (void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV6ADDR);
205 if (nvpair_value_nvlist(nvp, &v) != 0)
206 goto fail;
207 nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
208 if (nbytes != 0)
209 return (nbytes);
210 fail:
211 buf[0] = '\0';
212 return (0);
213 }
214
215 /*
216 * Converts IPADM_NVP_INTFID nvpair to a string representation for writing to
217 * the DB. The converted string format:
218 * IPADM_NVP_INTFID=<intfid/prefixlen>,{yes|no},{yes|no}
219 */
220 static size_t
221 i_ipadm_intfid_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
222 {
223 char addrbuf[IPADM_STRSIZE];
224 nvlist_t *v;
225 uint32_t prefixlen;
226 struct in6_addr in6addr;
227 char *stateless;
228 char *stateful;
229
230 assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
231 strcmp(nvpair_name(nvp), IPADM_NVP_INTFID) == 0);
232
233 (void) snprintf(buf, buflen, "%s=", IPADM_NVP_INTFID);
234 if (nvpair_value_nvlist(nvp, &v) != 0)
235 goto fail;
236 if (i_ipadm_nvl2in6_addr(v, IPADM_NVP_IPNUMADDR, &in6addr) !=
237 IPADM_SUCCESS)
238 goto fail;
239 (void) inet_ntop(AF_INET6, &in6addr, addrbuf,
240 sizeof (addrbuf));
241 (void) strlcat(buf, addrbuf, buflen);
242 if (nvlist_lookup_uint32(v, IPADM_NVP_PREFIXLEN, &prefixlen) != 0 ||
243 nvlist_lookup_string(v, IPADM_NVP_STATELESS, &stateless) != 0 ||
244 nvlist_lookup_string(v, IPADM_NVP_STATEFUL, &stateful) != 0)
245 goto fail;
246 (void) snprintf(addrbuf, sizeof (addrbuf), "/%d,%s,%s",
247 prefixlen, stateless, stateful);
248 return (strlcat(buf, addrbuf, buflen));
249 fail:
250 buf[0] = '\0';
251 return (0);
252 }
253
254 /*
255 * Converts IPADM_NVP_DHCP nvpair to a string representation for writing to the
256 * DB. The converted string format:
257 * IPADM_NVP_DHCP=<wait_time>,{yes|no}
258 */
259 static size_t
260 i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
261 {
262 char addrbuf[IPADM_STRSIZE];
263 int32_t wait;
264 boolean_t primary;
265 nvlist_t *v;
266
267 assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
268 strcmp(nvpair_name(nvp), IPADM_NVP_DHCP) == 0);
269
270 if (nvpair_value_nvlist(nvp, &v) != 0 ||
271 nvlist_lookup_int32(v, IPADM_NVP_WAIT, &wait) != 0 ||
272 nvlist_lookup_boolean_value(v, IPADM_NVP_PRIMARY, &primary) != 0) {
273 return (0);
274 }
275 (void) snprintf(buf, buflen, "%s=", IPADM_NVP_DHCP);
276 (void) snprintf(addrbuf, sizeof (addrbuf), "%d,%s", wait,
277 (primary ? "yes" : "no"));
278 return (strlcat(buf, addrbuf, buflen));
279 }
280
281 /*
282 * Constructs a "<name>=<value>" string from the nvpair, whose type must
283 * be STRING.
284 */
285 static size_t
286 i_ipadm_str_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
287 {
288 char *str = NULL;
289
290 assert(nvpair_type(nvp) == DATA_TYPE_STRING);
291 if (nvpair_value_string(nvp, &str) != 0)
292 return (0);
293 return (snprintf(buf, buflen, "%s=%s", nvpair_name(nvp), str));
294 }
295
296 /*
297 * Converts a nvlist to string of the form:
298 * <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
299 */
300 size_t
301 ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
302 {
303 nvpair_t *nvp = NULL;
304 uint_t nbytes = 0, tbytes = 0;
305 ipadm_conf_ent_t *ipent;
306 size_t bufsize = buflen;
307
308 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
309 nvp = nvlist_next_nvpair(nvl, nvp)) {
310 ipent = i_ipadm_find_conf_type(nvpair_name(nvp));
311 nbytes = (*ipent->ipent_wfunc)(nvp, buf, buflen);
312 /* add nvpair separator */
313 nbytes += snprintf(buf + nbytes, buflen - nbytes, "%s",
314 IPADM_NVPAIR_SEP);
315 buflen -= nbytes;
316 buf += nbytes;
317 tbytes += nbytes;
318 if (tbytes >= bufsize) /* buffer overflow */
319 return (0);
320 }
321 nbytes = snprintf(buf, buflen, "%c%c", '\n', '\0');
322 tbytes += nbytes;
323 if (tbytes >= bufsize)
324 return (0);
325 return (tbytes);
326 }
327
328 /*
329 * Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
330 * The value will be interpreted as explained at the top of this file.
331 */
332 static void
333 i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
334 {
335 ipadm_conf_ent_t *ipent;
336
337 ipent = i_ipadm_find_conf_type(name);
338 (*ipent->ipent_rfunc)(nvl, name, value);
339 }
340
341 /*
342 * Adds an nvpair for IPv4 addr to the nvlist. The "name" is the string in
343 * IPADM_NVP_IPV4ADDR. The "value" for IPADM_NVP_IPV4ADDR is another nvlist.
344 * Allocate the value nvlist for IPADM_NVP_IPV4ADDR if necessary, and add
345 * the address and hostnames from the address object `ipaddr' to it.
346 * Then add the allocated nvlist to `nvl'.
347 */
348 ipadm_status_t
349 i_ipadm_add_ipaddr2nvl(nvlist_t *nvl, ipadm_addrobj_t ipaddr)
350 {
351 nvlist_t *nvl_addr = NULL;
352 int err;
353 char *name;
354 sa_family_t af = ipaddr->ipadm_af;
355
356 if (af == AF_INET) {
357 name = IPADM_NVP_IPV4ADDR;
358 } else {
359 assert(af == AF_INET6);
360 name = IPADM_NVP_IPV6ADDR;
361 }
362
363 if (!nvlist_exists(nvl, name)) {
364 if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
365 return (ipadm_errno2status(err));
366 if ((err = nvlist_add_nvlist(nvl, name, nvl_addr)) != 0) {
367 nvlist_free(nvl_addr);
368 return (ipadm_errno2status(err));
369 }
370 nvlist_free(nvl_addr);
371 }
372 if ((err = nvlist_lookup_nvlist(nvl, name, &nvl_addr)) != 0 ||
373 (err = nvlist_add_string(nvl_addr, IPADM_NVP_IPADDRHNAME,
374 ipaddr->ipadm_static_aname)) != 0)
375 return (ipadm_errno2status(err));
376 if (!sockaddrunspec(&ipaddr->ipadm_static_dst_addr)) {
377 if ((err = nvlist_add_string(nvl_addr, IPADM_NVP_IPDADDRHNAME,
378 ipaddr->ipadm_static_dname)) != 0)
379 return (ipadm_errno2status(err));
380 }
381
382 return (IPADM_SUCCESS);
383 }
384
385 /*
386 * Adds an nvpair for IPv6 interface id to the nvlist. The "name" is
387 * the string in IPADM_NVP_INTFID. The "value" for IPADM_NVP_INTFID is another
388 * nvlist. Allocate the value nvlist for IPADM_NVP_INTFID if necessary, and add
389 * the interface id and its prefixlen from the address object `ipaddr' to it.
390 * Then add the allocated nvlist to `nvl'.
391 */
392 ipadm_status_t
393 i_ipadm_add_intfid2nvl(nvlist_t *nvl, ipadm_addrobj_t addr)
394 {
395 nvlist_t *nvl_addr = NULL;
396 struct in6_addr addr6;
397 int err;
398
399 if (!nvlist_exists(nvl, IPADM_NVP_INTFID)) {
400 if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
401 return (ipadm_errno2status(err));
402 if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_INTFID,
403 nvl_addr)) != 0) {
404 nvlist_free(nvl_addr);
405 return (ipadm_errno2status(err));
406 }
407 nvlist_free(nvl_addr);
408 }
409 if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID,
410 &nvl_addr)) != 0 || (err = nvlist_add_uint32(nvl_addr,
411 IPADM_NVP_PREFIXLEN, addr->ipadm_intfidlen)) != 0) {
412 return (ipadm_errno2status(err));
413 }
414 addr6 = addr->ipadm_intfid.sin6_addr;
415 if ((err = nvlist_add_uint8_array(nvl_addr, IPADM_NVP_IPNUMADDR,
416 addr6.s6_addr, 16)) != 0) {
417 return (ipadm_errno2status(err));
418 }
419 if (addr->ipadm_stateless)
420 err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "yes");
421 else
422 err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "no");
423 if (err != 0)
424 return (ipadm_errno2status(err));
425 if (addr->ipadm_stateful)
426 err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "yes");
427 else
428 err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "no");
429 if (err != 0)
430 return (ipadm_errno2status(err));
431
432 return (IPADM_SUCCESS);
433 }
434
435 /*
436 * Adds an nvpair for a dhcp address object to the nvlist. The "name" is
437 * the string in IPADM_NVP_DHCP. The "value" for IPADM_NVP_DHCP is another
438 * nvlist. Allocate the value nvlist for IPADM_NVP_DHCP if necessary, and add
439 * the parameters from the arguments `primary' and `wait'.
440 * Then add the allocated nvlist to `nvl'.
441 */
442 ipadm_status_t
443 i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
444 {
445 nvlist_t *nvl_dhcp = NULL;
446 int err;
447
448 if (!nvlist_exists(nvl, IPADM_NVP_DHCP)) {
449 if ((err = nvlist_alloc(&nvl_dhcp, NV_UNIQUE_NAME, 0)) != 0)
450 return (ipadm_errno2status(err));
451 if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_DHCP,
452 nvl_dhcp)) != 0) {
453 nvlist_free(nvl_dhcp);
454 return (ipadm_errno2status(err));
455 }
456 nvlist_free(nvl_dhcp);
457 }
458 if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvl_dhcp)) != 0 ||
459 (err = nvlist_add_int32(nvl_dhcp, IPADM_NVP_WAIT, wait)) != 0 ||
460 (err = nvlist_add_boolean_value(nvl_dhcp, IPADM_NVP_PRIMARY,
461 primary)) != 0) {
462 return (ipadm_errno2status(err));
463 }
464
465 return (IPADM_SUCCESS);
466 }
467
468 /*
469 * Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
470 */
471 static void
472 i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
473 {
474 /* if value is NULL create an empty node */
475 if (value == NULL)
476 (void) nvlist_add_string(nvl, name, "");
477 else
478 (void) nvlist_add_string(nvl, name, value);
479 }
480
481 /*
482 * `name' = IPADM_NVP_IPV4ADDR and
483 * `value' = <local numeric IP string or hostname,remote numeric IP string or
484 * hostname>
485 * This function will add an nvlist with the hostname information in
486 * nvpairs to the nvlist in `nvl'.
487 */
488 static void
489 i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
490 {
491 char *cp, *hname;
492 struct ipadm_addrobj_s ipaddr;
493
494 assert(strcmp(name, IPADM_NVP_IPV4ADDR) == 0 && value != NULL);
495
496 bzero(&ipaddr, sizeof (ipaddr));
497 ipaddr.ipadm_af = AF_INET;
498
499 hname = value; /* local hostname */
500 cp = strchr(hname, ',');
501 assert(cp != NULL);
502 *cp++ = '\0';
503 (void) strlcpy(ipaddr.ipadm_static_aname, hname,
504 sizeof (ipaddr.ipadm_static_aname));
505
506 if (*cp != '\0') {
507 /* we have a dst hostname */
508 (void) strlcpy(ipaddr.ipadm_static_dname, cp,
509 sizeof (ipaddr.ipadm_static_dname));
510 }
511 (void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
512 }
513
514 /*
515 * `name' = IPADM_NVP_IPV6ADDR and
516 * `value' = <local numeric IP string or hostname,remote numeric IP string or
517 * hostname>
518 * This function will add an nvlist with the hostname information in
519 * nvpairs to the nvlist in `nvl'.
520 */
521 static void
522 i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
523 {
524 char *cp, *hname;
525 struct ipadm_addrobj_s ipaddr;
526
527 assert(strcmp(name, IPADM_NVP_IPV6ADDR) == 0 && value != NULL);
528
529 bzero(&ipaddr, sizeof (ipaddr));
530 ipaddr.ipadm_af = AF_INET6;
531
532 hname = value; /* local hostname */
533 cp = strchr(hname, ',');
534 assert(cp != NULL);
535 *cp++ = '\0';
536 (void) strlcpy(ipaddr.ipadm_static_aname, hname,
537 sizeof (ipaddr.ipadm_static_aname));
538
539 if (*cp != '\0') {
540 /* we have a dst hostname */
541 (void) strlcpy(ipaddr.ipadm_static_dname, cp,
542 sizeof (ipaddr.ipadm_static_dname));
543 }
544 (void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
545 }
546
547 /*
548 * `name' = IPADM_NVP_INTFID and `value' = <intfid/prefixlen>,{yes,no},{yes|no}
549 * This function will add an nvlist with the address object information in
550 * nvpairs to the nvlist in `nvl'.
551 */
552 static void
553 i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
554 {
555 char *cp;
556 struct ipadm_addrobj_s ipaddr;
557 char *endp;
558 char *prefixlen;
559 char *stateless;
560 char *stateful;
561
562 assert(strcmp(name, IPADM_NVP_INTFID) == 0 && value != NULL);
563
564 bzero(&ipaddr, sizeof (ipaddr));
565
566 cp = strchr(value, '/');
567 assert(cp != NULL);
568
569 *cp++ = '\0';
570 ipaddr.ipadm_intfid.sin6_family = AF_INET6;
571 (void) inet_pton(AF_INET6, value, &ipaddr.ipadm_intfid.sin6_addr);
572
573 prefixlen = cp;
574 cp = strchr(cp, ',');
575 assert(cp != NULL);
576 *cp++ = '\0';
577
578 errno = 0;
579 ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
580 if (*endp != '\0' || errno != 0)
581 return;
582
583 stateless = cp;
584 stateful = strchr(stateless, ',');
585 assert(stateful != NULL);
586 *stateful++ = '\0';
587 ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
588 ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
589
590 /* Add all of it to the given nvlist */
591 (void) i_ipadm_add_intfid2nvl(nvl, &ipaddr);
592 }
593
594 /*
595 * `name' = IPADM_NVP_DHCP and `value' = <wait_time>,{yes|no}
596 * This function will add an nvlist with the dhcp address object information in
597 * nvpairs to the nvlist in `nvl'.
598 */
599 static void
600 i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
601 {
602 char *cp;
603 char *endp;
604 long wait_time;
605 boolean_t primary;
606
607 assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
608 cp = strchr(value, ',');
609 assert(cp != NULL);
610 *cp++ = '\0';
611 errno = 0;
612 wait_time = strtol(value, &endp, 10);
613 if (*endp != '\0' || errno != 0)
614 return;
615 primary = (strcmp(cp, "yes") == 0);
616 (void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
617 }
618
619 /*
620 * Parses the buffer, for name-value pairs and creates nvlist. The value
621 * is always considered to be a string.
622 */
623 int
624 ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
625 {
626 char *nv, *name, *val, *buf, *cp, *sep;
627 int err;
628
629 if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
630 return (EINVAL);
631 *ipnvl = NULL;
632
633 /*
634 * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
635 */
636 if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
637 return (EINVAL);
638
639 if ((cp = buf = strdup(inbuf)) == NULL)
640 return (errno);
641
642 while (isspace(*buf))
643 buf++;
644
645 if (*buf == '\0') {
646 err = EINVAL;
647 goto fail;
648 }
649
650 nv = buf;
651 /*
652 * work on one nvpair at a time and extract the name and value
653 */
654 sep = ((flags & IPADM_NORVAL) ? IPADM_NAME_SEP : IPADM_NVPAIR_SEP);
655 while ((nv = strsep(&buf, sep)) != NULL) {
656 if (*nv == '\n')
657 continue;
658 name = nv;
659 if ((val = strchr(nv, '=')) != NULL)
660 *val++ = '\0';
661 if (*ipnvl == NULL &&
662 (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0)
663 goto fail;
664 if (nvlist_exists(*ipnvl, name)) {
665 err = EEXIST;
666 goto fail;
667 }
668 /* Add the extracted nvpair to the nvlist `ipnvl'. */
669 (void) i_ipadm_add_nvpair(*ipnvl, name, val);
670 }
671 free(cp);
672 return (0);
673 fail:
674 free(cp);
675 nvlist_free(*ipnvl);
676 *ipnvl = NULL;
677 return (err);
678 }
679
680 /*
681 * Opens the data store for read/write operation. For write operation we open
682 * another file and scribble the changes to it and copy the new file back to
683 * old file.
684 */
685 int
686 ipadm_rw_db(db_wfunc_t *db_walk_func, void *arg, const char *db_file,
687 mode_t db_perms, ipadm_db_op_t db_op)
688 {
689 FILE *fp, *nfp = NULL;
690 char file[MAXPATHLEN];
691 char newfile[MAXPATHLEN];
692 int nfd;
693 boolean_t writeop;
694 int err = 0;
695
696 writeop = (db_op != IPADM_DB_READ);
697
698 (void) snprintf(file, MAXPATHLEN, "%s/%s", ipadm_rootdir, db_file);
699
700 /* open the data store */
701 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL)
702 return (errno);
703
704 if (writeop) {
705 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
706 ipadm_rootdir, db_file);
707 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
708 db_perms)) < 0) {
709 err = errno;
710 (void) fclose(fp);
711 return (err);
712 }
713
714 if ((nfp = fdopen(nfd, "w")) == NULL) {
715 err = errno;
716 (void) close(nfd);
717 (void) fclose(fp);
718 (void) unlink(newfile);
719 return (err);
720 }
721 }
722 err = ipadm_process_db_line(db_walk_func, arg, fp, nfp, db_op);
723 if (!writeop)
724 goto done;
725 if (err != 0 && err != ENOENT)
726 goto done;
727
728 if (fflush(nfp) == EOF) {
729 err = errno;
730 goto done;
731 }
732 (void) fclose(fp);
733 (void) fclose(nfp);
734
735 if (rename(newfile, file) < 0) {
736 err = errno;
737 (void) unlink(newfile);
738 }
739 return (err);
740 done:
741 if (nfp != NULL) {
742 (void) fclose(nfp);
743 if (err != 0)
744 (void) unlink(newfile);
745 }
746 (void) fclose(fp);
747 return (err);
748 }
749
750 /*
751 * Processes each line of the configuration file, skipping lines with
752 * leading spaces, blank lines and comments. The line form the DB
753 * is converted to nvlist and the callback function is called to process
754 * the list. The buf could be modified by the callback function and
755 * if this is a write operation and buf is not truncated, buf will
756 * be written to disk.
757 *
758 * Further if cont is set to B_FALSE, the remainder of the file will
759 * continue to be read (however callback function will not be called) and,
760 * if necessary, written to disk as well.
761 */
762 static int
763 ipadm_process_db_line(db_wfunc_t *db_walk_func, void *arg, FILE *fp, FILE *nfp,
764 ipadm_db_op_t db_op)
765 {
766 int err = 0;
767 char buf[MAXLINELEN];
768 boolean_t cont = B_TRUE;
769 int i, len;
770 nvlist_t *db_nvl = NULL;
771 boolean_t line_deleted = B_FALSE;
772
773 while (fgets(buf, MAXLINELEN, fp) != NULL) {
774 /*
775 * Skip leading spaces, blank lines, and comments.
776 */
777 len = strnlen(buf, MAXLINELEN);
778 for (i = 0; i < len; i++) {
779 if (!isspace(buf[i]))
780 break;
781 }
782
783 if (i != len && buf[i] != '#' && cont) {
784 if (ipadm_str2nvlist(buf, &db_nvl, 0) == 0) {
785 cont = db_walk_func(arg, db_nvl, buf,
786 MAXLINELEN, &err);
787 } else {
788 /* Delete corrupted line. */
789 buf[0] = '\0';
790 }
791 nvlist_free(db_nvl);
792 db_nvl = NULL;
793 }
794 if (err != 0)
795 break;
796 if (nfp != NULL && buf[0] == '\0')
797 line_deleted = B_TRUE;
798 if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
799 err = errno;
800 break;
801 }
802 }
803
804 if (err != 0 || !cont)
805 return (err);
806
807 if (db_op == IPADM_DB_WRITE) {
808 ipadm_dbwrite_cbarg_t *cb = arg;
809 nvlist_t *nvl = cb->dbw_nvl;
810
811 /*
812 * If the specified entry is not found above, we add
813 * the entry to the configuration file, here.
814 */
815 (void) memset(buf, 0, MAXLINELEN);
816 if (ipadm_nvlist2str(nvl, buf, MAXLINELEN) == 0)
817 err = ENOBUFS;
818 else if (fputs(buf, nfp) == EOF)
819 err = errno;
820 return (err);
821 }
822
823 if (db_op == IPADM_DB_DELETE && line_deleted)
824 return (0);
825
826 /* if we have come this far, then we didn't find any match */
827 return (ENOENT);
828 }