diff options
Diffstat (limited to 'usr/src/cmd/cmd-inet')
-rw-r--r-- | usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h | 9 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c | 85 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c | 88 |
3 files changed, 177 insertions, 5 deletions
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h index 36768b5ae0..4388c29971 100644 --- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h +++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h @@ -45,6 +45,7 @@ extern void ipmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t); /* ipmgmt_util.c */ extern void ipmgmt_log(int, const char *, ...); +extern int ipmgmt_cpfile(const char *, const char *, boolean_t); /* ipmgmt_persist.c */ @@ -137,8 +138,16 @@ extern ipmgmt_aobjmap_list_t aobjmap; * in-memory copy of list `aobjmap' on disk. This is done to recover from * daemon reboot (using svcadm) or crashes. */ +#define IPADM_TMPFS_DIR "/etc/svc/volatile/ipadm" #define ADDROBJ_MAPPING_DB_FILE IPADM_TMPFS_DIR"/aobjmap.conf" +/* + * A temporary copy of the ipadm configuration file might need + * to be created if write requests are encountered during boottime + * and the root filesystem is mounted read-only. + */ +#define IPADM_VOL_DB_FILE IPADM_TMPFS_DIR"/ipadm.conf" + extern int ipmgmt_db_walk(db_wfunc_t *, void *, ipadm_db_op_t); extern int ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *, uint32_t); extern boolean_t ipmgmt_aobjmap_init(void *, nvlist_t *, char *, diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c index 25e2f3a5ee..e316f888a2 100644 --- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c +++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c @@ -69,6 +69,9 @@ extern pthread_rwlock_t ipmgmt_dbconf_lock; +/* signifies whether volatile copy of data store is in use */ +static boolean_t ipmgmt_rdonly_root = B_FALSE; + /* * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed * in private nvpairs `proto', `ifname' & `aobjname'. @@ -358,8 +361,49 @@ ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, } /* + * This function only gets called if a volatile filesystem version + * of the configuration file has been created. This only happens in the + * extremely rare case that a request has been made to update the configuration + * file at boottime while the root filesystem was read-only. This is + * really a rare occurrence now that we don't support UFS root filesystems + * any longer. This function will periodically attempt to write the + * configuration back to its location on the root filesystem. Success + * will indicate that the filesystem is no longer read-only. + */ +/* ARGSUSED */ +static void * +ipmgmt_db_restore_thread(void *arg) +{ + int err; + + for (;;) { + (void) sleep(5); + (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock); + if (!ipmgmt_rdonly_root) + break; + err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE); + if (err == 0) { + ipmgmt_rdonly_root = B_FALSE; + break; + } + (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock); + } + (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock); + return (NULL); +} + +/* * This function takes the appropriate lock, read or write, based on the - * `db_op' and then calls DB walker ipadm_rw_db(). + * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated + * by the fact that we are not always guaranteed to have a writable root + * filesystem since it is possible that we are reading or writing during + * bootime while the root filesystem is still read-only. This is, by far, + * the exception case. Normally, this function will be called when the + * root filesystem is writable. In the unusual case where this is not + * true, the configuration file is copied to the volatile file system + * and is updated there until the root filesystem becomes writable. At + * that time the file will be moved back to its proper location by + * ipmgmt_db_restore_thread(). */ extern int ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op) @@ -367,9 +411,9 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op) int err; boolean_t writeop; mode_t mode; + pthread_t tid; writeop = (db_op != IPADM_DB_READ); - if (writeop) { (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock); mode = IPADM_FILE_MODE; @@ -378,7 +422,42 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op) mode = 0; } - err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE, mode, db_op); + /* + * Did a previous write attempt fail? If so, don't even try to + * read/write to IPADM_DB_FILE. + */ + if (!ipmgmt_rdonly_root) { + err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE, + mode, db_op); + if (err != EROFS) + goto done; + } + + /* + * If we haven't already copied the file to the volatile + * file system, do so. This should only happen on a failed + * writeop(i.e., we have acquired the write lock above). + */ + if (access(IPADM_VOL_DB_FILE, F_OK) != 0) { + assert(writeop); + err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE); + if (err != 0) + goto done; + err = pthread_create(&tid, NULL, ipmgmt_db_restore_thread, + NULL); + if (err != 0) { + (void) unlink(IPADM_VOL_DB_FILE); + goto done; + } + ipmgmt_rdonly_root = B_TRUE; + } + + /* + * Read/write from the volatile copy. + */ + err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE, + mode, db_op); +done: (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock); return (err); } diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c index 8ef9a09e3d..704dab2d36 100644 --- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c +++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -33,8 +32,12 @@ #include <stdio.h> #include <syslog.h> #include <stdarg.h> +#include <unistd.h> +#include <errno.h> #include "ipmgmt_impl.h" +#define IPMGMT_BUFSIZ 1024 + void ipmgmt_log(int pri, const char *fmt, ...) { @@ -44,3 +47,84 @@ ipmgmt_log(int pri, const char *fmt, ...) vsyslog(pri, fmt, alist); va_end(alist); } + +/* + * Copy a source file to a new destination. The source file will be + * removed if rdonly is false (i.e., used when the source file resides + * on a read-only file system). + * + * Returns 0 on success and errno on failure. + */ +int +ipmgmt_cpfile(const char *src, const char *dst, boolean_t rdonly) +{ + struct stat statbuf; + FILE *sfp, *dfp; + char buf[IPMGMT_BUFSIZ]; + size_t bytes; + int err = 0; + + /* + * Attempt to open the destination file first since we + * want to optimize for the case where it is read-only + * and will return EROFS. + */ + if ((dfp = fopen(dst, "w+")) == NULL) + return (errno); + + /* + * Require that the source file exists. + */ + if (stat(src, &statbuf) != 0) { + err = errno; + (void) fclose(dfp); + return (err); + } + if ((sfp = fopen(src, "r")) == NULL) { + err = errno; + (void) fclose(dfp); + return (err); + } + + /* + * Copy the file. + */ + while (((bytes = fread(buf, 1, sizeof (buf), sfp)) != 0) && + (errno == 0)) { + (void) fwrite(buf, bytes, 1, dfp); + if (errno != 0) + break; + } + if (errno != 0) + err = errno; + + (void) fclose(sfp); + (void) fclose(dfp); + + /* + * If any error occurred, then remove the destination file. + */ + if (err != 0) { + (void) unlink(dst); + return (err); + } + + /* + * Make sure the file attributes are correct. + */ + if (chmod(dst, IPADM_FILE_MODE) != 0 || + chown(dst, UID_NETADM, GID_NETADM) != 0) { + err = errno; + (void) unlink(dst); + return (err); + } + + /* + * If the source file does not reside on a read-only file system + * then remove it. + */ + if (!rdonly) + (void) unlink(src); + + return (0); +} |