add new run-generator
This is really useful for running commands like this: # systemd-run -i someimage.raw -b systemd.run='"some command line"' This will now run the command line inside a small Type=oneshot service and even propagate the exit code of the command back to the parent. And all that with the full system booted up. By default this causes the system to shutdown right after the command completed, but this can be tweaked with systemd.run_success_action= and systemd.run_failure_action=. Note that when used in VMs the exit status can of course not be propagate, as VMs don't really know a concept for that.
This commit is contained in:
parent
7af67e9a8b
commit
35a1ff4cfe
|
@ -1631,6 +1631,14 @@ executable('systemd-debug-generator',
|
|||
install : true,
|
||||
install_dir : systemgeneratordir)
|
||||
|
||||
executable('systemd-run-generator',
|
||||
'src/run-generator/run-generator.c',
|
||||
include_directories : includes,
|
||||
link_with : [libshared],
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true,
|
||||
install_dir : systemgeneratordir)
|
||||
|
||||
executable('systemd-fstab-generator',
|
||||
'src/fstab-generator/fstab-generator.c',
|
||||
'src/core/mount-setup.c',
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "generator.h"
|
||||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "specifier.h"
|
||||
#include "strv.h"
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
static char **arg_commands = NULL;
|
||||
static char *arg_success_action = NULL;
|
||||
static char *arg_failure_action = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_commands, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_success_action, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_failure_action, freep);
|
||||
|
||||
static int parse(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
if (proc_cmdline_key_streq(key, "systemd.run")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = strv_extend(&arg_commands, value);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.run_success_action")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_success_action, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.run_failure_action")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_failure_action, value) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generate(void) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *p;
|
||||
char **c;
|
||||
int r;
|
||||
|
||||
if (strv_isempty(arg_commands) && !arg_success_action)
|
||||
return 0;
|
||||
|
||||
p = strjoina(arg_dest, "/kernel-command-line.service");
|
||||
f = fopen(p, "wxe");
|
||||
if (!f)
|
||||
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
|
||||
|
||||
fputs("# Automatically generated by systemd-run-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Description=Command from Kernel Command Line\n"
|
||||
"Documentation=man:systemd-run-generator(8)\n"
|
||||
"SourcePath=/proc/cmdline\n", f);
|
||||
|
||||
if (!streq_ptr(arg_success_action, "none"))
|
||||
fprintf(f, "SuccessAction=%s\n",
|
||||
arg_success_action ?: "exit");
|
||||
|
||||
if (!streq_ptr(arg_failure_action, "none"))
|
||||
fprintf(f, "FailureAction=%s\n",
|
||||
arg_failure_action ?: "exit");
|
||||
|
||||
fputs("\n"
|
||||
"[Service]\n"
|
||||
"Type=oneshot\n"
|
||||
"StandardOutput=journal+console\n", f);
|
||||
|
||||
STRV_FOREACH(c, arg_commands) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
|
||||
a = specifier_escape(*c);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
fprintf(f, "ExecStart=%s\n", a);
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write unit file %s: %m", p);
|
||||
|
||||
/* Let's create a a target we can link "default.target" to */
|
||||
p = strjoina(arg_dest, "/kernel-command-line.target");
|
||||
r = write_string_file(
|
||||
p,
|
||||
"# Automatically generated by systemd-run-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Description=Command from Kernel Command Line\n"
|
||||
"Documentation=man:systemd-run-generator(8)\n"
|
||||
"SourcePath=/proc/cmdline\n"
|
||||
"Requires=kernel-command-line.service\n"
|
||||
"After=kernel-command-line.service\n",
|
||||
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create unit file %s: %m", p);
|
||||
|
||||
/* And now redirect default.target to our new target */
|
||||
p = strjoina(arg_dest, "/default.target");
|
||||
if (symlink("kernel-command-line.target", p) < 0)
|
||||
return log_error_errno(errno, "Failed to link unit file kernel-command-line.target → %s: %m", p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_setup_generator();
|
||||
|
||||
if (argc > 1 && argc != 4) {
|
||||
log_error("This program takes three or no arguments.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[1];
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = proc_cmdline_parse(parse, NULL, PROC_CMDLINE_RD_STRICT|PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
return generate();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
Loading…
Reference in New Issue