Skip to content

docs: clarify ExitType= and ConditionPathExists= semantics#42434

Open
lzwind wants to merge 1 commit into
systemd:mainfrom
lzwind:fix/docs-exittype-and-conditionpath
Open

docs: clarify ExitType= and ConditionPathExists= semantics#42434
lzwind wants to merge 1 commit into
systemd:mainfrom
lzwind:fix/docs-exittype-and-conditionpath

Conversation

@lzwind

@lzwind lzwind commented Jun 2, 2026

Copy link
Copy Markdown

Summary

  • systemd.service(5): Clarify that BOTH ExitType=main and ExitType=cgroup cannot be used with Type=oneshot. The previous text only mentioned ExitType=main and 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

  • Review the updated man pages for accuracy
  • Verify the ExitType=/Type=oneshot interaction description matches actual behavior

Co-developed-by: Claude Sonnet 4.6 [email protected]

@github-actions github-actions Bot added documentation please-review PR is ready for (re-)review by a maintainer labels Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Claude review: no issues found 🎉

Workflow run

Comment thread man/systemd.service.xml Outdated
<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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread man/systemd.service.xml Outdated
Comment on lines +313 to +317
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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 main bullet above (oneshot's ExecStart= 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.

Comment thread man/systemd.unit.xml Outdated
<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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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."

@hpt

hpt commented Jun 3, 2026

Copy link
Copy Markdown

Title

Re: ExitType=main cannot be used with Type=oneshot — this is incorrect

Body

The diff adds this text for ExitType=main:

Note that oneshot services have no main process, so ExitType=main cannot be used with Type=oneshot.

This is wrong on two counts:

1. Oneshot services DO have a main process

The main process for Type=oneshot is the process executing ExecStart=. It's tracked and shown in systemctl status as "Main PID". The distinctive behavior of oneshot is what happens after the main process exits (remaining ExecStartPost commands run; the service transitions to "active (exited)").

2. ExitType=main is accepted and works with Type=oneshot

Tested on systemd 257:

[Service]
Type=oneshot
ExitType=main
ExecStart=/usr/bin/sleep 1
ExecStartPost=/usr/bin/sleep 2

Result: unit starts, runs both commands, and finishes without any error or warning.

man systemd.service from the current release (v257) already says:

If set to main (the default), the service manager will consider the unit stopped when the main process, which is determined according to the Type=, exits. Consequently, it cannot be used with Type=oneshot.

This existing statement is also incorrect. The restriction doesn't exist in the code, and the combination works as expected.

Note on ExitType=cgroup

The ExitType=cgroup restriction for Type=oneshot is real (it's an explicit code-level rejection: "ExitType=cgroup set, which isn't allowed for Type=oneshot services. Refusing."), so that addition is accurate.

Suggested fix

Remove the incorrect restriction from ExitType=main in both main and cgroup descriptions:

-            <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 ExitType=main is the default for all service types including oneshot).

@lzwind lzwind force-pushed the fix/docs-exittype-and-conditionpath branch from d1e02fe to 802f5ca Compare June 4, 2026 01:57
@lzwind

lzwind commented Jun 4, 2026

Copy link
Copy Markdown
Author

Thanks @hpt for the detailed review! I've updated the PR based on your feedback:

Changes made:

  1. ExitType=main: Removed the incorrect statement that it cannot be used with Type=oneshot. (You're right that oneshot services DO have a main process and ExitType=main works correctly with them.)

  2. ExitType=cgroup: Removed the added explanation entirely — the original man page correctly didn't mention any oneshot restriction for cgroup.

  3. ConditionPathExists=: Simplified to say "any filesystem object" (removed redundant "file, directory") while keeping the broken symlink note.

The PR now only contains the accurate ConditionPathExists= clarification and removes the incorrect ExitType=main restriction from the original man page.

Comment thread man/systemd.service.xml Outdated
Comment on lines +308 to +309
<varname>Type=</varname>, exits. Note that oneshot services have no main process,
so <varname>ExitType=</varname><option>main</option> cannot be used with

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread man/systemd.service.xml
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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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=).

Comment thread man/systemd.unit.xml
<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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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".

@lzwind lzwind force-pushed the fix/docs-exittype-and-conditionpath branch from 6912146 to cfbf1f7 Compare June 10, 2026 00:59
- 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]>
@lzwind lzwind force-pushed the fix/docs-exittype-and-conditionpath branch from cfbf1f7 to df11059 Compare June 11, 2026 02:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-review documentation please-review PR is ready for (re-)review by a maintainer

Development

Successfully merging this pull request may close these issues.

systemd.service: clarify ExitType= documentation for Type=oneshot Clarify the function of ConditionPathExists=

3 participants