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