chiark / gitweb /
Merge nss-myhostname
[elogind.git] / src / notify / 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(SYSTEMD_FEATURES);
98                         return 0;
99
100                 case ARG_READY:
101                         arg_ready = true;
102                         break;
103
104                 case ARG_PID:
105
106                         if (optarg) {
107                                 if (parse_pid(optarg, &arg_pid) < 0) {
108                                         log_error("Failed to parse PID %s.", optarg);
109                                         return -EINVAL;
110                                 }
111                         } else
112                                 arg_pid = getppid();
113
114                         break;
115
116                 case ARG_STATUS:
117                         arg_status = optarg;
118                         break;
119
120                 case ARG_BOOTED:
121                         arg_booted = true;
122                         break;
123
124                 case ARG_READAHEAD:
125                         arg_readahead = optarg;
126                         break;
127
128                 case '?':
129                         return -EINVAL;
130
131                 default:
132                         log_error("Unknown option code %c", c);
133                         return -EINVAL;
134                 }
135         }
136
137         if (optind >= argc &&
138             !arg_ready &&
139             !arg_status &&
140             !arg_pid &&
141             !arg_booted &&
142             !arg_readahead) {
143                 help();
144                 return -EINVAL;
145         }
146
147         return 1;
148 }
149
150 int main(int argc, char* argv[]) {
151         char* our_env[4], **final_env = NULL;
152         unsigned i = 0;
153         char *status = NULL, *cpid = NULL, *n = NULL;
154         int r, retval = EXIT_FAILURE;
155
156         log_parse_environment();
157         log_open();
158
159         if ((r = parse_argv(argc, argv)) <= 0) {
160                 retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
161                 goto finish;
162         }
163
164         if (arg_booted)
165                 return sd_booted() <= 0;
166
167         if (arg_readahead) {
168                 if ((r = sd_readahead(arg_readahead)) < 0) {
169                         log_error("Failed to issue read-ahead control command: %s", strerror(-r));
170                         goto finish;
171                 }
172         }
173
174         if (arg_ready)
175                 our_env[i++] = (char*) "READY=1";
176
177         if (arg_status) {
178                 if (!(status = strappend("STATUS=", arg_status))) {
179                         log_error("Failed to allocate STATUS string.");
180                         goto finish;
181                 }
182
183                 our_env[i++] = status;
184         }
185
186         if (arg_pid > 0) {
187                 if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) {
188                         log_error("Failed to allocate MAINPID string.");
189                         goto finish;
190                 }
191
192                 our_env[i++] = cpid;
193         }
194
195         our_env[i++] = NULL;
196
197         if (!(final_env = strv_env_merge(2, our_env, argv + optind))) {
198                 log_error("Failed to merge string sets.");
199                 goto finish;
200         }
201
202         if (strv_length(final_env) <= 0) {
203                 retval = EXIT_SUCCESS;
204                 goto finish;
205         }
206
207         if (!(n = strv_join(final_env, "\n"))) {
208                 log_error("Failed to concatenate strings.");
209                 goto finish;
210         }
211
212         if ((r = sd_notify(false, n)) < 0) {
213                 log_error("Failed to notify init system: %s", strerror(-r));
214                 goto finish;
215         }
216
217         retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
218
219 finish:
220         free(status);
221         free(cpid);
222         free(n);
223
224         strv_free(final_env);
225
226         return retval;
227 }