1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include "alloc-util.h"
13 #include "format-util.h"
15 #include "main-func.h"
16 #include "parse-util.h"
17 #include "pretty-print.h"
18 #include "string-util.h"
20 #include "user-util.h"
23 static bool arg_ready
= false;
24 static pid_t arg_pid
= 0;
25 static const char *arg_status
= NULL
;
26 static bool arg_booted
= false;
27 static uid_t arg_uid
= UID_INVALID
;
28 static gid_t arg_gid
= GID_INVALID
;
30 static int help(void) {
31 _cleanup_free_
char *link
= NULL
;
34 r
= terminal_urlify_man("systemd-notify", "1", &link
);
38 printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
39 "Notify the init system about service status updates.\n\n"
40 " -h --help Show this help\n"
41 " --version Show package version\n"
42 " --ready Inform the init system about service start-up completion\n"
43 " --pid[=PID] Set main PID of daemon\n"
44 " --uid=USER Set user to send from\n"
45 " --status=TEXT Set status text\n"
46 " --booted Check if the system was booted up with systemd\n"
47 "\nSee the %s for details.\n"
48 , program_invocation_short_name
55 static int parse_argv(int argc
, char *argv
[]) {
66 static const struct option options
[] = {
67 { "help", no_argument
, NULL
, 'h' },
68 { "version", no_argument
, NULL
, ARG_VERSION
},
69 { "ready", no_argument
, NULL
, ARG_READY
},
70 { "pid", optional_argument
, NULL
, ARG_PID
},
71 { "status", required_argument
, NULL
, ARG_STATUS
},
72 { "booted", no_argument
, NULL
, ARG_BOOTED
},
73 { "uid", required_argument
, NULL
, ARG_UID
},
82 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
99 if (parse_pid(optarg
, &arg_pid
) < 0)
100 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
101 "Failed to parse PID %s.", optarg
);
116 const char *u
= optarg
;
118 r
= get_user_creds(&u
, &arg_uid
, &arg_gid
, NULL
, NULL
, 0);
119 if (r
== -ESRCH
) /* If the user doesn't exist, then accept it anyway as numeric */
120 r
= parse_uid(u
, &arg_uid
);
122 return log_error_errno(r
, "Can't resolve user %s: %m", optarg
);
131 assert_not_reached("Unhandled option");
135 if (optind
>= argc
&&
147 static int run(int argc
, char* argv
[]) {
148 _cleanup_free_
char *status
= NULL
, *cpid
= NULL
, *n
= NULL
;
149 _cleanup_strv_free_
char **final_env
= NULL
;
154 log_parse_environment();
157 r
= parse_argv(argc
, argv
);
162 return sd_booted() <= 0;
165 our_env
[i
++] = (char*) "READY=1";
168 status
= strappend("STATUS=", arg_status
);
172 our_env
[i
++] = status
;
176 if (asprintf(&cpid
, "MAINPID="PID_FMT
, arg_pid
) < 0)
184 final_env
= strv_env_merge(2, our_env
, argv
+ optind
);
188 if (strv_isempty(final_env
))
191 n
= strv_join(final_env
, "\n");
195 /* If this is requested change to the requested UID/GID. Note thta we only change the real UID here, and leave
196 the effective UID in effect (which is 0 for this to work). That's because we want the privileges to fake the
197 ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */
199 if (arg_gid
!= GID_INVALID
&&
200 setregid(arg_gid
, (gid_t
) -1) < 0)
201 return log_error_errno(errno
, "Failed to change GID: %m");
203 if (arg_uid
!= UID_INVALID
&&
204 setreuid(arg_uid
, (uid_t
) -1) < 0)
205 return log_error_errno(errno
, "Failed to change UID: %m");
207 r
= sd_pid_notify(arg_pid
? arg_pid
: getppid(), false, n
);
209 return log_error_errno(r
, "Failed to notify init system: %m");
211 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
212 "No status data could be sent: $NOTIFY_SOCKET was not set");
216 DEFINE_MAIN_FUNCTION(run
);