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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Argo Technologie SA.
25 */
26
27 /*
28 * Contains DB walker functions, which are of type `db_wfunc_t';
29 *
30 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
31 * size_t bufsize, int *errp);
32 *
33 * ipadm_rw_db() walks through the data store, one line at a time and calls
34 * these call back functions with:
35 * `cbarg' - callback argument
36 * `db_nvl' - representing a line from DB in nvlist_t form
37 * `buf' - character buffer to hold modified line
38 * `bufsize'- size of the buffer
39 * `errp' - captures any error inside the walker function.
40 *
41 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
42 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
43 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
367 cbarg->cb_ocnt++;
368 }
369 return (B_TRUE);
370 }
371
372 /*
373 * This function only gets called if a volatile filesystem version
374 * of the configuration file has been created. This only happens in the
375 * extremely rare case that a request has been made to update the configuration
376 * file at boottime while the root filesystem was read-only. This is
377 * really a rare occurrence now that we don't support UFS root filesystems
378 * any longer. This function will periodically attempt to write the
379 * configuration back to its location on the root filesystem. Success
380 * will indicate that the filesystem is no longer read-only.
381 */
382 /* ARGSUSED */
383 static void *
384 ipmgmt_db_restore_thread(void *arg)
385 {
386 int err;
387
388 for (;;) {
389 (void) sleep(5);
390 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
391 if (!ipmgmt_rdonly_root)
392 break;
393 err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
394 if (err == 0) {
395 ipmgmt_rdonly_root = B_FALSE;
396 break;
397 }
398 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
399 }
400 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
401 return (NULL);
402 }
403
404 /*
405 * This function takes the appropriate lock, read or write, based on the
406 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
407 * by the fact that we are not always guaranteed to have a writable root
408 * filesystem since it is possible that we are reading or writing during
409 * bootime while the root filesystem is still read-only. This is, by far,
410 * the exception case. Normally, this function will be called when the
411 * root filesystem is writable. In the unusual case where this is not
412 * true, the configuration file is copied to the volatile file system
413 * and is updated there until the root filesystem becomes writable. At
414 * that time the file will be moved back to its proper location by
415 * ipmgmt_db_restore_thread().
416 */
417 extern int
418 ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
419 {
420 int err;
421 boolean_t writeop;
422 mode_t mode;
423 pthread_t tid;
424 pthread_attr_t attr;
425
426 writeop = (db_op != IPADM_DB_READ);
427 if (writeop) {
428 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
429 mode = IPADM_FILE_MODE;
430 } else {
431 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
432 mode = 0;
433 }
434
435 /*
436 * Did a previous write attempt fail? If so, don't even try to
437 * read/write to IPADM_DB_FILE.
438 */
439 if (!ipmgmt_rdonly_root) {
440 err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
441 mode, db_op);
442 if (err != EROFS)
443 goto done;
444 }
445
446 /*
447 * If we haven't already copied the file to the volatile
448 * file system, do so. This should only happen on a failed
449 * writeop(i.e., we have acquired the write lock above).
450 */
451 if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
452 assert(writeop);
453 err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
454 if (err != 0)
455 goto done;
456 (void) pthread_attr_init(&attr);
457 (void) pthread_attr_setdetachstate(&attr,
458 PTHREAD_CREATE_DETACHED);
459 err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
460 NULL);
461 (void) pthread_attr_destroy(&attr);
462 if (err != 0) {
463 (void) unlink(IPADM_VOL_DB_FILE);
464 goto done;
465 }
466 ipmgmt_rdonly_root = B_TRUE;
467 }
468
469 /*
470 * Read/write from the volatile copy.
471 */
472 err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
473 mode, db_op);
474 done:
475 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
476 return (err);
477 }
478
479 /*
480 * Used to add an entry towards the end of DB. It just returns B_TRUE for
481 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
482 * line at the end.
483 */
484 /* ARGSUSED */
485 boolean_t
486 ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
487 {
488 return (B_TRUE);
489 }
490
491 /*
492 * This function is used to update or create an entry in DB. The nvlist_t,
1220 &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1221 return (B_TRUE);
1222 }
1223
1224 /* we found the match, delete the line from the db */
1225 buf[0] = '\0';
1226
1227 /* stop the walker */
1228 return (B_FALSE);
1229 }
1230
1231 /*
1232 * Adds or deletes aobjmap node information into a temporary cache file.
1233 */
1234 extern int
1235 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1236 {
1237 int err;
1238 ipadm_dbwrite_cbarg_t cb;
1239 nvlist_t *nvl = NULL;
1240
1241 if (op == IPADM_DB_WRITE) {
1242 if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1243 return (err);
1244 cb.dbw_nvl = nvl;
1245 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1246 cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1247 else
1248 cb.dbw_flags = 0;
1249
1250 err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
1251 ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
1252 nvlist_free(nvl);
1253 } else {
1254 assert(op == IPADM_DB_DELETE);
1255
1256 err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
1257 ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
1258 }
1259 return (err);
1260 }
1261
1262 /*
1263 * upgrades the ipadm data-store. It renames all the old private protocol
1264 * property names which start with leading protocol names to begin with
1265 * IPADM_PRIV_PROP_PREFIX.
1266 */
1267 /* ARGSUSED */
1268 boolean_t
1269 ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1270 int *errp)
1271 {
1272 nvpair_t *nvp;
1273 char *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1274 uint_t proto, nproto;
1275 char nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1276
1277 *errp = 0;
|
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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 * Copyright 2016 Argo Technologie SA.
26 */
27
28 /*
29 * Contains DB walker functions, which are of type `db_wfunc_t';
30 *
31 * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
32 * size_t bufsize, int *errp);
33 *
34 * ipadm_rw_db() walks through the data store, one line at a time and calls
35 * these call back functions with:
36 * `cbarg' - callback argument
37 * `db_nvl' - representing a line from DB in nvlist_t form
38 * `buf' - character buffer to hold modified line
39 * `bufsize'- size of the buffer
40 * `errp' - captures any error inside the walker function.
41 *
42 * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
43 * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
44 * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
368 cbarg->cb_ocnt++;
369 }
370 return (B_TRUE);
371 }
372
373 /*
374 * This function only gets called if a volatile filesystem version
375 * of the configuration file has been created. This only happens in the
376 * extremely rare case that a request has been made to update the configuration
377 * file at boottime while the root filesystem was read-only. This is
378 * really a rare occurrence now that we don't support UFS root filesystems
379 * any longer. This function will periodically attempt to write the
380 * configuration back to its location on the root filesystem. Success
381 * will indicate that the filesystem is no longer read-only.
382 */
383 /* ARGSUSED */
384 static void *
385 ipmgmt_db_restore_thread(void *arg)
386 {
387 int err;
388 char confpath[MAXPATHLEN];
389 char tmpconfpath[MAXPATHLEN];
390
391 ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
392 ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
393
394 for (;;) {
395 (void) sleep(5);
396 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
397 if (!ipmgmt_rdonly_root)
398 break;
399 err = ipmgmt_cpfile(tmpconfpath, confpath, B_FALSE);
400 if (err == 0) {
401 ipmgmt_rdonly_root = B_FALSE;
402 break;
403 }
404 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
405 }
406 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
407 return (NULL);
408 }
409
410 /*
411 * This function takes the appropriate lock, read or write, based on the
412 * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
413 * by the fact that we are not always guaranteed to have a writable root
414 * filesystem since it is possible that we are reading or writing during
415 * bootime while the root filesystem is still read-only. This is, by far,
416 * the exception case. Normally, this function will be called when the
417 * root filesystem is writable. In the unusual case where this is not
418 * true, the configuration file is copied to the volatile file system
419 * and is updated there until the root filesystem becomes writable. At
420 * that time the file will be moved back to its proper location by
421 * ipmgmt_db_restore_thread().
422 */
423 extern int
424 ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
425 {
426 int err;
427 boolean_t writeop;
428 mode_t mode;
429 pthread_t tid;
430 pthread_attr_t attr;
431 char confpath[MAXPATHLEN];
432 char tmpconfpath[MAXPATHLEN];
433
434 ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
435 ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
436
437 writeop = (db_op != IPADM_DB_READ);
438 if (writeop) {
439 (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
440 mode = IPADM_FILE_MODE;
441 } else {
442 (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
443 mode = 0;
444 }
445
446 /*
447 * Did a previous write attempt fail? If so, don't even try to
448 * read/write to the permanent configuration file.
449 */
450 if (!ipmgmt_rdonly_root) {
451 err = ipadm_rw_db(db_walk_func, db_warg, confpath, mode, db_op);
452 if (err != EROFS)
453 goto done;
454 }
455
456 /*
457 * If we haven't already copied the file to the volatile
458 * file system, do so. This should only happen on a failed
459 * writeop (i.e., we have acquired the write lock above).
460 */
461 if (access(tmpconfpath, F_OK) != 0) {
462 assert(writeop);
463 err = ipmgmt_cpfile(confpath, tmpconfpath, B_TRUE);
464 if (err != 0)
465 goto done;
466 (void) pthread_attr_init(&attr);
467 (void) pthread_attr_setdetachstate(&attr,
468 PTHREAD_CREATE_DETACHED);
469 err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
470 NULL);
471 (void) pthread_attr_destroy(&attr);
472 if (err != 0) {
473 (void) unlink(tmpconfpath);
474 goto done;
475 }
476 ipmgmt_rdonly_root = B_TRUE;
477 }
478
479 /*
480 * Read/write from the volatile copy.
481 */
482 err = ipadm_rw_db(db_walk_func, db_warg, tmpconfpath,
483 mode, db_op);
484 done:
485 (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
486 return (err);
487 }
488
489 /*
490 * Used to add an entry towards the end of DB. It just returns B_TRUE for
491 * every line of the DB. When we reach the end, ipadm_rw_db() adds the
492 * line at the end.
493 */
494 /* ARGSUSED */
495 boolean_t
496 ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
497 {
498 return (B_TRUE);
499 }
500
501 /*
502 * This function is used to update or create an entry in DB. The nvlist_t,
1230 &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1231 return (B_TRUE);
1232 }
1233
1234 /* we found the match, delete the line from the db */
1235 buf[0] = '\0';
1236
1237 /* stop the walker */
1238 return (B_FALSE);
1239 }
1240
1241 /*
1242 * Adds or deletes aobjmap node information into a temporary cache file.
1243 */
1244 extern int
1245 ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1246 {
1247 int err;
1248 ipadm_dbwrite_cbarg_t cb;
1249 nvlist_t *nvl = NULL;
1250 char aobjpath[MAXPATHLEN];
1251
1252 ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
1253
1254 if (op == IPADM_DB_WRITE) {
1255 if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1256 return (err);
1257 cb.dbw_nvl = nvl;
1258 if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1259 cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1260 else
1261 cb.dbw_flags = 0;
1262
1263 err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb, aobjpath,
1264 IPADM_FILE_MODE, IPADM_DB_WRITE);
1265 nvlist_free(nvl);
1266 } else {
1267 assert(op == IPADM_DB_DELETE);
1268
1269 err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep, aobjpath,
1270 IPADM_FILE_MODE, IPADM_DB_DELETE);
1271 }
1272 return (err);
1273 }
1274
1275 /*
1276 * upgrades the ipadm data-store. It renames all the old private protocol
1277 * property names which start with leading protocol names to begin with
1278 * IPADM_PRIV_PROP_PREFIX.
1279 */
1280 /* ARGSUSED */
1281 boolean_t
1282 ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1283 int *errp)
1284 {
1285 nvpair_t *nvp;
1286 char *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1287 uint_t proto, nproto;
1288 char nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1289
1290 *errp = 0;
|