Mercurial > illumos > illumos-gate
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 } |