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