4343#include "otcore.h"
4444
4545static void
46- do_remount (const char * target , bool writable )
46+ do_remount (const char * target , bool writable , bool use_warn )
4747{
4848 struct stat stbuf ;
4949 if (lstat (target , & stbuf ) < 0 )
@@ -53,18 +53,27 @@ do_remount (const char *target, bool writable)
5353 */
5454 if (S_ISLNK (stbuf .st_mode ))
5555 return ;
56- /* If not a mountpoint, skip it */
56+
5757 struct statvfs stvfsbuf ;
5858 if (statvfs (target , & stvfsbuf ) == -1 )
59- return ;
59+ err ( EXIT_FAILURE , "failed to statvfs(%s)" , target ) ;
6060
61- const bool currently_writable = ((stvfsbuf .f_flag & ST_RDONLY ) == 0 );
62- if (writable == currently_writable )
63- return ;
61+ if (writable )
62+ {
63+ // vfs could be 'rw' but fs 'ro', so use access to check
64+ if (access (target , W_OK ) == 0 )
65+ return ;
66+ }
67+ else
68+ {
69+ // ensure vfs 'ro' mount flags is set even if fs is ro
70+ if ((stvfsbuf .f_flag & ST_RDONLY ) != 0 )
71+ return ;
72+ }
6473
6574 int mnt_flags = MS_REMOUNT | MS_SILENT ;
6675 if (!writable )
67- mnt_flags |= MS_RDONLY ;
76+ mnt_flags |= MS_BIND | MS_RDONLY ;
6877 if (mount (target , target , NULL , mnt_flags , NULL ) < 0 )
6978 {
7079 /* Also ignore EINVAL - if the target isn't a mountpoint
@@ -76,7 +85,10 @@ do_remount (const char *target, bool writable)
7685 return ;
7786 }
7887
79- printf ("Remounted %s: %s\n" , writable ? "rw" : "ro" , target );
88+ if (use_warn )
89+ warn ("Remounted %s: %s\n" , writable ? "rw" : "ro" , target );
90+ else
91+ printf ("Remounted %s: %s\n" , writable ? "rw" : "ro" , target );
8092}
8193
8294/* Relabel the directory $real_path, which is going to be an overlayfs mount,
@@ -226,29 +238,25 @@ main (int argc, char *argv[])
226238 }
227239
228240 /* Handle remounting /sysroot; if it's explicitly marked as read-only (opt in)
229- * then ensure it's readonly, otherwise mount writable, the same as /
241+ * then ensure it's readonly, otherwise remount writable, the same as /
242+ * We should not need this so warn when we do remount.
230243 */
231244 gboolean sysroot_configured_readonly = FALSE;
232245 g_variant_dict_lookup (ostree_run_metadata , OTCORE_RUN_BOOTED_KEY_SYSROOT_RO , "b" ,
233246 & sysroot_configured_readonly );
234- do_remount ("/sysroot" , !sysroot_configured_readonly );
247+ do_remount ("/sysroot" , !sysroot_configured_readonly , true );
235248
236- /* And also make sure to make /etc rw again. We make this conditional on
237- * sysroot_configured_readonly && !transient_etc because only in that case is it a
238- * bind-mount. */
249+ /* Make sure /etc is 'rw'. We make this conditional on sysroot_configured_readonly
250+ * && !transient_etc because only in that case is it a bind-mount.
251+ * We should not need this so warn when we do remount.
252+ */
239253 if (sysroot_configured_readonly && !transient_etc )
240- do_remount ("/etc" , true);
241-
242- /* If /var was created as as an OSTree default bind mount (instead of being a separate
243- * filesystem) then remounting the root mount read-only also remounted it. So just like /etc, we
244- * need to make it read-write by default. If it was a separate filesystem, we expect it to be
245- * writable anyways, so it doesn't hurt to remount it if so.
246- *
247- * And if we started out with a writable system root, then we need
248- * to ensure that the /var bind mount created by the systemd generator
249- * is writable too.
254+ do_remount ("/etc" , true, true);
255+
256+ /* If mount uses the legacy mount API (before util-linux 2.39), then the 'rw'
257+ * mount option in the 'var.mount' unit is ignored, so we need to remount here.
250258 */
251- do_remount ("/var" , true);
259+ do_remount ("/var" , true, false );
252260
253261 exit (EXIT_SUCCESS );
254262}
0 commit comments