chiark / gitweb /
man: document systemd-journalctl(1)
[elogind.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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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 }