summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet')
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h9
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c85
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c88
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);
+}