Compare commits
No commits in common. "31c68e0277b84c5f2906d336cac9fc16594db8ce" and "4047a411f45e5e015126538902562416ed5aa5d3" have entirely different histories.
31c68e0277
...
4047a411f4
|
@ -1,102 +0,0 @@
|
||||||
---
|
|
||||||
title: Desktop Environment Integration
|
|
||||||
category: Concepts
|
|
||||||
layout: default
|
|
||||||
---
|
|
||||||
|
|
||||||
# Desktop Environments
|
|
||||||
|
|
||||||
NOTE: This document is a work-in-progress.
|
|
||||||
|
|
||||||
## Single Graphical Session
|
|
||||||
|
|
||||||
systemd only supports running one graphical session per user at a time.
|
|
||||||
While this might not have always been the case historically, having multiple
|
|
||||||
sessions for one user running at the same time is problematic.
|
|
||||||
The DBus session bus is shared between all the logins, and services that are
|
|
||||||
started must be implicitly assigned to the user's current graphical session.
|
|
||||||
|
|
||||||
In principle it is possible to run a single graphical session across multiple
|
|
||||||
logind seats, and this could be a way to use more than one display per user.
|
|
||||||
When a user logs in to a second seat, the seat resources could be assigned
|
|
||||||
to the existing session, allowing the graphical environment to present it
|
|
||||||
is a single seat.
|
|
||||||
Currently nothing like this is supported or even planned.
|
|
||||||
|
|
||||||
## Pre-defined systemd units
|
|
||||||
|
|
||||||
[`systemd.special(7)`](https://www.freedesktop.org/software/systemd/man/systemd.special.html)
|
|
||||||
defines the `graphical-session.target` and `graphical-session-pre.target` to
|
|
||||||
allow cross-desktop integration. Furthermore, systemd defines the three base
|
|
||||||
slices `background`, `apps` and `session`.
|
|
||||||
All units should be placed into one of these slices depending on their purposes:
|
|
||||||
|
|
||||||
* `session.slice`: Contains only processes essential to run the user's graphical session
|
|
||||||
* `apps.slice`: Contains all normal applications that the user is running
|
|
||||||
* `background.slice`: Useful for low-priority background tasks
|
|
||||||
|
|
||||||
The purpose of this grouping is to assign different priorities to the
|
|
||||||
applications.
|
|
||||||
This could e.g. mean reserving memory to session processes,
|
|
||||||
preferentially killing background tasks in out-of-memory situations
|
|
||||||
or assinging different memory/CPU/IO priorities to ensure that the session
|
|
||||||
runs smoothly under load.
|
|
||||||
|
|
||||||
TODO: Will there be a default to place units into e.g. `apps.slice` by default
|
|
||||||
rather than the root slice?
|
|
||||||
|
|
||||||
## XDG standardization for applications
|
|
||||||
|
|
||||||
To ensure cross-desktop compatibility and encourage sharing of good practices,
|
|
||||||
desktop environments should adhere to the following conventions:
|
|
||||||
|
|
||||||
* Application units should follow the scheme `apps-<launcher>-<ApplicationID>-<RANDOM>.service`,
|
|
||||||
e.g. `apps-gnome-org.gnome.Evince-12345.service`,
|
|
||||||
`apps-flatpak-org.telegram.desktop-12345.service` or `apps-KDE-org.kde.okular-12345.service`.
|
|
||||||
* Using `.service` units instead of `.scope` units, i.e. allowing systemd to
|
|
||||||
start the process on behalf of the caller,
|
|
||||||
instead of the caller starting the process and letting systemd know about it,
|
|
||||||
is encouraged.
|
|
||||||
* If no application ID is available, the launcher should generate a reasonable
|
|
||||||
name when possible (e.g. using `basename(argv[0])`). This name must not
|
|
||||||
contain a `-` character.
|
|
||||||
|
|
||||||
This has the following advantages:
|
|
||||||
* Using the `apps-<launcher>-` prefix means that the unit defaults can be
|
|
||||||
adjusted using desktop environment specific drop-in files.
|
|
||||||
* The application ID can be retrieved by stripping the prefix and postfix.
|
|
||||||
This in turn should map to the corresponding `.desktop` file when available
|
|
||||||
|
|
||||||
TODO: Define the name of slices that should be used.
|
|
||||||
This could be `apps-<launcher>-<ApplicationID>-<RANDOM>.slice`.
|
|
||||||
|
|
||||||
TODO: Does it really make sense to insert the `<launcher>`? In GNOME I am
|
|
||||||
currently using a drop-in to configure `BindTo=graphical-session.target`,
|
|
||||||
`CollectMode=inactive-or-failed` and `TimeoutSec=5s`. I feel that such a
|
|
||||||
policy makes sense, but it may make much more sense to just define a
|
|
||||||
global default for all (graphical) applications.
|
|
||||||
|
|
||||||
* Should application lifetime be bound to the session?
|
|
||||||
* May the user have applications that do not belong to the graphical session (e.g. launched from SSH)?
|
|
||||||
* Could we maybe add a default `apps-.service.d` drop-in configuration?
|
|
||||||
|
|
||||||
## XDG autostart integration
|
|
||||||
|
|
||||||
To allow XDG autostart integration, systemd will ship a cross-desktop generator
|
|
||||||
to create appropriate units for the autostart directory.
|
|
||||||
Desktop Environments will be able to make use of this simply by starting the
|
|
||||||
appropriate XDG related targets (representing e.g. content of the
|
|
||||||
`$XDG_CURRENT_DESKTOP` environment variable to handle `OnlyShowIn/NotShowIn`).
|
|
||||||
The names and ordering rules for these targets are to be defined.
|
|
||||||
|
|
||||||
This generator will likely never support certain desktop specific extensions.
|
|
||||||
One such example is the GNOME specific feature to bind a service to a settings
|
|
||||||
variable.
|
|
||||||
|
|
||||||
## Startup and shutdown best practices
|
|
||||||
|
|
||||||
Question here are:
|
|
||||||
|
|
||||||
* Are there strong opinions on how the session-leader process should watch the user's session units?
|
|
||||||
* Should systemd/logind/… provide an integrated way to define a session in terms of a running *user* unit?
|
|
||||||
* Is having `gnome-session-shutdown.target` that is run with `replace-irreversibly` considered a good practice?
|
|
|
@ -571,24 +571,6 @@ evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn870Z5E/
|
||||||
EVDEV_ABS_35=::30
|
EVDEV_ABS_35=::30
|
||||||
EVDEV_ABS_36=::29
|
EVDEV_ABS_36=::29
|
||||||
|
|
||||||
#########################################
|
|
||||||
# Star Labs
|
|
||||||
#########################################
|
|
||||||
|
|
||||||
# Star LabTop Mk III
|
|
||||||
evdev:name:ALPS0001:00 0911:5288 Touchpad:dmi:*svnStarLabs:pnLabTop*
|
|
||||||
EVDEV_ABS_00=0:2627:25
|
|
||||||
EVDEV_ABS_01=0:1331:20
|
|
||||||
EVDEV_ABS_35=0:2627:25
|
|
||||||
EVDEV_ABS_36=0:1331:20
|
|
||||||
|
|
||||||
# Star Lite Mk II
|
|
||||||
evdev:name:ALPS0001:00 0911:5288 Touchpad:dmi:*svnStarLabs:pnLite:*
|
|
||||||
EVDEV_ABS_00=55:1750:16
|
|
||||||
EVDEV_ABS_01=51:950:15
|
|
||||||
EVDEV_ABS_35=55:1750:16
|
|
||||||
EVDEV_ABS_36=51:950:15
|
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# System76
|
# System76
|
||||||
#########################################
|
#########################################
|
||||||
|
|
|
@ -407,10 +407,6 @@ sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrLenovoMIIX3-830:*
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnLENOVO:pn81H3:*
|
sensor:modalias:acpi:BOSC0200*:dmi:*:svnLENOVO:pn81H3:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# IdeaPad Miix 300
|
|
||||||
sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrMIIX300-*
|
|
||||||
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
|
|
||||||
|
|
||||||
# IdeaPad Miix 310 note this only is for BIOS version (bvr) 1HCN4?WW and 1HCN2?WW, which has
|
# IdeaPad Miix 310 note this only is for BIOS version (bvr) 1HCN4?WW and 1HCN2?WW, which has
|
||||||
# a portrait LCD panel, versions with bvr 1HCN3?WW have a landscape panel
|
# a portrait LCD panel, versions with bvr 1HCN3?WW have a landscape panel
|
||||||
sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN4?WW:*:svnLENOVO:pn80SG:*
|
sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN4?WW:*:svnLENOVO:pn80SG:*
|
||||||
|
|
|
@ -217,7 +217,8 @@
|
||||||
this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
|
this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
|
||||||
below) should be set to open access to the notification socket provided by systemd. If
|
below) should be set to open access to the notification socket provided by systemd. If
|
||||||
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
|
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
|
||||||
<option>main</option></para></listitem>.
|
<option>main</option>. Note that currently <varname>Type=</varname><option>notify</option> will not work if
|
||||||
|
used in combination with <varname>PrivateNetwork=</varname><option>yes</option>.</para></listitem>
|
||||||
|
|
||||||
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
|
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
|
||||||
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
|
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
"start:Start container as a service"
|
"start:Start container as a service"
|
||||||
"stop:Stop container (equal to poweroff)"
|
"stop:Stop container (equal to poweroff)"
|
||||||
"login:Get a login prompt on a VM/container"
|
"login:Get a login prompt on a VM/container"
|
||||||
"shell:Invoke a shell (or other command) in a container"
|
|
||||||
"enable:Enable automatic container start at boot"
|
"enable:Enable automatic container start at boot"
|
||||||
"disable:Disable automatic container start at boot"
|
"disable:Disable automatic container start at boot"
|
||||||
"poweroff:Power off one or more VMs/containers"
|
"poweroff:Power off one or more VMs/containers"
|
||||||
|
|
|
@ -701,18 +701,16 @@ int take_etc_passwd_lock(const char *root) {
|
||||||
bool valid_user_group_name_full(const char *u, bool strict) {
|
bool valid_user_group_name_full(const char *u, bool strict) {
|
||||||
const char *i;
|
const char *i;
|
||||||
long sz;
|
long sz;
|
||||||
bool warned = false;
|
|
||||||
|
|
||||||
/* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
|
/* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
|
||||||
* 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
|
* 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
|
||||||
*
|
*
|
||||||
* - We require that names fit into the appropriate utmp field
|
* - We require that names fit into the appropriate utmp field
|
||||||
* - We don't allow empty user names
|
* - We don't allow empty user names
|
||||||
* - No dots in the first character
|
* - No dots or digits in the first character
|
||||||
*
|
*
|
||||||
* If strict==true, additionally:
|
* If strict==true, additionally:
|
||||||
* - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
|
* - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
|
||||||
* - We don't allow a digit as the first character
|
|
||||||
*
|
*
|
||||||
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
|
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
|
||||||
*/
|
*/
|
||||||
|
@ -722,26 +720,17 @@ bool valid_user_group_name_full(const char *u, bool strict) {
|
||||||
|
|
||||||
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
||||||
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
||||||
!(u[0] >= '0' && u[0] <= '9' && !strict) &&
|
|
||||||
u[0] != '_')
|
u[0] != '_')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
|
bool warned = false;
|
||||||
|
|
||||||
if (only_digits_seen) {
|
|
||||||
log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
|
|
||||||
warned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = u+1; *i; i++) {
|
for (i = u+1; *i; i++) {
|
||||||
if (((*i >= 'a' && *i <= 'z') ||
|
if (((*i >= 'a' && *i <= 'z') ||
|
||||||
(*i >= 'A' && *i <= 'Z') ||
|
(*i >= 'A' && *i <= 'Z') ||
|
||||||
(*i >= '0' && *i <= '9') ||
|
(*i >= '0' && *i <= '9') ||
|
||||||
IN_SET(*i, '_', '-'))) {
|
IN_SET(*i, '_', '-')))
|
||||||
if (!(*i >= '0' && *i <= '9'))
|
|
||||||
only_digits_seen = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (*i == '.' && !strict) {
|
if (*i == '.' && !strict) {
|
||||||
if (!warned) {
|
if (!warned) {
|
||||||
|
@ -755,9 +744,6 @@ bool valid_user_group_name_full(const char *u, bool strict) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (only_digits_seen)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
||||||
assert_se(sz > 0);
|
assert_se(sz > 0);
|
||||||
|
|
||||||
|
|
|
@ -210,13 +210,11 @@ int unit_add_name(Unit *u, const char *text) {
|
||||||
if (unit_name_is_valid(text, UNIT_NAME_TEMPLATE)) {
|
if (unit_name_is_valid(text, UNIT_NAME_TEMPLATE)) {
|
||||||
|
|
||||||
if (!u->instance)
|
if (!u->instance)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return -EINVAL;
|
||||||
"instance is not set when adding name '%s': %m", text);
|
|
||||||
|
|
||||||
r = unit_name_replace_instance(text, u->instance, &s);
|
r = unit_name_replace_instance(text, u->instance, &s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_debug_errno(u, r,
|
return r;
|
||||||
"failed to build instance name from '%s': %m", text);
|
|
||||||
} else {
|
} else {
|
||||||
s = strdup(text);
|
s = strdup(text);
|
||||||
if (!s)
|
if (!s)
|
||||||
|
@ -226,43 +224,36 @@ int unit_add_name(Unit *u, const char *text) {
|
||||||
if (set_contains(u->names, s))
|
if (set_contains(u->names, s))
|
||||||
return 0;
|
return 0;
|
||||||
if (hashmap_contains(u->manager->units, s))
|
if (hashmap_contains(u->manager->units, s))
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST),
|
return -EEXIST;
|
||||||
"unit already exist when adding name '%s': %m", text);
|
|
||||||
|
|
||||||
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
|
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return -EINVAL;
|
||||||
"name '%s' is invalid: %m", text);
|
|
||||||
|
|
||||||
t = unit_name_to_type(s);
|
t = unit_name_to_type(s);
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return -EINVAL;
|
||||||
"failed to to derive unit type from name '%s': %m", text);
|
|
||||||
|
|
||||||
if (u->type != _UNIT_TYPE_INVALID && t != u->type)
|
if (u->type != _UNIT_TYPE_INVALID && t != u->type)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return -EINVAL;
|
||||||
"unit type is illegal: u->type(%d) and t(%d) for name '%s': %m",
|
|
||||||
u->type, t, text);
|
|
||||||
|
|
||||||
r = unit_name_to_instance(s, &i);
|
r = unit_name_to_instance(s, &i);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_debug_errno(u, r, "failed to extract instance from name '%s': %m", text);
|
return r;
|
||||||
|
|
||||||
if (i && !unit_type_may_template(t))
|
if (i && !unit_type_may_template(t))
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL), "templates are not allowed for name '%s': %m", text);
|
return -EINVAL;
|
||||||
|
|
||||||
/* Ensure that this unit is either instanced or not instanced,
|
/* Ensure that this unit is either instanced or not instanced,
|
||||||
* but not both. Note that we do allow names with different
|
* but not both. Note that we do allow names with different
|
||||||
* instance names however! */
|
* instance names however! */
|
||||||
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
|
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return -EINVAL;
|
||||||
"instance is illegal: u->type(%d), u->instance(%s) and i(%s) for name '%s': %m",
|
|
||||||
u->type, u->instance, i, text);
|
|
||||||
|
|
||||||
if (!unit_type_may_alias(t) && !set_isempty(u->names))
|
if (!unit_type_may_alias(t) && !set_isempty(u->names))
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST), "symlinks are not allowed for name '%s': %m", text);
|
return -EEXIST;
|
||||||
|
|
||||||
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
|
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(E2BIG), "too many units: %m");
|
return -E2BIG;
|
||||||
|
|
||||||
r = set_put(u->names, s);
|
r = set_put(u->names, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -272,7 +263,7 @@ int unit_add_name(Unit *u, const char *text) {
|
||||||
r = hashmap_put(u->manager->units, s, u);
|
r = hashmap_put(u->manager->units, s, u);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
(void) set_remove(u->names, s);
|
(void) set_remove(u->names, s);
|
||||||
return log_unit_debug_errno(u, r, "add unit to hashmap failed for name '%s': %m", text);
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->type == _UNIT_TYPE_INVALID) {
|
if (u->type == _UNIT_TYPE_INVALID) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ static void test_valid_user_group_name_compat(void) {
|
||||||
assert_se(valid_user_group_name_compat("eff."));
|
assert_se(valid_user_group_name_compat("eff."));
|
||||||
|
|
||||||
assert_se(valid_user_group_name_compat("some5"));
|
assert_se(valid_user_group_name_compat("some5"));
|
||||||
assert_se(valid_user_group_name_compat("5some"));
|
assert_se(!valid_user_group_name_compat("5some"));
|
||||||
assert_se(valid_user_group_name_compat("INNER5NUMBER"));
|
assert_se(valid_user_group_name_compat("INNER5NUMBER"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ static void test_valid_user_group_name_or_id_compat(void) {
|
||||||
assert_se(valid_user_group_name_or_id_compat("kk-k"));
|
assert_se(valid_user_group_name_or_id_compat("kk-k"));
|
||||||
|
|
||||||
assert_se(valid_user_group_name_or_id_compat("some5"));
|
assert_se(valid_user_group_name_or_id_compat("some5"));
|
||||||
assert_se(valid_user_group_name_or_id_compat("5some"));
|
assert_se(!valid_user_group_name_or_id_compat("5some"));
|
||||||
assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
|
assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ Description=Generate network units from Kernel command line
|
||||||
Documentation=man:systemd-network-generator.service(8)
|
Documentation=man:systemd-network-generator.service(8)
|
||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
Before=network-pre.target
|
Before=network-pre.target
|
||||||
Wants=network-pre.target
|
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
|
@ -20,4 +19,4 @@ RemainAfterExit=yes
|
||||||
ExecStart=@rootlibexecdir@/systemd-network-generator
|
ExecStart=@rootlibexecdir@/systemd-network-generator
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=sysinit.target
|
WantedBy=network-pre.target
|
||||||
|
|
Loading…
Reference in New Issue