]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/notify/notify.c
tree-wide: remove Lennart's copyright lines
[thirdparty/systemd.git] / src / notify / notify.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4a2a8b5a 2
4a2a8b5a 3#include <errno.h>
6f2deb84
LP
4#include <getopt.h>
5#include <stdio.h>
4a2a8b5a 6#include <stdlib.h>
6f2deb84 7#include <unistd.h>
4a2a8b5a 8
6f2deb84 9#include "sd-daemon.h"
81527be1 10
b5efdb8a 11#include "alloc-util.h"
4d1a6904 12#include "env-util.h"
f97b34a6 13#include "format-util.h"
6f2deb84 14#include "log.h"
6bedfcbb 15#include "parse-util.h"
07630cea 16#include "string-util.h"
6f2deb84 17#include "strv.h"
65c6b990 18#include "user-util.h"
6f2deb84 19#include "util.h"
4a2a8b5a
LP
20
21static bool arg_ready = false;
22static pid_t arg_pid = 0;
23static const char *arg_status = NULL;
96551bae 24static bool arg_booted = false;
65c6b990
LP
25static uid_t arg_uid = UID_INVALID;
26static gid_t arg_gid = GID_INVALID;
4a2a8b5a 27
601185b4 28static void help(void) {
2e33c433 29 printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
4a2a8b5a 30 "Notify the init system about service status updates.\n\n"
b57b0625
ZJS
31 " -h --help Show this help\n"
32 " --version Show package version\n"
33 " --ready Inform the init system about service start-up completion\n"
65c6b990
LP
34 " --pid[=PID] Set main PID of daemon\n"
35 " --uid=USER Set user to send from\n"
b57b0625
ZJS
36 " --status=TEXT Set status text\n"
37 " --booted Check if the system was booted up with systemd\n",
4a2a8b5a 38 program_invocation_short_name);
4a2a8b5a
LP
39}
40
41static int parse_argv(int argc, char *argv[]) {
42
43 enum {
44 ARG_READY = 0x100,
9aac0b2c 45 ARG_VERSION,
4a2a8b5a 46 ARG_PID,
96551bae 47 ARG_STATUS,
6624768c 48 ARG_BOOTED,
65c6b990 49 ARG_UID,
4a2a8b5a
LP
50 };
51
52 static const struct option options[] = {
6624768c 53 { "help", no_argument, NULL, 'h' },
9aac0b2c 54 { "version", no_argument, NULL, ARG_VERSION },
6624768c
LP
55 { "ready", no_argument, NULL, ARG_READY },
56 { "pid", optional_argument, NULL, ARG_PID },
57 { "status", required_argument, NULL, ARG_STATUS },
58 { "booted", no_argument, NULL, ARG_BOOTED },
65c6b990 59 { "uid", required_argument, NULL, ARG_UID },
eb9da376 60 {}
4a2a8b5a
LP
61 };
62
65c6b990 63 int c, r;
4a2a8b5a
LP
64
65 assert(argc >= 0);
66 assert(argv);
67
ee8c4568 68 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
4a2a8b5a
LP
69
70 switch (c) {
71
72 case 'h':
601185b4
ZJS
73 help();
74 return 0;
4a2a8b5a 75
9aac0b2c 76 case ARG_VERSION:
3f6fd1ba 77 return version();
9aac0b2c 78
4a2a8b5a
LP
79 case ARG_READY:
80 arg_ready = true;
81 break;
82
83 case ARG_PID:
84
85 if (optarg) {
86 if (parse_pid(optarg, &arg_pid) < 0) {
87 log_error("Failed to parse PID %s.", optarg);
88 return -EINVAL;
89 }
90 } else
91 arg_pid = getppid();
92
93 break;
94
95 case ARG_STATUS:
96 arg_status = optarg;
97 break;
98
96551bae
LP
99 case ARG_BOOTED:
100 arg_booted = true;
101 break;
102
65c6b990
LP
103 case ARG_UID: {
104 const char *u = optarg;
105
106 r = get_user_creds(&u, &arg_uid, &arg_gid, NULL, NULL);
107 if (r == -ESRCH) /* If the user doesn't exist, then accept it anyway as numeric */
108 r = parse_uid(u, &arg_uid);
109 if (r < 0)
110 return log_error_errno(r, "Can't resolve user %s: %m", optarg);
111
112 break;
113 }
114
4a2a8b5a
LP
115 case '?':
116 return -EINVAL;
117
118 default:
eb9da376 119 assert_not_reached("Unhandled option");
4a2a8b5a 120 }
ee8c4568 121 }
4a2a8b5a 122
2f02ce40
LP
123 if (optind >= argc &&
124 !arg_ready &&
125 !arg_status &&
126 !arg_pid &&
d6bc8348 127 !arg_booted) {
2f02ce40
LP
128 help();
129 return -EINVAL;
130 }
131
4a2a8b5a
LP
132 return 1;
133}
134
135int main(int argc, char* argv[]) {
be8f4e9e
LP
136 _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
137 _cleanup_strv_free_ char **final_env = NULL;
138 char* our_env[4];
4a2a8b5a 139 unsigned i = 0;
be8f4e9e 140 int r;
4a2a8b5a
LP
141
142 log_parse_environment();
2396fb04 143 log_open();
4a2a8b5a 144
6c12b52e 145 r = parse_argv(argc, argv);
be8f4e9e 146 if (r <= 0)
4a2a8b5a 147 goto finish;
4a2a8b5a 148
96551bae
LP
149 if (arg_booted)
150 return sd_booted() <= 0;
151
4a2a8b5a
LP
152 if (arg_ready)
153 our_env[i++] = (char*) "READY=1";
154
155 if (arg_status) {
be8f4e9e
LP
156 status = strappend("STATUS=", arg_status);
157 if (!status) {
158 r = log_oom();
4a2a8b5a
LP
159 goto finish;
160 }
161
162 our_env[i++] = status;
163 }
164
165 if (arg_pid > 0) {
de0671ee 166 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) {
be8f4e9e 167 r = log_oom();
4a2a8b5a
LP
168 goto finish;
169 }
170
171 our_env[i++] = cpid;
172 }
173
174 our_env[i++] = NULL;
175
be8f4e9e
LP
176 final_env = strv_env_merge(2, our_env, argv + optind);
177 if (!final_env) {
178 r = log_oom();
4a2a8b5a
LP
179 goto finish;
180 }
181
58629001 182 if (strv_isempty(final_env)) {
be8f4e9e 183 r = 0;
4a2a8b5a
LP
184 goto finish;
185 }
186
be8f4e9e
LP
187 n = strv_join(final_env, "\n");
188 if (!n) {
189 r = log_oom();
4a2a8b5a
LP
190 goto finish;
191 }
192
65c6b990
LP
193 /* If this is requested change to the requested UID/GID. Note thta we only change the real UID here, and leave
194 the effective UID in effect (which is 0 for this to work). That's because we want the privileges to fake the
195 ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */
196
197 if (arg_gid != GID_INVALID)
198 if (setregid(arg_gid, (gid_t) -1) < 0) {
199 r = log_error_errno(errno, "Failed to change GID: %m");
200 goto finish;
201 }
202
203 if (arg_uid != UID_INVALID)
204 if (setreuid(arg_uid, (uid_t) -1) < 0) {
205 r = log_error_errno(errno, "Failed to change UID: %m");
206 goto finish;
207 }
208
9de009a9 209 r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
be8f4e9e 210 if (r < 0) {
da927ba9 211 log_error_errno(r, "Failed to notify init system: %m");
4a2a8b5a 212 goto finish;
39b50ad1
EV
213 } else if (r == 0) {
214 log_error("No status data could be sent: $NOTIFY_SOCKET was not set");
15411c0c 215 r = -EOPNOTSUPP;
39b50ad1 216 }
4a2a8b5a
LP
217
218finish:
be8f4e9e 219 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
4a2a8b5a 220}