summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile-man.am5
-rw-r--r--Makefile.am9
-rw-r--r--catalog/systemd.ru.catalog.in27
-rw-r--r--man/systemd-mount.xml20
-rw-r--r--man/systemd-suspend.service.xml6
-rw-r--r--src/core/timer.c2
-rw-r--r--src/libsystemd/sd-event/sd-event.c7
-rw-r--r--src/mount/mount-tool.c100
-rw-r--r--src/run/run.c77
-rw-r--r--src/shared/ptyfwd.c30
-rw-r--r--src/shared/ptyfwd.h2
-rw-r--r--src/shared/seccomp-util.c4
-rw-r--r--src/test/test-af-list.c1
-rw-r--r--src/test/test-arphrd-list.c1
14 files changed, 255 insertions, 36 deletions
diff --git a/Makefile-man.am b/Makefile-man.am
index c47bedd0df..6f59658445 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -481,6 +481,7 @@ MANPAGES_ALIAS += \
man/systemd-udevd-control.socket.8 \
man/systemd-udevd-kernel.socket.8 \
man/systemd-udevd.8 \
+ man/systemd-umount.1 \
man/systemd-update-done.8 \
man/systemd-user.conf.5 \
man/systemd-volatile-root.8 \
@@ -837,6 +838,7 @@ man/systemd-tmpfiles-setup.service.8: man/systemd-tmpfiles.8
man/systemd-udevd-control.socket.8: man/systemd-udevd.service.8
man/systemd-udevd-kernel.socket.8: man/systemd-udevd.service.8
man/systemd-udevd.8: man/systemd-udevd.service.8
+man/systemd-umount.1: man/systemd-mount.1
man/systemd-update-done.8: man/systemd-update-done.service.8
man/systemd-user.conf.5: man/systemd-system.conf.5
man/systemd-volatile-root.8: man/systemd-volatile-root.service.8
@@ -1787,6 +1789,9 @@ man/systemd-udevd-kernel.socket.html: man/systemd-udevd.service.html
man/systemd-udevd.html: man/systemd-udevd.service.html
$(html-alias)
+man/systemd-umount.html: man/systemd-mount.html
+ $(html-alias)
+
man/systemd-update-done.html: man/systemd-update-done.service.html
$(html-alias)
diff --git a/Makefile.am b/Makefile.am
index c87c547e05..9a435e3a66 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -673,6 +673,15 @@ EXTRA_DIST += \
@INTLTOOL_POLICY_RULE@
+systemd-mount-install-hook:
+ -$(LN_S) systemd-mount $(DESTDIR)$(bindir)/systemd-umount
+
+systemd-mount-uninstall-hook:
+ -rm $(DESTDIR)$(bindir)/systemd-umount
+
+INSTALL_EXEC_HOOKS += systemd-mount-install-hook
+UNINSTALL_EXEC_HOOKS += systemd-mount-uninstall-hook
+
# ------------------------------------------------------------------------------
MANPAGES =
diff --git a/catalog/systemd.ru.catalog.in b/catalog/systemd.ru.catalog.in
index df55478592..3ee1ed63c0 100644
--- a/catalog/systemd.ru.catalog.in
+++ b/catalog/systemd.ru.catalog.in
@@ -1,7 +1,7 @@
# This file is part of systemd.
#
# Copyright 2012 Lennart Poettering
-# Copyright 2013-2016 Sergey Ptashnick
+# Copyright 2013-2017 Sergey Ptashnick
#
# 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
@@ -102,6 +102,18 @@ Documentation: man:core(5)
Вероятно, это произошло из-за ошибки, допущенной в коде программы.
Рекомендуется сообщить её разработчикам о возникшей проблеме.
+# Subject: Core file was truncated to @SIZE_LIMIT@ bytes
+-- 5aadd8e954dc4b1a8c954d63fd9e1137
+Subject: Файл с дампом памяти был урезан до @SIZE_LIMIT@ байт
+Defined-By: systemd
+Support: %SUPPORT_URL%
+Documentation: man:coredump.conf(5)
+
+Объем памяти процесса превысил ограничения на размер дампа, установленные
+для systemd-coredump(8). Записаны только первые @SIZE_LIMIT@ байт. Не исключено,
+что этот дамп еще пригоден для анализа, хотя инструменты для анализа
+дампов (например, gdb(1)) могут выдать предупреждение, что файл был урезан.
+
# Subject: A new session @SESSION_ID@ has been created for user @USER_ID@
-- 8d45620c1a4348dbb17410da57c60c66
Subject: Для пользователя @USER_ID@ создан новый сеанс @SESSION_ID@
@@ -175,6 +187,19 @@ Support: %SUPPORT_URL%
Запуск системных служб занял @USERSPACE_USEC@ микросекунд.
+# Subject: User manager start-up is now complete
+-- eed00a68ffd84e31882105fd973abdd1
+Subject: Завершен запуск менеджера пользовательского сеанса
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+Менеджер пользовательского сеанса для пользователя с идентификатором @_UID@
+был запущен. Все службы, стоявшие в очереди на запуск, также были запущены. Тем
+не менее, прочие службы могут все еще находиться в процессе запуска, либо могут
+быть запущены позднее.
+
+Запуск менеджера занял @USERSPACE_USEC@ микросекунд.
+
# Subject: System sleep state @SLEEP@ entered
-- 6bbd95ee977941e497c48be27c254128
Subject: Система перешла в состояние сна (@SLEEP@)
diff --git a/man/systemd-mount.xml b/man/systemd-mount.xml
index 06b7c85bd8..ab85dc5640 100644
--- a/man/systemd-mount.xml
+++ b/man/systemd-mount.xml
@@ -45,7 +45,8 @@
<refnamediv>
<refname>systemd-mount</refname>
- <refpurpose>Establish a mount or auto-mount point transiently</refpurpose>
+ <refname>systemd-umount</refname>
+ <refpurpose>Establish and destroy transient mount or auto-mount points</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -60,6 +61,11 @@
<arg choice="opt" rep="repeat"><replaceable>OPTIONS</replaceable></arg>
<arg choice="plain"><option>--list</option></arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-umount</command>
+ <arg choice="opt" rep="repeat"><replaceable>OPTIONS</replaceable></arg>
+ <arg choice="plain" rep="repeat"><replaceable>WHERE</replaceable></arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -91,6 +97,9 @@
<para>Use the <option>--list</option> command to show a terse table of all local, known block devices with file
systems that may be mounted with this command.</para>
+
+ <para><command>systemd-umount</command> can be used to unmount a mount or automount point. It is the same
+ as <command>systemd-mount</command> <option>--unmount</option>.</para>
</refsect1>
<refsect1>
@@ -239,6 +248,15 @@
such as labels, etc.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-u</option></term>
+ <term><option>--unmount</option></term>
+
+ <listitem><para>Stop the mount and automount units corresponding to the specified mount points
+ <replaceable>WHERE</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
<xi:include href="user-system-options.xml" xpointer="host" />
diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml
index a8beb86f4d..c7733f2885 100644
--- a/man/systemd-suspend.service.xml
+++ b/man/systemd-suspend.service.xml
@@ -89,8 +89,10 @@
<para>Note that scripts or binaries dropped in
<filename>/usr/lib/systemd/system-sleep/</filename> are intended
for local use only and should be considered hacks. If applications
- want to be notified of system suspend/hibernation and resume,
- there are much nicer interfaces available.</para>
+ want to react to system suspend/hibernation and resume,
+ they should rather use the <ulink
+ url="http://www.freedesktop.org/wiki/Software/systemd/inhibit">Inhibitor
+ interface</ulink>.</para>
<para>Note that
<filename>systemd-suspend.service</filename>,
diff --git a/src/core/timer.c b/src/core/timer.c
index d7441d638f..af67b7591a 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -350,7 +350,7 @@ static void add_random(Timer *t, usec_t *v) {
else
*v += add;
- log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
+ log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
}
static void timer_enter_waiting(Timer *t, bool initial) {
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index f94959adac..4816bd1f67 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -2226,11 +2226,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
}
static int source_dispatch(sd_event_source *s) {
+ EventSourceType saved_type;
int r = 0;
assert(s);
assert(s->pending || s->type == SOURCE_EXIT);
+ /* Save the event source type, here, so that we still know it after the event callback which might invalidate
+ * the event. */
+ saved_type = s->type;
+
if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
r = source_set_pending(s, false);
if (r < 0)
@@ -2318,7 +2323,7 @@ static int source_dispatch(sd_event_source *s) {
if (r < 0)
log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m",
- strna(s->description), event_source_type_to_string(s->type));
+ strna(s->description), event_source_type_to_string(saved_type));
if (s->n_ref == 0)
source_free(s);
diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c
index 9d79e81918..a277724029 100644
--- a/src/mount/mount-tool.c
+++ b/src/mount/mount-tool.c
@@ -40,6 +40,7 @@ enum {
ACTION_DEFAULT,
ACTION_MOUNT,
ACTION_AUTOMOUNT,
+ ACTION_UMOUNT,
ACTION_LIST,
} arg_action = ACTION_DEFAULT;
@@ -99,6 +100,7 @@ static void help(void) {
" Set automount unit property\n"
" --bind-device Bind automount unit to device\n"
" --list List mountable block devices\n"
+ " -u --umount Unmount mount points\n"
, program_invocation_short_name);
}
@@ -144,6 +146,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
{ "bind-device", no_argument, NULL, ARG_BIND_DEVICE },
{ "list", no_argument, NULL, ARG_LIST },
+ { "umount", no_argument, NULL, 'u' },
+ { "unmount", no_argument, NULL, 'u' },
{},
};
@@ -152,7 +156,10 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:A", options, NULL)) >= 0)
+ if (strstr(program_invocation_short_name, "systemd-umount"))
+ arg_action = ACTION_UMOUNT;
+
+ while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:Au", options, NULL)) >= 0)
switch (c) {
@@ -263,6 +270,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_LIST;
break;
+ case 'u':
+ arg_action = ACTION_UMOUNT;
+ break;
+
case '?':
return -EINVAL;
@@ -607,6 +618,89 @@ static int start_transient_automount(
return 0;
}
+static int stop_mount(
+ sd_bus *bus,
+ char **argv,
+ const char *suffix) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
+ _cleanup_free_ char *mount_unit = NULL;
+ int r;
+
+ if (!arg_no_block) {
+ r = bus_wait_for_jobs_new(bus, &w);
+ if (r < 0)
+ return log_error_errno(r, "Could not watch jobs: %m");
+ }
+
+ r = unit_name_from_path(arg_mount_where, suffix, &mount_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make mount unit name: %m");
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StopUnit");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* Name and mode */
+ r = sd_bus_message_append(m, "ss", mount_unit, "fail");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ polkit_agent_open_if_enabled();
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0)
+ return log_error_errno(r, "Failed to stop mount unit: %s", bus_error_message(&error, r));
+
+ if (w) {
+ const char *object;
+
+ r = sd_bus_message_read(reply, "o", &object);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = bus_wait_for_jobs_one(w, object, arg_quiet);
+ if (r < 0)
+ return r;
+ }
+
+ if (!arg_quiet)
+ log_info("Stopped unit %s%s%s for mount point: %s%s%s",
+ ansi_highlight(), mount_unit, ansi_normal(),
+ ansi_highlight(), arg_mount_where, ansi_normal());
+
+ return 0;
+}
+
+static int stop_mounts(
+ sd_bus *bus,
+ char **argv) {
+
+ int r;
+
+ r = stop_mount(bus, argv + optind, ".mount");
+ if (r < 0)
+ return r;
+
+ r = stop_mount(bus, argv + optind, ".automount");
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int acquire_mount_type(struct udev_device *d) {
const char *v;
@@ -1093,6 +1187,10 @@ int main(int argc, char* argv[]) {
r = start_transient_automount(bus, argv + optind);
break;
+ case ACTION_UMOUNT:
+ r = stop_mounts(bus, argv + optind);
+ break;
+
default:
assert_not_reached("Unexpected action.");
}
diff --git a/src/run/run.c b/src/run/run.c
index 99f03465b0..08f7e12336 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -403,6 +403,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_pty && arg_no_block) {
+ log_error("--pty is not compatible with --no-block.");
+ return -EINVAL;
+ }
+
if (arg_scope && with_timer()) {
log_error("Timer options are not supported in --scope mode.");
return -EINVAL;
@@ -784,21 +789,23 @@ static void run_context_free(RunContext *c) {
}
static void run_context_check_done(RunContext *c) {
- bool done = true;
+ bool done;
assert(c);
if (c->match)
- done = done && (c->active_state && STR_IN_SET(c->active_state, "inactive", "failed"));
+ done = STRPTR_IN_SET(c->active_state, "inactive", "failed");
+ else
+ done = true;
- if (c->forward)
- done = done && pty_forward_is_done(c->forward);
+ if (c->forward && done) /* If the service is gone, it's time to drain the output */
+ done = pty_forward_drain(c->forward);
if (done)
sd_event_exit(c->event, EXIT_SUCCESS);
}
-static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int run_context_update(RunContext *c, const char *path) {
static const struct bus_properties_map map[] = {
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
@@ -811,12 +818,11 @@ static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error
{}
};
- RunContext *c = userdata;
int r;
r = bus_map_all_properties(c->bus,
"org.freedesktop.systemd1",
- sd_bus_message_get_path(m),
+ path,
map,
c);
if (r < 0) {
@@ -828,6 +834,15 @@ static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error
return 0;
}
+static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ RunContext *c = userdata;
+
+ assert(m);
+ assert(c);
+
+ return run_context_update(c, sd_bus_message_get_path(m));
+}
+
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
RunContext *c = userdata;
@@ -985,6 +1000,8 @@ static int start_transient_service(
if (arg_wait || master >= 0) {
_cleanup_(run_context_free) RunContext c = {};
+ _cleanup_free_ char *path = NULL;
+ const char *mt;
c.bus = sd_bus_ref(bus);
@@ -1007,27 +1024,27 @@ static int start_transient_service(
pty_forward_set_handler(c.forward, pty_forward_handler, &c);
}
- if (arg_wait) {
- _cleanup_free_ char *path = NULL;
- const char *mt;
- path = unit_dbus_path_from_name(service);
- if (!path)
- return log_oom();
+ path = unit_dbus_path_from_name(service);
+ if (!path)
+ return log_oom();
- mt = strjoina("type='signal',"
- "sender='org.freedesktop.systemd1',"
- "path='", path, "',"
- "interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged'");
- r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c);
- if (r < 0)
- return log_error_errno(r, "Failed to add properties changed signal.");
+ mt = strjoina("type='signal',"
+ "sender='org.freedesktop.systemd1',"
+ "path='", path, "',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "member='PropertiesChanged'");
+ r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add properties changed signal.");
- r = sd_bus_attach_event(bus, c.event, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to attach bus to event loop.");
- }
+ r = sd_bus_attach_event(bus, c.event, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop.");
+
+ r = run_context_update(&c, path);
+ if (r < 0)
+ return r;
r = sd_event_loop(c.event);
if (r < 0)
@@ -1041,7 +1058,13 @@ static int start_transient_service(
fputc('\n', stdout);
}
- if (!arg_quiet) {
+ if (arg_wait && !arg_quiet) {
+
+ /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, in its
+ * original settings (i.e. proper line breaks), so that we can show the summary in a pretty
+ * way. */
+ c.forward = pty_forward_free(c.forward);
+
if (!isempty(c.result))
log_info("Finished with result: %s", strna(c.result));
@@ -1416,7 +1439,7 @@ int main(int argc, char* argv[]) {
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
* connection */
- if (arg_wait)
+ if (arg_wait || arg_pty)
r = bus_connect_transport(arg_transport, arg_host, arg_user, &bus);
else
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 293c6673fc..59b541d519 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -69,6 +69,7 @@ struct PTYForward {
bool read_from_master:1;
bool done:1;
+ bool drain:1;
bool last_char_set:1;
char last_char;
@@ -302,6 +303,11 @@ static int shovel(PTYForward *f) {
return pty_forward_done(f, 0);
}
+ /* If we were asked to drain, and there's nothing more to handle from the master, then call the callback
+ * too. */
+ if (f->drain && f->out_buffer_full == 0 && !f->master_readable)
+ return pty_forward_done(f, 0);
+
return 0;
}
@@ -438,6 +444,9 @@ int pty_forward_new(
r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
if (r < 0 && r != -EPERM)
return r;
+
+ if (r >= 0)
+ (void) sd_event_source_set_description(f->stdin_event_source, "ptyfwd-stdin");
}
r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f);
@@ -446,15 +455,21 @@ int pty_forward_new(
f->stdout_writable = true;
else if (r < 0)
return r;
+ else
+ (void) sd_event_source_set_description(f->stdout_event_source, "ptyfwd-stdout");
r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
if (r < 0)
return r;
+ (void) sd_event_source_set_description(f->master_event_source, "ptyfwd-master");
+
r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
if (r < 0)
return r;
+ (void) sd_event_source_set_description(f->sigwinch_event_source, "ptyfwd-sigwinch");
+
*ret = f;
f = NULL;
@@ -519,3 +534,18 @@ void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata
f->handler = cb;
f->userdata = userdata;
}
+
+bool pty_forward_drain(PTYForward *f) {
+ assert(f);
+
+ /* Starts draining the forwarder. Specifically:
+ *
+ * - Returns true if there are no unprocessed bytes from the pty, false otherwise
+ *
+ * - Makes sure the handler function is called the next time the number of unprocessed bytes hits zero
+ */
+
+ f->drain = true;
+
+ return f->out_buffer_full == 0 && !f->master_readable;
+}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index bd5d5fec0d..3fad1d3b26 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -51,4 +51,6 @@ bool pty_forward_is_done(PTYForward *f);
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata);
+bool pty_forward_drain(PTYForward *f);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 2c73cb8fa4..bd9c0aac60 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -171,11 +171,11 @@ int seccomp_init_for_arch(scmp_filter_ctx *ret, uint32_t arch, uint32_t default_
if (arch != SCMP_ARCH_NATIVE &&
arch != seccomp_arch_native()) {
- r = seccomp_arch_add(seccomp, arch);
+ r = seccomp_arch_remove(seccomp, seccomp_arch_native());
if (r < 0)
goto finish;
- r = seccomp_arch_remove(seccomp, seccomp_arch_native());
+ r = seccomp_arch_add(seccomp, arch);
if (r < 0)
goto finish;
diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c
index e2479133de..e5ca54c8e7 100644
--- a/src/test/test-af-list.c
+++ b/src/test/test-af-list.c
@@ -24,6 +24,7 @@
#include "string-util.h"
#include "util.h"
+_unused_ \
static const struct af_name* lookup_af(register const char *str, register GPERF_LEN_TYPE len);
#include "af-from-name.h"
diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c
index 8f4f342faa..bb51518c9c 100644
--- a/src/test/test-arphrd-list.c
+++ b/src/test/test-arphrd-list.c
@@ -24,6 +24,7 @@
#include "string-util.h"
#include "util.h"
+_unused_ \
static const struct arphrd_name* lookup_arphrd(register const char *str, register GPERF_LEN_TYPE len);
#include "arphrd-from-name.h"