Blame src/initrd/nm-initrd-generator.c

Packit Service 87a54e
/* SPDX-License-Identifier: LGPL-2.1-or-later */
Packit 5756e2
/*
Packit 5756e2
 * Copyright (C) 2018 Red Hat, Inc.
Packit 5756e2
 */
Packit 5756e2
Packit 5756e2
#include "nm-default.h"
Packit 5756e2
#include "nm-core-utils.h"
Packit 5756e2
#include "nm-core-internal.h"
Packit 5756e2
#include "nm-keyfile/nm-keyfile-internal.h"
Packit 5756e2
#include "nm-initrd-generator.h"
Packit 5756e2
#include "nm-glib-aux/nm-io-utils.h"
Packit Service 018b0a
#include "nm-config.h"
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit Service a1bd4f
#define _NMLOG(level, domain, ...)                                 \
Packit Service a1bd4f
    nm_log((level),                                                \
Packit Service a1bd4f
           (domain),                                               \
Packit Service a1bd4f
           NULL,                                                   \
Packit Service a1bd4f
           NULL,                                                   \
Packit Service a1bd4f
           "initrd-generator: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \
Packit Service a1bd4f
               _NM_UTILS_MACRO_REST(__VA_ARGS__))
Packit 5756e2
Packit 5756e2
/*****************************************************************************/
Packit 5756e2
Packit 5756e2
static void
Packit Service a1bd4f
output_conn(gpointer key, gpointer value, gpointer user_data)
Packit 5756e2
{
Packit Service a1bd4f
    const char *          basename        = key;
Packit Service a1bd4f
    NMConnection *        connection      = value;
Packit Service a1bd4f
    char *                connections_dir = user_data;
Packit Service a1bd4f
    nm_auto_unref_keyfile GKeyFile *file  = NULL;
Packit Service a1bd4f
    gs_free char *                  data  = NULL;
Packit Service a1bd4f
    gs_free_error GError *error           = NULL;
Packit Service a1bd4f
    gsize                 len;
Packit Service a1bd4f
Packit Service a1bd4f
    if (!nm_connection_normalize(connection, NULL, NULL, &error))
Packit Service a1bd4f
        goto err_out;
Packit Service a1bd4f
Packit Service a1bd4f
    file = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
Packit Service a1bd4f
    if (file == NULL)
Packit Service a1bd4f
        goto err_out;
Packit Service a1bd4f
Packit Service a1bd4f
    data = g_key_file_to_data(file, &len, &error);
Packit Service a1bd4f
    if (!data)
Packit Service a1bd4f
        goto err_out;
Packit Service a1bd4f
Packit Service a1bd4f
    if (connections_dir) {
Packit Service a1bd4f
        gs_free char *filename      = NULL;
Packit Service a1bd4f
        gs_free char *full_filename = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
        filename      = nm_keyfile_utils_create_filename(basename, TRUE);
Packit Service a1bd4f
        full_filename = g_build_filename(connections_dir, filename, NULL);
Packit Service a1bd4f
Packit Service a1bd4f
        if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, &error))
Packit Service a1bd4f
            goto err_out;
Packit Service a1bd4f
    } else
Packit Service a1bd4f
        g_print("\n*** Connection '%s' ***\n\n%s", basename, data);
Packit Service a1bd4f
Packit Service a1bd4f
    return;
Packit 5756e2
err_out:
Packit Service a1bd4f
    g_print("%s\n", error->message);
Packit 5756e2
}
Packit 5756e2
Packit Service a1bd4f
#define DEFAULT_SYSFS_DIR       "/sys"
Packit Service a1bd4f
#define DEFAULT_INITRD_DATA_DIR NMRUNDIR "/initrd"
Packit Service 018b0a
#define DEFAULT_RUN_CONFIG_DIR  NMRUNDIR "/conf.d"
Packit 5756e2
Packit 5756e2
int
Packit Service a1bd4f
main(int argc, char *argv[])
Packit 5756e2
{
Packit Service a1bd4f
    GHashTable *       connections;
Packit Service a1bd4f
    gs_free char *     connections_dir  = NULL;
Packit Service a1bd4f
    gs_free char *     initrd_dir       = NULL;
Packit Service a1bd4f
    gs_free char *     sysfs_dir        = NULL;
Packit Service 018b0a
    gs_free char *     run_config_dir   = NULL;
Packit Service a1bd4f
    gboolean           dump_to_stdout   = FALSE;
Packit Service a1bd4f
    gs_strfreev char **remaining        = NULL;
Packit Service a1bd4f
    GOptionEntry       option_entries[] = {
Packit Service a1bd4f
        {"connections-dir",
Packit Service a1bd4f
         'c',
Packit Service a1bd4f
         0,
Packit Service a1bd4f
         G_OPTION_ARG_FILENAME,
Packit Service a1bd4f
         &connections_dir,
Packit Service a1bd4f
         "Output connection directory",
Packit Service a1bd4f
         NM_KEYFILE_PATH_NAME_RUN},
Packit Service a1bd4f
        {"initrd-data-dir",
Packit Service a1bd4f
         'i',
Packit Service a1bd4f
         0,
Packit Service a1bd4f
         G_OPTION_ARG_FILENAME,
Packit Service a1bd4f
         &initrd_dir,
Packit Service a1bd4f
         "Output initrd data directory",
Packit Service a1bd4f
         DEFAULT_INITRD_DATA_DIR},
Packit Service a1bd4f
        {"sysfs-dir",
Packit Service a1bd4f
         'd',
Packit Service a1bd4f
         0,
Packit Service a1bd4f
         G_OPTION_ARG_FILENAME,
Packit Service a1bd4f
         &sysfs_dir,
Packit Service a1bd4f
         "The sysfs mount point",
Packit Service a1bd4f
         DEFAULT_SYSFS_DIR},
Packit Service 018b0a
        {"run-config-dir",
Packit Service 018b0a
         'r',
Packit Service 018b0a
         0,
Packit Service 018b0a
         G_OPTION_ARG_FILENAME,
Packit Service 018b0a
         &run_config_dir,
Packit Service 018b0a
         "Output config directory",
Packit Service 018b0a
         DEFAULT_RUN_CONFIG_DIR},
Packit Service a1bd4f
        {"stdout",
Packit Service a1bd4f
         's',
Packit Service a1bd4f
         0,
Packit Service a1bd4f
         G_OPTION_ARG_NONE,
Packit Service a1bd4f
         &dump_to_stdout,
Packit Service a1bd4f
         "Dump connections to standard output",
Packit Service a1bd4f
         NULL},
Packit Service a1bd4f
        {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL},
Packit Service a1bd4f
        {NULL}};
Packit Service a1bd4f
    nm_auto_free_option_context GOptionContext *option_context = NULL;
Packit Service a1bd4f
    gs_free_error GError *error                                = NULL;
Packit Service a1bd4f
    gs_free char *        hostname                             = NULL;
Packit Service a1bd4f
    int                   errsv;
Packit Service 018b0a
    gint64                carrier_timeout_sec = 0;
Packit Service a1bd4f
Packit Service a1bd4f
    option_context = g_option_context_new(
Packit Service a1bd4f
        "-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
Packit Service a1bd4f
        "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] "
Packit Service 018b0a
        "[rd.znet=...] [rd.net.timeout.carrier=...] ... ");
Packit Service a1bd4f
Packit Service a1bd4f
    g_option_context_set_summary(option_context, "Generate early NetworkManager configuration.");
Packit Service a1bd4f
    g_option_context_set_description(
Packit Service a1bd4f
        option_context,
Packit Service a1bd4f
        "This tool scans the command line for options relevant to network\n"
Packit Service a1bd4f
        "configuration and creates configuration files for an early instance\n"
Packit Service a1bd4f
        "of NetworkManager run from the initial ramdisk during early boot.");
Packit Service a1bd4f
    g_option_context_add_main_entries(option_context, option_entries, GETTEXT_PACKAGE);
Packit Service a1bd4f
Packit Service a1bd4f
    if (!g_option_context_parse(option_context, &argc, &argv, &error)) {
Packit Service a1bd4f
        _LOGW(LOGD_CORE, "%s", error->message);
Packit Service a1bd4f
        return 1;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!remaining) {
Packit Service a1bd4f
        /* No arguments, no networking. Don't bother. */
Packit Service a1bd4f
        return 0;
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service a1bd4f
    if (!connections_dir)
Packit Service a1bd4f
        connections_dir = g_strdup(NM_KEYFILE_PATH_NAME_RUN);
Packit Service a1bd4f
    if (!sysfs_dir)
Packit Service a1bd4f
        sysfs_dir = g_strdup(DEFAULT_SYSFS_DIR);
Packit Service a1bd4f
    if (!initrd_dir)
Packit Service a1bd4f
        initrd_dir = g_strdup(DEFAULT_INITRD_DATA_DIR);
Packit Service 018b0a
    if (!run_config_dir)
Packit Service 018b0a
        run_config_dir = g_strdup(DEFAULT_RUN_CONFIG_DIR);
Packit Service a1bd4f
Packit Service 018b0a
    connections = nmi_cmdline_reader_parse(sysfs_dir,
Packit Service 018b0a
                                           (const char *const *) remaining,
Packit Service 018b0a
                                           &hostname,
Packit Service 018b0a
                                           &carrier_timeout_sec);
Packit Service a1bd4f
Packit Service a1bd4f
    if (dump_to_stdout) {
Packit Service 018b0a
        nm_clear_g_free(&connections_dir);
Packit Service 018b0a
        nm_clear_g_free(&initrd_dir);
Packit Service 018b0a
        nm_clear_g_free(&run_config_dir);
Packit Service a1bd4f
        if (hostname)
Packit Service a1bd4f
            g_print("\n*** Hostname '%s' ***\n", hostname);
Packit Service 018b0a
        if (carrier_timeout_sec != 0)
Packit Service 018b0a
            g_print("\n*** Carrier Wait Timeout %" G_GINT64_FORMAT " sec ***\n",
Packit Service 018b0a
                    carrier_timeout_sec);
Packit Service a1bd4f
    } else {
Packit Service 018b0a
        if (g_mkdir_with_parents(connections_dir, 0755) != 0) {
Packit Service 018b0a
            errsv = errno;
Packit Service 018b0a
            _LOGW(LOGD_CORE, "%s: %s", connections_dir, nm_strerror_native(errsv));
Packit Service 018b0a
            return 1;
Packit Service 018b0a
        }
Packit Service a1bd4f
        if (g_mkdir_with_parents(initrd_dir, 0755) != 0) {
Packit Service a1bd4f
            errsv = errno;
Packit Service a1bd4f
            _LOGW(LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native(errsv));
Packit Service a1bd4f
            return 1;
Packit Service a1bd4f
        }
Packit Service 018b0a
        if (g_mkdir_with_parents(run_config_dir, 0755) != 0) {
Packit Service 018b0a
            errsv = errno;
Packit Service 018b0a
            _LOGW(LOGD_CORE, "%s: %s", run_config_dir, nm_strerror_native(errsv));
Packit Service 018b0a
            return 1;
Packit Service 018b0a
        }
Packit Service a1bd4f
Packit Service a1bd4f
        if (hostname) {
Packit Service a1bd4f
            gs_free char *hostname_file = NULL;
Packit Service a1bd4f
            gs_free char *data          = NULL;
Packit Service a1bd4f
Packit Service a1bd4f
            hostname_file = g_strdup_printf("%s/hostname", initrd_dir);
Packit Service a1bd4f
            data          = g_strdup_printf("%s\n", hostname);
Packit Service a1bd4f
Packit Service a1bd4f
            if (!g_file_set_contents(hostname_file, data, strlen(data), &error)) {
Packit Service a1bd4f
                _LOGW(LOGD_CORE, "%s: %s", hostname_file, error->message);
Packit Service a1bd4f
                return 1;
Packit Service a1bd4f
            }
Packit Service a1bd4f
        }
Packit Service 018b0a
        if (carrier_timeout_sec != 0) {
Packit Service 018b0a
            nm_auto_unref_keyfile GKeyFile *keyfile  = NULL;
Packit Service 018b0a
            gs_free char *                  filename = NULL;
Packit Service 018b0a
Packit Service 018b0a
            keyfile = g_key_file_new();
Packit Service 018b0a
            g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR);
Packit Service 018b0a
            filename = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir);
Packit Service 018b0a
Packit Service 018b0a
            g_key_file_set_value(keyfile,
Packit Service 018b0a
                                 NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout",
Packit Service 018b0a
                                 NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE,
Packit Service 018b0a
                                 "*");
Packit Service 018b0a
            g_key_file_set_int64(keyfile,
Packit Service 018b0a
                                 NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout",
Packit Service 018b0a
                                 NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
Packit Service 018b0a
                                 carrier_timeout_sec * 1000);
Packit Service 018b0a
Packit Service 018b0a
            if (!g_key_file_save_to_file(keyfile, filename, &error)) {
Packit Service 018b0a
                _LOGW(LOGD_CORE, "%s: %s", filename, error->message);
Packit Service 018b0a
                return 1;
Packit Service 018b0a
            }
Packit Service 018b0a
        }
Packit Service a1bd4f
    }
Packit Service a1bd4f
Packit Service 018b0a
    g_hash_table_foreach(connections, output_conn, connections_dir);
Packit Service 018b0a
    g_hash_table_destroy(connections);
Packit Service 018b0a
Packit Service a1bd4f
    return 0;
Packit 5756e2
}