Skip to content

Commit

Permalink
Remove hard condition on ostree= karg
Browse files Browse the repository at this point in the history
Some kernel images are delivered in a signed kernel + cmdline +
initramfs + dtb blob. When this is added to the commit server side, only
after this do you know what the cmdline is, this creates a recursion
issue. To avoid this, in the case where we don't have an ostree= karg
boot from the latest symlink in /sysroot/ostree.
  • Loading branch information
ericcurtin committed Apr 6, 2023
1 parent c927142 commit d1b620e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 5 deletions.
1 change: 0 additions & 1 deletion src/boot/ostree-prepare-root.service
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
Description=OSTree Prepare OS/
Documentation=man:ostree(1)
DefaultDependencies=no
ConditionKernelCommandLine=ostree
ConditionPathExists=/etc/initrd-release
OnFailure=emergency.target
After=sysroot.mount
Expand Down
2 changes: 1 addition & 1 deletion src/boot/ostree-remount.service
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Description=OSTree Remount OS/ Bind Mounts
Documentation=man:ostree(1)
DefaultDependencies=no
ConditionKernelCommandLine=ostree
ConditionPathExists=/run/ostree
OnFailure=emergency.target
Conflicts=umount.target
# Run after core mounts
Expand Down
104 changes: 104 additions & 0 deletions src/switchroot/ostree-mount-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#ifndef __OSTREE_MOUNT_UTIL_H_
#define __OSTREE_MOUNT_UTIL_H_

#include <dirent.h>
#include <err.h>
#include <stdlib.h>
#include <sys/statvfs.h>
Expand Down Expand Up @@ -72,6 +73,19 @@ read_proc_cmdline (void)
return cmdline;
}

static inline void
free_char (char **to_free)
{
free (*to_free);
}

static inline void
close_dir (DIR **dir)
{
if (*dir)
closedir (*dir);
}

static inline char *
read_proc_cmdline_ostree (void)
{
Expand Down Expand Up @@ -106,6 +120,96 @@ read_proc_cmdline_ostree (void)
return ret;
}

static inline int
append_latest_link(char* dir_str, int* len, int* cap) {
char* append_from = dir_str + *len;
int appended_len = 0;
DIR __attribute__ ((cleanup(close_dir))) *dir = opendir(dir_str);
if (!dir)
{
fprintf(stderr, "'%s' %d", strerror(errno), __LINE__);
return 1;
}

struct dirent *ent = 0;
for (time_t latest = 0; (ent = readdir(dir)); )
{
if (ent->d_type != DT_LNK)
continue;

struct stat lsb;
lsb.st_mtime = 0;
char ent_str[PATH_MAX + sizeof (ent->d_name)];
snprintf(ent_str, sizeof (ent_str), "%s/%s", dir_str, ent->d_name);
if (lstat(ent_str, &lsb) == -1)
{
fprintf(stderr, "'%s' %d", strerror(errno), __LINE__);
return 1;
}

if (latest <= lsb.st_mtime)
{
appended_len = snprintf(append_from, *cap, "/%s", ent->d_name);
latest = lsb.st_mtime;
}
}

*len += appended_len;
*cap = PATH_MAX - *len;

return 0;
}

static inline int
append_osname_sum_deployserial(char* dir_str, int* len, int* cap) {
for (int i = 0; i < 3; ++i)
{
DIR __attribute__ ((cleanup(close_dir))) *dir1 = opendir(dir_str);
if (!dir1)
{
fprintf(stderr, "%s:%d\n", strerror(errno), __LINE__);
return 1;
}

for (struct dirent *ent = 0; (ent = readdir(dir1)); )
{
if (ent->d_name[0] != '.')
{
*len += snprintf(dir_str + *len, *cap, "/%s", ent->d_name);
*cap = PATH_MAX - *len;
break;
}
}
}

return 0;
}

/* This function is for boot arrangements where it is not possible to use a
* karg/cmdline (normally when the cmdline is part of the commit),
* alternatively this function uses the latest symlink in prefix + /ostree
* the prefix is normally "/sysroot"
*/
static inline char*
gen_ostree_target (const char* prefix)
{
char dir_str[PATH_MAX];
int dir_str_len = snprintf(dir_str, sizeof(dir_str), "%s/ostree", prefix);
int dir_str_cap = PATH_MAX - dir_str_len;
const int prefix_len = strlen(prefix);

if (append_latest_link(dir_str, &dir_str_len, &dir_str_cap))
return strdup("");

if (append_osname_sum_deployserial(dir_str, &dir_str_len, &dir_str_cap))
return strdup("");

/* We don't want the initial part included, we want to start at /ostree from
* the caller perspective.
*/
return strdup(dir_str + prefix_len);
}

/* This is an API for other projects to determine whether or not the
* currently running system is ostree-controlled.
*/
Expand Down
8 changes: 6 additions & 2 deletions src/switchroot/ostree-prepare-root.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,15 @@ resolve_deploy_path (const char * root_mountpoint)
{
char destpath[PATH_MAX];
struct stat stbuf;
char *ostree_target, *deploy_path;
char __attribute__ ((cleanup(free_char))) *ostree_target;
char *deploy_path;

ostree_target = read_proc_cmdline_ostree ();
if (!ostree_target)
errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/...");
ostree_target = gen_ostree_target (root_mountpoint);

if (!ostree_target)
errx (EXIT_FAILURE, "Could not find OSTree target either via ostree=/ostree/boot.N/ or searching,...");

if (snprintf (destpath, sizeof(destpath), "%s/%s", root_mountpoint, ostree_target) < 0)
err (EXIT_FAILURE, "failed to assemble ostree target path");
Expand Down
5 changes: 4 additions & 1 deletion src/switchroot/ostree-system-generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ main(int argc, char *argv[])
* exit so that we don't error, but at the same time work where switchroot
* is PID 1 (and so hasn't created /run/ostree-booted).
*/
char *ostree_cmdline = read_proc_cmdline_ostree ();
char __attribute__ ((cleanup(free_char))) *ostree_cmdline = read_proc_cmdline_ostree ();
if (!ostree_cmdline)
ostree_cmdline = gen_ostree_target("/sysroot");

if (!ostree_cmdline)
exit (EXIT_SUCCESS);

Expand Down

0 comments on commit d1b620e

Please sign in to comment.