SYSTEMD-NOTIFY(1)

๐ŸŒธ SYSTEMD-NOTIFY(1) ๐ŸŒธ

okay bestie, welcome to systemd-notify, section 1 of the manuals. pull up a chair, grab a boba, this one's lowkey a banger ๐Ÿ’…


โœจ NAME โœจ

systemd-notify โ€” notify the service manager that your service finished starting up, plus whatever other daemon status glow-ups you wanna announce ๐Ÿฆ‹


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

systemd-notify [OPTIONS...] [VARIABLE=VALUE...]

systemd-notify --exec [OPTIONS...] [VARIABLE=VALUE...] ; -- {CMDLINE...}

systemd-notify --fork [OPTIONS...] -- {CMDLINE...}

๐Ÿ’– DESCRIPTION ๐Ÿ’–

so, systemd-notify is the little messenger your service scripts call when they wanna tell the service manager that things changed. it can send literally any information you want, encoded as a list of strings that's shaped just like an environment block. but the main character use case? telling everyone the service finished starting up. that's the moment. that's the vibe. ๐Ÿ‘‘

fr fr, this thing is mostly just a wrapper around sd_notify() so that shell scripts can get in on the fun. want the full tea? go read sd_notify(3).

your command line can carry a whole list of environment variables, and those get sent along as part of the status update. slay.

โš ๏ธ heads up bestie: systemd will straight-up refuse your status updates unless NotifyAccess= is set appropriately for the service unit you're calling this from. no cap. check systemd.service(5) for the details.

okay this next part is important so listen up ๐Ÿซถ. sd_notify() notifications only get attributed to units correctly if either:

  • the sending process is still around at the time the service manager processes the message, or
  • the sending process is explicitly runtime-tracked by the service manager.

that second one happens when the service manager originally forked off the process โ€” i.e. it applies to all processes that match NotifyAccess=main or NotifyAccess=exec. but flip it around: if some auxiliary process of the unit sends an sd_notify() message and then immediately dips out, the service manager might not be able to attribute that message to the unit properly, and so it'll just ignore it โ€” even if NotifyAccess=all is set for it. ๐Ÿ’€

to fix that whole situation, systemd-notify will wait until the notification message has actually been processed by the service manager. but when --no-block is used, that synchronization for reception of notifications gets disabled, which means the race condition above may absolutely happen if the invoking process is not the service manager or wasn't spawned by the service manager. yikes.

here's the other cute trick: systemd-notify will first attempt to invoke sd_notify() while pretending to have the PID of the parent process of systemd-notify โ€” that's the invoking process, hi. this only succeeds when you invoke it with sufficient privileges. if it fails, it falls back to invoking under its own PID. why does this matter? because when the tool gets invoked from a shell script, the shell process โ€” not the systemd-notify process โ€” shows up as the sender of the message. and that's super helpful if the shell process is the main process of a service, because of the limitations of NotifyAccess=all. wanna tweak this behaviour? use the --pid= switch. โœจ


๐Ÿ’… OPTIONS ๐Ÿ’…

here's everything you can pass, bestie. the following options are understood:

  • --ready โ€” tell the invoking service manager that service start-up (or a configuration reload) is complete. this is equivalent to systemd-notify READY=1. for the full semantics of this option, see sd_notify(3). โœ…
  • --reloading โ€” tell the invoking service manager that a configuration reload cycle is beginning. equivalent to systemd-notify RELOADING=1 โ€” but bestie, it implicitly also sets a MONOTONIC_USEC= field, as required for Type=notify-reload services. see systemd.service(5) for that. semantics deets in sd_notify(3).

Added in version 253.

  • --stopping โ€” tell the invoking service manager that the service is entering its shutdown phase. equivalent to systemd-notify STOPPING=1. semantics deets in sd_notify(3).

Added in version 253.

  • --pid= โ€” inform the service manager about the main PID of the service. takes a PID as its argument. if the argument is specified as "auto" or just omitted entirely, the PID of the process that invoked systemd-notify is used โ€” except if that's the service manager. if the argument is "self", the PID of the systemd-notify command itself is used. and if "parent" is specified, the calling process' PID is used โ€” even if it is the service manager. --pid=auto is equivalent to systemd-notify --pid=$PID. semantics deets in sd_notify(3).

systemd-notify will first attempt to invoke sd_notify() pretending to have the PID you specified with --pid=. this only succeeds when invoked with sufficient privileges. on failure, it falls back to invoking it under its own PID. effectively, this means a privileged invocation of systemd-notify --pid= may circumvent NotifyAccess=main or NotifyAccess=exec restrictions that are enforced for a service. ๐Ÿ‘€

if this switch is used in an unprivileged systemd-notify invocation, from a process that's supposed to become the new main process of a service โ€” and which is not the process forked off by the service manager (or the current main process) โ€” then it is essential to set NotifyAccess=all in the service unit file. otherwise the notification will be ignored, for security reasons. see systemd.service(5).
  • *--uid=USER* โ€” set the user ID to send the notification from. takes a UNIX user name or a numeric UID. when specified, the notification message gets sent with the specified UID as the sender, instead of the user the command was invoked as. this option requires sufficient privileges to be able to manipulate the user identity of the process.

Added in version 237.

  • --status= โ€” send a free-form, human-readable status string for the daemon to the service manager. this option takes the status string as its argument. equivalent to systemd-notify STATUS=.... semantics deets in sd_notify(3). this info shows up in systemctl(1)'s status output, among other places. ๐ŸŽ€
  • --booted โ€” returns 0 if the system was booted up with systemd, and non-zero otherwise. if this option is passed, no message is sent. so yeah, this option is unrelated to all the other options. for semantics deets, see sd_booted(3). another way to check this state is to call systemctl(1) with the is-system-running command. it'll output "offline" if the system wasn't booted with systemd โ€” though ngl, the return value has a different meaning there.
  • --no-block โ€” do not synchronously wait for the requested operation to finish. this one's only recommended when systemd-notify is spawned by the service manager, or when the invoking process is directly spawned by the service manager and has enough privileges to let systemd-notify send the notification on its behalf. sending notifications with this option set is prone to race conditions in all other cases. ๐Ÿ’€

Added in version 246.

  • --exec โ€” if specified, systemd-notify will execute another command line after it completed its operation, replacing its own process. if you use this, the list of assignments to include in the message sent must be followed by a ";" character (as a separate argument), followed by the command line to execute. this permits "chaining" of commands โ€” i.e. issuing one operation and then immediately another, without changing PIDs. iconic.
note that many shells interpret ";" as their own separator for command lines, so when systemd-notify is invoked from a shell, the semicolon usually has to be escaped as "\;". ๐Ÿ™ˆ

Added in version 254.

  • --fd= โ€” send a file descriptor along with the notification message. super useful when invoked in services that have the FileDescriptorStoreMax= setting enabled โ€” see systemd.service(5). the specified file descriptor must be passed to systemd-notify when invoked. this option may be used multiple times to pass multiple file descriptors in a single notification message.

to use this from a bash(1) shell, use an expression like this:

systemd-notify --fd=4 --fd=5 4</some/file 5</some/other/file

Added in version 254.

  • --fdname= โ€” set a name to assign to the file descriptors passed via --fd= (see above). this controls the "FDNAME=" field. this setting may only be specified once, and it applies to all file descriptors passed. if you want multiple file descriptors with different file descriptor names, invoke this tool multiple times. ๐Ÿฆ‹

Added in version 254.

  • --fork โ€” instead of sending a notification message, fork off a command line and wait until a "READY=1" message is received from it. in other words: this makes systemd-notify the receiver of notification messages instead of the sender, swapping roles. main character energy fr. this is useful to quickly fork off a process that implements the sd_notify() protocol from a shell script. the invoked command line will have standard input and standard output connected to /dev/null, but standard error will be inherited from the invoking process. the numeric process ID is written to standard output by systemd-notify (unless --quiet is specified), which you may use to later terminate the forked off process.
note that processes forked off like this will likely remain running after systemd-notify already returned, which means they'll end up reparented to the closest process reaper โ€” typically the per-user or system service manager.
also note: this option should not be used to invoke full services ad-hoc. use systemd-run for that, bestie.

also note that when invoked with this switch, systemd-notify will exit successfully under two distinct conditions:

  1. systemd-notify received a "READY=1" notification from the child it just forked off.
  2. the child process exited cleanly (with exit status zero) before sending "READY=1".

example use:

# PID=$(systemd-notify --fork -- mycommand)
...
kill "$PID"
unset PID

Added in version 258.

  • --quiet, -q โ€” turn off the output of the numeric process ID when --fork is used. ๐Ÿคซ

Added in version 258.

  • -h, --help โ€” print a short help text and exit.
  • --version โ€” print a short version string and exit.

๐ŸŒˆ EXIT STATUS ๐ŸŒˆ

on success, 0 is returned. otherwise, a non-zero failure code. that's it, that's the whole vibe check. โญ


๐ŸŒˆ EXAMPLE ๐ŸŒˆ

โœจ Example 1. Start-up Notification and Status Updates โœจ

Okay bestie, picture this: a lil shell daemon that does its setup, then announces itself to the init system once its communication channel is all ready. Then, the whole time it's running, it keeps dropping status updates like it's posting to its story. ๐Ÿ’…

#!/bin/sh

mkfifo /tmp/waldo
systemd-notify --ready --status="Waiting for data..."

while : ; do
        read -r a < /tmp/waldo
        systemd-notify --status="Processing $a"

        # Do something with $a ...

        systemd-notify --status="Waiting for data..."
done

No cap, that's the whole vibe: mkfifo sets up the channel, --ready says "we're up, bestie," --status keeps everyone in the loop, and the while : ; do loop just keeps on keeping on forever. ๐Ÿ”โœจ


๐Ÿ’– SEE ALSO ๐Ÿ’–

The squad, the group chat, the whole friend group you should go hang out with next:


And that's a wrap on SYSTEMD-NOTIFY(1), bestie!! ๐ŸŽ€๐Ÿฆ‹ This lil masterpiece is from systemd 262.1, and yeah it's dated โ€” manuals age like fine wine, not like milk, so you're good. Go forth and notify. ๐Ÿ‘‘๐Ÿ’–

๐Ÿ“ฆ where this page comes from
  • arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms