Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

notify: beef up --pid= logic #15642

Merged
merged 1 commit into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions man/systemd-notify.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@
<varlistentry>
<term><option>--pid=</option></term>

<listitem><para>Inform the init system about the main PID of
the daemon. Takes a PID as argument. If the argument is
omitted, the PID of the process that invoked
<command>systemd-notify</command> is used. This is equivalent
to <command>systemd-notify MAINPID=$PID</command>. For details
about the semantics of this option see
<listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
used — even if it is the service manager. This is equivalent to <command>systemd-notify
MAINPID=$PID</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>

Expand Down
55 changes: 49 additions & 6 deletions src/notify/notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ static int help(void) {
return 0;
}

static pid_t manager_pid(void) {
const char *e;
pid_t pid;
int r;

/* If we run as a service managed by systemd --user the $MANAGERPID environment variable points to
* the service manager's PID. */
e = getenv("MANAGERPID");
if (!e)
return 0;

r = parse_pid(e, &pid);
if (r < 0) {
log_warning_errno(r, "$MANAGERPID is set to an invalid PID, ignoring: %s", e);
return 0;
}

return pid;
}

static int parse_argv(int argc, char *argv[]) {

enum {
Expand Down Expand Up @@ -96,13 +116,24 @@ static int parse_argv(int argc, char *argv[]) {
break;

case ARG_PID:
if (isempty(optarg) || streq(optarg, "auto")) {
arg_pid = getppid();

if (optarg) {
if (parse_pid(optarg, &arg_pid) < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse PID %s.", optarg);
} else
if (arg_pid <= 1 ||
arg_pid == manager_pid()) /* Don't send from PID 1 or the service
* manager's PID (which might be distinct from
* 1, if we are a --user instance), that'd just
* be confusing for the service manager */
arg_pid = getpid();
} else if (streq(optarg, "parent"))
arg_pid = getppid();
else if (streq(optarg, "self"))
arg_pid = getpid();
else {
r = parse_pid(optarg, &arg_pid);
if (r < 0)
return log_error_errno(r, "Failed to parse PID %s.", optarg);
}

break;

Expand Down Expand Up @@ -151,6 +182,7 @@ static int run(int argc, char* argv[]) {
_cleanup_strv_free_ char **final_env = NULL;
char* our_env[4];
unsigned i = 0;
pid_t source_pid;
int r;

log_show_color(true);
Expand Down Expand Up @@ -207,7 +239,18 @@ static int run(int argc, char* argv[]) {
setreuid(arg_uid, (uid_t) -1) < 0)
return log_error_errno(errno, "Failed to change UID: %m");

r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
if (arg_pid > 0)
source_pid = arg_pid;
else {
/* Pretend the message originates from our parent, given that we are typically called from a
* shell script, i.e. we are not the main process of a service but only a child of it. */
source_pid = getppid();
if (source_pid <= 1 ||
source_pid == manager_pid()) /* safety check: don't claim we'd send anything from PID 1
* or the service manager itself */
source_pid = 0;
}
r = sd_pid_notify(source_pid, false, n);
if (r < 0)
return log_error_errno(r, "Failed to notify init system: %m");
if (r == 0)
Expand Down