static int path_is_on_readonly_fs (char *path) { struct statvfs stvfsbuf; if (statvfs (path, &stvfsbuf) == -1) { perrorv ("statvfs(%s): ", path); exit (1); } return (stvfsbuf.f_flag & ST_RDONLY) != 0; }
int main(int argc, char *argv[]) { const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL }; struct stat stbuf; int i; if (path_is_on_readonly_fs ("/")) { /* If / isn't writable, don't do any remounts; we don't want * to clear the readonly flag in that case. */ maybe_mount_tmpfs_on_var (); exit (0); } for (i = 0; remounts[i] != NULL; i++) { const char *target = remounts[i]; if (lstat (target, &stbuf) < 0) continue; /* Silently ignore symbolic links; we expect these to point to * /sysroot, and thus there isn't a bind mount there. */ if (S_ISLNK (stbuf.st_mode)) continue; if (mount (target, target, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) { /* Also ignore ENINVAL - if the target isn't a mountpoint * already, then assume things are OK. */ if (errno != EINVAL) { perrorv ("failed to remount %s", target); exit (1); } } } maybe_mount_tmpfs_on_var (); exit (0); }
int main(int argc, char *argv[]) { const char *readonly_bind_mounts[] = { "/usr", NULL }; const char *root_mountpoint = NULL; char *ostree_target = NULL; char *deploy_path = NULL; char srcpath[PATH_MAX]; char destpath[PATH_MAX]; struct stat stbuf; int i; if (argc < 2) { fprintf (stderr, "usage: ostree-prepare-root SYSROOT\n"); exit (1); } root_mountpoint = argv[1]; ostree_target = parse_ostree_cmdline (); if (!ostree_target) { fprintf (stderr, "No OSTree target; expected ostree=/ostree/boot.N/...\n"); exit (1); } snprintf (destpath, sizeof(destpath), "%s/%s", root_mountpoint, ostree_target); fprintf (stderr, "Examining %s\n", destpath); if (lstat (destpath, &stbuf) < 0) { perrorv ("Couldn't find specified OSTree root '%s': ", destpath); exit (1); } if (!S_ISLNK (stbuf.st_mode)) { fprintf (stderr, "OSTree target is not a symbolic link: %s\n", destpath); exit (1); } deploy_path = realpath (destpath, NULL); if (deploy_path == NULL) { perrorv ("realpath(%s) failed: ", destpath); exit (1); } fprintf (stderr, "Resolved OSTree target to: %s\n", deploy_path); /* Work-around for a kernel bug: for some reason the kernel * refuses switching root if any file systems are mounted * MS_SHARED. Hence remount them MS_PRIVATE here as a * work-around. * * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ if (mount (NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) { perrorv ("Failed to make \"/\" private mount: %m"); exit (1); } /* Make deploy_path a bind mount, so we can move it later */ if (mount (deploy_path, deploy_path, NULL, MS_BIND, NULL) < 0) { perrorv ("failed to initial bind mount %s", deploy_path); exit (1); } snprintf (destpath, sizeof(destpath), "%s/sysroot", deploy_path); if (mount (root_mountpoint, destpath, NULL, MS_BIND, NULL) < 0) { perrorv ("Failed to bind mount %s to '%s'", root_mountpoint, destpath); exit (1); } snprintf (srcpath, sizeof(srcpath), "%s/../../var", deploy_path); snprintf (destpath, sizeof(destpath), "%s/var", deploy_path); if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0) { perrorv ("failed to bind mount %s to %s", srcpath, destpath); exit (1); } for (i = 0; readonly_bind_mounts[i] != NULL; i++) { snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, readonly_bind_mounts[i]); if (mount (destpath, destpath, NULL, MS_BIND, NULL) < 0) { perrorv ("failed to bind mount (class:readonly) %s", destpath); exit (1); } if (mount (destpath, destpath, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0) { perrorv ("failed to bind mount (class:readonly) %s", destpath); exit (1); } } /* This is a bit hacky - move our deployment to /sysroot, since * systemd's initrd-switch-root target hardcodes looking for it * there. */ if (mount (deploy_path, root_mountpoint, NULL, MS_MOVE, NULL) < 0) { perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint); exit (1); } exit (0); }