]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/notify.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / notify.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <getopt.h>
24 #include <error.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <systemd/sd-daemon.h>
31
32 #include "strv.h"
33 #include "util.h"
34 #include "log.h"
35 #include "sd-readahead.h"
36 #include "build.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 static const char *arg_readahead = NULL;
43
44 static int help(void) {
45
46 printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
47 "Notify the init system about service status updates.\n\n"
48 " -h --help Show this help\n"
49 " --version Show package version\n"
50 " --ready Inform the init system about service start-up completion\n"
51 " --pid[=PID] Set main pid of daemon\n"
52 " --status=TEXT Set status text\n"
53 " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n"
54 " --readahead=ACTION Controls read-ahead operations\n",
55 program_invocation_short_name);
56
57 return 0;
58 }
59
60 static int parse_argv(int argc, char *argv[]) {
61
62 enum {
63 ARG_READY = 0x100,
64 ARG_VERSION,
65 ARG_PID,
66 ARG_STATUS,
67 ARG_BOOTED,
68 ARG_READAHEAD
69 };
70
71 static const struct option options[] = {
72 { "help", no_argument, NULL, 'h' },
73 { "version", no_argument, NULL, ARG_VERSION },
74 { "ready", no_argument, NULL, ARG_READY },
75 { "pid", optional_argument, NULL, ARG_PID },
76 { "status", required_argument, NULL, ARG_STATUS },
77 { "booted", no_argument, NULL, ARG_BOOTED },
78 { "readahead", required_argument, NULL, ARG_READAHEAD },
79 { NULL, 0, NULL, 0 }
80 };
81
82 int c;
83
84 assert(argc >= 0);
85 assert(argv);
86
87 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
88
89 switch (c) {
90
91 case 'h':
92 help();
93 return 0;
94
95 case ARG_VERSION:
96 puts(PACKAGE_STRING);
97 puts(DISTRIBUTION);
98 puts(SYSTEMD_FEATURES);
99 return 0;
100
101 case ARG_READY:
102 arg_ready = true;
103 break;
104
105 case ARG_PID:
106
107 if (optarg) {
108 if (parse_pid(optarg, &arg_pid) < 0) {
109 log_error("Failed to parse PID %s.", optarg);
110 return -EINVAL;
111 }
112 } else
113 arg_pid = getppid();
114
115 break;
116
117 case ARG_STATUS:
118 arg_status = optarg;
119 break;
120
121 case ARG_BOOTED:
122 arg_booted = true;
123 break;
124
125 case ARG_READAHEAD:
126 arg_readahead = optarg;
127 break;
128
129 case '?':
130 return -EINVAL;
131
132 default:
133 log_error("Unknown option code %c", c);
134 return -EINVAL;
135 }
136 }
137
138 if (optind >= argc &&
139 !arg_ready &&
140 !arg_status &&
141 !arg_pid &&
142 !arg_booted &&
143 !arg_readahead) {
144 help();
145 return -EINVAL;
146 }
147
148 return 1;
149 }
150
151 int main(int argc, char* argv[]) {
152 char* our_env[4], **final_env = NULL;
153 unsigned i = 0;
154 char *status = NULL, *cpid = NULL, *n = NULL;
155 int r, retval = EXIT_FAILURE;
156
157 log_parse_environment();
158 log_open();
159
160 if ((r = parse_argv(argc, argv)) <= 0) {
161 retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
162 goto finish;
163 }
164
165 if (arg_booted)
166 return sd_booted() <= 0;
167
168 if (arg_readahead) {
169 if ((r = sd_readahead(arg_readahead)) < 0) {
170 log_error("Failed to issue read-ahead control command: %s", strerror(-r));
171 goto finish;
172 }
173 }
174
175 if (arg_ready)
176 our_env[i++] = (char*) "READY=1";
177
178 if (arg_status) {
179 if (!(status = strappend("STATUS=", arg_status))) {
180 log_error("Failed to allocate STATUS string.");
181 goto finish;
182 }
183
184 our_env[i++] = status;
185 }
186
187 if (arg_pid > 0) {
188 if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) {
189 log_error("Failed to allocate MAINPID string.");
190 goto finish;
191 }
192
193 our_env[i++] = cpid;
194 }
195
196 our_env[i++] = NULL;
197
198 if (!(final_env = strv_env_merge(2, our_env, argv + optind))) {
199 log_error("Failed to merge string sets.");
200 goto finish;
201 }
202
203 if (strv_length(final_env) <= 0) {
204 retval = EXIT_SUCCESS;
205 goto finish;
206 }
207
208 if (!(n = strv_join(final_env, "\n"))) {
209 log_error("Failed to concatenate strings.");
210 goto finish;
211 }
212
213 if ((r = sd_notify(false, n)) < 0) {
214 log_error("Failed to notify init system: %s", strerror(-r));
215 goto finish;
216 }
217
218 retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
219
220 finish:
221 free(status);
222 free(cpid);
223 free(n);
224
225 strv_free(final_env);
226
227 return retval;
228 }