chiark / gitweb /
pam_systemd: new option for the session class
[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
38 static bool arg_ready = false;
39 static pid_t arg_pid = 0;
40 static const char *arg_status = NULL;
41 static bool arg_booted = false;
42 static const char *arg_readahead = NULL;
43
44 static int help(void) {
45
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         return 0;
58 }
59
60 static int parse_argv(int argc, char *argv[]) {
61
62         enum {
63                 ARG_READY = 0x100,
64                 ARG_VERSION,
65                 ARG_PID,
66                 ARG_STATUS,
67                 ARG_BOOTED,
68                 ARG_READAHEAD
69         };
70
71         static const struct option options[] = {
72                 { "help",      no_argument,       NULL, 'h'           },
73                 { "version",   no_argument,       NULL, ARG_VERSION   },
74                 { "ready",     no_argument,       NULL, ARG_READY     },
75                 { "pid",       optional_argument, NULL, ARG_PID       },
76                 { "status",    required_argument, NULL, ARG_STATUS    },
77                 { "booted",    no_argument,       NULL, ARG_BOOTED    },
78                 { "readahead", required_argument, NULL, ARG_READAHEAD },
79                 { NULL,        0,                 NULL, 0             }
80         };
81
82         int c;
83
84         assert(argc >= 0);
85         assert(argv);
86
87         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
88
89                 switch (c) {
90
91                 case 'h':
92                         help();
93                         return 0;
94
95                 case ARG_VERSION:
96                         puts(PACKAGE_STRING);
97                         puts(DISTRIBUTION);
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         if ((r = parse_argv(argc, argv)) <= 0) {
161                 retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
162                 goto finish;
163         }
164
165         if (arg_booted)
166                 return sd_booted() <= 0;
167
168         if (arg_readahead) {
169                 if ((r = sd_readahead(arg_readahead)) < 0) {
170                         log_error("Failed to issue read-ahead control command: %s", strerror(-r));
171                         goto finish;
172                 }
173         }
174
175         if (arg_ready)
176                 our_env[i++] = (char*) "READY=1";
177
178         if (arg_status) {
179                 if (!(status = strappend("STATUS=", arg_status))) {
180                         log_error("Failed to allocate STATUS string.");
181                         goto finish;
182                 }
183
184                 our_env[i++] = status;
185         }
186
187         if (arg_pid > 0) {
188                 if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) {
189                         log_error("Failed to allocate MAINPID string.");
190                         goto finish;
191                 }
192
193                 our_env[i++] = cpid;
194         }
195
196         our_env[i++] = NULL;
197
198         if (!(final_env = strv_env_merge(2, our_env, argv + optind))) {
199                 log_error("Failed to merge string sets.");
200                 goto finish;
201         }
202
203         if (strv_length(final_env) <= 0) {
204                 retval = EXIT_SUCCESS;
205                 goto finish;
206         }
207
208         if (!(n = strv_join(final_env, "\n"))) {
209                 log_error("Failed to concatenate strings.");
210                 goto finish;
211         }
212
213         if ((r = sd_notify(false, n)) < 0) {
214                 log_error("Failed to notify init system: %s", strerror(-r));
215                 goto finish;
216         }
217
218         retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
219
220 finish:
221         free(status);
222         free(cpid);
223         free(n);
224
225         strv_free(final_env);
226
227         return retval;
228 }