]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/partition/repart.c
tree-wide: Use log_setup() everywhere
[thirdparty/systemd.git] / src / partition / repart.c
index db1d00974e3771058b7122b58b8da69689fe65f7..ddacdce5b52c04a6dabdcd169c868bb30c85f281 100644 (file)
@@ -146,6 +146,8 @@ static bool arg_legend = true;
 static void *arg_key = NULL;
 static size_t arg_key_size = 0;
 static EVP_PKEY *arg_private_key = NULL;
+static KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
+static char *arg_private_key_source = NULL;
 static X509 *arg_certificate = NULL;
 static char *arg_tpm2_device = NULL;
 static uint32_t arg_tpm2_seal_key_handle = 0;
@@ -177,6 +179,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep);
@@ -297,6 +300,7 @@ typedef struct Partition {
         char **exclude_files_target;
         char **make_directories;
         char **subvolumes;
+        char *default_subvolume;
         EncryptMode encrypt;
         VerityMode verity;
         char *verity_match_key;
@@ -1665,6 +1669,41 @@ static int config_parse_make_dirs(
         }
 }
 
+static int config_parse_default_subvolume(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **subvol = ASSERT_PTR(data);
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        if (isempty(rvalue)) {
+                *subvol = mfree(*subvol);
+                return 0;
+        }
+
+        r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &p);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to expand specifiers in DefaultSubvolume= parameter, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+        if (r < 0)
+                return 0;
+
+        return free_and_replace(*subvol, p);
+}
+
 static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode");
 
 static int config_parse_gpt_flags(
@@ -1755,7 +1794,7 @@ static int config_parse_mountpoint(
 
         const char *q = rvalue;
         r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
-                               &where, &options, NULL);
+                               &where, &options);
         if (r == -ENOMEM)
                 return log_oom();
         if (r < 0) {
@@ -1812,7 +1851,7 @@ static int config_parse_encrypted_volume(
 
         const char *q = rvalue;
         r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
-                               &volume, &keyfile, &options, NULL);
+                               &volume, &keyfile, &options);
         if (r == -ENOMEM)
                 return log_oom();
         if (r < 0) {
@@ -1858,37 +1897,38 @@ static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mod
 static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
 
         ConfigTableItem table[] = {
-                { "Partition", "Type",                     config_parse_type,             0, &p->type                    },
-                { "Partition", "Label",                    config_parse_label,            0, &p->new_label               },
-                { "Partition", "UUID",                     config_parse_uuid,             0, p                           },
-                { "Partition", "Priority",                 config_parse_int32,            0, &p->priority                },
-                { "Partition", "Weight",                   config_parse_weight,           0, &p->weight                  },
-                { "Partition", "PaddingWeight",            config_parse_weight,           0, &p->padding_weight          },
-                { "Partition", "SizeMinBytes",             config_parse_size4096,        -1, &p->size_min                },
-                { "Partition", "SizeMaxBytes",             config_parse_size4096,         1, &p->size_max                },
-                { "Partition", "PaddingMinBytes",          config_parse_size4096,        -1, &p->padding_min             },
-                { "Partition", "PaddingMaxBytes",          config_parse_size4096,         1, &p->padding_max             },
-                { "Partition", "FactoryReset",             config_parse_bool,             0, &p->factory_reset           },
-                { "Partition", "CopyBlocks",               config_parse_copy_blocks,      0, p                           },
-                { "Partition", "Format",                   config_parse_fstype,           0, &p->format                  },
-                { "Partition", "CopyFiles",                config_parse_copy_files,       0, &p->copy_files              },
-                { "Partition", "ExcludeFiles",             config_parse_exclude_files,    0, &p->exclude_files_source    },
-                { "Partition", "ExcludeFilesTarget",       config_parse_exclude_files,    0, &p->exclude_files_target    },
-                { "Partition", "MakeDirectories",          config_parse_make_dirs,        0, &p->make_directories        },
-                { "Partition", "Encrypt",                  config_parse_encrypt,          0, &p->encrypt                 },
-                { "Partition", "Verity",                   config_parse_verity,           0, &p->verity                  },
-                { "Partition", "VerityMatchKey",           config_parse_string,           0, &p->verity_match_key        },
-                { "Partition", "Flags",                    config_parse_gpt_flags,        0, &p->gpt_flags               },
-                { "Partition", "ReadOnly",                 config_parse_tristate,         0, &p->read_only               },
-                { "Partition", "NoAuto",                   config_parse_tristate,         0, &p->no_auto                 },
-                { "Partition", "GrowFileSystem",           config_parse_tristate,         0, &p->growfs                  },
-                { "Partition", "SplitName",                config_parse_string,           0, &p->split_name_format       },
-                { "Partition", "Minimize",                 config_parse_minimize,         0, &p->minimize                },
-                { "Partition", "Subvolumes",               config_parse_make_dirs,        0, &p->subvolumes              },
-                { "Partition", "VerityDataBlockSizeBytes", config_parse_block_size,       0, &p->verity_data_block_size  },
-                { "Partition", "VerityHashBlockSizeBytes", config_parse_block_size,       0, &p->verity_hash_block_size  },
-                { "Partition", "MountPoint",               config_parse_mountpoint,       0, p                           },
-                { "Partition", "EncryptedVolume",          config_parse_encrypted_volume, 0, p                           },
+                { "Partition", "Type",                     config_parse_type,              0, &p->type                    },
+                { "Partition", "Label",                    config_parse_label,             0, &p->new_label               },
+                { "Partition", "UUID",                     config_parse_uuid,              0, p                           },
+                { "Partition", "Priority",                 config_parse_int32,             0, &p->priority                },
+                { "Partition", "Weight",                   config_parse_weight,            0, &p->weight                  },
+                { "Partition", "PaddingWeight",            config_parse_weight,            0, &p->padding_weight          },
+                { "Partition", "SizeMinBytes",             config_parse_size4096,         -1, &p->size_min                },
+                { "Partition", "SizeMaxBytes",             config_parse_size4096,          1, &p->size_max                },
+                { "Partition", "PaddingMinBytes",          config_parse_size4096,         -1, &p->padding_min             },
+                { "Partition", "PaddingMaxBytes",          config_parse_size4096,          1, &p->padding_max             },
+                { "Partition", "FactoryReset",             config_parse_bool,              0, &p->factory_reset           },
+                { "Partition", "CopyBlocks",               config_parse_copy_blocks,       0, p                           },
+                { "Partition", "Format",                   config_parse_fstype,            0, &p->format                  },
+                { "Partition", "CopyFiles",                config_parse_copy_files,        0, &p->copy_files              },
+                { "Partition", "ExcludeFiles",             config_parse_exclude_files,     0, &p->exclude_files_source    },
+                { "Partition", "ExcludeFilesTarget",       config_parse_exclude_files,     0, &p->exclude_files_target    },
+                { "Partition", "MakeDirectories",          config_parse_make_dirs,         0, &p->make_directories        },
+                { "Partition", "Encrypt",                  config_parse_encrypt,           0, &p->encrypt                 },
+                { "Partition", "Verity",                   config_parse_verity,            0, &p->verity                  },
+                { "Partition", "VerityMatchKey",           config_parse_string,            0, &p->verity_match_key        },
+                { "Partition", "Flags",                    config_parse_gpt_flags,         0, &p->gpt_flags               },
+                { "Partition", "ReadOnly",                 config_parse_tristate,          0, &p->read_only               },
+                { "Partition", "NoAuto",                   config_parse_tristate,          0, &p->no_auto                 },
+                { "Partition", "GrowFileSystem",           config_parse_tristate,          0, &p->growfs                  },
+                { "Partition", "SplitName",                config_parse_string,            0, &p->split_name_format       },
+                { "Partition", "Minimize",                 config_parse_minimize,          0, &p->minimize                },
+                { "Partition", "Subvolumes",               config_parse_make_dirs,         0, &p->subvolumes              },
+                { "Partition", "DefaultSubvolume",         config_parse_default_subvolume, 0, &p->default_subvolume       },
+                { "Partition", "VerityDataBlockSizeBytes", config_parse_block_size,        0, &p->verity_data_block_size  },
+                { "Partition", "VerityHashBlockSizeBytes", config_parse_block_size,        0, &p->verity_hash_block_size  },
+                { "Partition", "MountPoint",               config_parse_mountpoint,        0, p                           },
+                { "Partition", "EncryptedVolume",          config_parse_encrypted_volume,  0, p                           },
                 {}
         };
         int r;
@@ -2015,6 +2055,14 @@ static int partition_read_definition(Partition *p, const char *path, const char
                 return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
                                   "Subvolumes= cannot be used with --offline=yes");
 
+        if (p->default_subvolume && arg_offline > 0)
+                return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                  "DefaultSubvolume= cannot be used with --offline=yes");
+
+        if (p->default_subvolume && !path_strv_contains(p->subvolumes, p->default_subvolume))
+                return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
+                                  "DefaultSubvolume= must be one of the paths in Subvolumes=");
+
         /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
         if ((IN_SET(p->type.designator,
                     PARTITION_ROOT_VERITY,
@@ -3326,8 +3374,8 @@ static int context_dump(Context *context, bool late) {
         if (r < 0)
                 return r;
 
-        /* Make sure we only write the partition bar once, even if we're writing the partition table twice to
-         * communicate roothashes. */
+        /* Only write the partition bar once, even if we're writing the partition table twice to communicate
+         * roothashes. */
         if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) && !late) {
                 putc('\n', stdout);
 
@@ -3733,6 +3781,11 @@ static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
         return 0;
 }
 
+static bool loop_device_error_is_fatal(const Partition *p, int r) {
+        assert(p);
+        return arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes) || p->default_subvolume;
+}
+
 static int partition_target_prepare(
                 Context *context,
                 Partition *p,
@@ -3772,7 +3825,7 @@ static int partition_target_prepare(
 
         if (arg_offline <= 0) {
                 r = loop_device_make(whole_fd, O_RDWR, p->offset, size, context->sector_size, 0, LOCK_EX, &d);
-                if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
+                if (r < 0 && loop_device_error_is_fatal(p, r))
                         return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
                 if (r >= 0) {
                         t->loop = TAKE_PTR(d);
@@ -4014,9 +4067,9 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Must provide all PCR values when using TPM2 device key.");
                 } else {
-                        r = tpm2_context_new(arg_tpm2_device, &tpm2_context);
+                        r = tpm2_context_new_or_warn(arg_tpm2_device, &tpm2_context);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to create TPM2 context: %m");
+                                return r;
 
                         if (!tpm2_pcr_values_has_all_values(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values)) {
                                 r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values);
@@ -4236,7 +4289,7 @@ static int partition_format_verity_hash(
         if (PARTITION_EXISTS(p)) /* Never format existing partitions */
                 return 0;
 
-        /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
+        /* Minimized partitions will use the copy blocks logic so skip those here. */
         if (p->copy_blocks_fd >= 0)
                 return 0;
 
@@ -4875,6 +4928,27 @@ static int do_make_directories(Partition *p, const char *root) {
         return 0;
 }
 
+static int set_default_subvolume(Partition *p, const char *root) {
+        _cleanup_free_ char *path = NULL;
+        int r;
+
+        assert(p);
+        assert(root);
+
+        if (!p->default_subvolume)
+                return 0;
+
+        path = path_join(root, p->default_subvolume);
+        if (!path)
+                return log_oom();
+
+        r = btrfs_subvol_make_default(path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make '%s' the default subvolume: %m", p->default_subvolume);
+
+        return 0;
+}
+
 static bool partition_needs_populate(Partition *p) {
         assert(p);
         return !strv_isempty(p->copy_files) || !strv_isempty(p->make_directories);
@@ -4949,6 +5023,9 @@ static int partition_populate_filesystem(Context *context, Partition *p, const c
                 if (do_make_directories(p, fs) < 0)
                         _exit(EXIT_FAILURE);
 
+                if (set_default_subvolume(p, fs) < 0)
+                        _exit(EXIT_FAILURE);
+
                 r = syncfs_path(AT_FDCWD, fs);
                 if (r < 0) {
                         log_error_errno(r, "Failed to synchronize written files: %m");
@@ -4983,7 +5060,7 @@ static int context_mkfs(Context *context) {
                 if (!p->format)
                         continue;
 
-                /* Minimized partitions will use the copy blocks logic so let's make sure to skip those here. */
+                /* Minimized partitions will use the copy blocks logic so skip those here. */
                 if (p->copy_blocks_fd >= 0)
                         continue;
 
@@ -4994,7 +5071,7 @@ static int context_mkfs(Context *context) {
                 assert(p->new_size != UINT64_MAX);
                 assert(p->new_size >= (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
 
-                /* If we're doing encryption, we make sure we keep free space at the end which is required
+                /* If we're doing encryption, keep free space at the end which is required
                  * for cryptsetup's offline encryption. */
                 r = partition_target_prepare(context, p,
                                              p->new_size - (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0),
@@ -5043,8 +5120,8 @@ static int context_mkfs(Context *context) {
                         return r;
 
                 /* The mkfs binary we invoked might have removed our temporary file when we're not operating
-                 * on a loop device, so let's make sure we open the file again to make sure our file
-                 * descriptor points to any potential new file. */
+                 * on a loop device, so open the file again to make sure our file descriptor points to actual
+                 * new file. */
 
                 if (t->fd >= 0 && t->path && !t->loop) {
                         safe_close(t->fd);
@@ -6544,7 +6621,7 @@ static int context_minimize(Context *context) {
 
                         if (arg_offline <= 0) {
                                 r = loop_device_make(fd, O_RDWR, 0, UINT64_MAX, context->sector_size, 0, LOCK_EX, &d);
-                                if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r)) || !strv_isempty(p->subvolumes)))
+                                if (r < 0 && loop_device_error_is_fatal(p, r))
                                         return log_error_errno(r, "Failed to make loopback device of %s: %m", temp);
                         }
 
@@ -6806,8 +6883,14 @@ static int help(void) {
                "                          Specify disk image dissection policy\n"
                "     --definitions=DIR    Find partition definitions in specified directory\n"
                "     --key-file=PATH      Key to use when encrypting partitions\n"
-               "     --private-key=PATH   Private key to use when generating verity roothash\n"
-               "                          signatures\n"
+               "     --private-key=PATH|URI\n"
+               "                          Private key to use when generating verity roothash\n"
+               "                          signatures, or an engine or provider specific\n"
+               "                          designation if --private-key-source= is used.\n"
+               "     --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
+               "                          Specify how to use the --private-key=. Allows to use\n"
+               "                          an OpenSSL engine/provider when generating verity\n"
+               "                          roothash signatures\n"
                "     --certificate=PATH   PEM certificate to use when generating verity\n"
                "                          roothash signatures\n"
                "     --tpm2-device=PATH   Path to TPM2 device node to use\n"
@@ -6857,7 +6940,7 @@ static int help(void) {
 }
 
 static int parse_argv(int argc, char *argv[]) {
-        _cleanup_free_ char *private_key = NULL, *private_key_uri = NULL;
+        _cleanup_free_ char *private_key = NULL;
 
         enum {
                 ARG_VERSION = 0x100,
@@ -6878,7 +6961,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_JSON,
                 ARG_KEY_FILE,
                 ARG_PRIVATE_KEY,
-                ARG_PRIVATE_KEY_URI,
+                ARG_PRIVATE_KEY_SOURCE,
                 ARG_CERTIFICATE,
                 ARG_TPM2_DEVICE,
                 ARG_TPM2_DEVICE_KEY,
@@ -6921,7 +7004,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "json",                 required_argument, NULL, ARG_JSON                 },
                 { "key-file",             required_argument, NULL, ARG_KEY_FILE             },
                 { "private-key",          required_argument, NULL, ARG_PRIVATE_KEY          },
-                { "private-key-uri",      required_argument, NULL, ARG_PRIVATE_KEY_URI      },
+                { "private-key-source",   required_argument, NULL, ARG_PRIVATE_KEY_SOURCE   },
                 { "certificate",          required_argument, NULL, ARG_CERTIFICATE          },
                 { "tpm2-device",          required_argument, NULL, ARG_TPM2_DEVICE          },
                 { "tpm2-device-key",      required_argument, NULL, ARG_TPM2_DEVICE_KEY      },
@@ -7115,12 +7198,14 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_PRIVATE_KEY_URI: {
-                        r = free_and_strdup_warn(&private_key_uri, optarg);
+                case ARG_PRIVATE_KEY_SOURCE:
+                        r = parse_openssl_key_source_argument(
+                                        optarg,
+                                        &arg_private_key_source,
+                                        &arg_private_key_source_type);
                         if (r < 0)
                                 return r;
                         break;
-                }
 
                 case ARG_CERTIFICATE: {
                         _cleanup_free_ char *cert = NULL;
@@ -7465,12 +7550,7 @@ static int parse_argv(int argc, char *argv[]) {
                         *p = gpt_partition_type_override_architecture(*p, arg_architecture);
         }
 
-        if (private_key && private_key_uri)
-                return log_error_errno(
-                                SYNTHETIC_ERRNO(EINVAL),
-                                "Cannot specify both --private-key= and --private-key-uri=.");
-
-        if (private_key) {
+        if (private_key && arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
                 _cleanup_(erase_and_freep) char *k = NULL;
                 size_t n = 0;
 
@@ -7485,16 +7565,22 @@ static int parse_argv(int argc, char *argv[]) {
                 r = parse_private_key(k, n, &arg_private_key);
                 if (r < 0)
                         return r;
-        } else if (private_key_uri) {
+        } else if (private_key &&
+                   IN_SET(arg_private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER)) {
                 /* This must happen after parse_x509_certificate() is called above, otherwise
                  * signing later will get stuck as the parsed private key won't have the
                  * certificate, so this block cannot be inline in ARG_PRIVATE_KEY. */
-                r = openssl_load_key_from_token(private_key_uri, &arg_private_key);
+                r = openssl_load_key_from_token(
+                                arg_private_key_source_type,
+                                arg_private_key_source,
+                                private_key,
+                                &arg_private_key);
                 if (r < 0)
                         return log_error_errno(
                                         r,
-                                        "Failed to load key '%s' from OpenSSL provider: %m",
-                                        private_key);
+                                        "Failed to load key '%s' from OpenSSL private key source %s: %m",
+                                        private_key,
+                                        arg_private_key_source);
         }
 
         return 1;
@@ -7919,9 +8005,7 @@ static int run(int argc, char *argv[]) {
         bool node_is_our_loop = false;
         int r;
 
-        log_show_color(true);
-        log_parse_environment();
-        log_open();
+        log_setup();
 
         r = parse_argv(argc, argv);
         if (r <= 0)
@@ -7998,7 +8082,7 @@ static int run(int argc, char *argv[]) {
                 if (!d)
                         return log_oom();
 
-                r = search_and_access(d, F_OK, NULL, CONF_PATHS_USR_STRV("systemd/repart/definitions"), &dp);
+                r = search_and_access(d, F_OK, NULL, CONF_PATHS_STRV("systemd/repart/definitions"), &dp);
                 if (r < 0)
                         return log_error_errno(r, "DDI type '%s' is not defined: %m", arg_make_ddi);