1
0
mirror of https://github.com/systemd/systemd synced 2025-11-18 00:04:46 +01:00

Compare commits

...

8 Commits

Author SHA1 Message Date
Daan De Meyer
308d40626d basic: Use xopenat_full() in mkdir_p_root_full() 2025-10-28 13:01:48 +01:00
Yu Watanabe
16e52afad2
man: handle leading/trailing/repeating whitespaces in anchor links (#39423)
So even if a <term> section contains newlines, we get a reasonable
anchor link to it.

Before:
```
<dt id="
  bind
  UNIT
  PATH
  [PATH]
"><span class="term">
...
<a class="headerlink" title="Permalink to this term" href="#%0A%20%20%20%20%20%20%20%20%20%20%20%20bind%0A%20%20%20%20%20%20%20%20%20%20%20%20UNIT%0A%20%20%20%20%20%20%20%20%20%20%20%20PATH%0A%20%20%20%20%20%20%20%20%20%20%20%20[PATH]%0A%20%20%20%20%20%20%20%20%20%20">¶</a>
```

After:
```
<dt id="bind UNIT PATH [PATH]"><span class="term">
...
<a class="headerlink" title="Permalink to this term" href="#bind%20UNIT%20PATH%20[PATH]">¶</a>
```

Resolves: https://github.com/systemd/systemd/issues/39196

---

The reverts are not strictly necessary here (as already pointed out in
https://github.com/systemd/systemd/pull/39154#issuecomment-3360118164)
but they were helpful in checking if the fix works as expected. I can
drop them if needed.
2025-10-28 15:28:54 +09:00
Yu Watanabe
bdbd902606
logind: support deserializing session leader through pidfdid (#39440)
Fixes #39437
2025-10-28 15:28:09 +09:00
Yu Watanabe
84f3f30e72 udev-watch: allow to log from child process
Otherwise, it is hard to debug issues in reread_partition_table().

This also drop unnecessary FORK_RLIMIT_NOFILE_SAFE flag.
2025-10-28 15:22:21 +09:00
Mike Yuan
ebb730b96d
TEST-35-LOGIN: test coldplug without fdstore on kernels with pidfd id 2025-10-25 19:42:58 +02:00
Mike Yuan
45eea629e3
logind: support deserializing session leader through pidfdid
People make weird assumptions around state preservation and
expect logind to be stoppable. While this is realistically
not OK we can probably improve things a little.

This complements f01d8658a3a57d05a5156aefd32d8137c3ee3996 and
adds support for deserializing the LEADER_PIDFDID= field.
We still prioritize pidfd if got one from fdstore (as with
service_notify_message_parse_new_pid() in pid1), but otherwise
this should make logind restart more robust when fdstore
gets spuriously cleared.

Fixes #39437
2025-10-25 19:42:58 +02:00
Frantisek Sumsal
3b4b3b8a95 Revert "Update systemctl.xml"
This reverts commit b0fe317d14c4e9a02ff661c2ccd37f093cfda396.
This reverts commit 9f4f7f0372688127adc27f82a75db58749eb6d6e.
2025-10-23 15:42:28 +02:00
Frantisek Sumsal
7168535165 man: handle leading/trailing/repeating whitespaces in anchor links
So even if a <term> section contains newlines, we get a reasonable
anchor link to it.

Before:
<dt id="
  bind
  UNIT
  PATH
  [PATH]
"><span class="term">
...
<a class="headerlink" title="Permalink to this term" href="#%0A%20%20%20%20%20%20%20%20%20%20%20%20bind%0A%20%20%20%20%20%20%20%20%20%20%20%20UNIT%0A%20%20%20%20%20%20%20%20%20%20%20%20PATH%0A%20%20%20%20%20%20%20%20%20%20%20%20[PATH]%0A%20%20%20%20%20%20%20%20%20%20">¶</a>

After:
<dt id="bind UNIT PATH [PATH]"><span class="term">
...
<a class="headerlink" title="Permalink to this term" href="#bind%20UNIT%20PATH%20[PATH]">¶</a>

Resolves: #39196
2025-10-23 15:42:28 +02:00
7 changed files with 111 additions and 47 deletions

View File

@ -158,6 +158,8 @@
<xsl:param name="keyNode"/>
<!-- suggested value for generatedID output, a contextually meaningful ID string -->
<xsl:param name="templateID"/>
<!-- Strip leading and trailing whitespaces, and replace repeating whitespaces with a single space -->
<xsl:variable name="normalizedID" select="normalize-space($templateID)"/>
<xsl:variable name="conflictSource" select="preceding::refsect1/title|preceding::refsect1/info/title|
preceding::refsect2/title|preceding::refsect2/info/title|
preceding::varlistentry/term[1]"/>
@ -165,10 +167,10 @@
<xsl:choose>
<!-- special case conflictCount = 0 to preserve compatibility with URLs generated by previous versions of this XSL stylesheet where possible -->
<xsl:when test="$conflictCount = 0">
<xsl:value-of select="$templateID"/>
<xsl:value-of select="$normalizedID"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($templateID, $conflictCount)"/>
<xsl:value-of select="concat($normalizedID, $conflictCount)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

View File

@ -375,7 +375,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
<term><command>list-dependencies</command> <optional><replaceable>UNIT</replaceable></optional></term>
<term>
<command>list-dependencies</command>
<optional><replaceable>UNIT</replaceable>...</optional>
</term>
<listitem>
<para>Shows units required and wanted by the specified
@ -691,7 +694,12 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
<term><command>bind</command> <replaceable>UNIT</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
<term>
<command>bind</command>
<replaceable>UNIT</replaceable>
<replaceable>PATH</replaceable>
[<replaceable>PATH</replaceable>]
</term>
<listitem><para>Bind-mounts a file or directory from the host into the specified unit's mount
namespace. The first path argument is the source file or directory on the host, the second path
@ -718,7 +726,13 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
<term><command>mount-image</command> <replaceable>UNIT</replaceable> <replaceable>IMAGE</replaceable> [<replaceable>PATH</replaceable> [<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]</term>
<term>
<command>mount-image</command>
<replaceable>UNIT</replaceable>
<replaceable>IMAGE</replaceable>
[<replaceable>PATH</replaceable>
[<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]
</term>
<listitem><para>Mounts an image from the host into the specified unit's mount namespace. The first
path argument is the source image on the host, the second path argument is the destination
@ -1201,8 +1215,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
<term><command>add-wants <replaceable>TARGET</replaceable> <replaceable>UNIT</replaceable></command></term>
<term><command>add-requires <replaceable>TARGET</replaceable> <replaceable>UNIT</replaceable></command></term>
<term><command>add-wants <replaceable>TARGET</replaceable>
<replaceable>UNIT</replaceable></command></term>
<term><command>add-requires <replaceable>TARGET</replaceable>
<replaceable>UNIT</replaceable></command></term>
<listitem>
<para>Adds <literal>Wants=</literal> or <literal>Requires=</literal>
@ -1428,7 +1444,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem>
</varlistentry>
<varlistentry>
<term><command>import-environment</command> <replaceable>VARIABLE…</replaceable></term>
<term>
<command>import-environment</command>
<replaceable>VARIABLE…</replaceable>
</term>
<listitem>
<para>Import all, one or more environment variables set on the client into the systemd manager

View File

@ -237,22 +237,19 @@ int mkdir_p_root_full(const char *root, const char *p, uid_t uid, gid_t gid, mod
if (r < 0)
return r;
if (path_strv_contains(subvolumes, p))
r = btrfs_subvol_make_fallback(dfd, bn, m);
else
r = RET_NERRNO(mkdirat(dfd, bn, m));
if (r == -EEXIST)
_cleanup_close_ int nfd = xopenat_full(
dfd, bn,
O_DIRECTORY|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC,
path_strv_contains(subvolumes, p) ? XO_SUBVOLUME : 0,
m);
if (nfd == -EEXIST)
return 0;
if (r < 0)
return r;
if (nfd < 0)
return nfd;
if (ts == USEC_INFINITY && !uid_is_valid(uid) && !gid_is_valid(gid))
return 1;
_cleanup_close_ int nfd = openat(dfd, bn, O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
if (nfd < 0)
return -errno;
if (ts != USEC_INFINITY) {
struct timespec tspec;
timespec_store(&tspec, ts);

View File

@ -409,6 +409,46 @@ static int session_load_devices(Session *s, const char *devices) {
return r;
}
static int session_load_leader(Session *s, uint64_t pidfdid) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
assert(s);
assert(pid_is_valid(s->deserialized_pid));
assert(!pidref_is_set(&s->leader));
if (pidfdid == 0 && s->leader_fd_saved)
/* We have no pidfd id for stable reference, but the pidfd has been submitted to fdstore.
* manager_enumerate_fds() will dispatch the leader fd for us later. */
return 0;
r = pidref_set_pid(&pidref, s->deserialized_pid);
if (r < 0)
return log_error_errno(r, "Failed to deserialize leader PID for session '%s': %m", s->id);
if (pidref.fd < 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to acquire pidfd for session leader '" PID_FMT "', refusing.",
pidref.pid);
if (pidfdid > 0) {
r = pidref_acquire_pidfd_id(&pidref);
if (r < 0)
return log_error_errno(r, "Failed to acquire pidfd id of deserialized leader '" PID_FMT "': %m",
pidref.pid);
if (pidref.fd_id != pidfdid)
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
"Deserialized pidfd id for process " PID_FMT " (%" PRIu64 ") doesn't match with the current one (%" PRIu64 "), refusing.",
pidref.pid, pidfdid, pidref.fd_id);
}
r = session_set_leader_consume(s, TAKE_PIDREF(pidref));
if (r < 0)
return log_error_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
return 1;
}
int session_load(Session *s) {
_cleanup_free_ char *remote = NULL,
*seat = NULL,
@ -418,6 +458,7 @@ int session_load(Session *s) {
*position = NULL,
*leader_pid = NULL,
*leader_fd_saved = NULL,
*leader_pidfdid = NULL,
*type = NULL,
*original_type = NULL,
*class = NULL,
@ -452,6 +493,7 @@ int session_load(Session *s) {
"POSITION", &position,
"LEADER", &leader_pid,
"LEADER_FD_SAVED", &leader_fd_saved,
"LEADER_PIDFDID", &leader_pidfdid,
"TYPE", &type,
"ORIGINAL_TYPE", &original_type,
"CLASS", &class,
@ -594,8 +636,6 @@ int session_load(Session *s) {
}
if (leader_pid) {
assert(!pidref_is_set(&s->leader));
r = parse_pid(leader_pid, &s->deserialized_pid);
if (r < 0)
return log_error_errno(r, "Failed to parse LEADER=%s: %m", leader_pid);
@ -605,25 +645,19 @@ int session_load(Session *s) {
if (r < 0)
return log_error_errno(r, "Failed to parse LEADER_FD_SAVED=%s: %m", leader_fd_saved);
s->leader_fd_saved = r > 0;
if (s->leader_fd_saved)
/* The leader fd will be acquired from fdstore later */
return 0;
}
_cleanup_(pidref_done) PidRef p = PIDREF_NULL;
uint64_t pidfdid;
if (leader_pidfdid) {
r = safe_atou64(leader_pidfdid, &pidfdid);
if (r < 0)
return log_error_errno(r, "Failed to parse LEADER_PIDFDID=%s: %m", leader_pidfdid);
} else
pidfdid = 0;
r = pidref_set_pid(&p, s->deserialized_pid);
r = session_load_leader(s, pidfdid);
if (r < 0)
return log_error_errno(r, "Failed to deserialize leader PID for session '%s': %m", s->id);
if (p.fd < 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to acquire pidfd for session leader '" PID_FMT "', refusing.",
p.pid);
r = session_set_leader_consume(s, TAKE_PIDREF(p));
if (r < 0)
return log_error_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
return r;
}
return 0;

View File

@ -40,6 +40,7 @@
#include "process-util.h"
#include "service-util.h"
#include "signal-util.h"
#include "stat-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "udev-util.h"
@ -448,19 +449,28 @@ static int deliver_session_leader_fd_consume(Session *s, const char *fdname, int
assert(fdname);
assert(fd >= 0);
if (!pid_is_valid(s->deserialized_pid)) {
/* Already deserialized via pidfd id? */
if (pidref_is_set(&s->leader)) {
assert(s->leader.pid == s->deserialized_pid);
assert(s->leader.fd >= 0);
r = fd_inode_same(fd, s->leader.fd);
if (r < 0)
return log_warning_errno(r, "Failed to compare pidfd with deserialized leader for session '%s': %m",
s->id);
if (r > 0)
return 0;
log_warning("Got leader pidfd for session '%s' which mismatches with the deserialized process, resetting with pidfd.",
s->id);
} else if (!pid_is_valid(s->deserialized_pid)) {
r = log_warning_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
"Got leader pidfd for session '%s', but LEADER= is not set, refusing.",
s->id);
goto fail_close;
}
if (!s->leader_fd_saved)
log_warning("Got leader pidfd for session '%s', but not recorded in session state, proceeding anyway.",
s->id);
else
assert(!pidref_is_set(&s->leader));
r = pidref_set_pidfd_take(&leader_fdstore, fd);
if (r < 0) {
if (r == -ESRCH)

View File

@ -191,7 +191,7 @@ static int synthesize_change(Manager *manager, sd_device *dev) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(udev-synth)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG,
&pidref);
if (r < 0)
return r;

View File

@ -32,13 +32,15 @@ Environment=SYSTEMD_LOG_LEVEL=debug
EOF
# We test "coldplug" (completely stop and start logind) here. So we need to preserve
# the fdstore, which might contain session leader pidfds. This is extremely rare use case
# and shall not be considered fully supported.
# the fdstore, which might contain session leader pidfds, but only if pidfd id isn't
# a thing. This is extremely rare use case and shall not be considered fully supported.
# See also: https://github.com/systemd/systemd/pull/30610#discussion_r1440507850
systemctl edit --runtime --stdin systemd-logind.service --drop-in=fdstore-preserve.conf <<EOF
if systemd-analyze compare-versions "$(uname -r)" lt 6.9; then
systemctl edit --runtime --stdin systemd-logind.service --drop-in=fdstore-preserve.conf <<EOF
[Service]
FileDescriptorStorePreserve=yes
EOF
fi
systemctl restart systemd-logind.service
}