1
0
mirror of https://github.com/systemd/systemd synced 2026-03-16 18:14:46 +01:00

Compare commits

..

15 Commits

Author SHA1 Message Date
Lennart Poettering
83a04afc06
Merge pull request #19686 from keszybz/os-release-modernization-and-examples
os-release modernization and examples
2021-05-22 14:44:50 +02:00
Lennart Poettering
4c483e2647
Merge pull request #19693 from poettering/sleep-tweaks
sleep code refactoring + automatic fallback from hybrid sleep to suspend
2021-05-22 14:35:26 +02:00
Zbigniew Jędrzejewski-Szmek
412339835e man/check-os-release.py: strip trailing whitespace
The shell parser would do that, so so should we.
2021-05-22 12:20:51 +02:00
Zbigniew Jędrzejewski-Szmek
c0527e1f95 man: say that initrd-release is like os-release 2021-05-22 12:20:51 +02:00
Lennart Poettering
c3565fe81f sleep: clarify that failure setting env var is not fatal 2021-05-22 11:00:04 +02:00
Lennart Poettering
3d1321117e sleep: if hybrid sleep fails, do regular suspend
Fixes #19550
2021-05-22 11:00:04 +02:00
Lennart Poettering
b0c035e3c8 sleep: remove duplicate logging
execute() logs about all errors, hence only log about what's new, i.e.
what we'll do as consequence, and don't mention the error cause again.
2021-05-22 11:00:04 +02:00
Lennart Poettering
887b2019b6 sleep: don't check for EADV
EADV is not generated anymore since
6d176522f5480ea9e9a83de5ef5ea5e0d95b79cb, let's hence not check for it
anymore.
2021-05-22 11:00:00 +02:00
Lennart Poettering
61dc84817e sleep: can_sleep_state() + can_sleep_disk() don#t return plain booleans 2021-05-22 11:00:00 +02:00
Lennart Poettering
c8cd8ca398 sleep: use SleepOperation enum everywhere and drop sleep_settings()
Instead of comparing strings everywhere, let's use the new enum. This
allows us to drop sleep_settings(), since the operation enum can be
directly used as index into the config settings.

Some minor other refactoring is done, but mostly just shifting thing
around a bit, no actual change in behaviour.
2021-05-22 11:00:00 +02:00
Lennart Poettering
be2a4b0d7e sleep: introduce high-level SleepOperation enum 2021-05-22 10:58:22 +02:00
Zbigniew Jędrzejewski-Szmek
8fd67ab5a3 man: reword description of BUILD_ID in os-release
Our description was pretty hard to parse. Let's replace it with a description
loosely based on a fairly clear description written by a distro that actually
uses BUILD_ID:
https://developer.rigado.com/docsets/Working-with-the-Rigado-Vesta-Gateway/latest/production/versioning-images.html#the-rigos-scheme.
2021-05-21 17:06:28 +02:00
Zbigniew Jędrzejewski-Szmek
3ca606d103 man: add example os-release mangling in python
This is also not entirely obvious. I think the code I came
up with is pretty elegant ;] The final part of of the code that makes
use of the parsed data is kept very similar to the shell code on purpose,
even though it could be written a bit more idiomatically.
2021-05-21 16:33:04 +02:00
Zbigniew Jędrzejewski-Szmek
e839ebe551 man: add an example how to correctly read os-release in shell
This is not entirely obvious.

The logic of how to interpret the fields applies in any language, so drop the
pointless mention of C or shell.
2021-05-21 16:32:54 +02:00
Zbigniew Jędrzejewski-Szmek
00e3abe024 man: reorder fields in os-release
Let's order the fields from the most general to least: os name, os variant, os
version, machine-parseable version details, metadata, special settings. I added
section headers to roughly group the settings. The division is not strict,
because for example CPE_NAME also includes the version, and PRETTY_NAME may
too, but it still makes it easier to find the right name.

Also split out Examples to separate paragraphs:
almost all descriptions had "Example:" at the end, where multiple
examples were listed. Splitting this out to separate paragraphs
makes the whole thing much easier to read.

Add missing markup and punctuation while at it.

About
- If not set, defaults to <literal>NAME=Linux</literal>.
+ If not set, a default of <literal>NAME=Linux</literal> may be used.
and similar changes: in many circumstances, if this is not set, no value should
be used. The fallback mostly make sense when we need to present something to the
user. So let's reword this to not imply that the default is necessary.
2021-05-21 12:24:14 +02:00
10 changed files with 536 additions and 453 deletions

28
man/check-os-release.py Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/python
import ast
import re
def read_os_release():
try:
f = open('/etc/os-release')
except FileNotFoundError:
f = open('/usr/lib/os-release')
for line_number, line in enumerate(f):
if m := re.match(r'([A-Z][A-Z_0-9]+)=(.*?)\s*$', line):
name, val = m.groups()
if val and val[0] in '"\'':
val = ast.literal_eval(val)
yield name, val
else:
print(f'Warning: bad line {line_number}: {line}', file=sys.stderr)
os_release = dict(read_os_release())
pretty_name = os_release.get('PRETTY_NAME', 'Linux')
print(f'Running on {pretty_name}')
if (os_release.get('ID', 'linux') == 'debian' or
os_release.get('ID_LIKE', None) == 'debian'):
print('Looks like Debian!')

10
man/check-os-release.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/sh -eu
test -e /etc/os-release && os_release='/etc/os-release' || os_release='/usr/lib/os-release'
. "${os_release}"
echo "Running on ${PRETTY_NAME:-Linux}"
if [ "${ID:-linux}" = "debian" ] || [ "${ID_LIKE:-}" = "debian" ]; then
echo "Looks like Debian!"
fi

View File

@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="os-release">
<refentry id="os-release" xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>os-release</title>
<productname>systemd</productname>
@ -16,12 +16,14 @@
<refnamediv>
<refname>os-release</refname>
<refname>initrd-release</refname>
<refpurpose>Operating system identification</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>/etc/os-release</filename></para>
<para><filename>/usr/lib/os-release</filename></para>
<para><filename>/etc/initrd-release</filename></para>
</refsynopsisdiv>
<refsect1>
@ -79,6 +81,19 @@
<para>For a longer rationale for <filename>os-release</filename>
please refer to the <ulink
url="http://0pointer.de/blog/projects/os-release">Announcement of <filename>/etc/os-release</filename></ulink>.</para>
<refsect2>
<title><filename>/etc/initrd-release</filename></title>
<para>In the <ulink
url="https://www.kernel.org/doc/html/latest/admin-guide/initrd.html">initrd</ulink>,
<filename>/etc/initrd-release</filename> plays the same role as <filename>os-release</filename> in the
main system. Additionally, the presence of that file means that the system is in the initrd phase.
<filename>/etc/os-release</filename> should be symlinked to <filename>/etc/initrd-release</filename>
(or vice versa), so programs that only look for <filename>/etc/os-release</filename> (as described
above) work correctly. The rest of this document that talks about <filename>os-release</filename>
should be understood to apply to <filename>initrd-release</filename> too.</para>
</refsect2>
</refsect1>
<refsect1>
@ -87,130 +102,194 @@
<para>The following OS identifications parameters may be set using
<filename>os-release</filename>:</para>
<variablelist class='environment-variables'>
<refsect2>
<title>General information identifying the operating system</title>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>NAME=</varname></term>
<listitem><para>A string identifying the operating system,
without a version component, and suitable for presentation to
the user. If not set, defaults to
<literal>NAME=Linux</literal>. Example:
<literal>NAME=Fedora</literal> or <literal>NAME="Debian
GNU/Linux"</literal>.</para></listitem>
</varlistentry>
<listitem><para>A string identifying the operating system, without a version component, and
suitable for presentation to the user. If not set, a default of <literal>NAME=Linux</literal> may
be used.</para>
<varlistentry>
<term><varname>VERSION=</varname></term>
<listitem><para>A string identifying the operating system
version, excluding any OS name information, possibly including
a release code name, and suitable for presentation to the
user. This field is optional. Example:
<literal>VERSION=17</literal> or <literal>VERSION="17 (Beefy
Miracle)"</literal>.</para></listitem>
<para>Examples: <literal>NAME=Fedora</literal>, <literal>NAME="Debian GNU/Linux"</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ID=</varname></term>
<listitem><para>A lower-case string (no spaces or other
characters outside of 09, az, ".", "_" and "-") identifying
the operating system, excluding any version information and
suitable for processing by scripts or usage in generated
filenames. If not set, defaults to
<literal>ID=linux</literal>. Example:
<literal>ID=fedora</literal> or
<literal>ID=debian</literal>.</para></listitem>
<listitem><para>A lower-case string (no spaces or other characters outside of 09, az, ".", "_"
and "-") identifying the operating system, excluding any version information and suitable for
processing by scripts or usage in generated filenames. If not set, a default of
<literal>ID=linux</literal> may be used.</para>
<para>Examples: <literal>ID=fedora</literal>, <literal>ID=debian</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ID_LIKE=</varname></term>
<listitem><para>A space-separated list of operating system
identifiers in the same syntax as the <varname>ID=</varname>
setting. It should list identifiers of operating systems that
are closely related to the local operating system in regards
to packaging and programming interfaces, for example listing
one or more OS identifiers the local OS is a derivative from.
An OS should generally only list other OS identifiers it
itself is a derivative of, and not any OSes that are derived
from it, though symmetric relationships are possible. Build
scripts and similar should check this variable if they need to
identify the local operating system and the value of
<varname>ID=</varname> is not recognized. Operating systems
should be listed in order of how closely the local operating
system relates to the listed ones, starting with the closest.
This field is optional. Example: for an operating system with
<literal>ID=centos</literal>, an assignment of
<literal>ID_LIKE="rhel fedora"</literal> would be appropriate.
For an operating system with <literal>ID=ubuntu</literal>, an
assignment of <literal>ID_LIKE=debian</literal> is
appropriate.</para></listitem>
<listitem><para>A space-separated list of operating system identifiers in the same syntax as the
<varname>ID=</varname> setting. It should list identifiers of operating systems that are closely
related to the local operating system in regards to packaging and programming interfaces, for
example listing one or more OS identifiers the local OS is a derivative from. An OS should
generally only list other OS identifiers it itself is a derivative of, and not any OSes that are
derived from it, though symmetric relationships are possible. Build scripts and similar should
check this variable if they need to identify the local operating system and the value of
<varname>ID=</varname> is not recognized. Operating systems should be listed in order of how
closely the local operating system relates to the listed ones, starting with the closest. This
field is optional.</para>
<para>Examples: for an operating system with <literal>ID=centos</literal>, an assignment of
<literal>ID_LIKE="rhel fedora"</literal> would be appropriate. For an operating system with
<literal>ID=ubuntu</literal>, an assignment of <literal>ID_LIKE=debian</literal> is appropriate.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VERSION_CODENAME=</varname></term>
<term><varname>PRETTY_NAME=</varname></term>
<listitem><para>
A lower-case string (no spaces or other characters outside of
09, az, ".", "_" and "-") identifying the operating system
release code name, excluding any OS name information or
release version, and suitable for processing by scripts or
usage in generated filenames. This field is optional and may
not be implemented on all systems.
Examples:
<literal>VERSION_CODENAME=buster</literal>,
<literal>VERSION_CODENAME=xenial</literal>
<listitem><para>A pretty operating system name in a format suitable for presentation to the
user. May or may not contain a release code name or OS version of some kind, as suitable. If not
set, a default of <literal>PRETTY_NAME="Linux"</literal> may be used</para>
<para>Example: <literal>PRETTY_NAME="Fedora 17 (Beefy Miracle)"</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CPE_NAME=</varname></term>
<listitem><para>A CPE name for the operating system, in URI binding syntax, following the <ulink
url="http://scap.nist.gov/specifications/cpe/">Common Platform Enumeration Specification</ulink> as
proposed by the NIST. This field is optional.</para>
<para>Example: <literal>CPE_NAME="cpe:/o:fedoraproject:fedora:17"</literal></para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VARIANT=</varname></term>
<listitem><para>A string identifying a specific variant or edition of the operating system suitable
for presentation to the user. This field may be used to inform the user that the configuration of
this system is subject to a specific divergent set of rules or default configuration settings. This
field is optional and may not be implemented on all systems.</para>
<para>Examples: <literal>VARIANT="Server Edition"</literal>, <literal>VARIANT="Smart Refrigerator
Edition"</literal>.</para>
<para>Note: this field is for display purposes only. The <varname>VARIANT_ID</varname> field should
be used for making programmatic decisions.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VARIANT_ID=</varname></term>
<listitem><para>A lower-case string (no spaces or other characters outside of 09, az, ".", "_" and
"-"), identifying a specific variant or edition of the operating system. This may be interpreted by
other packages in order to determine a divergent default configuration. This field is optional and
may not be implemented on all systems.</para>
<para>Examples: <literal>VARIANT_ID=server</literal>, <literal>VARIANT_ID=embedded</literal>.
</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Information about the version of the operating system</title>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>VERSION=</varname></term>
<listitem><para>A string identifying the operating system version, excluding any OS name
information, possibly including a release code name, and suitable for presentation to the
user. This field is optional.</para>
<para>Examples: <literal>VERSION=17</literal>, <literal>VERSION="17 (Beefy Miracle)"</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VERSION_ID=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces
or other characters outside of 09, az, ".", "_" and "-")
identifying the operating system version, excluding any OS
name information or release code name, and suitable for
processing by scripts or usage in generated filenames. This
field is optional. Example: <literal>VERSION_ID=17</literal>
or <literal>VERSION_ID=11.04</literal>.</para></listitem>
</varlistentry>
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the operating system version, excluding any OS name information
or release code name, and suitable for processing by scripts or usage in generated filenames. This
field is optional.</para>
<varlistentry>
<term><varname>PRETTY_NAME=</varname></term>
<listitem><para>A pretty operating system name in a format
suitable for presentation to the user. May or may not contain
a release code name or OS version of some kind, as suitable.
If not set, defaults to
<literal>PRETTY_NAME="Linux"</literal>. Example:
<literal>PRETTY_NAME="Fedora 17 (Beefy
Miracle)"</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ANSI_COLOR=</varname></term>
<listitem><para>A suggested presentation color when showing the OS name on the console. This should
be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for setting
graphical rendition. This field is optional. Example: <literal>ANSI_COLOR="0;31"</literal> for red,
<literal>ANSI_COLOR="1;34"</literal> for light blue, or
<literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CPE_NAME=</varname></term>
<listitem><para>A CPE name for the operating system, in URI
binding syntax, following the
<ulink url="http://scap.nist.gov/specifications/cpe/">Common
Platform Enumeration Specification</ulink> as proposed by the
NIST. This field is optional. Example:
<literal>CPE_NAME="cpe:/o:fedoraproject:fedora:17"</literal>
<para>Examples: <literal>VERSION_ID=17</literal>, <literal>VERSION_ID=11.04</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VERSION_CODENAME=</varname></term>
<listitem><para>A lower-case string (no spaces or other characters outside of 09, az, ".", "_"
and "-") identifying the operating system release code name, excluding any OS name information or
release version, and suitable for processing by scripts or usage in generated filenames. This field
is optional and may not be implemented on all systems.</para>
<para>Examples: <literal>VERSION_CODENAME=buster</literal>,
<literal>VERSION_CODENAME=xenial</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>BUILD_ID=</varname></term>
<listitem><para>A string uniquely identifying the system image originally used as the installation
base. In most cases, <varname>VERSION_ID</varname> or
<varname>IMAGE_ID</varname>+<varname>IMAGE_VERSION</varname> are updated when the entire system
image is replaced during an update. <varname>BUILD_ID</varname> may be used in distributions where
the original installation image version is important: <varname>VERSION_ID</varname> would change
during incremental system updates, but <varname>BUILD_ID</varname> would not. This field is
optional.</para>
<para>Examples: <literal>BUILD_ID="2013-03-20.3"</literal>, <literal>BUILD_ID=201303203</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_ID=</varname></term>
<listitem><para> A lower-case string (no spaces or other characters outside of 09, az, ".", "_"
and "-"), identifying a specific image of the operating system. This is supposed to be used for
environments where OS images are prepared, built, shipped and updated as comprehensive, consistent
OS images. This field is optional and may not be implemented on all systems, in particularly not on
those that are not managed via images but put together and updated from individual packages and on
the local system.</para>
<para>Examples: <literal>IMAGE_ID=vendorx-cashier-system</literal>,
<literal>IMAGE_ID=netbook-image</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_VERSION=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the OS image version. This is supposed to be used together with
<varname>IMAGE_ID</varname> described above, to discern different versions of the same image.
</para>
<para>Examples: <literal>IMAGE_VERSION=33</literal>, <literal>IMAGE_VERSION=47.1rc1</literal>.
</para></listitem>
</varlistentry>
</variablelist>
<para>To summarize: if the image updates are built and shipped as comprehensive units,
<varname>IMAGE_ID</varname>+<varname>IMAGE_VERSION</varname> is the best fit. Otherwise, if updates
eventually completely replace previously installed contents, as in a typical binary distribution,
<varname>VERSION_ID</varname> should be used to identify major releases of the operating system.
<varname>BUILD_ID</varname> may be used instead or in addition to <varname>VERSION_ID</varname> when
the original system image version is important.</para>
</refsect2>
<refsect2>
<title>Presentation information and links</title>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>HOME_URL=</varname></term>
<term><varname>DOCUMENTATION_URL=</varname></term>
@ -218,118 +297,72 @@
<term><varname>BUG_REPORT_URL=</varname></term>
<term><varname>PRIVACY_POLICY_URL=</varname></term>
<listitem><para>Links to resources on the Internet related to
the operating system.
<varname>HOME_URL=</varname> should refer to the homepage of
the operating system, or alternatively some homepage of the
specific version of the operating system.
<varname>DOCUMENTATION_URL=</varname> should refer to the main
documentation page for this operating system.
<varname>SUPPORT_URL=</varname> should refer to the main
support page for the operating system, if there is any. This
is primarily intended for operating systems which vendors
provide support for. <varname>BUG_REPORT_URL=</varname> should
refer to the main bug reporting page for the operating system,
if there is any. This is primarily intended for operating
systems that rely on community QA.
<varname>PRIVACY_POLICY_URL=</varname> should refer to the
main privacy policy page for the operating system, if there is
any. These settings are optional, and providing only some of
these settings is common. These URLs are intended to be
exposed in "About this system" UIs behind links with captions
such as "About this Operating System", "Obtain Support",
"Report a Bug", or "Privacy Policy". The values should be in
<ulink url="https://tools.ietf.org/html/rfc3986">RFC3986
format</ulink>, and should be <literal>http:</literal> or
<literal>https:</literal> URLs, and possibly
<literal>mailto:</literal> or <literal>tel:</literal>. Only
one URL shall be listed in each setting. If multiple resources
need to be referenced, it is recommended to provide an online
landing page linking all available resources. Examples:
<literal>HOME_URL="https://fedoraproject.org/"</literal> and
<literal>BUG_REPORT_URL="https://bugzilla.redhat.com/"</literal></para></listitem>
</varlistentry>
<listitem><para>Links to resources on the Internet related to the operating system.
<varname>HOME_URL=</varname> should refer to the homepage of the operating system, or alternatively
some homepage of the specific version of the operating system.
<varname>DOCUMENTATION_URL=</varname> should refer to the main documentation page for this
operating system. <varname>SUPPORT_URL=</varname> should refer to the main support page for the
operating system, if there is any. This is primarily intended for operating systems which vendors
provide support for. <varname>BUG_REPORT_URL=</varname> should refer to the main bug reporting page
for the operating system, if there is any. This is primarily intended for operating systems that
rely on community QA. <varname>PRIVACY_POLICY_URL=</varname> should refer to the main privacy
policy page for the operating system, if there is any. These settings are optional, and providing
only some of these settings is common. These URLs are intended to be exposed in "About this system"
UIs behind links with captions such as "About this Operating System", "Obtain Support", "Report a
Bug", or "Privacy Policy". The values should be in <ulink
url="https://tools.ietf.org/html/rfc3986">RFC3986 format</ulink>, and should be
<literal>http:</literal> or <literal>https:</literal> URLs, and possibly <literal>mailto:</literal>
or <literal>tel:</literal>. Only one URL shall be listed in each setting. If multiple resources
need to be referenced, it is recommended to provide an online landing page linking all available
resources.</para>
<varlistentry>
<term><varname>BUILD_ID=</varname></term>
<listitem><para>A string uniquely identifying the system image
used as the origin for a distribution (it is not updated with
system updates). The field can be identical between different
VERSION_IDs as BUILD_ID is an only a unique identifier to a
specific version. Distributions that release each update as a
new version would only need to use VERSION_ID as each build is
already distinct based on the VERSION_ID. This field is
optional. Example: <literal>BUILD_ID="2013-03-20.3"</literal>
or <literal>BUILD_ID=201303203</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VARIANT=</varname></term>
<listitem><para>
A string identifying a specific variant or edition of the
operating system suitable for presentation to the user. This
field may be used to inform the user that the configuration of
this system is subject to a specific divergent set of rules or
default configuration settings. This field is optional and may
not be implemented on all systems.
Examples:
<literal>VARIANT="Server Edition"</literal>,
<literal>VARIANT="Smart Refrigerator Edition"</literal>
Note: this field is for display purposes only. The
<varname>VARIANT_ID</varname> field should be used for making
programmatic decisions.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VARIANT_ID=</varname></term>
<listitem><para>
A lower-case string (no spaces or other characters outside of
09, az, ".", "_" and "-"), identifying a specific variant or
edition of the operating system. This may be interpreted by
other packages in order to determine a divergent default
configuration. This field is optional and may not be
implemented on all systems.
Examples:
<literal>VARIANT_ID=server</literal>,
<literal>VARIANT_ID=embedded</literal>
</para></listitem>
<para>Examples: <literal>HOME_URL="https://fedoraproject.org/"</literal>,
<literal>BUG_REPORT_URL="https://bugzilla.redhat.com/"</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>LOGO=</varname></term>
<listitem><para>
A string, specifying the name of an icon as defined by <ulink
url="http://standards.freedesktop.org/icon-theme-spec/latest">
freedesktop.org Icon Theme Specification</ulink>. This can be
used by graphical applications to display an operating
system's or distributor's logo. This field is optional and
may not necessarily be implemented on all systems.
Examples:
<literal>LOGO=fedora-logo</literal>,
<literal>LOGO=distributor-logo-opensuse</literal>
<listitem><para>A string, specifying the name of an icon as defined by <ulink
url="http://standards.freedesktop.org/icon-theme-spec/latest">freedesktop.org Icon Theme
Specification</ulink>. This can be used by graphical applications to display an operating system's
or distributor's logo. This field is optional and may not necessarily be implemented on all
systems.</para>
<para>Examples: <literal>LOGO=fedora-logo</literal>, <literal>LOGO=distributor-logo-opensuse</literal>
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ANSI_COLOR=</varname></term>
<listitem><para>A suggested presentation color when showing the OS name on the console. This should
be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for setting
graphical rendition. This field is optional.</para>
<para>Examples: <literal>ANSI_COLOR="0;31"</literal> for red, <literal>ANSI_COLOR="1;34"</literal>
for light blue, or <literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue.
</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Distribution-level defaults and metadata</title>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>DEFAULT_HOSTNAME=</varname></term>
<listitem><para>A string specifying the hostname if
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry> is not
present and no other configuration source specifies the hostname. Must be either a single DNS label
(a string composed of 7-bit ASCII lower-case characters and no spaces or dots, limited to the format
allowed for DNS domain name labels), or a sequence of such labels separated by single dots that forms
a valid DNS FQDN. The hostname must be at most 64 characters, which is a Linux limitation (DNS allows
longer names).</para>
(a string composed of 7-bit ASCII lower-case characters and no spaces or dots, limited to the
format allowed for DNS domain name labels), or a sequence of such labels separated by single dots
that forms a valid DNS FQDN. The hostname must be at most 64 characters, which is a Linux
limitation (DNS allows longer names).</para>
<para>See
<citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
<para>See <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of how
<citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
determines the fallback hostname.</para></listitem>
@ -340,66 +373,47 @@
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the operating system extensions support level, to indicate which
extension images are supported (See:
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
Example: <literal>SYSEXT_LEVEL=2</literal> or
<literal>SYSEXT_LEVEL=15.14</literal>.</para></listitem>
extension images are supported. See:
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>)
for more information.</para>
<para>Examples: <literal>SYSEXT_LEVEL=2</literal>, <literal>SYSEXT_LEVEL=15.14</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_ID=</varname></term>
<listitem><para> A lower-case string (no spaces or other characters outside of 09, az, ".", "_" and
"-"), identifying a specific image of the operating system. This is supposed to be used for
environments where OS images are prepared, built, shipped and updated as comprehensive, consistent OS
images. This field is optional and may not be implemented on all systems, in particularly not on those
that are not managed via images but put together and updated from individual packages and on the
local system. Examples: <literal>IMAGE_ID=vendorx-cashier-system</literal>,
<literal>IMAGE_ID=netbook-image</literal> </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>IMAGE_VERSION=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the OS image version. This is supposed to be used together with
<varname>IMAGE_ID</varname> described above, to discern different versions of the same
image. Examples: <literal>IMAGE_VERSION=33</literal>,
<literal>IMAGE_VERSION=47.1rc1</literal> </para></listitem>
</varlistentry>
</variablelist>
</refsect2>
<para>If you are reading this file from C code or a shell script
to determine the OS or a specific version of it, use the
<varname>ID</varname> and <varname>VERSION_ID</varname> fields,
possibly with <varname>ID_LIKE</varname> as fallback for
<varname>ID</varname>. When looking for an OS identification
string for presentation to the user use the
<varname>PRETTY_NAME</varname> field.</para>
<refsect2>
<title>Notes</title>
<para>Note that operating system vendors may choose not to provide
version information, for example to accommodate for rolling
releases. In this case, <varname>VERSION</varname> and
<varname>VERSION_ID</varname> may be unset. Applications should
not rely on these fields to be set.</para>
<para>If you are using this file to determine the OS or a specific version of it, use the
<varname>ID</varname> and <varname>VERSION_ID</varname> fields, possibly with
<varname>ID_LIKE</varname> as fallback for <varname>ID</varname>. When looking for an OS identification
string for presentation to the user use the <varname>PRETTY_NAME</varname> field.</para>
<para>Operating system vendors may extend the file
format and introduce new fields. It is highly
recommended to prefix new fields with an OS specific
name in order to avoid name clashes. Applications
reading this file must ignore unknown fields. Example:
<literal>DEBIAN_BTS="debbugs://bugs.debian.org/"</literal></para>
<para>Note that operating system vendors may choose not to provide version information, for example to
accommodate for rolling releases. In this case, <varname>VERSION</varname> and
<varname>VERSION_ID</varname> may be unset. Applications should not rely on these fields to be
set.</para>
<para>Container and sandbox runtime managers may make the host's
identification data available to applications by providing the host's
<filename>/etc/os-release</filename> (if available, otherwise
<para>Operating system vendors may extend the file format and introduce new fields. It is highly
recommended to prefix new fields with an OS specific name in order to avoid name clashes. Applications
reading this file must ignore unknown fields.</para>
<para>Example: <literal>DEBIAN_BTS="debbugs://bugs.debian.org/"</literal>.</para>
<para>Container and sandbox runtime managers may make the host's identification data available to
applications by providing the host's <filename>/etc/os-release</filename> (if available, otherwise
<filename>/usr/lib/os-release</filename> as a fallback) as
<filename>/run/host/os-release</filename>.</para>
</refsect2>
</refsect1>
<refsect1>
<title>Example</title>
<title>Examples</title>
<example>
<title><filename>os-release</filename> file for Fedora Workstation</title>
<programlisting>NAME=Fedora
VERSION="32 (Workstation Edition)"
@ -420,6 +434,22 @@ REDHAT_SUPPORT_PRODUCT_VERSION=32
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
VARIANT="Workstation Edition"
VARIANT_ID=workstation</programlisting>
</example>
<example>
<title>Reading <filename>os-release</filename> in
<citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry></title>
<programlisting><xi:include href="check-os-release.sh" parse="text" /></programlisting>
</example>
<example>
<title>Reading <filename>os-release</filename> in
<citerefentry><refentrytitle>python</refentrytitle><manvolnum>1</manvolnum></citerefentry></title>
<programlisting><xi:include href="check-os-release.py" parse="text" /></programlisting>
</example>
</refsect1>
<refsect1>

View File

@ -61,7 +61,7 @@ manpages = [
['org.freedesktop.resolve1', '5', [], 'ENABLE_RESOLVE'],
['org.freedesktop.systemd1', '5', [], ''],
['org.freedesktop.timedate1', '5', [], 'ENABLE_TIMEDATED'],
['os-release', '5', [], ''],
['os-release', '5', ['initrd-release'], ''],
['pam_systemd', '8', [], 'HAVE_PAM'],
['pam_systemd_home', '8', [], 'ENABLE_PAM_HOME'],
['portablectl', '1', [], 'ENABLE_PORTABLED'],

View File

@ -102,20 +102,20 @@ int manager_handle_action(
}
if (handle == HANDLE_SUSPEND)
supported = can_sleep("suspend") > 0;
supported = can_sleep(SLEEP_SUSPEND) > 0;
else if (handle == HANDLE_HIBERNATE)
supported = can_sleep("hibernate") > 0;
supported = can_sleep(SLEEP_HIBERNATE) > 0;
else if (handle == HANDLE_HYBRID_SLEEP)
supported = can_sleep("hybrid-sleep") > 0;
supported = can_sleep(SLEEP_HYBRID_SLEEP) > 0;
else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE)
supported = can_sleep("suspend-then-hibernate") > 0;
supported = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE) > 0;
else if (handle == HANDLE_KEXEC)
supported = access(KEXEC, X_OK) >= 0;
else
supported = true;
if (!supported && IN_SET(handle, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP, HANDLE_SUSPEND_THEN_HIBERNATE)) {
supported = can_sleep("suspend") > 0;
supported = can_sleep(SLEEP_SUSPEND) > 0;
if (supported) {
log_notice("Requested %s operation is not supported, using regular suspend instead.",
handle_action_to_string(handle));

View File

@ -1851,7 +1851,7 @@ static int method_do_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
SleepOperation sleep_operation,
bool with_flags,
sd_bus_error *error) {
@ -1894,14 +1894,14 @@ static int method_do_shutdown_or_sleep(
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
"There's already a shutdown or sleep operation in progress");
if (sleep_verb) {
r = can_sleep(sleep_verb);
if (sleep_operation >= 0) {
r = can_sleep(sleep_operation);
if (r == -ENOSPC)
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not enough swap space for hibernation");
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Sleep verb \"%s\" not supported", sleep_verb);
"Sleep verb \"%s\" not supported", sleep_operation_to_string(sleep_operation));
if (r < 0)
return r;
}
@ -1928,7 +1928,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"),
error);
}
@ -1943,7 +1943,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"),
error);
}
@ -1958,7 +1958,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
"org.freedesktop.login1.halt",
"org.freedesktop.login1.halt-multiple-sessions",
"org.freedesktop.login1.halt-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"),
error);
}
@ -1973,7 +1973,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
"suspend",
SLEEP_SUSPEND,
sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"),
error);
}
@ -1988,7 +1988,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hibernate",
SLEEP_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"),
error);
}
@ -2003,7 +2003,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_HYBRID_SLEEP,
sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"),
error);
}
@ -2018,7 +2018,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_SUSPEND_THEN_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"),
error);
}
@ -2317,7 +2317,7 @@ static int method_can_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
SleepOperation sleep_operation,
sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@ -2335,8 +2335,8 @@ static int method_can_shutdown_or_sleep(
assert(action_multiple_sessions);
assert(action_ignore_inhibit);
if (sleep_verb) {
r = can_sleep(sleep_verb);
if (sleep_operation >= 0) {
r = can_sleep(sleep_operation);
if (IN_SET(r, 0, -ENOSPC))
return sd_bus_reply_method_return(message, "s", "na");
if (r < 0)
@ -2358,7 +2358,7 @@ static int method_can_shutdown_or_sleep(
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
handle = handle_action_from_string(sleep_verb);
handle = handle_action_from_string(sleep_operation_to_string(sleep_operation));
if (handle >= 0) {
const char *target;
@ -2434,7 +2434,7 @@ static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_e
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2447,7 +2447,7 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2460,7 +2460,7 @@ static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error
"org.freedesktop.login1.halt",
"org.freedesktop.login1.halt-multiple-sessions",
"org.freedesktop.login1.halt-ignore-inhibit",
NULL,
_SLEEP_OPERATION_INVALID,
error);
}
@ -2473,7 +2473,7 @@ static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_er
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
"suspend",
SLEEP_SUSPEND,
error);
}
@ -2486,7 +2486,7 @@ static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hibernate",
SLEEP_HIBERNATE,
error);
}
@ -2499,7 +2499,7 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
SLEEP_HYBRID_SLEEP,
error);
}
@ -2512,7 +2512,7 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"suspend-then-hibernate",
SLEEP_SUSPEND_THEN_HIBERNATE,
error);
}

View File

@ -29,6 +29,7 @@
#include "path-util.h"
#include "sleep-config.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@ -48,14 +49,14 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
{ "Sleep", "AllowSuspendThenHibernate", config_parse_tristate, 0, &allow_s2h },
{ "Sleep", "AllowHybridSleep", config_parse_tristate, 0, &allow_hybrid_sleep },
{ "Sleep", "SuspendMode", config_parse_strv, 0, &sc->suspend_modes },
{ "Sleep", "SuspendState", config_parse_strv, 0, &sc->suspend_states },
{ "Sleep", "HibernateMode", config_parse_strv, 0, &sc->hibernate_modes },
{ "Sleep", "HibernateState", config_parse_strv, 0, &sc->hibernate_states },
{ "Sleep", "HybridSleepMode", config_parse_strv, 0, &sc->hybrid_modes },
{ "Sleep", "HybridSleepState", config_parse_strv, 0, &sc->hybrid_states },
{ "Sleep", "SuspendMode", config_parse_strv, 0, sc->modes + SLEEP_SUSPEND },
{ "Sleep", "SuspendState", config_parse_strv, 0, sc->states + SLEEP_SUSPEND },
{ "Sleep", "HibernateMode", config_parse_strv, 0, sc->modes + SLEEP_HIBERNATE },
{ "Sleep", "HibernateState", config_parse_strv, 0, sc->states + SLEEP_HIBERNATE },
{ "Sleep", "HybridSleepMode", config_parse_strv, 0, sc->modes + SLEEP_HYBRID_SLEEP },
{ "Sleep", "HybridSleepState", config_parse_strv, 0, sc->states + SLEEP_HYBRID_SLEEP },
{ "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_sec},
{ "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_sec },
{}
};
@ -69,29 +70,29 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
NULL);
/* use default values unless set */
sc->allow_suspend = allow_suspend != 0;
sc->allow_hibernate = allow_hibernate != 0;
sc->allow_hybrid_sleep = allow_hybrid_sleep >= 0 ? allow_hybrid_sleep
sc->allow[SLEEP_SUSPEND] = allow_suspend != 0;
sc->allow[SLEEP_HIBERNATE] = allow_hibernate != 0;
sc->allow[SLEEP_HYBRID_SLEEP] = allow_hybrid_sleep >= 0 ? allow_hybrid_sleep
: (allow_suspend != 0 && allow_hibernate != 0);
sc->allow_s2h = allow_s2h >= 0 ? allow_s2h
sc->allow[SLEEP_SUSPEND_THEN_HIBERNATE] = allow_s2h >= 0 ? allow_s2h
: (allow_suspend != 0 && allow_hibernate != 0);
if (!sc->suspend_states)
sc->suspend_states = strv_new("mem", "standby", "freeze");
if (!sc->hibernate_modes)
sc->hibernate_modes = strv_new("platform", "shutdown");
if (!sc->hibernate_states)
sc->hibernate_states = strv_new("disk");
if (!sc->hybrid_modes)
sc->hybrid_modes = strv_new("suspend", "platform", "shutdown");
if (!sc->hybrid_states)
sc->hybrid_states = strv_new("disk");
if (!sc->states[SLEEP_SUSPEND])
sc->states[SLEEP_SUSPEND] = strv_new("mem", "standby", "freeze");
if (!sc->modes[SLEEP_HIBERNATE])
sc->modes[SLEEP_HIBERNATE] = strv_new("platform", "shutdown");
if (!sc->states[SLEEP_HIBERNATE])
sc->states[SLEEP_HIBERNATE] = strv_new("disk");
if (!sc->modes[SLEEP_HYBRID_SLEEP])
sc->modes[SLEEP_HYBRID_SLEEP] = strv_new("suspend", "platform", "shutdown");
if (!sc->states[SLEEP_HYBRID_SLEEP])
sc->states[SLEEP_HYBRID_SLEEP] = strv_new("disk");
if (sc->hibernate_delay_sec == 0)
sc->hibernate_delay_sec = 2 * USEC_PER_HOUR;
/* ensure values set for all required fields */
if (!sc->suspend_states || !sc->hibernate_modes
|| !sc->hibernate_states || !sc->hybrid_modes || !sc->hybrid_states)
if (!sc->states[SLEEP_SUSPEND] || !sc->modes[SLEEP_HIBERNATE]
|| !sc->states[SLEEP_HIBERNATE] || !sc->modes[SLEEP_HYBRID_SLEEP] || !sc->states[SLEEP_HYBRID_SLEEP])
return log_oom();
*ret_sleep_config = TAKE_PTR(sc);
@ -588,10 +589,15 @@ int read_fiemap(int fd, struct fiemap **ret) {
return 0;
}
static int can_sleep_internal(const char *verb, bool check_allowed, const SleepConfig *sleep_config);
static int can_sleep_internal(const SleepConfig *sleep_config, SleepOperation operation, bool check_allowed);
static bool can_s2h(const SleepConfig *sleep_config) {
const char *p;
static const SleepOperation operations[] = {
SLEEP_SUSPEND,
SLEEP_HIBERNATE,
};
int r;
if (!clock_supported(CLOCK_BOOTTIME_ALARM)) {
@ -599,42 +605,40 @@ static bool can_s2h(const SleepConfig *sleep_config) {
return false;
}
FOREACH_STRING(p, "suspend", "hibernate") {
r = can_sleep_internal(p, false, sleep_config);
if (IN_SET(r, 0, -ENOSPC, -EADV)) {
log_debug("Unable to %s system.", p);
for (size_t i = 0; i < ELEMENTSOF(operations); i++) {
r = can_sleep_internal(sleep_config, operations[i], false);
if (IN_SET(r, 0, -ENOSPC)) {
log_debug("Unable to %s system.", sleep_operation_to_string(operations[i]));
return false;
}
if (r < 0)
return log_debug_errno(r, "Failed to check if %s is possible: %m", p);
return log_debug_errno(r, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations[i]));
}
return true;
}
static int can_sleep_internal(const char *verb, bool check_allowed, const SleepConfig *sleep_config) {
bool allow;
char **modes = NULL, **states = NULL;
int r;
static int can_sleep_internal(
const SleepConfig *sleep_config,
SleepOperation operation,
bool check_allowed) {
assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
assert(operation >= 0);
assert(operation < _SLEEP_OPERATION_MAX);
r = sleep_settings(verb, sleep_config, &allow, &modes, &states);
if (r < 0)
return false;
if (check_allowed && !allow) {
log_debug("Sleep mode \"%s\" is disabled by configuration.", verb);
if (check_allowed && !sleep_config->allow[operation]) {
log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation));
return false;
}
if (streq(verb, "suspend-then-hibernate"))
if (operation == SLEEP_SUSPEND_THEN_HIBERNATE)
return can_s2h(sleep_config);
if (!can_sleep_state(states) || !can_sleep_disk(modes))
if (can_sleep_state(sleep_config->states[operation]) <= 0 ||
can_sleep_disk(sleep_config->modes[operation]) <= 0)
return false;
if (streq(verb, "suspend"))
if (operation == SLEEP_SUSPEND)
return true;
if (!enough_swap_for_hibernation())
@ -643,7 +647,7 @@ static int can_sleep_internal(const char *verb, bool check_allowed, const SleepC
return true;
}
int can_sleep(const char *verb) {
int can_sleep(SleepOperation operation) {
_cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
int r;
@ -651,51 +655,26 @@ int can_sleep(const char *verb) {
if (r < 0)
return r;
return can_sleep_internal(verb, true, sleep_config);
}
int sleep_settings(const char *verb, const SleepConfig *sleep_config, bool *ret_allow, char ***ret_modes, char ***ret_states) {
assert(verb);
assert(sleep_config);
assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
if (streq(verb, "suspend")) {
*ret_allow = sleep_config->allow_suspend;
*ret_modes = sleep_config->suspend_modes;
*ret_states = sleep_config->suspend_states;
} else if (streq(verb, "hibernate")) {
*ret_allow = sleep_config->allow_hibernate;
*ret_modes = sleep_config->hibernate_modes;
*ret_states = sleep_config->hibernate_states;
} else if (streq(verb, "hybrid-sleep")) {
*ret_allow = sleep_config->allow_hybrid_sleep;
*ret_modes = sleep_config->hybrid_modes;
*ret_states = sleep_config->hybrid_states;
} else if (streq(verb, "suspend-then-hibernate")) {
*ret_allow = sleep_config->allow_s2h;
*ret_modes = *ret_states = NULL;
}
/* suspend modes empty by default */
if ((!ret_modes && !streq(verb, "suspend")) || !ret_states)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No modes or states set for %s; Check sleep.conf", verb);
return 0;
return can_sleep_internal(sleep_config, operation, true);
}
SleepConfig* free_sleep_config(SleepConfig *sc) {
if (!sc)
return NULL;
strv_free(sc->suspend_modes);
strv_free(sc->suspend_states);
strv_free(sc->hibernate_modes);
strv_free(sc->hibernate_states);
strv_free(sc->hybrid_modes);
strv_free(sc->hybrid_states);
for (SleepOperation i = 0; i < _SLEEP_OPERATION_MAX; i++) {
strv_free(sc->modes[i]);
strv_free(sc->states[i]);
}
return mfree(sc);
}
static const char* const sleep_operation_table[_SLEEP_OPERATION_MAX] = {
[SLEEP_SUSPEND] = "suspend",
[SLEEP_HIBERNATE] = "hibernate",
[SLEEP_HYBRID_SLEEP] = "hybrid-sleep",
[SLEEP_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
};
DEFINE_STRING_TABLE_LOOKUP(sleep_operation, SleepOperation);

View File

@ -4,20 +4,20 @@
#include <linux/fiemap.h>
#include "time-util.h"
typedef enum SleepOperation {
SLEEP_SUSPEND,
SLEEP_HIBERNATE,
SLEEP_HYBRID_SLEEP,
SLEEP_SUSPEND_THEN_HIBERNATE,
_SLEEP_OPERATION_MAX,
_SLEEP_OPERATION_INVALID = -EINVAL,
} SleepOperation;
typedef struct SleepConfig {
bool allow_suspend; /* AllowSuspend */
bool allow_hibernate; /* AllowHibernation */
bool allow_s2h; /* AllowSuspendThenHibernate */
bool allow_hybrid_sleep; /* AllowHybridSleep */
char **suspend_modes; /* SuspendMode */
char **suspend_states; /* SuspendState */
char **hibernate_modes; /* HibernateMode */
char **hibernate_states; /* HibernateState */
char **hybrid_modes; /* HybridSleepMode */
char **hybrid_states; /* HybridSleepState */
usec_t hibernate_delay_sec; /* HibernateDelaySec */
bool allow[_SLEEP_OPERATION_MAX];
char **modes[_SLEEP_OPERATION_MAX];
char **states[_SLEEP_OPERATION_MAX];
usec_t hibernate_delay_sec;
} SleepConfig;
SleepConfig* free_sleep_config(SleepConfig *sc);
@ -48,12 +48,13 @@ typedef struct HibernateLocation {
HibernateLocation* hibernate_location_free(HibernateLocation *hl);
DEFINE_TRIVIAL_CLEANUP_FUNC(HibernateLocation*, hibernate_location_free);
int sleep_settings(const char *verb, const SleepConfig *sleep_config, bool *ret_allow, char ***ret_modes, char ***ret_states);
int read_fiemap(int fd, struct fiemap **ret);
int parse_sleep_config(SleepConfig **sleep_config);
int find_hibernate_location(HibernateLocation **ret_hibernate_location);
int can_sleep(const char *verb);
int can_sleep(SleepOperation operation);
int can_sleep_disk(char **types);
int can_sleep_state(char **types);
const char* sleep_operation_to_string(SleepOperation s) _const_;
SleepOperation sleep_operation_from_string(const char *s) _pure_;

View File

@ -35,9 +35,7 @@
#include "time-util.h"
#include "util.h"
static char* arg_verb = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_verb, freep);
static SleepOperation arg_operation = _SLEEP_OPERATION_INVALID;
static int write_hibernate_location_info(const HibernateLocation *hibernate_location) {
char offset_str[DECIMAL_STR_MAX(uint64_t)];
@ -169,11 +167,17 @@ static int lock_all_homes(void) {
return 0;
}
static int execute(char **modes, char **states, const char *action) {
static int execute(
const SleepConfig *sleep_config,
SleepOperation operation,
const char *action) {
char *arguments[] = {
NULL,
(char*) "pre",
arg_verb,
/* NB: we use 'arg_operation' instead of 'operation' here, as we want to communicate the overall
* operation here, not the specific one, in case of s2h. */
(char*) sleep_operation_to_string(arg_operation),
NULL
};
static const char* const dirs[] = {
@ -181,10 +185,24 @@ static int execute(char **modes, char **states, const char *action) {
NULL
};
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(hibernate_location_freep) HibernateLocation *hibernate_location = NULL;
_cleanup_fclose_ FILE *f = NULL;
char **modes, **states;
int r;
assert(sleep_config);
assert(operation >= 0);
assert(operation < _SLEEP_OPERATION_MAX);
assert(operation != SLEEP_SUSPEND_THEN_HIBERNATE); /* Handled by execute_s2h() instead */
states = sleep_config->states[operation];
modes = sleep_config->modes[operation];
if (strv_isempty(states))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No sleep states configured for sleep operation %s, can't sleep.",
sleep_operation_to_string(operation));
/* This file is opened first, so that if we hit an error,
* we can abort before modifying any state. */
f = fopen("/sys/power/state", "we");
@ -211,29 +229,34 @@ static int execute(char **modes, char **states, const char *action) {
return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;
}
/* Pass an action string to the call-outs. This is mostly our operation string, except if the
* hibernate step of s-t-h fails, in which case we communicate that with a separate action. */
if (!action)
action = sleep_operation_to_string(operation);
r = setenv("SYSTEMD_SLEEP_ACTION", action, 1);
if (r != 0)
log_warning_errno(errno, "Error setting SYSTEMD_SLEEP_ACTION=%s: %m", action);
log_warning_errno(errno, "Error setting SYSTEMD_SLEEP_ACTION=%s, ignoring: %m", action);
(void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
(void) lock_all_homes();
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
LOG_MESSAGE("Suspending system..."),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("Entering sleep state '%s'...", sleep_operation_to_string(operation)),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
r = write_state(&f, states);
if (r < 0)
log_struct_errno(LOG_ERR, r,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
LOG_MESSAGE("Failed to suspend system. System resumed again: %m"),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("Failed to put system to sleep. System resumed again: %m"),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
else
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
LOG_MESSAGE("System resumed."),
"SLEEP=%s", arg_verb);
LOG_MESSAGE("System returned from sleep state."),
"SLEEP=%s", sleep_operation_to_string(arg_operation));
arguments[1] = (char*) "post";
(void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
@ -262,7 +285,7 @@ static int execute_s2h(const SleepConfig *sleep_config) {
if (r < 0)
return log_error_errno(errno, "Error setting hibernate timer: %m");
r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend");
r = execute(sleep_config, SLEEP_SUSPEND, NULL);
if (r < 0)
return r;
@ -278,13 +301,13 @@ static int execute_s2h(const SleepConfig *sleep_config) {
log_debug("Attempting to hibernate after waking from %s timer",
format_timespan(buf, sizeof(buf), sleep_config->hibernate_delay_sec, USEC_PER_SEC));
r = execute(sleep_config->hibernate_modes, sleep_config->hibernate_states, "hibernate");
r = execute(sleep_config, SLEEP_HIBERNATE, NULL);
if (r < 0) {
log_notice_errno(r, "Couldn't hibernate, will try to suspend again: %m");
log_notice("Couldn't hibernate, will try to suspend again.");
r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend-after-failed-hibernate");
r = execute(sleep_config, SLEEP_SUSPEND, "suspend-after-failed-hibernate");
if (r < 0)
return log_error_errno(r, "Could neither hibernate nor suspend, giving up: %m");
return r;
}
return 0;
@ -351,20 +374,14 @@ static int parse_argv(int argc, char *argv[]) {
"Usage: %s COMMAND",
program_invocation_short_name);
arg_verb = strdup(argv[optind]);
if (!arg_verb)
return log_oom();
if (!STR_IN_SET(arg_verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown command '%s'.", arg_verb);
arg_operation = sleep_operation_from_string(argv[optind]);
if (arg_operation < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command '%s'.", argv[optind]);
return 1 /* work to do */;
}
static int run(int argc, char *argv[]) {
bool allow;
char **modes = NULL, **states = NULL;
_cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
int r;
@ -378,19 +395,37 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
r = sleep_settings(arg_verb, sleep_config, &allow, &modes, &states);
if (r < 0)
return r;
if (!allow)
if (!sleep_config->allow[arg_operation])
return log_error_errno(SYNTHETIC_ERRNO(EACCES),
"Sleep mode \"%s\" is disabled by configuration, refusing.",
arg_verb);
"Sleep operation \"%s\" is disabled by configuration, refusing.",
sleep_operation_to_string(arg_operation));
if (streq(arg_verb, "suspend-then-hibernate"))
return execute_s2h(sleep_config);
else
return execute(modes, states, arg_verb);
switch (arg_operation) {
case SLEEP_SUSPEND_THEN_HIBERNATE:
r = execute_s2h(sleep_config);
break;
case SLEEP_HYBRID_SLEEP:
r = execute(sleep_config, SLEEP_HYBRID_SLEEP, NULL);
if (r < 0) {
/* If we can't hybrid sleep, then let's try to suspend at least. After all, the user
* asked us to do both: suspend + hibernate, and it's almost certainly the
* hibernation that failed, hence still do the other thing, the suspend. */
log_notice("Couldn't hybrid sleep, will try to suspend instead.");
r = execute(sleep_config, SLEEP_SUSPEND, "suspend-after-failed-hybrid-sleep");
}
break;
default:
r = execute(sleep_config, arg_operation, NULL);
break;
}
return r;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -25,16 +25,16 @@ static void test_parse_sleep_config(void) {
_cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys;
sum = strv_join(sleep_config->suspend_modes, ", ");
sus = strv_join(sleep_config->suspend_states, ", ");
him = strv_join(sleep_config->hibernate_modes, ", ");
his = strv_join(sleep_config->hibernate_states, ", ");
hym = strv_join(sleep_config->hybrid_modes, ", ");
hys = strv_join(sleep_config->hybrid_states, ", ");
log_debug(" allow_suspend: %u", sleep_config->allow_suspend);
log_debug(" allow_hibernate: %u", sleep_config->allow_hibernate);
log_debug(" allow_s2h: %u", sleep_config->allow_s2h);
log_debug(" allow_hybrid_sleep: %u", sleep_config->allow_hybrid_sleep);
sum = strv_join(sleep_config->modes[SLEEP_SUSPEND], ", ");
sus = strv_join(sleep_config->states[SLEEP_SUSPEND], ", ");
him = strv_join(sleep_config->modes[SLEEP_HIBERNATE], ", ");
his = strv_join(sleep_config->states[SLEEP_HIBERNATE], ", ");
hym = strv_join(sleep_config->modes[SLEEP_HYBRID_SLEEP], ", ");
hys = strv_join(sleep_config->states[SLEEP_HYBRID_SLEEP], ", ");
log_debug(" allow_suspend: %u", sleep_config->allow[SLEEP_SUSPEND]);
log_debug(" allow_hibernate: %u", sleep_config->allow[SLEEP_HIBERNATE]);
log_debug(" allow_s2h: %u", sleep_config->allow[SLEEP_SUSPEND_THEN_HIBERNATE]);
log_debug(" allow_hybrid_sleep: %u", sleep_config->allow[SLEEP_HYBRID_SLEEP]);
log_debug(" suspend modes: %s", sum);
log_debug(" states: %s", sus);
log_debug(" hibernate modes: %s", him);
@ -98,13 +98,13 @@ static void test_sleep(void) {
log_info("Freeze configured: %s", yes_no(can_sleep_state(freeze) > 0));
log_info("/= high-level sleep verbs =/");
r = can_sleep("suspend");
r = can_sleep(SLEEP_SUSPEND);
log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("hibernate");
r = can_sleep(SLEEP_HIBERNATE);
log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("hybrid-sleep");
r = can_sleep(SLEEP_HYBRID_SLEEP);
log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
r = can_sleep("suspend-then-hibernate");
r = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE);
log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : strerror_safe(r));
}