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