chiark / gitweb /
Unify parse_argv style
[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 void help(void) {
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
58 static int parse_argv(int argc, char *argv[]) {
59
60         enum {
61                 ARG_READY = 0x100,
62                 ARG_VERSION,
63                 ARG_PID,
64                 ARG_STATUS,
65                 ARG_BOOTED,
66                 ARG_READAHEAD
67         };
68
69         static const struct option options[] = {
70                 { "help",      no_argument,       NULL, 'h'           },
71                 { "version",   no_argument,       NULL, ARG_VERSION   },
72                 { "ready",     no_argument,       NULL, ARG_READY     },
73                 { "pid",       optional_argument, NULL, ARG_PID       },
74                 { "status",    required_argument, NULL, ARG_STATUS    },
75                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
76                 { "readahead", required_argument, NULL, ARG_READAHEAD },
77                 {}
78         };
79
80         int c;
81
82         assert(argc >= 0);
83         assert(argv);
84
85         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
86
87                 switch (c) {
88
89                 case 'h':
90                         help();
91                         return 0;
92
93                 case ARG_VERSION:
94                         puts(PACKAGE_STRING);
95                         puts(SYSTEMD_FEATURES);
96                         return 0;
97
98                 case ARG_READY:
99                         arg_ready = true;
100                         break;
101
102                 case ARG_PID:
103
104                         if (optarg) {
105                                 if (parse_pid(optarg, &arg_pid) < 0) {
106                                         log_error("Failed to parse PID %s.", optarg);
107                                         return -EINVAL;
108                                 }
109                         } else
110                                 arg_pid = getppid();
111
112                         break;
113
114                 case ARG_STATUS:
115                         arg_status = optarg;
116                         break;
117
118                 case ARG_BOOTED:
119                         arg_booted = true;
120                         break;
121
122                 case ARG_READAHEAD:
123                         arg_readahead = optarg;
124                         break;
125
126                 case '?':
127                         return -EINVAL;
128
129                 default:
130                         assert_not_reached("Unhandled option");
131                 }
132
133         if (optind >= argc &&
134             !arg_ready &&
135             !arg_status &&
136             !arg_pid &&
137             !arg_booted &&
138             !arg_readahead) {
139                 help();
140                 return -EINVAL;
141         }
142
143         return 1;
144 }
145
146 int main(int argc, char* argv[]) {
147         _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
148         _cleanup_strv_free_ char **final_env = NULL;
149         char* our_env[4];
150         unsigned i = 0;
151         int r;
152
153         log_parse_environment();
154         log_open();
155
156         r = parse_argv(argc, argv);
157         if (r <= 0)
158                 goto finish;
159
160         if (arg_booted)
161                 return sd_booted() <= 0;
162
163         if (arg_readahead) {
164                 r = sd_readahead(arg_readahead);
165                 if (r < 0) {
166                         log_error("Failed to issue read-ahead control command: %s", strerror(-r));
167                         goto finish;
168                 }
169         }
170
171         if (arg_ready)
172                 our_env[i++] = (char*) "READY=1";
173
174         if (arg_status) {
175                 status = strappend("STATUS=", arg_status);
176                 if (!status) {
177                         r = log_oom();
178                         goto finish;
179                 }
180
181                 our_env[i++] = status;
182         }
183
184         if (arg_pid > 0) {
185                 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) {
186                         r = log_oom();
187                         goto finish;
188                 }
189
190                 our_env[i++] = cpid;
191         }
192
193         our_env[i++] = NULL;
194
195         final_env = strv_env_merge(2, our_env, argv + optind);
196         if (!final_env) {
197                 r = log_oom();
198                 goto finish;
199         }
200
201         if (strv_length(final_env) <= 0) {
202                 r = 0;
203                 goto finish;
204         }
205
206         n = strv_join(final_env, "\n");
207         if (!n) {
208                 r = log_oom();
209                 goto finish;
210         }
211
212         r = sd_pid_notify(arg_pid, false, n);
213         if (r < 0) {
214                 log_error("Failed to notify init system: %s", strerror(-r));
215                 goto finish;
216         }
217
218         if (r == 0)
219                 r = -ENOTSUP;
220
221 finish:
222         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
223 }