1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
14 #include "sd-daemon.h"
16 #include "alloc-util.h"
18 #include "format-util.h"
20 #include "parse-util.h"
21 #include "string-util.h"
23 #include "user-util.h"
26 static bool arg_ready
= false;
27 static pid_t arg_pid
= 0;
28 static const char *arg_status
= NULL
;
29 static bool arg_booted
= false;
30 static uid_t arg_uid
= UID_INVALID
;
31 static gid_t arg_gid
= GID_INVALID
;
33 static void help(void) {
34 printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
35 "Notify the init system about service status updates.\n\n"
36 " -h --help Show this help\n"
37 " --version Show package version\n"
38 " --ready Inform the init system about service start-up completion\n"
39 " --pid[=PID] Set main PID of daemon\n"
40 " --uid=USER Set user to send from\n"
41 " --status=TEXT Set status text\n"
42 " --booted Check if the system was booted up with systemd\n",
43 program_invocation_short_name
);
46 static int parse_argv(int argc
, char *argv
[]) {
57 static const struct option options
[] = {
58 { "help", no_argument
, NULL
, 'h' },
59 { "version", no_argument
, NULL
, ARG_VERSION
},
60 { "ready", no_argument
, NULL
, ARG_READY
},
61 { "pid", optional_argument
, NULL
, ARG_PID
},
62 { "status", required_argument
, NULL
, ARG_STATUS
},
63 { "booted", no_argument
, NULL
, ARG_BOOTED
},
64 { "uid", required_argument
, NULL
, ARG_UID
},
73 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
91 if (parse_pid(optarg
, &arg_pid
) < 0) {
92 log_error("Failed to parse PID %s.", optarg
);
109 const char *u
= optarg
;
111 r
= get_user_creds(&u
, &arg_uid
, &arg_gid
, NULL
, NULL
);
112 if (r
== -ESRCH
) /* If the user doesn't exist, then accept it anyway as numeric */
113 r
= parse_uid(u
, &arg_uid
);
115 return log_error_errno(r
, "Can't resolve user %s: %m", optarg
);
124 assert_not_reached("Unhandled option");
128 if (optind
>= argc
&&
140 int main(int argc
, char* argv
[]) {
141 _cleanup_free_
char *status
= NULL
, *cpid
= NULL
, *n
= NULL
;
142 _cleanup_strv_free_
char **final_env
= NULL
;
147 log_parse_environment();
150 r
= parse_argv(argc
, argv
);
155 return sd_booted() <= 0;
158 our_env
[i
++] = (char*) "READY=1";
161 status
= strappend("STATUS=", arg_status
);
167 our_env
[i
++] = status
;
171 if (asprintf(&cpid
, "MAINPID="PID_FMT
, arg_pid
) < 0) {
181 final_env
= strv_env_merge(2, our_env
, argv
+ optind
);
187 if (strv_isempty(final_env
)) {
192 n
= strv_join(final_env
, "\n");
198 /* If this is requested change to the requested UID/GID. Note thta we only change the real UID here, and leave
199 the effective UID in effect (which is 0 for this to work). That's because we want the privileges to fake the
200 ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */
202 if (arg_gid
!= GID_INVALID
)
203 if (setregid(arg_gid
, (gid_t
) -1) < 0) {
204 r
= log_error_errno(errno
, "Failed to change GID: %m");
208 if (arg_uid
!= UID_INVALID
)
209 if (setreuid(arg_uid
, (uid_t
) -1) < 0) {
210 r
= log_error_errno(errno
, "Failed to change UID: %m");
214 r
= sd_pid_notify(arg_pid
? arg_pid
: getppid(), false, n
);
216 log_error_errno(r
, "Failed to notify init system: %m");
219 log_error("No status data could be sent: $NOTIFY_SOCKET was not set");
224 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;