chiark / gitweb /
install: improve paths we show the user when enabling/disabling
[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 #include "env-util.h"
38
39 static bool arg_ready = false;
40 static pid_t arg_pid = 0;
41 static const char *arg_status = NULL;
42 static bool arg_booted = false;
43 static const char *arg_readahead = NULL;
44
45 static int help(void) {
46
47         printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
48                "Notify the init system about service status updates.\n\n"
49                "  -h --help             Show this help\n"
50                "     --version          Show package version\n"
51                "     --ready            Inform the init system about service start-up completion\n"
52                "     --pid[=PID]        Set main pid of daemon\n"
53                "     --status=TEXT      Set status text\n"
54                "     --booted           Returns 0 if the system was booted up with systemd, non-zero otherwise\n"
55                "     --readahead=ACTION Controls read-ahead operations\n",
56                program_invocation_short_name);
57
58         return 0;
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63         enum {
64                 ARG_READY = 0x100,
65                 ARG_VERSION,
66                 ARG_PID,
67                 ARG_STATUS,
68                 ARG_BOOTED,
69                 ARG_READAHEAD
70         };
71
72         static const struct option options[] = {
73                 { "help",      no_argument,       NULL, 'h'           },
74                 { "version",   no_argument,       NULL, ARG_VERSION   },
75                 { "ready",     no_argument,       NULL, ARG_READY     },
76                 { "pid",       optional_argument, NULL, ARG_PID       },
77                 { "status",    required_argument, NULL, ARG_STATUS    },
78                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
79                 { "readahead", required_argument, NULL, ARG_READAHEAD },
80                 {}
81         };
82
83         int c;
84
85         assert(argc >= 0);
86         assert(argv);
87
88         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
89
90                 switch (c) {
91
92                 case 'h':
93                         return help();
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                         assert_not_reached("Unhandled option");
133                 }
134         }
135
136         if (optind >= argc &&
137             !arg_ready &&
138             !arg_status &&
139             !arg_pid &&
140             !arg_booted &&
141             !arg_readahead) {
142                 help();
143                 return -EINVAL;
144         }
145
146         return 1;
147 }
148
149 int main(int argc, char* argv[]) {
150         _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
151         _cleanup_strv_free_ char **final_env = NULL;
152         char* our_env[4];
153         unsigned i = 0;
154         int r;
155
156         log_parse_environment();
157         log_open();
158
159         r = parse_argv(argc, argv);
160         if (r <= 0)
161                 goto finish;
162
163         if (arg_booted)
164                 return sd_booted() <= 0;
165
166         if (arg_readahead) {
167                 r = sd_readahead(arg_readahead);
168                 if (r < 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                 status = strappend("STATUS=", arg_status);
179                 if (!status) {
180                         r = log_oom();
181                         goto finish;
182                 }
183
184                 our_env[i++] = status;
185         }
186
187         if (arg_pid > 0) {
188                 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) {
189                         r = log_oom();
190                         goto finish;
191                 }
192
193                 our_env[i++] = cpid;
194         }
195
196         our_env[i++] = NULL;
197
198         final_env = strv_env_merge(2, our_env, argv + optind);
199         if (!final_env) {
200                 r = log_oom();
201                 goto finish;
202         }
203
204         if (strv_length(final_env) <= 0) {
205                 r = 0;
206                 goto finish;
207         }
208
209         n = strv_join(final_env, "\n");
210         if (!n) {
211                 r = log_oom();
212                 goto finish;
213         }
214
215         r = sd_pid_notify(arg_pid, false, n);
216         if (r < 0) {
217                 log_error("Failed to notify init system: %s", strerror(-r));
218                 goto finish;
219         }
220
221         if (r == 0)
222                 r = -ENOTSUP;
223
224 finish:
225         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
226 }