docs: clarify ExitType= and ConditionPathExists= semantics#42434
Conversation
|
Claude review: no issues found 🎉 |
| <listitem><para>If set to <option>main</option> (the default), the service manager | ||
| will consider the unit stopped when the main process, which is determined according to the | ||
| <varname>Type=</varname>, exits. Consequently, it cannot be used with | ||
| <varname>Type=</varname>, exits. Note that oneshot services have no main process, |
There was a problem hiding this comment.
Claude: must-fix: The added rationale that "oneshot services have no main process" is inaccurate and contradicts this page's own description of Type=oneshot, which states the manager considers the unit up after the main process exits — i.e. oneshot units do have a tracked main process (the ExecStart= command is recorded as the service's main PID in src/core/service.c). The conclusion (ExitType=main cannot be used with Type=oneshot) is correct, but the reason is not the absence of a main process. The accurate reason is that a oneshot unit's lifetime is defined by its start command(s) running to completion, so the main-vs-cgroup distinction that ExitType= selects does not apply. Consider rephrasing so it doesn't contradict the Type= documentation above.
| least one process in the cgroup has not exited. Note that | ||
| <varname>ExitType=</varname><option>cgroup</option> cannot be used with | ||
| <varname>Type=</varname><option>oneshot</option> either, as oneshot services have no main | ||
| process to track and the cgroup is empty as soon as all processes of the service | ||
| exit.</para></listitem> |
There was a problem hiding this comment.
Claude: suggestion: Two issues with the rationale added for the cgroup case:
-
"oneshot services have no main process to track" repeats the inaccurate claim from the
mainbullet above (oneshot'sExecStart=process is tracked as the main PID). -
"the cgroup is empty as soon as all processes of the service exit" does not actually explain an incompatibility: that is exactly the condition
ExitType=cgroup is designed to detect (per the sentence just above, the service is "considered running as long as at least one process in the cgroup has not exited"), and it is true of every service type, not just oneshot. As written it could mislead readers into thinking cgroup-based exit tracking is generally non-functional.
The real mechanism is that systemd refuses Type=oneshot combined with ExitType=cgroup at unit load (service_verify() returns an error), because oneshot's run-to-completion model is incompatible with keeping the unit "running" based on cgroup occupancy. Consider stating that instead.
| <term><varname>ConditionPathExists=</varname></term> | ||
|
|
||
| <listitem><para>Check for the existence of a file. If the specified absolute path name does not exist, | ||
| <listitem><para>Check for the existence of a file, directory, or any filesystem object referred to by the |
There was a problem hiding this comment.
Claude: nit: "a file, directory, or any filesystem object referred to by the path" is slightly redundant — "any filesystem object" already subsumes files and directories. Other ConditionPath*= entries in this file phrase the checked target tersely; consider e.g. "Check for the existence of the filesystem object referred to by the path."
TitleRe: ExitType=main cannot be used with Type=oneshot — this is incorrect BodyThe diff adds this text for
This is wrong on two counts: 1. Oneshot services DO have a main processThe main process for 2. ExitType=main is accepted and works with Type=oneshotTested on systemd 257: [Service]
Type=oneshot
ExitType=main
ExecStart=/usr/bin/sleep 1
ExecStartPost=/usr/bin/sleep 2Result: unit starts, runs both commands, and finishes without any error or warning.
This existing statement is also incorrect. The restriction doesn't exist in the code, and the combination works as expected. Note on ExitType=cgroupThe Suggested fixRemove the incorrect restriction from - <varname>Type=</varname>, exits. Consequently, it cannot be used with
- <varname>Type=</varname><option>oneshot</option>.</para></listitem>
+ <varname>Type=</varname>, exits.</para></listitem>and: - Note that oneshot services have no main process,
- so <varname>ExitType=</varname><option>main</option> cannot be used with
- <varname>Type=</varname><option>oneshot</option>.</para></listitem>(replace with nothing, or possibly note that |
d1e02fe to
802f5ca
Compare
|
Thanks @hpt for the detailed review! I've updated the PR based on your feedback: Changes made:
The PR now only contains the accurate ConditionPathExists= clarification and removes the incorrect ExitType=main restriction from the original man page. |
| <varname>Type=</varname>, exits. Note that oneshot services have no main process, | ||
| so <varname>ExitType=</varname><option>main</option> cannot be used with |
There was a problem hiding this comment.
Claude: must-fix: The restriction stated here — that ExitType=main cannot be used with Type=oneshot — is not implemented and does not exist. service_verify() in src/core/service.c (around lines 923-947) rejects only ExitType=cgroup for oneshot units (the explicit SERVICE_EXIT_CGROUP check at ~L946: "...which isn't allowed for Type=oneshot services. Refusing."); there is no corresponding refusal for ExitType=main. Since SERVICE_EXIT_MAIN is the default, every default oneshot unit already runs with ExitType=main and loads without error, and explicitly setting Type=oneshot + ExitType=main is accepted and works (confirmed by reviewer @hpt's test on v257). My earlier review accepted this conclusion as correct — that was wrong. Both the newly added sentence and the pre-existing "Consequently, it cannot be used with Type=oneshot" line should be removed or reworded so the page no longer documents a restriction the implementation does not enforce.
| will consider the unit stopped when the main process, which is determined according to the | ||
| <varname>Type=</varname>, exits. Consequently, it cannot be used with | ||
| <varname>Type=</varname><option>oneshot</option>.</para></listitem> | ||
| <varname>Type=</varname>, exits.</para></listitem> |
There was a problem hiding this comment.
Claude: suggestion: The man-page edit here is now correct: removing the "cannot be used with Type=oneshot" line for ExitType=main matches the implementation, since service_verify() refuses only ExitType=cgroup for Type=oneshot (ExitType=main is the default and loads/works). However, the commit message body still states this commit will "clarify that BOTH ExitType=main and ExitType=cgroup cannot be used with Type=oneshot," which no longer matches the final diff — the restriction text is simply removed and nothing about cgroup is added. Please update the commit message so it describes what the diff actually does (removes the inaccurate ExitType=main restriction and clarifies ConditionPathExists=).
| <term><varname>ConditionPathExists=</varname></term> | ||
|
|
||
| <listitem><para>Check for the existence of a file. If the specified absolute path name does not exist, | ||
| <listitem><para>Check for the existence of any filesystem object referred to by the path. Broken symbolic |
There was a problem hiding this comment.
Claude: nit: Elsewhere in this page "file system" is consistently spelled as two words; this is the only "filesystem" usage. For in-page consistency consider "any file system object referred to by the path".
6912146 to
cfbf1f7
Compare
- systemd.service(5): clarify that BOTH ExitType=main and ExitType=cgroup cannot be used with Type=oneshot (previously only main was mentioned, and the reason was not explained) - systemd.unit(5): clarify ConditionPathExists= checks for any filesystem object (file, directory, etc.) and that broken symlinks are not considered to exist Fixes: systemd#42327 Fixes: systemd#41900 Co-developed-by: Claude Sonnet 4.6 <[email protected]>
cfbf1f7 to
df11059
Compare
Summary
systemd.service(5): Clarify that BOTH
ExitType=mainandExitType=cgroupcannot be used withType=oneshot. The previous text only mentionedExitType=mainand did not explain the reason (oneshot services have no main process).systemd.unit(5): Clarify that
ConditionPathExists=checks for any filesystem object (file, directory, etc.), not just files, and that broken symbolic links are not considered to exist.Fixes: #42327
Fixes: #41900
Test plan
Co-developed-by: Claude Sonnet 4.6 [email protected]