Merge pull request #2113 from cgwalters/prepare-root-sysroot-ro
Move ro /sysroot bind mount of /etc into initramfs
This commit is contained in:
commit
936301608a
|
|
@ -30,11 +30,13 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define INITRAMFS_MOUNT_VAR "/run/ostree/initramfs-mount-var"
|
#define INITRAMFS_MOUNT_VAR "/run/ostree/initramfs-mount-var"
|
||||||
|
#define _OSTREE_SYSROOT_READONLY_STAMP "/run/ostree-sysroot-ro.stamp"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
path_is_on_readonly_fs (char *path)
|
path_is_on_readonly_fs (const char *path)
|
||||||
{
|
{
|
||||||
struct statvfs stvfsbuf;
|
struct statvfs stvfsbuf;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -83,6 +84,47 @@
|
||||||
/* Initialized early in main */
|
/* Initialized early in main */
|
||||||
static bool running_as_pid1;
|
static bool running_as_pid1;
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
sysroot_is_configured_ro (const char *sysroot)
|
||||||
|
{
|
||||||
|
char * config_path = NULL;
|
||||||
|
assert (asprintf (&config_path, "%s/ostree/repo/config", sysroot) != -1);
|
||||||
|
FILE *f = fopen(config_path, "r");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Missing expected repo config: %s\n", config_path);
|
||||||
|
free (config_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free (config_path);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
char *line = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t nread;
|
||||||
|
/* Note getline() will reuse the previous buffer */
|
||||||
|
bool in_sysroot = false;
|
||||||
|
while ((nread = getline (&line, &len, f)) != -1)
|
||||||
|
{
|
||||||
|
/* This is an awful hack to avoid depending on GLib in the
|
||||||
|
* initramfs right now.
|
||||||
|
*/
|
||||||
|
if (strstr (line, "[sysroot]") == line)
|
||||||
|
in_sysroot = true;
|
||||||
|
else if (*line == '[')
|
||||||
|
in_sysroot = false;
|
||||||
|
else if (in_sysroot && strstr (line, "readonly=true") == line)
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (f);
|
||||||
|
free (line);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
resolve_deploy_path (const char * root_mountpoint)
|
resolve_deploy_path (const char * root_mountpoint)
|
||||||
{
|
{
|
||||||
|
|
@ -192,6 +234,33 @@ main(int argc, char *argv[])
|
||||||
if (chdir (deploy_path) < 0)
|
if (chdir (deploy_path) < 0)
|
||||||
err (EXIT_FAILURE, "failed to chdir to deploy_path");
|
err (EXIT_FAILURE, "failed to chdir to deploy_path");
|
||||||
|
|
||||||
|
/* Query the repository configuration - this is an operating system builder
|
||||||
|
* choice. More info: https://github.com/ostreedev/ostree/pull/1767
|
||||||
|
*/
|
||||||
|
const bool sysroot_readonly = sysroot_is_configured_ro (root_arg);
|
||||||
|
const bool sysroot_currently_writable = !path_is_on_readonly_fs (root_arg);
|
||||||
|
|
||||||
|
#ifdef USE_LIBSYSTEMD
|
||||||
|
sd_journal_send ("MESSAGE=sysroot configured read-only: %d, currently writable: %d",
|
||||||
|
(int)sysroot_readonly, (int)sysroot_currently_writable, NULL);
|
||||||
|
#endif
|
||||||
|
if (sysroot_readonly)
|
||||||
|
{
|
||||||
|
if (!sysroot_currently_writable)
|
||||||
|
errx (EXIT_FAILURE, "sysroot=readonly currently requires writable / in initramfs");
|
||||||
|
/* Now, /etc is not normally a bind mount, but if we have a readonly
|
||||||
|
* sysroot, we still need a writable /etc. And to avoid race conditions
|
||||||
|
* we ensure it's writable in the initramfs, before we switchroot at all.
|
||||||
|
*/
|
||||||
|
if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0)
|
||||||
|
err (EXIT_FAILURE, "failed to make /etc a bind mount");
|
||||||
|
/* Pass on the fact that we discovered a readonly sysroot to ostree-remount.service */
|
||||||
|
int fd = open (_OSTREE_SYSROOT_READONLY_STAMP, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
|
||||||
|
if (fd < 0)
|
||||||
|
err (EXIT_FAILURE, "failed to create %s", _OSTREE_SYSROOT_READONLY_STAMP);
|
||||||
|
(void) close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
/* Default to true, but in the systemd case, default to false because it's handled by
|
/* Default to true, but in the systemd case, default to false because it's handled by
|
||||||
* ostree-system-generator. */
|
* ostree-system-generator. */
|
||||||
bool mount_var = true;
|
bool mount_var = true;
|
||||||
|
|
|
||||||
|
|
@ -81,24 +81,6 @@ do_remount (const char *target,
|
||||||
printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target);
|
printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
sysroot_is_configured_ro (void)
|
|
||||||
{
|
|
||||||
struct stat stbuf;
|
|
||||||
static const char config_path[] = "/ostree/repo/config";
|
|
||||||
if (stat (config_path, &stbuf) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
|
|
||||||
if (!g_key_file_load_from_file (keyfile, config_path, 0, NULL))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (g_key_file_get_boolean (keyfile, "sysroot", "readonly", NULL))
|
|
||||||
puts ("Ignoring sysroot.readonly config; see https://github.com/coreos/fedora-coreos-tracker/issues/488.");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
@ -124,25 +106,10 @@ main(int argc, char *argv[])
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Query the repository configuration - this is an operating system builder
|
/* Handle remounting /sysroot read-only now */
|
||||||
* choice.
|
if (unlink (_OSTREE_SYSROOT_READONLY_STAMP) == 0)
|
||||||
* */
|
|
||||||
const bool sysroot_readonly = sysroot_is_configured_ro ();
|
|
||||||
|
|
||||||
/* Mount the sysroot read-only if we're configured to do so.
|
|
||||||
* Note we only get here if / is already writable.
|
|
||||||
*/
|
|
||||||
do_remount ("/sysroot", !sysroot_readonly);
|
|
||||||
|
|
||||||
if (sysroot_readonly)
|
|
||||||
{
|
{
|
||||||
/* Now, /etc is not normally a bind mount, but remounting the
|
do_remount ("/sysroot", false);
|
||||||
* sysroot above made it read-only since it's on the same filesystem.
|
|
||||||
* Make it a self-bind mount, so we can then mount it read-write.
|
|
||||||
*/
|
|
||||||
if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0)
|
|
||||||
err (EXIT_FAILURE, "failed to make /etc a bind mount");
|
|
||||||
do_remount ("/etc", true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If /var was created as as an OSTree default bind mount (instead of being a separate filesystem)
|
/* If /var was created as as an OSTree default bind mount (instead of being a separate filesystem)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue