mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
mute console kernel log/pid1 status output while firstboot is running (#39101)
This is also preparation for the installer later, split out of #38764. It makes the experience a lot nicer if our nice little tools aren't constantly interrupted by log spew from the kernel. Fixes: #34448
This commit is contained in:
@@ -1050,6 +1050,10 @@ manpages = [
|
||||
['systemd-modules-load.service', '8', ['systemd-modules-load'], 'HAVE_KMOD'],
|
||||
['systemd-mount', '1', ['systemd-umount'], ''],
|
||||
['systemd-mountfsd.service', '8', ['systemd-mountfsd'], 'ENABLE_MOUNTFSD'],
|
||||
['systemd-mute-console',
|
||||
'1',
|
||||
['systemd-mute-console.socket', 'systemd-mute-console@.service'],
|
||||
''],
|
||||
['systemd-network-generator.service', '8', ['systemd-network-generator'], ''],
|
||||
['systemd-networkd-wait-online.service',
|
||||
'8',
|
||||
|
||||
@@ -354,6 +354,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--mute-console=</option></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If true kernel log output and service manager status output
|
||||
to the system console is temporarily disabled while <command>systemd-firstboot</command> is running,
|
||||
so that its own output is not interrupted. Defaults to false.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
||||
79
man/systemd-mute-console.xml
Normal file
79
man/systemd-mute-console.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="systemd-mute-console"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-mute-console</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-mute-console</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-mute-console</refname>
|
||||
<refname>systemd-mute-console@.service</refname>
|
||||
<refname>systemd-mute-console.socket</refname>
|
||||
<refpurpose>Temporarily mute kernel log output and service manager status output to the system console</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>systemd-mute-console</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<para><filename>systemd-mute-console@.service</filename></para>
|
||||
<para><filename>systemd-mute-console.socket</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>The <command>systemd-mute-console</command> tool and service may be used to
|
||||
temporarily mute the log output of the kernel as well as the status output of the service manager to
|
||||
the system console. It may be used by tools running on the console to ensure their terminal output is not
|
||||
interrupted by unrelated messages.</para>
|
||||
|
||||
<para>The tool can be invoked directly in which case it will mute the two outputs and then issue an
|
||||
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<literal>READY=1</literal> notification once that is completed. On <constant>SIGINT</constant> or
|
||||
<constant>SIGTERM</constant> output is unmuted again. Alternatively it can be invoked via Varlink
|
||||
IPC.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--kernel=<replaceable>bool</replaceable></option></term>
|
||||
<term><option>--pid1=<replaceable>bool</replaceable></option></term>
|
||||
<listitem><para>Individually controls which output to mute. If true is specified the respective
|
||||
output is muted, if false the output is left as is. Defaults to true.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -2384,6 +2384,7 @@ subdir('src/measure')
|
||||
subdir('src/modules-load')
|
||||
subdir('src/mount')
|
||||
subdir('src/mountfsd')
|
||||
subdir('src/mute-console')
|
||||
subdir('src/network')
|
||||
subdir('src/notify')
|
||||
subdir('src/nspawn')
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-id128.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ask-password-api.h"
|
||||
@@ -86,6 +87,7 @@ static bool arg_welcome = true;
|
||||
static bool arg_reset = false;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
static bool arg_chrome = true;
|
||||
static bool arg_mute_console = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
@@ -99,13 +101,17 @@ STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
|
||||
static void print_welcome(int rfd) {
|
||||
static void print_welcome(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
|
||||
static bool done = false;
|
||||
const char *pn, *ac;
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
assert(mute_console_link);
|
||||
|
||||
if (!*mute_console_link && arg_mute_console)
|
||||
(void) mute_console(mute_console_link);
|
||||
|
||||
if (!arg_welcome)
|
||||
return;
|
||||
@@ -227,7 +233,7 @@ static int locale_is_ok(const char *name, void *userdata) {
|
||||
return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
|
||||
}
|
||||
|
||||
static int prompt_locale(int rfd) {
|
||||
static int prompt_locale(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_strv_free_ char **locales = NULL;
|
||||
bool acquired_from_creds = false;
|
||||
int r;
|
||||
@@ -279,7 +285,7 @@ static int prompt_locale(int rfd) {
|
||||
/* Not setting arg_locale_message here, since it defaults to LANG anyway */
|
||||
}
|
||||
} else {
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
r = prompt_loop("Please enter the new system locale name or number",
|
||||
GLYPH_WORLD,
|
||||
@@ -321,7 +327,7 @@ static int prompt_locale(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_locale(int rfd) {
|
||||
static int process_locale(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_close_ int pfd = -EBADF;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
char* locales[3];
|
||||
@@ -357,7 +363,7 @@ static int process_locale(int rfd) {
|
||||
}
|
||||
}
|
||||
|
||||
r = prompt_locale(rfd);
|
||||
r = prompt_locale(rfd, mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -394,7 +400,7 @@ static int keymap_is_ok(const char* name, void *userdata) {
|
||||
return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
|
||||
}
|
||||
|
||||
static int prompt_keymap(int rfd) {
|
||||
static int prompt_keymap(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_strv_free_ char **kmaps = NULL;
|
||||
int r;
|
||||
|
||||
@@ -422,7 +428,7 @@ static int prompt_keymap(int rfd) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read keymaps: %m");
|
||||
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
return prompt_loop(
|
||||
"Please enter the new keymap name or number",
|
||||
@@ -439,7 +445,7 @@ static int prompt_keymap(int rfd) {
|
||||
&arg_keymap);
|
||||
}
|
||||
|
||||
static int process_keymap(int rfd) {
|
||||
static int process_keymap(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_close_ int pfd = -EBADF;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
_cleanup_strv_free_ char **keymap = NULL;
|
||||
@@ -474,7 +480,7 @@ static int process_keymap(int rfd) {
|
||||
}
|
||||
}
|
||||
|
||||
r = prompt_keymap(rfd);
|
||||
r = prompt_keymap(rfd, mute_console_link);
|
||||
if (r == -ENOENT)
|
||||
return 0; /* don't fail if no keymaps are installed */
|
||||
if (r < 0)
|
||||
@@ -508,7 +514,7 @@ static int timezone_is_ok(const char *name, void *userdata) {
|
||||
return timezone_is_valid(name, LOG_DEBUG);
|
||||
}
|
||||
|
||||
static int prompt_timezone(int rfd) {
|
||||
static int prompt_timezone(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_strv_free_ char **zones = NULL;
|
||||
int r;
|
||||
|
||||
@@ -534,7 +540,7 @@ static int prompt_timezone(int rfd) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot query timezone list: %m");
|
||||
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
return prompt_loop(
|
||||
"Please enter the new timezone name or number",
|
||||
@@ -551,7 +557,7 @@ static int prompt_timezone(int rfd) {
|
||||
&arg_timezone);
|
||||
}
|
||||
|
||||
static int process_timezone(int rfd) {
|
||||
static int process_timezone(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_close_ int pfd = -EBADF;
|
||||
_cleanup_free_ char *f = NULL, *relpath = NULL;
|
||||
const char *e;
|
||||
@@ -592,7 +598,7 @@ static int process_timezone(int rfd) {
|
||||
}
|
||||
}
|
||||
|
||||
r = prompt_timezone(rfd);
|
||||
r = prompt_timezone(rfd, mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -616,7 +622,7 @@ static int hostname_is_ok(const char *name, void *userdata) {
|
||||
return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
|
||||
}
|
||||
|
||||
static int prompt_hostname(int rfd) {
|
||||
static int prompt_hostname(int rfd, sd_varlink **mute_console_link) {
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
@@ -629,7 +635,7 @@ static int prompt_hostname(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
r = prompt_loop("Please enter the new hostname",
|
||||
GLYPH_LABEL,
|
||||
@@ -652,7 +658,7 @@ static int prompt_hostname(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_hostname(int rfd) {
|
||||
static int process_hostname(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_close_ int pfd = -EBADF;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
int r;
|
||||
@@ -671,7 +677,7 @@ static int process_hostname(int rfd) {
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = prompt_hostname(rfd);
|
||||
r = prompt_hostname(rfd, mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -720,7 +726,7 @@ static int process_machine_id(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prompt_root_password(int rfd) {
|
||||
static int prompt_root_password(int rfd, sd_varlink **mute_console_link) {
|
||||
const char *msg1, *msg2;
|
||||
int r;
|
||||
|
||||
@@ -737,10 +743,10 @@ static int prompt_root_password(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
msg1 = strjoina("Please enter the new root password (empty to skip):");
|
||||
msg2 = strjoina("Please enter the new root password again:");
|
||||
msg1 = "Please enter the new root password (empty to skip):";
|
||||
msg2 = "Please enter the new root password again:";
|
||||
|
||||
suggest_passwords();
|
||||
|
||||
@@ -817,7 +823,7 @@ static int shell_is_ok(const char *path, void *userdata) {
|
||||
return find_shell(rfd, path) >= 0;
|
||||
}
|
||||
|
||||
static int prompt_root_shell(int rfd) {
|
||||
static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) {
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
@@ -838,7 +844,7 @@ static int prompt_root_shell(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_welcome(rfd);
|
||||
print_welcome(rfd, mute_console_link);
|
||||
|
||||
return prompt_loop(
|
||||
"Please enter the new root shell",
|
||||
@@ -1005,7 +1011,7 @@ static int write_root_shadow(int etc_fd, const char *hashed_password) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_root_account(int rfd) {
|
||||
static int process_root_account(int rfd, sd_varlink **mute_console_link) {
|
||||
_cleanup_close_ int pfd = -EBADF;
|
||||
_cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
|
||||
_cleanup_(erase_and_freep) char *_hashed_password = NULL;
|
||||
@@ -1059,7 +1065,7 @@ static int process_root_account(int rfd) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = prompt_root_shell(rfd);
|
||||
r = prompt_root_shell(rfd, mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1078,7 +1084,7 @@ static int process_root_account(int rfd) {
|
||||
arg_root_password_is_hashed = true;
|
||||
}
|
||||
|
||||
r = prompt_root_password(rfd);
|
||||
r = prompt_root_password(rfd, mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1246,6 +1252,8 @@ static int help(void) {
|
||||
" --welcome=no Disable the welcome text\n"
|
||||
" --chrome=no Don't show color bar at top and bottom of\n"
|
||||
" terminal\n"
|
||||
" --mute-console=yes Tell kernel/PID 1 to not write to the console\n"
|
||||
" while running\n"
|
||||
" --reset Remove existing files\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
@@ -1293,6 +1301,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_WELCOME,
|
||||
ARG_CHROME,
|
||||
ARG_RESET,
|
||||
ARG_MUTE_CONSOLE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@@ -1331,6 +1340,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "welcome", required_argument, NULL, ARG_WELCOME },
|
||||
{ "chrome", required_argument, NULL, ARG_CHROME },
|
||||
{ "reset", no_argument, NULL, ARG_RESET },
|
||||
{ "mute-console", required_argument, NULL, ARG_MUTE_CONSOLE },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1550,6 +1560,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_reset = true;
|
||||
break;
|
||||
|
||||
case ARG_MUTE_CONSOLE:
|
||||
r = parse_boolean_argument("--mute-console=", optarg, &arg_mute_console);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1712,27 +1729,28 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = process_locale(rfd);
|
||||
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *mute_console_link = NULL;
|
||||
r = process_locale(rfd, &mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && !offline)
|
||||
(void) reload_system_manager(&bus);
|
||||
|
||||
r = process_keymap(rfd);
|
||||
r = process_keymap(rfd, &mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && !offline)
|
||||
(void) reload_vconsole(&bus);
|
||||
|
||||
r = process_timezone(rfd);
|
||||
r = process_timezone(rfd, &mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = process_hostname(rfd);
|
||||
r = process_hostname(rfd, &mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = process_root_account(rfd);
|
||||
r = process_root_account(rfd, &mute_console_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
9
src/mute-console/meson.build
Normal file
9
src/mute-console/meson.build
Normal file
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
executables += [
|
||||
executable_template + {
|
||||
'name' : 'systemd-mute-console',
|
||||
'public' : true,
|
||||
'sources' : files('mute-console.c'),
|
||||
},
|
||||
]
|
||||
419
src/mute-console/mute-console.c
Normal file
419
src/mute-console/mute-console.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-event.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ansi-color.h"
|
||||
#include "build.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "bus-util.h"
|
||||
#include "daemon-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "parse-argument.h"
|
||||
#include "pretty-print.h"
|
||||
#include "printk-util.h"
|
||||
#include "varlink-io.systemd.MuteConsole.h"
|
||||
#include "varlink-util.h"
|
||||
#include "virt.h"
|
||||
|
||||
static bool arg_mute_pid1 = true;
|
||||
static bool arg_mute_kernel = true;
|
||||
static bool arg_varlink = false;
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
||||
r = terminal_urlify_man("systemd-mute-console", "1", &link);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...]\n"
|
||||
"\n%sMute status output to the console.%s\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --kernel=BOOL Mute kernel log output\n"
|
||||
" --pid1=BOOL Mute PID 1 status output\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
ansi_normal(),
|
||||
link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_KERNEL,
|
||||
ARG_PID1,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "kernel", required_argument, NULL, ARG_KERNEL },
|
||||
{ "pid1", required_argument, NULL, ARG_PID1 },
|
||||
{}
|
||||
};
|
||||
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hq", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 'h':
|
||||
return help();
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_PID1:
|
||||
r = parse_boolean_argument("--pid1=", optarg, &arg_mute_pid1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case ARG_KERNEL:
|
||||
r = parse_boolean_argument("--kernel=", optarg, &arg_mute_kernel);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
||||
if (r > 0)
|
||||
arg_varlink = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int set_show_status(const char *value) {
|
||||
int r;
|
||||
assert(value);
|
||||
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
r = bus_connect_system_systemd(&bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to systemd: %m");
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
r = bus_call_method(bus, bus_systemd_mgr, "SetShowStatus", &error, /* ret_reply= */ NULL, "s", value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to issue SetShowStatus() method call: %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct Context {
|
||||
bool mute_pid1;
|
||||
bool mute_kernel;
|
||||
|
||||
bool muted_pid1;
|
||||
int saved_kernel;
|
||||
|
||||
sd_varlink *link;
|
||||
} Context;
|
||||
|
||||
static int mute_pid1(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!c->mute_pid1) {
|
||||
log_debug("Muting of PID 1 status console output disabled.");
|
||||
c->muted_pid1 = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = set_show_status("no");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_debug("Successfully muted PID 1 status console output.");
|
||||
|
||||
c->muted_pid1 = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmute_pid1(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!c->muted_pid1) {
|
||||
log_debug("Not restoring PID 1 status console output level.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = set_show_status("");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_debug("Successfully unmuted PID 1 status console output.");
|
||||
c->muted_pid1 = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mute_kernel(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!arg_mute_kernel) {
|
||||
log_debug("Muting of kernel printk() console output disabled.");
|
||||
c->saved_kernel = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (detect_container() > 0) {
|
||||
log_debug("Skipping muting of print() console output, because running in a container.");
|
||||
c->saved_kernel = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int level = sysctl_printk_read();
|
||||
if (level < 0)
|
||||
return log_error_errno(level, "Failed to read kernel printk() console output level: %m");
|
||||
|
||||
if (level == 0) {
|
||||
log_info("Not muting kernel printk() console output, since it is already disabled.");
|
||||
c->saved_kernel = -1; /* don't bother with restoring */
|
||||
} else {
|
||||
r = sysctl_printk_write(0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to change kernel printk() console output level: %m");
|
||||
|
||||
log_debug("Successfully muted kernel printk() console output.");
|
||||
c->saved_kernel = level;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unmute_kernel(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (c->saved_kernel < 0) {
|
||||
log_debug("Not restoring kernel printk() console output level.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int level = sysctl_printk_read();
|
||||
if (level < 0)
|
||||
return log_error_errno(level, "Failed to read kernel printk() console output level: %m");
|
||||
|
||||
if (level != 0) {
|
||||
log_info("Not unmuting kernel printk() console output, since it has been changed externally in the meantime.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sysctl_printk_write(c->saved_kernel);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to unmute kernel printk() console output level: %m");
|
||||
|
||||
log_debug("Successfully unmuted kernel printk() console output.");
|
||||
c->saved_kernel = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void context_done(Context *c) {
|
||||
assert(c);
|
||||
|
||||
(void) unmute_pid1(c);
|
||||
(void) unmute_kernel(c);
|
||||
|
||||
if (c->link) {
|
||||
(void) sd_varlink_set_userdata(c->link, NULL);
|
||||
c->link = sd_varlink_flush_close_unref(c->link);
|
||||
}
|
||||
}
|
||||
|
||||
static Context* context_free(Context *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
context_done(c);
|
||||
return mfree(c);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Context*, context_free);
|
||||
|
||||
static void vl_on_disconnect(sd_varlink_server *server, sd_varlink *link, void *userdata) {
|
||||
assert(link);
|
||||
|
||||
Context *c = sd_varlink_get_userdata(link);
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
context_free(c);
|
||||
}
|
||||
|
||||
static int vl_method_mute(
|
||||
sd_varlink *link,
|
||||
sd_json_variant *parameters,
|
||||
sd_varlink_method_flags_t flags,
|
||||
void *userdata) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
_cleanup_(context_freep) Context *nc = new(Context, 1);
|
||||
if (!nc)
|
||||
return -ENOMEM;
|
||||
|
||||
*nc = (Context) {
|
||||
.mute_pid1 = true,
|
||||
.mute_kernel = true,
|
||||
.saved_kernel = -1,
|
||||
};
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "kernel", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(Context, mute_kernel), 0 },
|
||||
{ "pid1", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(Context, mute_pid1), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, nc);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
|
||||
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
|
||||
|
||||
r = sd_varlink_server_bind_disconnect(sd_varlink_get_server(link), vl_on_disconnect);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sd_varlink_set_userdata(link, nc);
|
||||
nc->link = sd_varlink_ref(link);
|
||||
Context *c = TAKE_PTR(nc); /* the Context object is now managed by the disconnect handler, not us anymore */
|
||||
|
||||
r = 0;
|
||||
RET_GATHER(r, mute_pid1(c));
|
||||
RET_GATHER(r, mute_kernel(c));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Let client know we are muted now. We use sd_varlink_notify() here (rather than sd_varlink_reply())
|
||||
* because we want to keep the method call open, as we want that the lifetime of the
|
||||
* connection/method call to determine how long we keep the console muted. */
|
||||
r = sd_varlink_notify(link, /* parameters= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl_server(void) {
|
||||
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
|
||||
int r;
|
||||
|
||||
/* Invocation as Varlink service */
|
||||
|
||||
r = varlink_server_new(
|
||||
&varlink_server,
|
||||
SD_VARLINK_SERVER_ROOT_ONLY|
|
||||
SD_VARLINK_SERVER_HANDLE_SIGINT|
|
||||
SD_VARLINK_SERVER_HANDLE_SIGTERM,
|
||||
/* userdata= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||
|
||||
r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_MuteConsole);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add Varlink interface: %m");
|
||||
|
||||
r = sd_varlink_server_bind_method_many(
|
||||
varlink_server,
|
||||
"io.systemd.MuteConsole.Mute", vl_method_mute);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind Varlink methods: %m");
|
||||
|
||||
r = sd_varlink_server_loop_auto(varlink_server);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to run Varlink event loop: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char* argv[]) {
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (arg_varlink)
|
||||
return vl_server();
|
||||
|
||||
if (!arg_mute_pid1 && !arg_mute_kernel)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not asked to mute anything, refusing.");
|
||||
|
||||
_cleanup_(context_done) Context c = {
|
||||
.mute_pid1 = arg_mute_pid1,
|
||||
.mute_kernel = arg_mute_kernel,
|
||||
.saved_kernel = -1,
|
||||
};
|
||||
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
r = sd_event_new(&event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get default event source: %m");
|
||||
|
||||
(void) sd_event_set_watchdog(event, true);
|
||||
(void) sd_event_set_signal_exit(event, true);
|
||||
|
||||
int ret = 0;
|
||||
RET_GATHER(ret, mute_pid1(&c));
|
||||
RET_GATHER(ret, mute_kernel(&c));
|
||||
|
||||
/* Now tell service manager we area ready to go */
|
||||
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message =
|
||||
notify_start("READY=1\n"
|
||||
"STATUS=Console status output muted temporarily.",
|
||||
"STOPPING=1\n"
|
||||
"STATUS=Console status output unmuted.");
|
||||
|
||||
/* Now wait for SIGINT/SIGTERM */
|
||||
r = sd_event_loop(event);
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, log_error_errno(r, "Failed to run event loop: %m"));
|
||||
|
||||
RET_GATHER(ret, unmute_pid1(&c));
|
||||
RET_GATHER(ret, unmute_kernel(&c));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
@@ -154,6 +154,7 @@ shared_sources = files(
|
||||
'polkit-agent.c',
|
||||
'portable-util.c',
|
||||
'pretty-print.c',
|
||||
'printk-util.c',
|
||||
'prompt-util.c',
|
||||
'ptyfwd.c',
|
||||
'qrcode-util.c',
|
||||
@@ -201,6 +202,7 @@ shared_sources = files(
|
||||
'varlink-io.systemd.ManagedOOM.c',
|
||||
'varlink-io.systemd.Manager.c',
|
||||
'varlink-io.systemd.MountFileSystem.c',
|
||||
'varlink-io.systemd.MuteConsole.c',
|
||||
'varlink-io.systemd.NamespaceResource.c',
|
||||
'varlink-io.systemd.Network.c',
|
||||
'varlink-io.systemd.PCRExtend.c',
|
||||
|
||||
42
src/shared/printk-util.c
Normal file
42
src/shared/printk-util.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "printk-util.h"
|
||||
#include "sysctl-util.h"
|
||||
|
||||
int sysctl_printk_read(void) {
|
||||
int r;
|
||||
|
||||
_cleanup_free_ char *sysctl_printk_vals = NULL;
|
||||
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
|
||||
|
||||
_cleanup_free_ char *sysctl_printk_curr = NULL;
|
||||
const char *p = sysctl_printk_vals;
|
||||
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to split out kernel printk priority: %m");
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Short read while reading kernel.printk sysctl");
|
||||
|
||||
int current_lvl;
|
||||
r = safe_atoi(sysctl_printk_curr, ¤t_lvl);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse kernel.printk sysctl: %s", sysctl_printk_vals);
|
||||
|
||||
return current_lvl;
|
||||
}
|
||||
|
||||
int sysctl_printk_write(int l) {
|
||||
int r;
|
||||
|
||||
r = sysctl_writef("kernel/printk", "%i", l);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to set kernel.printk to %i: %m", l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
5
src/shared/printk-util.h
Normal file
5
src/shared/printk-util.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int sysctl_printk_read(void);
|
||||
int sysctl_printk_write(int l);
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sd-varlink.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "log.h"
|
||||
@@ -330,3 +332,60 @@ void chrome_hide(void) {
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int vl_on_reply(sd_varlink *link, sd_json_variant *parameters, const char *error_id, sd_varlink_reply_flags_t flags, void *userdata) {
|
||||
assert(link);
|
||||
|
||||
/* We want to keep the link around (since its lifetime defines the lifetime of the console muting),
|
||||
* hence let's detach it from the event loop now, and then exit the event loop. */
|
||||
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = sd_event_ref(ASSERT_PTR(sd_varlink_get_event(link)));
|
||||
sd_varlink_detach_event(link);
|
||||
(void) sd_event_exit(e, (error_id || !FLAGS_SET(flags, SD_VARLINK_REPLY_CONTINUES)) ? -EBADR : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mute_console(sd_varlink **ret_link) {
|
||||
int r;
|
||||
|
||||
assert(ret_link);
|
||||
|
||||
/* Talks to the MuteConsole service, and asks for output to the console to be muted, as long as the
|
||||
* connection is retained */
|
||||
|
||||
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL;
|
||||
r = sd_varlink_connect_address(&link, "/run/systemd/io.systemd.MuteConsole");
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to connect to console muting service: %m");
|
||||
|
||||
_cleanup_(sd_event_unrefp) sd_event* event = NULL;
|
||||
r = sd_event_new(&event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_varlink_attach_event(link, event, /* priority= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_varlink_bind_reply(link, vl_on_reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_varlink_set_relative_timeout(link, UINT64_MAX);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to disable method call time-out: %m");
|
||||
|
||||
r = sd_varlink_observe(link, "io.systemd.MuteConsole.Mute", /* parameters= */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to issue Mute() call to io.systemd.MuteConsole: %m");
|
||||
|
||||
/* Now run the event loop, it will exit on the first reply, which is when we know the console output
|
||||
* is now muted. */
|
||||
r = sd_event_loop(event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_link = TAKE_PTR(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,3 +29,5 @@ int prompt_loop(const char *text,
|
||||
|
||||
int chrome_show(const char *top, const char *bottom);
|
||||
void chrome_hide(void);
|
||||
|
||||
int mute_console(sd_varlink **ret_link);
|
||||
|
||||
19
src/shared/varlink-io.systemd.MuteConsole.c
Normal file
19
src/shared/varlink-io.systemd.MuteConsole.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
#include "varlink-io.systemd.MuteConsole.h"
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Mute,
|
||||
SD_VARLINK_FIELD_COMMENT("Whether to mute the kernel's output to the console (defaults to true)."),
|
||||
SD_VARLINK_DEFINE_INPUT(kernel, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Whether to mute PID1's output to the console (defaults to true)."),
|
||||
SD_VARLINK_DEFINE_INPUT(pid1, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_MuteConsole,
|
||||
"io.systemd.MuteConsole",
|
||||
SD_VARLINK_INTERFACE_COMMENT("API for temporarily muting noisy output to the main kernel console"),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Mute kernel and PID 1 output to the main kernel console"),
|
||||
&vl_method_Mute);
|
||||
6
src/shared/varlink-io.systemd.MuteConsole.h
Normal file
6
src/shared/varlink-io.systemd.MuteConsole.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_MuteConsole;
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "pidref.h"
|
||||
#include "printk-util.h"
|
||||
#include "process-util.h"
|
||||
#include "reboot-util.h"
|
||||
#include "rlimit-util.h"
|
||||
@@ -272,42 +273,14 @@ int sync_with_progress(int fd) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int read_current_sysctl_printk_log_level(void) {
|
||||
_cleanup_free_ char *sysctl_printk_vals = NULL, *sysctl_printk_curr = NULL;
|
||||
int current_lvl;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
|
||||
|
||||
p = sysctl_printk_vals;
|
||||
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to split out kernel printk priority: %m");
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Short read while reading kernel.printk sysctl");
|
||||
|
||||
r = safe_atoi(sysctl_printk_curr, ¤t_lvl);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse kernel.printk sysctl: %s", sysctl_printk_vals);
|
||||
|
||||
return current_lvl;
|
||||
}
|
||||
|
||||
static void bump_sysctl_printk_log_level(int min_level) {
|
||||
int current_lvl, r;
|
||||
|
||||
/* Set the logging level to be able to see messages with log level smaller or equal to min_level */
|
||||
|
||||
current_lvl = read_current_sysctl_printk_log_level();
|
||||
int current_lvl = sysctl_printk_read();
|
||||
if (current_lvl < 0 || current_lvl >= min_level + 1)
|
||||
return;
|
||||
|
||||
r = sysctl_writef("kernel/printk", "%i", min_level + 1);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to bump kernel.printk to %i: %m", min_level + 1);
|
||||
(void) sysctl_printk_write(min_level + 1);
|
||||
}
|
||||
|
||||
static void init_watchdog(void) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "varlink-io.systemd.Manager.h"
|
||||
#include "varlink-io.systemd.ManagedOOM.h"
|
||||
#include "varlink-io.systemd.MountFileSystem.h"
|
||||
#include "varlink-io.systemd.MuteConsole.h"
|
||||
#include "varlink-io.systemd.NamespaceResource.h"
|
||||
#include "varlink-io.systemd.Network.h"
|
||||
#include "varlink-io.systemd.PCRExtend.h"
|
||||
@@ -166,6 +167,8 @@ TEST(parse_format) {
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_UserDatabase);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_MuteConsole);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_NamespaceResource);
|
||||
print_separator();
|
||||
test_parse_format_one(&vl_interface_io_systemd_Journal);
|
||||
|
||||
@@ -587,8 +587,13 @@ static int reply_callback(
|
||||
else
|
||||
r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
/* Let the caller know we have received at least one reply now. This is useful for
|
||||
* subscription style interfaces where the first reply indicates the subscription being
|
||||
* successfully enabled. */
|
||||
(void) sd_notify(/* unset_environment= */ false, "READY=1");
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!arg_quiet)
|
||||
sd_json_variant_dump(parameters, arg_json_format_flags, stdout, NULL);
|
||||
|
||||
40
test/units/TEST-74-AUX-UTILS.mute-console.sh
Executable file
40
test/units/TEST-74-AUX-UTILS.mute-console.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
if ! command -v systemd-mute-console >/dev/null; then
|
||||
echo "systemd-mute-console is not installed, skipping the test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PID="$(systemd-notify --fork -- systemd-mute-console)"
|
||||
sleep .5
|
||||
kill "$PID"
|
||||
unset PID
|
||||
|
||||
(! systemd-mute-console --kernel=no --pid1=no)
|
||||
|
||||
PID="$(systemd-notify --fork -- systemd-mute-console --kernel=yes --pid1=yes)"
|
||||
sleep .5
|
||||
kill "$PID"
|
||||
unset PID
|
||||
|
||||
varlinkctl introspect "$(which systemd-mute-console)"
|
||||
|
||||
PID="$(systemd-notify --fork -- varlinkctl call -E "$(which systemd-mute-console)" io.systemd.MuteConsole.Mute '{}')"
|
||||
sleep .5
|
||||
kill "$PID"
|
||||
unset PID
|
||||
|
||||
PID="$(systemd-notify --fork -- varlinkctl call -E "$(which systemd-mute-console)" io.systemd.MuteConsole.Mute '{"pid1":true, "kernel":true}')"
|
||||
sleep .5
|
||||
kill "$PID"
|
||||
unset PID
|
||||
|
||||
varlinkctl introspect /run/systemd/io.systemd.MuteConsole
|
||||
|
||||
PID="$(systemd-notify --fork -- varlinkctl call -E /run/systemd/io.systemd.MuteConsole io.systemd.MuteConsole.Mute '{}')"
|
||||
sleep .5
|
||||
kill "$PID"
|
||||
unset PID
|
||||
@@ -143,6 +143,12 @@ units = [
|
||||
},
|
||||
{ 'file' : 'modprobe@.service' },
|
||||
{ 'file' : 'multi-user.target' },
|
||||
{
|
||||
'file' : 'systemd-mute-console.socket',
|
||||
'symlinks' : ['sockets.target.wants/']
|
||||
},
|
||||
{ 'file' : 'systemd-mute-console@.service' },
|
||||
{ 'file' : 'system-systemd\\x2dmute\\x2dconsole.slice' },
|
||||
{ 'file' : 'network-online.target' },
|
||||
{ 'file' : 'network-pre.target' },
|
||||
{ 'file' : 'network.target' },
|
||||
|
||||
19
units/system-systemd\x2dmute\x2dconsole.slice
Normal file
19
units/system-systemd\x2dmute\x2dconsole.slice
Normal file
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Console Output Muting Service Slice
|
||||
Documentation=man:systemd-mute-console(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Slice]
|
||||
# Serialize requests to mute the console.
|
||||
ConcurrencySoftMax=1
|
||||
@@ -22,6 +22,7 @@ After=systemd-remount-fs.service
|
||||
After=systemd-sysusers.service systemd-tmpfiles-setup.service
|
||||
# Let vconsole-setup do its setup before starting user interaction:
|
||||
After=systemd-vconsole-setup.service
|
||||
After=systemd-mute-console.socket
|
||||
|
||||
Wants=first-boot-complete.target
|
||||
Before=first-boot-complete.target sysinit.target
|
||||
@@ -31,7 +32,7 @@ Before=shutdown.target
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=systemd-firstboot --prompt-locale --prompt-keymap --prompt-timezone --prompt-root-password
|
||||
ExecStart=systemd-firstboot --prompt-locale --prompt-keymap --prompt-timezone --prompt-root-password --mute-console=yes
|
||||
StandardOutput=tty
|
||||
StandardInput=tty
|
||||
StandardError=tty
|
||||
|
||||
22
units/systemd-mute-console.socket
Normal file
22
units/systemd-mute-console.socket
Normal file
@@ -0,0 +1,22 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Console Output Muting Service Socket
|
||||
Documentation=man:systemd-mute-console(8)
|
||||
DefaultDependencies=no
|
||||
Before=sockets.target
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.MuteConsole
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
18
units/systemd-mute-console@.service
Normal file
18
units/systemd-mute-console@.service
Normal file
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Console Output Muting Service
|
||||
Documentation=man:systemd-mute-console(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
|
||||
[Service]
|
||||
ExecStart=systemd-mute-console
|
||||
Reference in New Issue
Block a user