]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/notify/notify.c
Merge pull request #7695 from yuwata/transient-socket
[thirdparty/systemd.git] / src / notify / notify.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <getopt.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 #include "sd-daemon.h"
28
29 #include "alloc-util.h"
30 #include "env-util.h"
31 #include "format-util.h"
32 #include "log.h"
33 #include "parse-util.h"
34 #include "string-util.h"
35 #include "strv.h"
36 #include "util.h"
37
38 static bool arg_ready = false;
39 static pid_t arg_pid = 0;
40 static const char *arg_status = NULL;
41 static bool arg_booted = false;
42
43 static void help(void) {
44 printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
45 "Notify the init system about service status updates.\n\n"
46 " -h --help Show this help\n"
47 " --version Show package version\n"
48 " --ready Inform the init system about service start-up completion\n"
49 " --pid[=PID] Set main pid of daemon\n"
50 " --status=TEXT Set status text\n"
51 " --booted Check if the system was booted up with systemd\n",
52 program_invocation_short_name);
53 }
54
55 static int parse_argv(int argc, char *argv[]) {
56
57 enum {
58 ARG_READY = 0x100,
59 ARG_VERSION,
60 ARG_PID,
61 ARG_STATUS,
62 ARG_BOOTED,
63 };
64
65 static const struct option options[] = {
66 { "help", no_argument, NULL, 'h' },
67 { "version", no_argument, NULL, ARG_VERSION },
68 { "ready", no_argument, NULL, ARG_READY },
69 { "pid", optional_argument, NULL, ARG_PID },
70 { "status", required_argument, NULL, ARG_STATUS },
71 { "booted", no_argument, NULL, ARG_BOOTED },
72 {}
73 };
74
75 int c;
76
77 assert(argc >= 0);
78 assert(argv);
79
80 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
81
82 switch (c) {
83
84 case 'h':
85 help();
86 return 0;
87
88 case ARG_VERSION:
89 return version();
90
91 case ARG_READY:
92 arg_ready = true;
93 break;
94
95 case ARG_PID:
96
97 if (optarg) {
98 if (parse_pid(optarg, &arg_pid) < 0) {
99 log_error("Failed to parse PID %s.", optarg);
100 return -EINVAL;
101 }
102 } else
103 arg_pid = getppid();
104
105 break;
106
107 case ARG_STATUS:
108 arg_status = optarg;
109 break;
110
111 case ARG_BOOTED:
112 arg_booted = true;
113 break;
114
115 case '?':
116 return -EINVAL;
117
118 default:
119 assert_not_reached("Unhandled option");
120 }
121 }
122
123 if (optind >= argc &&
124 !arg_ready &&
125 !arg_status &&
126 !arg_pid &&
127 !arg_booted) {
128 help();
129 return -EINVAL;
130 }
131
132 return 1;
133 }
134
135 int main(int argc, char* argv[]) {
136 _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
137 _cleanup_strv_free_ char **final_env = NULL;
138 char* our_env[4];
139 unsigned i = 0;
140 int r;
141
142 log_parse_environment();
143 log_open();
144
145 r = parse_argv(argc, argv);
146 if (r <= 0)
147 goto finish;
148
149 if (arg_booted)
150 return sd_booted() <= 0;
151
152 if (arg_ready)
153 our_env[i++] = (char*) "READY=1";
154
155 if (arg_status) {
156 status = strappend("STATUS=", arg_status);
157 if (!status) {
158 r = log_oom();
159 goto finish;
160 }
161
162 our_env[i++] = status;
163 }
164
165 if (arg_pid > 0) {
166 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) {
167 r = log_oom();
168 goto finish;
169 }
170
171 our_env[i++] = cpid;
172 }
173
174 our_env[i++] = NULL;
175
176 final_env = strv_env_merge(2, our_env, argv + optind);
177 if (!final_env) {
178 r = log_oom();
179 goto finish;
180 }
181
182 if (strv_isempty(final_env)) {
183 r = 0;
184 goto finish;
185 }
186
187 n = strv_join(final_env, "\n");
188 if (!n) {
189 r = log_oom();
190 goto finish;
191 }
192
193 r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
194 if (r < 0) {
195 log_error_errno(r, "Failed to notify init system: %m");
196 goto finish;
197 } else if (r == 0) {
198 log_error("No status data could be sent: $NOTIFY_SOCKET was not set");
199 r = -EOPNOTSUPP;
200 }
201
202 finish:
203 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
204 }