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