diff --git a/src/boot/ostree-prepare-root.service b/src/boot/ostree-prepare-root.service index 510d866a4c..797148c9bc 100644 --- a/src/boot/ostree-prepare-root.service +++ b/src/boot/ostree-prepare-root.service @@ -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 diff --git a/src/boot/ostree-remount.service b/src/boot/ostree-remount.service index 7c0d01a3bb..9f56248462 100644 --- a/src/boot/ostree-remount.service +++ b/src/boot/ostree-remount.service @@ -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 diff --git a/src/switchroot/ostree-mount-util.h b/src/switchroot/ostree-mount-util.h index 92bc802786..bcb267a474 100644 --- a/src/switchroot/ostree-mount-util.h +++ b/src/switchroot/ostree-mount-util.h @@ -21,6 +21,7 @@ #ifndef __OSTREE_MOUNT_UTIL_H_ #define __OSTREE_MOUNT_UTIL_H_ +#include #include #include #include @@ -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) { @@ -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. */ diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index a5fbc8a810..7c59602479 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -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"); diff --git a/src/switchroot/ostree-system-generator.c b/src/switchroot/ostree-system-generator.c index bd0901bcff..f85db2e1fe 100644 --- a/src/switchroot/ostree-system-generator.c +++ b/src/switchroot/ostree-system-generator.c @@ -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);