chiark / gitweb /
machine-id: initialize from $container_uuid if not set otherwise
[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
37 static bool arg_ready = false;
38 static pid_t arg_pid = 0;
39 static const char *arg_status = NULL;
40 static bool arg_booted = false;
41 static const char *arg_readahead = NULL;
42
43 static int help(void) {
44
45         printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
46                "Notify the init system about service status updates.\n\n"
47                "  -h --help             Show this help\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           Returns 0 if the system was booted up with systemd, non-zero otherwise\n"
52                "     --readahead=ACTION Controls read-ahead operations\n",
53                program_invocation_short_name);
54
55         return 0;
56 }
57
58 static int parse_argv(int argc, char *argv[]) {
59
60         enum {
61                 ARG_READY = 0x100,
62                 ARG_PID,
63                 ARG_STATUS,
64                 ARG_BOOTED,
65                 ARG_READAHEAD
66         };
67
68         static const struct option options[] = {
69                 { "help",      no_argument,       NULL, 'h'           },
70                 { "ready",     no_argument,       NULL, ARG_READY     },
71                 { "pid",       optional_argument, NULL, ARG_PID       },
72                 { "status",    required_argument, NULL, ARG_STATUS    },
73                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
74                 { "readahead", required_argument, NULL, ARG_READAHEAD },
75                 { NULL,        0,                 NULL, 0             }
76         };
77
78         int c;
79
80         assert(argc >= 0);
81         assert(argv);
82
83         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
84
85                 switch (c) {
86
87                 case 'h':
88                         help();
89                         return 0;
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 ARG_READAHEAD:
116                         arg_readahead = optarg;
117                         break;
118
119                 case '?':
120                         return -EINVAL;
121
122                 default:
123                         log_error("Unknown option code %c", c);
124                         return -EINVAL;
125                 }
126         }
127
128         if (optind >= argc &&
129             !arg_ready &&
130             !arg_status &&
131             !arg_pid &&
132             !arg_booted &&
133             !arg_readahead) {
134                 help();
135                 return -EINVAL;
136         }
137
138         return 1;
139 }
140
141 int main(int argc, char* argv[]) {
142         char* our_env[4], **final_env = NULL;
143         unsigned i = 0;
144         char *status = NULL, *cpid = NULL, *n = NULL;
145         int r, retval = EXIT_FAILURE;
146
147         log_parse_environment();
148         log_open();
149
150         if ((r = parse_argv(argc, argv)) <= 0) {
151                 retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
152                 goto finish;
153         }
154
155         if (arg_booted)
156                 return sd_booted() <= 0;
157
158         if (arg_readahead) {
159                 if ((r = sd_readahead(arg_readahead)) < 0) {
160                         log_error("Failed to issue read-ahead control command: %s", strerror(-r));
161                         goto finish;
162                 }
163         }
164
165         if (arg_ready)
166                 our_env[i++] = (char*) "READY=1";
167
168         if (arg_status) {
169                 if (!(status = strappend("STATUS=", arg_status))) {
170                         log_error("Failed to allocate STATUS string.");
171                         goto finish;
172                 }
173
174                 our_env[i++] = status;
175         }
176
177         if (arg_pid > 0) {
178                 if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) {
179                         log_error("Failed to allocate MAINPID string.");
180                         goto finish;
181                 }
182
183                 our_env[i++] = cpid;
184         }
185
186         our_env[i++] = NULL;
187
188         if (!(final_env = strv_env_merge(2, our_env, argv + optind))) {
189                 log_error("Failed to merge string sets.");
190                 goto finish;
191         }
192
193         if (strv_length(final_env) <= 0) {
194                 retval = EXIT_SUCCESS;
195                 goto finish;
196         }
197
198         if (!(n = strv_join(final_env, "\n"))) {
199                 log_error("Failed to concatenate strings.");
200                 goto finish;
201         }
202
203         if ((r = sd_notify(false, n)) < 0) {
204                 log_error("Failed to notify init system: %s", strerror(-r));
205                 goto finish;
206         }
207
208         retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
209
210 finish:
211         free(status);
212         free(cpid);
213         free(n);
214
215         strv_free(final_env);
216
217         return retval;
218 }