chiark / gitweb /
a8ffbe9c8cb26475e385b9e230781c7ea2a2990e
[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 <errno.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27
28 #include "systemd/sd-daemon.h"
29
30 #include "strv.h"
31 #include "util.h"
32 #include "log.h"
33 #include "build.h"
34 #include "env-util.h"
35
36 static bool arg_ready = false;
37 static pid_t arg_pid = 0;
38 static const char *arg_status = NULL;
39 static bool arg_booted = false;
40
41 static void help(void) {
42         printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
43                "Notify the init system about service status updates.\n\n"
44                "  -h --help            Show this help\n"
45                "     --version         Show package version\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          Check if the system was booted up with systemd\n",
50                program_invocation_short_name);
51 }
52
53 static int parse_argv(int argc, char *argv[]) {
54
55         enum {
56                 ARG_READY = 0x100,
57                 ARG_VERSION,
58                 ARG_PID,
59                 ARG_STATUS,
60                 ARG_BOOTED,
61         };
62
63         static const struct option options[] = {
64                 { "help",      no_argument,       NULL, 'h'           },
65                 { "version",   no_argument,       NULL, ARG_VERSION   },
66                 { "ready",     no_argument,       NULL, ARG_READY     },
67                 { "pid",       optional_argument, NULL, ARG_PID       },
68                 { "status",    required_argument, NULL, ARG_STATUS    },
69                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
70                 {}
71         };
72
73         int c;
74
75         assert(argc >= 0);
76         assert(argv);
77
78         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
79
80                 switch (c) {
81
82                 case 'h':
83                         help();
84                         return 0;
85
86                 case ARG_VERSION:
87                         puts(PACKAGE_STRING);
88                         puts(SYSTEMD_FEATURES);
89                         return 0;
90
91                 case ARG_READY:
92                         arg_ready = true;
93                         break;
94
95                 case ARG_PID:
96
97                         if (optarg) {
98                                 if (parse_pid(optarg, &arg_pid) < 0) {
99                                         log_error("Failed to parse PID %s.", optarg);
100                                         return -EINVAL;
101                                 }
102                         } else
103                                 arg_pid = getppid();
104
105                         break;
106
107                 case ARG_STATUS:
108                         arg_status = optarg;
109                         break;
110
111                 case ARG_BOOTED:
112                         arg_booted = true;
113                         break;
114
115                 case '?':
116                         return -EINVAL;
117
118                 default:
119                         assert_not_reached("Unhandled option");
120                 }
121         }
122
123         if (optind >= argc &&
124             !arg_ready &&
125             !arg_status &&
126             !arg_pid &&
127             !arg_booted) {
128                 help();
129                 return -EINVAL;
130         }
131
132         return 1;
133 }
134
135 int main(int argc, char* argv[]) {
136         _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL;
137         _cleanup_strv_free_ char **final_env = NULL;
138         char* our_env[4];
139         unsigned i = 0;
140         int r;
141
142         log_parse_environment();
143         log_open();
144
145         r = parse_argv(argc, argv);
146         if (r <= 0)
147                 goto finish;
148
149         if (arg_booted)
150                 return sd_booted() <= 0;
151
152         if (arg_ready)
153                 our_env[i++] = (char*) "READY=1";
154
155         if (arg_status) {
156                 status = strappend("STATUS=", arg_status);
157                 if (!status) {
158                         r = log_oom();
159                         goto finish;
160                 }
161
162                 our_env[i++] = status;
163         }
164
165         if (arg_pid > 0) {
166                 if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) {
167                         r = log_oom();
168                         goto finish;
169                 }
170
171                 our_env[i++] = cpid;
172         }
173
174         our_env[i++] = NULL;
175
176         final_env = strv_env_merge(2, our_env, argv + optind);
177         if (!final_env) {
178                 r = log_oom();
179                 goto finish;
180         }
181
182         if (strv_length(final_env) <= 0) {
183                 r = 0;
184                 goto finish;
185         }
186
187         n = strv_join(final_env, "\n");
188         if (!n) {
189                 r = log_oom();
190                 goto finish;
191         }
192
193         r = sd_pid_notify(arg_pid, false, n);
194         if (r < 0) {
195                 log_error_errno(r, "Failed to notify init system: %m");
196                 goto finish;
197         }
198
199         if (r == 0)
200                 r = -ENOTSUP;
201
202 finish:
203         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
204 }