Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2015 Joyent, Inc.
25 25 * Copyright 2016 Argo Technologie SA.
26 26 */
27 27
28 28 /*
29 29 * Contains DB walker functions, which are of type `db_wfunc_t';
30 30 *
31 31 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
32 32 * size_t bufsize, int *errp);
33 33 *
34 34 * ipadm_rw_db() walks through the data store, one line at a time and calls
35 35 * these call back functions with:
36 36 * `cbarg' - callback argument
37 37 * `db_nvl' - representing a line from DB in nvlist_t form
38 38 * `buf' - character buffer to hold modified line
39 39 * `bufsize'- size of the buffer
40 40 * `errp' - captures any error inside the walker function.
41 41 *
42 42 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
43 43 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
44 44 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
45 45 * the modified `buf' is written back into DB.
46 46 *
47 47 * All the 'read' callback functions, retrieve the information from the DB, by
48 48 * reading `db_nvl' and then populate the `cbarg'.
49 49 */
50 50
51 51 #include <stdlib.h>
52 52 #include <strings.h>
53 53 #include <errno.h>
54 54 #include <assert.h>
55 55 #include <sys/types.h>
56 56 #include <sys/socket.h>
57 57 #include <netinet/in.h>
58 58 #include <arpa/inet.h>
59 59 #include <unistd.h>
60 60 #include "ipmgmt_impl.h"
61 61
62 62 /* SCF related property group names and property names */
63 63 #define IPMGMTD_APP_PG "ipmgmtd"
64 64 #define IPMGMTD_PROP_FBD "first_boot_done"
65 65 #define IPMGMTD_PROP_DBVER "datastore_version"
66 66 #define IPMGMTD_TRUESTR "true"
67 67
68 68 #define ATYPE "_atype" /* name of the address type nvpair */
69 69 #define FLAGS "_flags" /* name of the flags nvpair */
70 70
71 71 /*
72 72 * flag used by ipmgmt_persist_aobjmap() to indicate address type is
73 73 * IPADM_ADDR_IPV6_ADDRCONF.
74 74 */
75 75 #define IPMGMT_ATYPE_V6ACONF 0x1
76 76
77 77 extern pthread_rwlock_t ipmgmt_dbconf_lock;
78 78
79 79 /* signifies whether volatile copy of data store is in use */
80 80 static boolean_t ipmgmt_rdonly_root = B_FALSE;
81 81
82 82 /*
83 83 * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
84 84 * in private nvpairs `proto', `ifname' & `aobjname'.
85 85 */
86 86 static boolean_t
87 87 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
88 88 const char *aobjname)
89 89 {
90 90 char *db_proto = NULL, *db_ifname = NULL;
91 91 char *db_aobjname = NULL;
92 92 nvpair_t *nvp;
93 93 char *name;
94 94
95 95 /* walk through db_nvl and retrieve all its private nvpairs */
96 96 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
97 97 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
98 98 name = nvpair_name(nvp);
99 99 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
100 100 (void) nvpair_value_string(nvp, &db_proto);
101 101 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
102 102 (void) nvpair_value_string(nvp, &db_ifname);
103 103 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
104 104 (void) nvpair_value_string(nvp, &db_aobjname);
105 105 }
106 106
107 107 if (proto != NULL && proto[0] == '\0')
108 108 proto = NULL;
109 109 if (ifname != NULL && ifname[0] == '\0')
110 110 ifname = NULL;
111 111 if (aobjname != NULL && aobjname[0] == '\0')
112 112 aobjname = NULL;
113 113
114 114 if ((proto == NULL && db_proto != NULL) ||
115 115 (proto != NULL && db_proto == NULL) ||
116 116 (proto != NULL && db_proto != NULL &&
117 117 strcmp(proto, db_proto) != 0)) {
118 118 /* no intersection - different protocols. */
119 119 return (B_FALSE);
120 120 }
121 121 if ((ifname == NULL && db_ifname != NULL) ||
122 122 (ifname != NULL && db_ifname == NULL) ||
123 123 (ifname != NULL && db_ifname != NULL &&
124 124 strcmp(ifname, db_ifname) != 0)) {
125 125 /* no intersection - different interfaces. */
126 126 return (B_FALSE);
127 127 }
128 128 if ((aobjname == NULL && db_aobjname != NULL) ||
129 129 (aobjname != NULL && db_aobjname == NULL) ||
130 130 (aobjname != NULL && db_aobjname != NULL &&
131 131 strcmp(aobjname, db_aobjname) != 0)) {
132 132 /* no intersection - different address objects */
133 133 return (B_FALSE);
134 134 }
135 135
136 136 return (B_TRUE);
137 137 }
138 138
139 139 /*
140 140 * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
141 141 */
142 142 static boolean_t
143 143 ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
144 144 {
145 145 nvpair_t *nvp;
146 146 char *name;
147 147 char *proto = NULL, *ifname = NULL, *aobjname = NULL;
148 148
149 149 /* walk through in_nvl and retrieve all its private nvpairs */
150 150 for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
151 151 nvp = nvlist_next_nvpair(in_nvl, nvp)) {
152 152 name = nvpair_name(nvp);
153 153 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
154 154 (void) nvpair_value_string(nvp, &proto);
155 155 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
156 156 (void) nvpair_value_string(nvp, &ifname);
157 157 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
158 158 (void) nvpair_value_string(nvp, &aobjname);
159 159 }
160 160
161 161 return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
162 162 }
163 163
164 164 /*
165 165 * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
166 166 * in private nvpairs `proto', `ifname' & `aobjname'.
167 167 */
168 168 static boolean_t
169 169 ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
170 170 const char *ifname, char *aobjname)
171 171 {
172 172 char *db_ifname = NULL, *db_proto = NULL;
173 173 char *db_aobjname = NULL;
174 174 nvpair_t *nvp;
175 175 char *name;
176 176
177 177 /* walk through db_nvl and retrieve all private nvpairs */
178 178 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
179 179 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
180 180 name = nvpair_name(nvp);
181 181 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
182 182 (void) nvpair_value_string(nvp, &db_proto);
183 183 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
184 184 (void) nvpair_value_string(nvp, &db_ifname);
185 185 else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
186 186 (void) nvpair_value_string(nvp, &db_aobjname);
187 187 }
188 188
189 189 if (proto != NULL && proto[0] != '\0') {
190 190 if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
191 191 return (B_FALSE);
192 192 }
193 193 if (ifname != NULL && ifname[0] != '\0') {
194 194 if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
195 195 return (B_FALSE);
196 196 }
197 197 if (aobjname != NULL && aobjname[0] != '\0') {
198 198 if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
199 199 return (B_FALSE);
200 200 }
201 201
202 202 return (B_TRUE);
203 203 }
204 204
205 205 /*
206 206 * Retrieves the property value from the DB. The property whose value is to be
207 207 * retrieved is in `pargp->ia_pname'.
208 208 */
209 209 /* ARGSUSED */
210 210 boolean_t
211 211 ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
212 212 int *errp)
213 213 {
214 214 ipmgmt_prop_arg_t *pargp = arg;
215 215 boolean_t cont = B_TRUE;
216 216 char *pval;
217 217 int err = 0;
218 218
219 219 *errp = 0;
220 220
221 221 if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
222 222 pargp->ia_ifname, pargp->ia_aobjname))
223 223 return (B_TRUE);
224 224
225 225 if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
226 226 &pval)) == 0) {
227 227 (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
228 228 /*
229 229 * We have retrieved what we are looking for.
230 230 * Stop the walker.
231 231 */
232 232 cont = B_FALSE;
233 233 } else {
234 234 if (err == ENOENT)
235 235 err = 0;
236 236 *errp = err;
237 237 }
238 238
239 239 return (cont);
240 240 }
241 241
242 242 /*
243 243 * Removes the property value from the DB. The property whose value is to be
244 244 * removed is in `pargp->ia_pname'.
245 245 */
246 246 /* ARGSUSED */
247 247 boolean_t
248 248 ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
249 249 int *errp)
250 250 {
251 251 ipmgmt_prop_arg_t *pargp = arg;
252 252
253 253 *errp = 0;
254 254 if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
255 255 pargp->ia_ifname, pargp->ia_aobjname))
256 256 return (B_TRUE);
257 257
258 258 if (!nvlist_exists(db_nvl, pargp->ia_pname))
259 259 return (B_TRUE);
260 260
261 261 /*
262 262 * We found the property in the DB. If IPMGMT_REMOVE is not set then
263 263 * delete the entry from the db. If it is set, then the property is a
264 264 * multi-valued property so just remove the specified values from DB.
265 265 */
266 266 if (pargp->ia_flags & IPMGMT_REMOVE) {
267 267 char *dbpval = NULL;
268 268 char *inpval = pargp->ia_pval;
269 269 char pval[MAXPROPVALLEN];
270 270 char *val, *lasts;
271 271
272 272 *errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
273 273 if (*errp != 0)
274 274 return (B_FALSE);
275 275
276 276 /*
277 277 * multi-valued properties are represented as comma separated
278 278 * values. Use string tokenizer functions to split them and
279 279 * search for the value to be removed.
280 280 */
281 281 bzero(pval, sizeof (pval));
282 282 if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
283 283 if (strcmp(val, inpval) != 0)
284 284 (void) strlcat(pval, val, MAXPROPVALLEN);
285 285 while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
286 286 if (strcmp(val, inpval) != 0) {
287 287 if (pval[0] != '\0')
288 288 (void) strlcat(pval, ",",
289 289 MAXPROPVALLEN);
290 290 (void) strlcat(pval, val,
291 291 MAXPROPVALLEN);
292 292 }
293 293 }
294 294 } else {
295 295 if (strcmp(dbpval, inpval) != 0)
296 296 *errp = ENOENT;
297 297 else
298 298 buf[0] = '\0';
299 299 return (B_FALSE);
300 300 }
301 301 *errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
302 302 if (*errp != 0)
303 303 return (B_FALSE);
304 304
305 305 (void) memset(buf, 0, buflen);
306 306 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
307 307 /* buffer overflow */
308 308 *errp = ENOBUFS;
309 309 }
310 310 } else {
311 311 buf[0] = '\0';
312 312 }
313 313
314 314 /* stop the search */
315 315 return (B_FALSE);
316 316 }
317 317
318 318 /*
319 319 * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
320 320 * found, when one of the following occurs first.
321 321 * - the input aobjname matches the db aobjname. Return the db address.
322 322 * - the input interface matches the db interface. Return all the
323 323 * matching db lines with addresses.
324 324 */
325 325 /* ARGSUSED */
326 326 boolean_t
327 327 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
328 328 int *errp)
329 329 {
330 330 ipmgmt_getaddr_cbarg_t *cbarg = arg;
331 331 char *db_aobjname = NULL;
332 332 char *db_ifname = NULL;
333 333 nvlist_t *db_addr = NULL;
334 334 char name[IPMGMT_STRSIZE];
335 335 nvpair_t *nvp;
336 336 boolean_t add_nvl = B_FALSE;
337 337
338 338 /* Parse db nvlist */
339 339 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
340 340 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
341 341 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
342 342 (void) nvpair_value_nvlist(nvp, &db_addr);
343 343 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
344 344 (void) nvpair_value_string(nvp, &db_ifname);
345 345 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
346 346 (void) nvpair_value_string(nvp, &db_aobjname);
347 347 }
348 348
349 349 if (db_aobjname == NULL) /* Not an address */
350 350 return (B_TRUE);
351 351
352 352 /* Check for a match between the aobjnames or the interface name */
353 353 if (cbarg->cb_aobjname[0] != '\0') {
354 354 if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
355 355 add_nvl = B_TRUE;
356 356 } else if (cbarg->cb_ifname[0] != '\0') {
357 357 if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
358 358 add_nvl = B_TRUE;
359 359 } else {
360 360 add_nvl = B_TRUE;
361 361 }
362 362
363 363 if (add_nvl) {
364 364 (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
365 365 cbarg->cb_ocnt);
366 366 *errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
367 367 if (*errp == 0)
368 368 cbarg->cb_ocnt++;
369 369 }
370 370 return (B_TRUE);
371 371 }
372 372
373 373 /*
374 374 * This function only gets called if a volatile filesystem version
375 375 * of the configuration file has been created. This only happens in the
376 376 * extremely rare case that a request has been made to update the configuration
377 377 * file at boottime while the root filesystem was read-only. This is
378 378 * really a rare occurrence now that we don't support UFS root filesystems
379 379 * any longer. This function will periodically attempt to write the
380 380 * configuration back to its location on the root filesystem. Success
381 381 * will indicate that the filesystem is no longer read-only.
382 382 */
383 383 /* ARGSUSED */
384 384 static void *
385 385 ipmgmt_db_restore_thread(void *arg)
386 386 {
387 387 int err;
388 388 char confpath[MAXPATHLEN];
389 389 char tmpconfpath[MAXPATHLEN];
390 390
391 391 ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
392 392 ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
393 393
394 394 for (;;) {
395 395 (void) sleep(5);
396 396 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
397 397 if (!ipmgmt_rdonly_root)
398 398 break;
399 399 err = ipmgmt_cpfile(tmpconfpath, confpath, B_FALSE);
400 400 if (err == 0) {
401 401 ipmgmt_rdonly_root = B_FALSE;
402 402 break;
403 403 }
404 404 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
405 405 }
406 406 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
407 407 return (NULL);
408 408 }
409 409
410 410 /*
411 411 * This function takes the appropriate lock, read or write, based on the
412 412 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
413 413 * by the fact that we are not always guaranteed to have a writable root
414 414 * filesystem since it is possible that we are reading or writing during
415 415 * bootime while the root filesystem is still read-only. This is, by far,
416 416 * the exception case. Normally, this function will be called when the
417 417 * root filesystem is writable. In the unusual case where this is not
418 418 * true, the configuration file is copied to the volatile file system
419 419 * and is updated there until the root filesystem becomes writable. At
420 420 * that time the file will be moved back to its proper location by
421 421 * ipmgmt_db_restore_thread().
422 422 */
423 423 extern int
424 424 ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
425 425 {
426 426 int err;
427 427 boolean_t writeop;
428 428 mode_t mode;
429 429 pthread_t tid;
430 430 pthread_attr_t attr;
431 431 char confpath[MAXPATHLEN];
432 432 char tmpconfpath[MAXPATHLEN];
433 433
434 434 ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
435 435 ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
436 436
437 437 writeop = (db_op != IPADM_DB_READ);
438 438 if (writeop) {
439 439 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
440 440 mode = IPADM_FILE_MODE;
441 441 } else {
442 442 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
443 443 mode = 0;
444 444 }
445 445
446 446 /*
447 447 * Did a previous write attempt fail? If so, don't even try to
448 448 * read/write to the permanent configuration file.
449 449 */
450 450 if (!ipmgmt_rdonly_root) {
451 451 err = ipadm_rw_db(db_walk_func, db_warg, confpath, mode, db_op);
452 452 if (err != EROFS)
453 453 goto done;
454 454 }
455 455
456 456 /*
457 457 * If we haven't already copied the file to the volatile
458 458 * file system, do so. This should only happen on a failed
459 459 * writeop (i.e., we have acquired the write lock above).
460 460 */
461 461 if (access(tmpconfpath, F_OK) != 0) {
462 462 assert(writeop);
463 463 err = ipmgmt_cpfile(confpath, tmpconfpath, B_TRUE);
464 464 if (err != 0)
465 465 goto done;
466 466 (void) pthread_attr_init(&attr);
467 467 (void) pthread_attr_setdetachstate(&attr,
468 468 PTHREAD_CREATE_DETACHED);
469 469 err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
470 470 NULL);
471 471 (void) pthread_attr_destroy(&attr);
472 472 if (err != 0) {
473 473 (void) unlink(tmpconfpath);
474 474 goto done;
475 475 }
476 476 ipmgmt_rdonly_root = B_TRUE;
477 477 }
478 478
479 479 /*
480 480 * Read/write from the volatile copy.
481 481 */
482 482 err = ipadm_rw_db(db_walk_func, db_warg, tmpconfpath,
483 483 mode, db_op);
484 484 done:
485 485 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
486 486 return (err);
487 487 }
488 488
489 489 /*
490 490 * Used to add an entry towards the end of DB. It just returns B_TRUE for
491 491 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
492 492 * line at the end.
493 493 */
494 494 /* ARGSUSED */
495 495 boolean_t
496 496 ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
497 497 {
498 498 return (B_TRUE);
499 499 }
500 500
501 501 /*
502 502 * This function is used to update or create an entry in DB. The nvlist_t,
503 503 * `in_nvl', represents the line we are looking for. Once we ensure the right
504 504 * line from DB, we update that entry.
505 505 */
506 506 boolean_t
507 507 ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
508 508 int *errp)
509 509 {
510 510 ipadm_dbwrite_cbarg_t *cb = arg;
511 511 uint_t flags = cb->dbw_flags;
512 512 nvlist_t *in_nvl = cb->dbw_nvl;
513 513 nvpair_t *nvp;
514 514 char *name, *instrval = NULL, *dbstrval = NULL;
515 515 char pval[MAXPROPVALLEN];
516 516
517 517 *errp = 0;
518 518 if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
519 519 return (B_TRUE);
520 520
521 521 for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
522 522 nvp = nvlist_next_nvpair(in_nvl, nvp)) {
523 523 name = nvpair_name(nvp);
524 524 if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
525 525 break;
526 526 }
527 527
528 528 if (nvp == NULL)
529 529 return (B_TRUE);
530 530
531 531 assert(nvpair_type(nvp) == DATA_TYPE_STRING);
532 532
533 533 if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
534 534 return (B_FALSE);
535 535
536 536 /*
537 537 * If IPMGMT_APPEND is set then we are dealing with multi-valued
538 538 * properties. We append to the entry from the db, with the new value.
539 539 */
540 540 if (flags & IPMGMT_APPEND) {
541 541 if ((*errp = nvlist_lookup_string(db_nvl, name,
542 542 &dbstrval)) != 0)
543 543 return (B_FALSE);
544 544 (void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
545 545 instrval);
546 546 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
547 547 return (B_FALSE);
548 548 } else {
549 549 /* case of in-line update of a db entry */
550 550 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
551 551 return (B_FALSE);
552 552 }
553 553
554 554 (void) memset(buf, 0, buflen);
555 555 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
556 556 /* buffer overflow */
557 557 *errp = ENOBUFS;
558 558 }
559 559
560 560 /* we updated the DB entry, so do not continue */
561 561 return (B_FALSE);
562 562 }
563 563
564 564 /*
565 565 * For the given `cbarg->cb_ifname' interface, retrieves any persistent
566 566 * interface information (used in 'ipadm show-if')
567 567 */
568 568 /* ARGSUSED */
569 569 boolean_t
570 570 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
571 571 int *errp)
572 572 {
573 573 ipmgmt_getif_cbarg_t *cbarg = arg;
574 574 char *ifname = cbarg->cb_ifname;
575 575 char *intf = NULL;
576 576 ipadm_if_info_t *ifp = NULL;
577 577 sa_family_t af;
578 578 char *afstr;
579 579
580 580 *errp = 0;
581 581 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
582 582 nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
583 583 (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
584 584 return (B_TRUE);
585 585 }
586 586 af = atoi(afstr);
587 587 for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
588 588 if (strcmp(ifp->ifi_name, intf) == 0)
589 589 break;
590 590 }
591 591 if (ifp == NULL) {
592 592 ipadm_if_info_t *new;
593 593
594 594 if ((new = calloc(1, sizeof (*new))) == NULL) {
595 595 *errp = ENOMEM;
596 596 return (B_FALSE); /* don't continue the walk */
597 597 }
598 598 new->ifi_next = cbarg->cb_ifinfo;
599 599 cbarg->cb_ifinfo = new;
600 600 ifp = new;
601 601 (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
602 602 }
603 603
604 604 if (af == AF_INET) {
605 605 ifp->ifi_pflags |= IFIF_IPV4;
606 606 } else {
607 607 assert(af == AF_INET6);
608 608 ifp->ifi_pflags |= IFIF_IPV6;
609 609 }
610 610
611 611 /* Terminate the walk if we found both v4 and v6 interfaces. */
612 612 if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
613 613 (ifp->ifi_pflags & IFIF_IPV6))
614 614 return (B_FALSE);
615 615
616 616 return (B_TRUE);
617 617 }
618 618
619 619 /*
620 620 * Deletes those entries from the database for which interface name
621 621 * matches with the given `cbarg->cb_ifname'
622 622 */
623 623 /* ARGSUSED */
624 624 boolean_t
625 625 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
626 626 int *errp)
627 627 {
628 628 ipmgmt_if_cbarg_t *cbarg = arg;
629 629 boolean_t isv6 = (cbarg->cb_family == AF_INET6);
630 630 char *ifname = cbarg->cb_ifname;
631 631 char *modstr = NULL;
632 632 char *afstr;
633 633 char *aobjname;
634 634 uint_t proto;
635 635 ipmgmt_aobjmap_t *head;
636 636 boolean_t aobjfound = B_FALSE;
637 637
638 638 *errp = 0;
639 639
640 640 if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
641 641 return (B_TRUE);
642 642
643 643 if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
644 644 if (atoi(afstr) == cbarg->cb_family)
645 645 goto delete;
646 646 return (B_TRUE);
647 647 }
648 648
649 649 /* Reset all the interface configurations for 'ifname' */
650 650 if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
651 651 nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
652 652 goto delete;
653 653 }
654 654 if (!isv6 &&
655 655 (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
656 656 nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
657 657 goto delete;
658 658 }
659 659
660 660 if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
661 661 /*
662 662 * This must be an address property. Delete this
663 663 * line if there is a match in the address family.
664 664 */
665 665 head = aobjmap.aobjmap_head;
666 666 while (head != NULL) {
667 667 if (strcmp(head->am_aobjname, aobjname) == 0) {
668 668 aobjfound = B_TRUE;
669 669 if (head->am_family == cbarg->cb_family)
670 670 goto delete;
671 671 }
672 672 head = head->am_next;
673 673 }
674 674 /*
675 675 * If aobjfound = B_FALSE, then this address is not
676 676 * available in active configuration. We should go ahead
677 677 * and delete it.
678 678 */
679 679 if (!aobjfound)
680 680 goto delete;
681 681 }
682 682
683 683 /*
684 684 * If we are removing both v4 and v6 interface, then we get rid of
685 685 * all the properties for that interface. On the other hand, if we
686 686 * are deleting only v4 instance of an interface, then we delete v4
687 687 * properties only.
688 688 */
689 689 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
690 690 proto = ipadm_str2proto(modstr);
691 691 switch (proto) {
692 692 case MOD_PROTO_IPV6:
693 693 if (isv6)
694 694 goto delete;
695 695 break;
696 696 case MOD_PROTO_IPV4:
697 697 if (!isv6)
698 698 goto delete;
699 699 break;
700 700 case MOD_PROTO_IP:
701 701 /* this should never be the case, today */
702 702 assert(0);
703 703 break;
704 704 }
705 705 }
706 706 /* Not found a match yet. Continue processing the db */
707 707 return (B_TRUE);
708 708 delete:
709 709 /* delete the line from the db */
710 710 buf[0] = '\0';
711 711 return (B_TRUE);
712 712 }
713 713
714 714 /*
715 715 * Deletes those entries from the database for which address object name
716 716 * matches with the given `cbarg->cb_aobjname'
717 717 */
718 718 /* ARGSUSED */
719 719 boolean_t
720 720 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
721 721 int *errp)
722 722 {
723 723 ipmgmt_resetaddr_cbarg_t *cbarg = arg;
724 724 char *aobjname = cbarg->cb_aobjname;
725 725
726 726 *errp = 0;
727 727 if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
728 728 return (B_TRUE);
729 729
730 730 /* delete the line from the db */
731 731 buf[0] = '\0';
732 732 return (B_TRUE);
733 733 }
734 734
735 735 /*
736 736 * Retrieves all interface props, including addresses, for given interface(s).
737 737 * `invl' contains the list of interfaces, for which information need to be
738 738 * retrieved.
739 739 */
740 740 /* ARGSUSED */
741 741 boolean_t
742 742 ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
743 743 int *errp)
744 744 {
745 745 ipmgmt_initif_cbarg_t *cbarg = arg;
746 746 nvlist_t *onvl = cbarg->cb_onvl;
747 747 nvlist_t *invl = cbarg->cb_invl;
748 748 sa_family_t in_af = cbarg->cb_family;
749 749 char *db_ifname;
750 750
751 751 *errp = 0;
752 752 if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
753 753 nvlist_exists(invl, db_ifname)) {
754 754 char name[IPMGMT_STRSIZE];
755 755 sa_family_t db_af = in_af;
756 756 uint_t proto;
757 757 char *pstr;
758 758
759 759 if (in_af != AF_UNSPEC) {
760 760 if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
761 761 &pstr) == 0) {
762 762 proto = ipadm_str2proto(pstr);
763 763 if (proto == MOD_PROTO_IPV4)
764 764 db_af = AF_INET;
765 765 else if (proto == MOD_PROTO_IPV6)
766 766 db_af = AF_INET6;
767 767 else
768 768 db_af = in_af;
769 769 } else {
770 770 if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
771 771 nvlist_exists(db_nvl, IPADM_NVP_DHCP))
772 772 db_af = AF_INET;
773 773 else
774 774 db_af = AF_INET6;
775 775 }
776 776 }
777 777 if (in_af == db_af) {
778 778 (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
779 779 cbarg->cb_ocnt);
780 780 *errp = nvlist_add_nvlist(onvl, name, db_nvl);
781 781 if (*errp == 0)
782 782 cbarg->cb_ocnt++;
783 783 }
784 784 }
785 785 return (B_TRUE);
786 786 }
787 787
788 788 /*
789 789 * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
790 790 * into `aobjmap' structure.
791 791 */
792 792 static int
793 793 i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
794 794 {
795 795 ipmgmt_aobjmap_t *new, *head;
796 796
797 797 head = aobjmap.aobjmap_head;
798 798 if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
799 799 return (ENOMEM);
800 800 *new = *nodep;
801 801 new->am_next = NULL;
802 802
803 803 /* Add the node at the beginning of the list */
804 804 if (head == NULL) {
805 805 aobjmap.aobjmap_head = new;
806 806 } else {
807 807 new->am_next = aobjmap.aobjmap_head;
808 808 aobjmap.aobjmap_head = new;
809 809 }
810 810 return (0);
811 811 }
812 812
813 813 /*
814 814 * A recursive function to generate alphabetized number given a decimal number.
815 815 * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
816 816 * 'ab', 'ac', et al.
817 817 */
818 818 static void
819 819 i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
820 820 {
821 821 if (num >= 26)
822 822 i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
823 823 if (*cp != endp) {
824 824 *cp[0] = 'a' + (num % 26);
825 825 (*cp)++;
826 826 }
827 827 }
828 828
829 829 /*
830 830 * This function generates an `aobjname', when required, and then does
831 831 * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
832 832 * through the `aobjmap' to check if an address object with the same
833 833 * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
834 834 * `aobjname's are not allowed.
835 835 *
836 836 * If `nodep->am_aobjname' is an empty string then the daemon generates an
837 837 * `aobjname' using the `am_nextnum', which contains the next number to be
838 838 * used to generate `aobjname'. `am_nextnum' is converted to base26 using
839 839 * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
840 840 *
841 841 * `am_nextnum' will be 0 to begin with. Every time an address object that
842 842 * needs `aobjname' is added it's incremented by 1. So for the first address
843 843 * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
844 844 * For the second address object on that interface `am_aobjname' will be net0/_b
845 845 * and `am_nextnum' will incremented to 2.
846 846 */
847 847 static int
848 848 i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
849 849 {
850 850 ipmgmt_aobjmap_t *head;
851 851 uint32_t nextnum;
852 852
853 853 for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
854 854 if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
855 855 break;
856 856 nextnum = (head == NULL ? 0 : head->am_nextnum);
857 857
858 858 /*
859 859 * if `aobjname' is empty, then the daemon has to generate the
860 860 * next `aobjname' for the given interface and family.
861 861 */
862 862 if (nodep->am_aobjname[0] == '\0') {
863 863 char tmpstr[IPADM_AOBJ_USTRSIZ - 1]; /* 1 for leading '_' */
864 864 char *cp = tmpstr;
865 865 char *endp = tmpstr + sizeof (tmpstr);
866 866
867 867 i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
868 868
869 869 if (cp == endp)
870 870 return (EINVAL);
871 871 cp[0] = '\0';
872 872
873 873 if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
874 874 nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
875 875 return (EINVAL);
876 876 }
877 877 nodep->am_nextnum = ++nextnum;
878 878 } else {
879 879 for (head = aobjmap.aobjmap_head; head != NULL;
880 880 head = head->am_next) {
881 881 if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
882 882 return (EEXIST);
883 883 }
884 884 nodep->am_nextnum = nextnum;
885 885 }
886 886 return (i_ipmgmt_add_amnode(nodep));
887 887 }
888 888
889 889 /*
890 890 * Performs following operations on the global `aobjmap' linked list.
891 891 * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
892 892 * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
893 893 * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
894 894 * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
895 895 */
896 896 int
897 897 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
898 898 {
899 899 ipmgmt_aobjmap_t *head, *prev, *matched = NULL;
900 900 boolean_t update = B_TRUE;
901 901 int err = 0;
902 902 ipadm_db_op_t db_op;
903 903
904 904 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
905 905
906 906 head = aobjmap.aobjmap_head;
907 907 switch (op) {
908 908 case ADDROBJ_ADD:
909 909 /*
910 910 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
911 911 * update, else add the new node.
912 912 */
913 913 for (; head != NULL; head = head->am_next) {
914 914 /*
915 915 * For IPv6, we need to distinguish between the
916 916 * linklocal and non-linklocal nodes
917 917 */
918 918 if (strcmp(head->am_aobjname,
919 919 nodep->am_aobjname) == 0 &&
920 920 (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
921 921 head->am_linklocal == nodep->am_linklocal))
922 922 break;
923 923 }
924 924
925 925 if (head != NULL) {
926 926 /* update the node */
927 927 (void) strlcpy(head->am_ifname, nodep->am_ifname,
928 928 sizeof (head->am_ifname));
929 929 head->am_lnum = nodep->am_lnum;
930 930 head->am_family = nodep->am_family;
931 931 head->am_flags = nodep->am_flags;
932 932 head->am_atype = nodep->am_atype;
933 933 if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
934 934 head->am_ifid = nodep->am_ifid;
935 935 head->am_linklocal = nodep->am_linklocal;
936 936 }
937 937 } else {
938 938 for (head = aobjmap.aobjmap_head; head != NULL;
939 939 head = head->am_next) {
940 940 if (strcmp(head->am_ifname,
941 941 nodep->am_ifname) == 0)
942 942 break;
943 943 }
944 944 nodep->am_nextnum = (head == NULL ? 0 :
945 945 head->am_nextnum);
946 946 err = i_ipmgmt_add_amnode(nodep);
947 947 }
948 948 db_op = IPADM_DB_WRITE;
949 949 break;
950 950 case ADDROBJ_DELETE:
951 951 prev = head;
952 952 while (head != NULL) {
953 953 if (strcmp(head->am_aobjname,
954 954 nodep->am_aobjname) == 0) {
955 955 nodep->am_atype = head->am_atype;
956 956 /*
957 957 * There could be multiple IPV6_ADDRCONF nodes,
958 958 * with same address object name, so check for
959 959 * logical number also.
960 960 */
961 961 if (head->am_atype !=
962 962 IPADM_ADDR_IPV6_ADDRCONF ||
963 963 nodep->am_lnum == head->am_lnum)
964 964 break;
965 965 }
966 966 prev = head;
967 967 head = head->am_next;
968 968 }
969 969 if (head != NULL) {
970 970 /*
971 971 * If the address object is in both active and
972 972 * persistent configuration and the user is deleting it
973 973 * only from active configuration then mark this node
974 974 * for deletion by reseting IPMGMT_ACTIVE bit.
975 975 * With this the same address object name cannot
976 976 * be reused until it is permanently removed.
977 977 */
978 978 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
979 979 nodep->am_flags == IPMGMT_ACTIVE) {
980 980 /* Update flags in the in-memory map. */
981 981 head->am_flags &= ~IPMGMT_ACTIVE;
982 982 head->am_lnum = -1;
983 983
984 984 /* Update info in file. */
985 985 db_op = IPADM_DB_WRITE;
986 986 *nodep = *head;
987 987 } else {
988 988 (void) strlcpy(nodep->am_ifname,
989 989 head->am_ifname,
990 990 sizeof (nodep->am_ifname));
991 991 /* otherwise delete the node */
992 992 if (head == aobjmap.aobjmap_head)
993 993 aobjmap.aobjmap_head = head->am_next;
994 994 else
995 995 prev->am_next = head->am_next;
996 996 free(head);
997 997 db_op = IPADM_DB_DELETE;
998 998 }
999 999 } else {
1000 1000 err = ENOENT;
1001 1001 }
1002 1002 break;
1003 1003 case ADDROBJ_LOOKUPADD:
1004 1004 err = i_ipmgmt_lookupadd_amnode(nodep);
1005 1005 update = B_FALSE;
1006 1006 break;
1007 1007 case ADDROBJ_SETLIFNUM:
1008 1008 update = B_FALSE;
1009 1009 for (; head != NULL; head = head->am_next) {
1010 1010 if (strcmp(head->am_ifname,
1011 1011 nodep->am_ifname) == 0 &&
1012 1012 head->am_family == nodep->am_family &&
1013 1013 head->am_lnum == nodep->am_lnum) {
1014 1014 err = EEXIST;
1015 1015 break;
1016 1016 }
1017 1017 if (strcmp(head->am_aobjname,
1018 1018 nodep->am_aobjname) == 0) {
1019 1019 matched = head;
1020 1020 }
1021 1021 }
1022 1022 if (err == EEXIST)
1023 1023 break;
1024 1024 if (matched != NULL) {
1025 1025 /* update the lifnum */
1026 1026 matched->am_lnum = nodep->am_lnum;
1027 1027 } else {
1028 1028 err = ENOENT;
1029 1029 }
1030 1030 break;
1031 1031 default:
1032 1032 assert(0);
1033 1033 }
1034 1034
1035 1035 if (err == 0 && update)
1036 1036 err = ipmgmt_persist_aobjmap(nodep, db_op);
1037 1037
1038 1038 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
1039 1039
1040 1040 return (err);
1041 1041 }
1042 1042
1043 1043 /*
1044 1044 * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1045 1045 * The content to be written to DB must be represented as nvlist_t.
1046 1046 */
1047 1047 static int
1048 1048 i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
1049 1049 {
1050 1050 int err;
1051 1051 char strval[IPMGMT_STRSIZE];
1052 1052
1053 1053 *nvl = NULL;
1054 1054 if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
1055 1055 goto fail;
1056 1056
1057 1057 if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
1058 1058 np->am_aobjname)) != 0)
1059 1059 goto fail;
1060 1060
1061 1061 if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
1062 1062 np->am_ifname)) != 0)
1063 1063 goto fail;
1064 1064
1065 1065 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
1066 1066 if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
1067 1067 goto fail;
1068 1068
1069 1069 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
1070 1070 if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
1071 1071 goto fail;
1072 1072
1073 1073 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
1074 1074 if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
1075 1075 goto fail;
1076 1076
1077 1077 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
1078 1078 if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
1079 1079 goto fail;
1080 1080
1081 1081 if (np->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1082 1082 struct sockaddr_in6 *in6;
1083 1083
1084 1084 in6 = (struct sockaddr_in6 *)&np->am_ifid;
1085 1085 if (np->am_linklocal &&
1086 1086 IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1087 1087 if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1088 1088 "default")) != 0)
1089 1089 goto fail;
1090 1090 } else {
1091 1091 if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1092 1092 IPMGMT_STRSIZE) == NULL) {
1093 1093 err = errno;
1094 1094 goto fail;
1095 1095 }
1096 1096 if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1097 1097 strval)) != 0)
1098 1098 goto fail;
1099 1099 }
1100 1100 } else {
1101 1101 if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1102 1102 "")) != 0)
1103 1103 goto fail;
1104 1104 }
1105 1105 return (err);
1106 1106 fail:
1107 1107 nvlist_free(*nvl);
1108 1108 return (err);
1109 1109 }
1110 1110
1111 1111 /*
1112 1112 * Read the aobjmap data store and build the in-memory representation
1113 1113 * of the aobjmap. We don't need to hold any locks while building this as
1114 1114 * we do this in very early stage of daemon coming up, even before the door
1115 1115 * is opened.
1116 1116 */
1117 1117 /* ARGSUSED */
1118 1118 extern boolean_t
1119 1119 ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1120 1120 int *errp)
1121 1121 {
1122 1122 nvpair_t *nvp = NULL;
1123 1123 char *name, *strval = NULL;
1124 1124 ipmgmt_aobjmap_t node;
1125 1125 struct sockaddr_in6 *in6;
1126 1126
1127 1127 *errp = 0;
1128 1128 node.am_next = NULL;
1129 1129 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1130 1130 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1131 1131 name = nvpair_name(nvp);
1132 1132
1133 1133 if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
1134 1134 return (B_TRUE);
1135 1135 if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
1136 1136 (void) strlcpy(node.am_aobjname, strval,
1137 1137 sizeof (node.am_aobjname));
1138 1138 } else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
1139 1139 (void) strlcpy(node.am_ifname, strval,
1140 1140 sizeof (node.am_ifname));
1141 1141 } else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
1142 1142 node.am_lnum = atoi(strval);
1143 1143 } else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
1144 1144 node.am_family = (sa_family_t)atoi(strval);
1145 1145 } else if (strcmp(FLAGS, name) == 0) {
1146 1146 node.am_flags = atoi(strval);
1147 1147 } else if (strcmp(ATYPE, name) == 0) {
1148 1148 node.am_atype = (ipadm_addr_type_t)atoi(strval);
1149 1149 } else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
1150 1150 if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1151 1151 in6 = (struct sockaddr_in6 *)&node.am_ifid;
1152 1152 if (strcmp(strval, "default") == 0) {
1153 1153 bzero(in6, sizeof (node.am_ifid));
1154 1154 node.am_linklocal = B_TRUE;
1155 1155 } else {
1156 1156 (void) inet_pton(AF_INET6, strval,
1157 1157 &in6->sin6_addr);
1158 1158 if (IN6_IS_ADDR_UNSPECIFIED(
1159 1159 &in6->sin6_addr))
1160 1160 node.am_linklocal = B_TRUE;
1161 1161 }
1162 1162 }
1163 1163 }
1164 1164 }
1165 1165
1166 1166 /* we have all the information we need, add the node */
1167 1167 *errp = i_ipmgmt_add_amnode(&node);
1168 1168
1169 1169 return (B_TRUE);
1170 1170 }
1171 1171
1172 1172 /*
1173 1173 * Updates an entry from the temporary cache file, which matches the given
1174 1174 * address object name.
1175 1175 */
1176 1176 /* ARGSUSED */
1177 1177 static boolean_t
1178 1178 ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1179 1179 size_t buflen, int *errp)
1180 1180 {
1181 1181 ipadm_dbwrite_cbarg_t *cb = arg;
1182 1182 nvlist_t *in_nvl = cb->dbw_nvl;
1183 1183 uint32_t flags = cb->dbw_flags;
1184 1184 char *db_lifnumstr = NULL, *in_lifnumstr = NULL;
1185 1185
1186 1186 *errp = 0;
1187 1187 if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
1188 1188 return (B_TRUE);
1189 1189
1190 1190 if (flags & IPMGMT_ATYPE_V6ACONF) {
1191 1191 if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1192 1192 &db_lifnumstr) != 0 ||
1193 1193 nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
1194 1194 &in_lifnumstr) != 0 ||
1195 1195 (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
1196 1196 strcmp(db_lifnumstr, in_lifnumstr) != 0))
1197 1197 return (B_TRUE);
1198 1198 }
1199 1199
1200 1200 /* we found the match */
1201 1201 (void) memset(buf, 0, buflen);
1202 1202 if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
1203 1203 /* buffer overflow */
1204 1204 *errp = ENOBUFS;
1205 1205 }
1206 1206
1207 1207 /* stop the walker */
1208 1208 return (B_FALSE);
1209 1209 }
1210 1210
1211 1211 /*
1212 1212 * Deletes an entry from the temporary cache file, which matches the given
1213 1213 * address object name.
1214 1214 */
1215 1215 /* ARGSUSED */
1216 1216 static boolean_t
1217 1217 ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1218 1218 size_t buflen, int *errp)
1219 1219 {
1220 1220 ipmgmt_aobjmap_t *nodep = arg;
1221 1221 char *db_lifnumstr = NULL;
1222 1222
1223 1223 *errp = 0;
1224 1224 if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
1225 1225 nodep->am_aobjname))
1226 1226 return (B_TRUE);
1227 1227
1228 1228 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1229 1229 if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1230 1230 &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1231 1231 return (B_TRUE);
1232 1232 }
1233 1233
1234 1234 /* we found the match, delete the line from the db */
1235 1235 buf[0] = '\0';
1236 1236
1237 1237 /* stop the walker */
1238 1238 return (B_FALSE);
1239 1239 }
1240 1240
1241 1241 /*
1242 1242 * Adds or deletes aobjmap node information into a temporary cache file.
1243 1243 */
1244 1244 extern int
1245 1245 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1246 1246 {
1247 1247 int err;
1248 1248 ipadm_dbwrite_cbarg_t cb;
1249 1249 nvlist_t *nvl = NULL;
1250 1250 char aobjpath[MAXPATHLEN];
1251 1251
1252 1252 ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
1253 1253
1254 1254 if (op == IPADM_DB_WRITE) {
1255 1255 if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1256 1256 return (err);
1257 1257 cb.dbw_nvl = nvl;
1258 1258 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1259 1259 cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1260 1260 else
1261 1261 cb.dbw_flags = 0;
1262 1262
1263 1263 err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb, aobjpath,
1264 1264 IPADM_FILE_MODE, IPADM_DB_WRITE);
1265 1265 nvlist_free(nvl);
1266 1266 } else {
1267 1267 assert(op == IPADM_DB_DELETE);
1268 1268
1269 1269 err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep, aobjpath,
1270 1270 IPADM_FILE_MODE, IPADM_DB_DELETE);
1271 1271 }
1272 1272 return (err);
1273 1273 }
1274 1274
1275 1275 /*
1276 1276 * upgrades the ipadm data-store. It renames all the old private protocol
1277 1277 * property names which start with leading protocol names to begin with
1278 1278 * IPADM_PRIV_PROP_PREFIX.
1279 1279 */
1280 1280 /* ARGSUSED */
1281 1281 boolean_t
1282 1282 ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1283 1283 int *errp)
1284 1284 {
1285 1285 nvpair_t *nvp;
1286 1286 char *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1287 1287 uint_t proto, nproto;
1288 1288 char nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1289 1289
1290 1290 *errp = 0;
1291 1291 /*
1292 1292 * We are interested in lines which contain protocol properties. We
1293 1293 * walk through other lines in the DB.
1294 1294 */
1295 1295 if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
1296 1296 nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
1297 1297 return (B_TRUE);
1298 1298 }
1299 1299 assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
1300 1300
1301 1301 /*
1302 1302 * extract the propname from the `db_nvl' and also extract the
1303 1303 * protocol from the `db_nvl'.
1304 1304 */
1305 1305 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1306 1306 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1307 1307 name = nvpair_name(nvp);
1308 1308 if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
1309 1309 if (nvpair_value_string(nvp, &protostr) != 0)
1310 1310 return (B_TRUE);
1311 1311 } else {
1312 1312 assert(!IPADM_PRIV_NVP(name));
1313 1313 pname = name;
1314 1314 if (nvpair_value_string(nvp, &pval) != 0)
1315 1315 return (B_TRUE);
1316 1316 }
1317 1317 }
1318 1318
1319 1319 /* if the private property is in the right format return */
1320 1320 if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
1321 1321 strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1322 1322 return (B_TRUE);
1323 1323 }
1324 1324 /* if it's a public property move onto the next property */
1325 1325 nproto = proto = ipadm_str2proto(protostr);
1326 1326 if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
1327 1327 &nproto) != 0) {
1328 1328 return (B_TRUE);
1329 1329 }
1330 1330
1331 1331 /* replace the old protocol with new protocol, if required */
1332 1332 if (nproto != proto) {
1333 1333 protostr = ipadm_proto2str(nproto);
1334 1334 if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
1335 1335 protostr) != 0) {
1336 1336 return (B_TRUE);
1337 1337 }
1338 1338 }
1339 1339
1340 1340 /* replace the old property name with new property name, if required */
1341 1341 /* add the prefix to property name */
1342 1342 (void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
1343 1343 if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
1344 1344 nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
1345 1345 return (B_TRUE);
1346 1346 }
1347 1347 (void) memset(buf, 0, buflen);
1348 1348 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1349 1349 /* buffer overflow */
1350 1350 *errp = ENOBUFS;
1351 1351 }
1352 1352 return (B_TRUE);
1353 1353 }
1354 1354
1355 1355 /*
1356 1356 * Called during boot.
1357 1357 *
1358 1358 * Walk through the DB and apply all the global module properties. We plow
1359 1359 * through the DB even if we fail to apply property.
1360 1360 */
1361 1361 /* ARGSUSED */
1362 1362 static boolean_t
1363 1363 ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1364 1364 int *errp)
1365 1365 {
1366 1366 ipadm_handle_t iph = cbarg;
1367 1367 nvpair_t *nvp, *pnvp;
1368 1368 char *strval = NULL, *name, *mod = NULL, *pname;
1369 1369 char tmpstr[IPMGMT_STRSIZE];
1370 1370 uint_t proto;
1371 1371
1372 1372 /*
1373 1373 * We could have used nvl_exists() directly, however we need several
1374 1374 * calls to it and each call traverses the list. Since this codepath
1375 1375 * is exercised during boot, let's traverse the list ourselves and do
1376 1376 * the necessary checks.
1377 1377 */
1378 1378 for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1379 1379 nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1380 1380 name = nvpair_name(nvp);
1381 1381 if (IPADM_PRIV_NVP(name)) {
1382 1382 if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1383 1383 strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1384 1384 return (B_TRUE);
1385 1385 else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1386 1386 nvpair_value_string(nvp, &mod) != 0)
1387 1387 return (B_TRUE);
1388 1388 } else {
1389 1389 /* possible a property */
1390 1390 pnvp = nvp;
1391 1391 }
1392 1392 }
1393 1393
1394 1394 /* if we are here than we found a global property */
1395 1395 assert(mod != NULL);
1396 1396 assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1397 1397
1398 1398 proto = ipadm_str2proto(mod);
1399 1399 name = nvpair_name(pnvp);
1400 1400 if (nvpair_value_string(pnvp, &strval) == 0) {
1401 1401 if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1402 1402 strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1403 1403 /* private protocol property */
1404 1404 pname = &name[1];
1405 1405 } else if (ipadm_legacy2new_propname(name, tmpstr,
1406 1406 sizeof (tmpstr), &proto) == 0) {
1407 1407 pname = tmpstr;
1408 1408 } else {
1409 1409 pname = name;
1410 1410 }
1411 1411 if (ipadm_set_prop(iph, pname, strval, proto,
1412 1412 IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1413 1413 ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1414 1414 pname);
1415 1415 }
1416 1416 }
1417 1417
1418 1418 return (B_TRUE);
1419 1419 }
1420 1420
1421 1421 /* initialize global module properties */
1422 1422 void
1423 1423 ipmgmt_init_prop()
1424 1424 {
1425 1425 ipadm_handle_t iph = NULL;
1426 1426
1427 1427 if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
1428 1428 ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
1429 1429 "persisted protocol properties");
1430 1430 return;
1431 1431 }
1432 1432 /* ipmgmt_db_init() logs warnings if there are any issues */
1433 1433 (void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
1434 1434 ipadm_close(iph);
1435 1435 }
1436 1436
1437 1437 void
1438 1438 ipmgmt_release_scf_resources(scf_resources_t *res)
1439 1439 {
1440 1440 scf_entry_destroy(res->sr_ent);
1441 1441 scf_transaction_destroy(res->sr_tx);
1442 1442 scf_value_destroy(res->sr_val);
1443 1443 scf_property_destroy(res->sr_prop);
1444 1444 scf_pg_destroy(res->sr_pg);
1445 1445 scf_instance_destroy(res->sr_inst);
1446 1446 (void) scf_handle_unbind(res->sr_handle);
1447 1447 scf_handle_destroy(res->sr_handle);
1448 1448 }
1449 1449
1450 1450 /*
1451 1451 * It creates the necessary SCF handles and binds the given `fmri' to an
1452 1452 * instance. These resources are required for retrieving property value,
1453 1453 * creating property groups and modifying property values.
1454 1454 */
1455 1455 int
1456 1456 ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1457 1457 {
1458 1458 res->sr_tx = NULL;
1459 1459 res->sr_ent = NULL;
1460 1460 res->sr_inst = NULL;
1461 1461 res->sr_pg = NULL;
1462 1462 res->sr_prop = NULL;
1463 1463 res->sr_val = NULL;
1464 1464
1465 1465 if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1466 1466 return (-1);
1467 1467
1468 1468 if (scf_handle_bind(res->sr_handle) != 0) {
1469 1469 scf_handle_destroy(res->sr_handle);
1470 1470 return (-1);
1471 1471 }
1472 1472 if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1473 1473 goto failure;
1474 1474 if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1475 1475 res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1476 1476 goto failure;
1477 1477 }
1478 1478 /* we will create the rest of the resources on demand */
1479 1479 return (0);
1480 1480
1481 1481 failure:
1482 1482 ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
1483 1483 scf_strerror(scf_error()));
1484 1484 ipmgmt_release_scf_resources(res);
1485 1485 return (-1);
1486 1486 }
1487 1487
1488 1488 /*
1489 1489 * persists the `pval' for a given property `pname' in SCF. The only supported
1490 1490 * SCF property types are INTEGER and ASTRING.
1491 1491 */
1492 1492 static int
1493 1493 ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
1494 1494 scf_type_t ptype)
1495 1495 {
1496 1496 int result = -1;
1497 1497 boolean_t new;
1498 1498
1499 1499 if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
1500 1500 goto failure;
1501 1501 switch (ptype) {
1502 1502 case SCF_TYPE_INTEGER:
1503 1503 scf_value_set_integer(res->sr_val, *(int64_t *)pval);
1504 1504 break;
1505 1505 case SCF_TYPE_ASTRING:
1506 1506 if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
1507 1507 ipmgmt_log(LOG_WARNING, "Error setting string value %s "
1508 1508 "for property %s: %s", pval, pname,
1509 1509 scf_strerror(scf_error()));
1510 1510 goto failure;
1511 1511 }
1512 1512 break;
1513 1513 default:
1514 1514 goto failure;
1515 1515 }
1516 1516
1517 1517 if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
1518 1518 goto failure;
1519 1519 if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
1520 1520 goto failure;
1521 1521 if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
1522 1522 goto failure;
1523 1523
1524 1524 retry:
1525 1525 new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
1526 1526 if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
1527 1527 goto failure;
1528 1528 if (new) {
1529 1529 if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
1530 1530 pname, ptype) == -1) {
1531 1531 goto failure;
1532 1532 }
1533 1533 } else {
1534 1534 if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
1535 1535 pname, ptype) == -1) {
1536 1536 goto failure;
1537 1537 }
1538 1538 }
1539 1539
1540 1540 if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1541 1541 goto failure;
1542 1542
1543 1543 result = scf_transaction_commit(res->sr_tx);
1544 1544 if (result == 0) {
1545 1545 scf_transaction_reset(res->sr_tx);
1546 1546 if (scf_pg_update(res->sr_pg) == -1) {
1547 1547 goto failure;
1548 1548 }
1549 1549 goto retry;
1550 1550 }
1551 1551 if (result == -1)
1552 1552 goto failure;
1553 1553 return (0);
1554 1554
1555 1555 failure:
1556 1556 ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
1557 1557 scf_strerror(scf_error()));
1558 1558 return (-1);
1559 1559 }
1560 1560
1561 1561 /*
1562 1562 * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1563 1563 * places it in `pval'.
1564 1564 */
1565 1565 static int
1566 1566 ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1567 1567 void *pval, scf_type_t ptype)
1568 1568 {
1569 1569 ssize_t numvals;
1570 1570 scf_simple_prop_t *prop;
1571 1571
1572 1572 prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1573 1573 numvals = scf_simple_prop_numvalues(prop);
1574 1574 if (numvals <= 0)
1575 1575 goto ret;
1576 1576 switch (ptype) {
1577 1577 case SCF_TYPE_INTEGER:
1578 1578 *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1579 1579 break;
1580 1580 case SCF_TYPE_ASTRING:
1581 1581 *(char **)pval = scf_simple_prop_next_astring(prop);
1582 1582 break;
1583 1583 }
1584 1584 ret:
1585 1585 scf_simple_prop_free(prop);
1586 1586 return (numvals);
1587 1587 }
1588 1588
1589 1589 /*
1590 1590 * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1591 1591 */
1592 1592 static int
1593 1593 ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1594 1594 void *pval, scf_type_t ptype)
1595 1595 {
1596 1596 scf_error_t err;
1597 1597
1598 1598 if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1599 1599 ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1600 1600 scf_strerror(scf_error()));
1601 1601 return (-1);
1602 1602 }
1603 1603
1604 1604 if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
1605 1605 0, res->sr_pg) != 0) {
1606 1606 if ((err = scf_error()) != SCF_ERROR_EXISTS) {
1607 1607 ipmgmt_log(LOG_WARNING,
1608 1608 "Error adding property group '%s/%s': %s",
1609 1609 pgname, pname, scf_strerror(err));
1610 1610 return (-1);
1611 1611 }
1612 1612 /*
1613 1613 * if the property group already exists, then we get the
1614 1614 * composed view of the property group for the given instance.
1615 1615 */
1616 1616 if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
1617 1617 res->sr_pg) != 0) {
1618 1618 ipmgmt_log(LOG_WARNING, "Error getting composed view "
1619 1619 "of the property group '%s/%s': %s", pgname, pname,
1620 1620 scf_strerror(scf_error()));
1621 1621 return (-1);
1622 1622 }
1623 1623 }
1624 1624
1625 1625 return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
1626 1626 }
1627 1627
1628 1628 /*
1629 1629 * Returns B_TRUE, if the non-global zone is being booted for the first time
1630 1630 * after being installed. This is required to setup the ipadm data-store for
1631 1631 * the first boot of the non-global zone. Please see, PSARC 2010/166,
1632 1632 * for more info.
1633 1633 *
1634 1634 * Note that, this API cannot be used to determine first boot post image-update.
1635 1635 * 'pkg image-update' clones the current BE and the existing value of
1636 1636 * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1637 1637 * to B_TRUE.
1638 1638 */
1639 1639 boolean_t
1640 1640 ipmgmt_ngz_firstboot_postinstall()
1641 1641 {
1642 1642 scf_resources_t res;
1643 1643 boolean_t bval = B_TRUE;
1644 1644 char *strval;
1645 1645
1646 1646 /* we always err on the side of caution */
1647 1647 if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
1648 1648 return (bval);
1649 1649
1650 1650 if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
1651 1651 SCF_TYPE_ASTRING) > 0) {
1652 1652 bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
1653 1653 B_FALSE : B_TRUE);
1654 1654 } else {
1655 1655 /*
1656 1656 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1657 1657 * Since we err on the side of caution, we ignore the return
1658 1658 * error and return B_TRUE.
1659 1659 */
1660 1660 (void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
1661 1661 IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1662 1662 }
1663 1663 ipmgmt_release_scf_resources(&res);
1664 1664 return (bval);
1665 1665 }
1666 1666
1667 1667 /*
1668 1668 * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1669 1669 * Today we have to take care of, one case of, upgrading from version 0 to
1670 1670 * version 1, so we will use boolean_t as means to decide if upgrade is needed
1671 1671 * or not. Further, the upcoming projects might completely move the flatfile
1672 1672 * data-store into SCF and hence we shall keep this interface simple.
1673 1673 */
1674 1674 boolean_t
1675 1675 ipmgmt_needs_upgrade(scf_resources_t *res)
1676 1676 {
1677 1677 boolean_t bval = B_TRUE;
1678 1678 int64_t *verp;
1679 1679
1680 1680 if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
1681 1681 &verp, SCF_TYPE_INTEGER) > 0) {
1682 1682 if (*verp == IPADM_DB_VERSION)
1683 1683 bval = B_FALSE;
1684 1684 }
1685 1685 /*
1686 1686 * 'datastore_version' doesn't exist. Which means that we need to
1687 1687 * upgrade the datastore. We will create 'datastore_version' and set
1688 1688 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1689 1689 */
1690 1690 return (bval);
1691 1691 }
1692 1692
1693 1693 /*
1694 1694 * This is called after the successful upgrade of the local data-store. With
1695 1695 * the data-store upgraded to recent version we don't have to do anything on
1696 1696 * subsequent reboots.
1697 1697 */
1698 1698 void
1699 1699 ipmgmt_update_dbver(scf_resources_t *res)
1700 1700 {
1701 1701 int64_t version = IPADM_DB_VERSION;
1702 1702
1703 1703 (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1704 1704 IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1705 1705 }
|
↓ open down ↓ |
1705 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX