Implement bind mount to overwrite /etc/resolv.conf instead of the
current method of rename followed by copy. The bind mount method
works even if the file is designated as immutable
Signed-off-by: Srihari Parimi <sparimi(a)redhat.com>
---
daemon/sh.c | 86 ++++++++++++++++++++++-------------------------------
1 file changed, 35 insertions(+), 51 deletions(-)
diff --git a/daemon/sh.c b/daemon/sh.c
index 74e003410..aab9a4534 100644
--- a/daemon/sh.c
+++ b/daemon/sh.c
@@ -150,8 +150,9 @@ free_bind_state (struct bind_state *bs)
static int
set_up_etc_resolv_conf (struct resolver_state *rs)
{
+ char *src_etc_resolv = "/etc/resolv.conf";
struct stat statbuf;
- CLEANUP_FREE char *buf = NULL;
+ int r, fd = -1;
rs->sysroot_etc_resolv_conf_old = NULL;
@@ -161,50 +162,43 @@ set_up_etc_resolv_conf (struct resolver_state *rs)
reply_with_perror ("malloc");
goto error;
}
-
- /* If /etc/resolv.conf exists, rename it to the backup file. Note
- * that on Ubuntu it's a dangling symlink.
+ /* If /sysroot/etc/resolv.conf does not exist, create one for mount
+ * bind to succeed. lstat() call handles dnagling links
*/
- if (lstat (rs->sysroot_etc_resolv_conf, &statbuf) == 0) {
- /* Make a random name for the backup file. */
- if (asprintf (&buf, "%s/etc/XXXXXXXX", sysroot) == -1) {
- reply_with_perror ("asprintf");
- goto error;
- }
- if (random_name (buf) == -1) {
- reply_with_perror ("random_name");
- goto error;
- }
- rs->sysroot_etc_resolv_conf_old = strdup (buf);
- if (!rs->sysroot_etc_resolv_conf_old) {
- reply_with_perror ("strdup");
- goto error;
+ if (lstat (rs->sysroot_etc_resolv_conf, &statbuf) != 0) {
+ if (errno != ENOENT) {
+ reply_with_perror ("lstat: %s", rs->sysroot_etc_resolv_conf);
+ return -1;
}
-
- if (verbose)
- fprintf (stderr, "renaming %s to %s\n", rs->sysroot_etc_resolv_conf,
- rs->sysroot_etc_resolv_conf_old);
-
- if (rename (rs->sysroot_etc_resolv_conf,
- rs->sysroot_etc_resolv_conf_old) == -1) {
- reply_with_perror ("rename: %s to %s", rs->sysroot_etc_resolv_conf,
- rs->sysroot_etc_resolv_conf_old);
- goto error;
+ /* create empty file */
+ fd = open (rs->sysroot_etc_resolv_conf,
+ O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
+ if (fd == -1) {
+ reply_with_perror ("open: %s", rs->sysroot_etc_resolv_conf);
+ return -1;
}
+ close(fd);
}
-
- /* Now that the guest's <sysroot>/etc/resolv.conf is out the way, we
- * can create our own copy of the appliance /etc/resolv.conf.
- */
- ignore_value (command (NULL, NULL, "cp", "/etc/resolv.conf",
- rs->sysroot_etc_resolv_conf, NULL));
-
+ if (verbose)
+ fprintf (stderr, "mount %s to %s\n", src_etc_resolv,
+ rs->sysroot_etc_resolv_conf);
+ /* mount bind read only */
+ r = command (NULL, NULL, "mount", "--bind", "-o ro",
src_etc_resolv,
+ rs->sysroot_etc_resolv_conf, NULL);
+ if (r == -1) {
+ reply_with_perror ("mount: %s to %s failed\n",
+ src_etc_resolv, rs->sysroot_etc_resolv_conf);
+ goto error;
+ }
+ if (verbose)
+ fprintf (stderr, "mount %s to %s done\n", src_etc_resolv,
+ rs->sysroot_etc_resolv_conf);
rs->mounted = true;
+
return 0;
- error:
+error:
free (rs->sysroot_etc_resolv_conf);
- free (rs->sysroot_etc_resolv_conf_old);
return -1;
}
@@ -212,20 +206,10 @@ static void
free_resolver_state (struct resolver_state *rs)
{
if (rs->mounted) {
- unlink (rs->sysroot_etc_resolv_conf);
-
- if (rs->sysroot_etc_resolv_conf_old) {
- if (verbose)
- fprintf (stderr, "renaming %s to %s\n",
rs->sysroot_etc_resolv_conf_old,
- rs->sysroot_etc_resolv_conf);
-
- if (rename (rs->sysroot_etc_resolv_conf_old,
- rs->sysroot_etc_resolv_conf) == -1)
- perror ("error: could not restore /etc/resolv.conf");
-
- free (rs->sysroot_etc_resolv_conf_old);
- }
-
+ /* umount sysroot_etc_resolv_conf */
+ if (verbose)
+ fprintf (stderr, "umount %s\n", rs->sysroot_etc_resolv_conf);
+ umount_ignore_fail(rs->sysroot_etc_resolv_conf);
free (rs->sysroot_etc_resolv_conf);
rs->mounted = false;
}
--
2.52.0