2 * collectd - src/daemon/cmd.c
3 * Copyright (C) 2005-2007 Florian octo Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
30 static void *do_flush(void __attribute__((unused)) * arg) {
31 INFO("Flushing all data.");
32 plugin_flush(/* plugin = */ NULL,
35 INFO("Finished flushing all data.");
40 static void sig_int_handler(int __attribute__((unused)) signal) {
44 static void sig_term_handler(int __attribute__((unused)) signal) {
48 static void sig_usr1_handler(int __attribute__((unused)) signal) {
52 /* flushing the data might take a while,
53 * so it should be done asynchronously */
54 pthread_attr_init(&attr);
55 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
56 pthread_create(&thread, &attr, do_flush, NULL);
57 pthread_attr_destroy(&attr);
61 static int pidfile_create(void) {
63 const char *file = global_option_get("PIDFile");
65 if ((fh = fopen(file, "w")) == NULL) {
66 ERROR("fopen (%s): %s", file, STRERRNO);
70 fprintf(fh, "%i\n", (int)getpid());
74 } /* static int pidfile_create (const char *file) */
76 static int pidfile_remove(void) {
77 const char *file = global_option_get("PIDFile");
82 } /* static int pidfile_remove (const char *file) */
83 #endif /* COLLECT_DAEMON */
86 static int notify_upstart(void) {
87 char const *upstart_job = getenv("UPSTART_JOB");
89 if (upstart_job == NULL)
92 if (strcmp(upstart_job, "collectd") != 0) {
93 WARNING("Environment specifies unexpected UPSTART_JOB=\"%s\", expected "
94 "\"collectd\". Ignoring the variable.",
99 NOTICE("Upstart detected, stopping now to signal readiness.");
101 unsetenv("UPSTART_JOB");
106 static int notify_systemd(void) {
108 const char *notifysocket = getenv("NOTIFY_SOCKET");
109 if (notifysocket == NULL)
112 if ((strlen(notifysocket) < 2) ||
113 ((notifysocket[0] != '@') && (notifysocket[0] != '/'))) {
114 ERROR("invalid notification socket NOTIFY_SOCKET=\"%s\": path must be "
119 NOTICE("Systemd detected, trying to signal readiness.");
121 unsetenv("NOTIFY_SOCKET");
124 #if defined(SOCK_CLOEXEC)
125 fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, /* protocol = */ 0);
127 fd = socket(AF_UNIX, SOCK_DGRAM, /* protocol = */ 0);
130 ERROR("creating UNIX socket failed: %s", STRERRNO);
134 struct sockaddr_un su = {0};
135 su.sun_family = AF_UNIX;
136 if (notifysocket[0] != '@') {
137 /* regular UNIX socket */
138 sstrncpy(su.sun_path, notifysocket, sizeof(su.sun_path));
139 su_size = sizeof(su);
141 /* Linux abstract namespace socket: specify address as "\0foo", i.e.
142 * start with a null byte. Since null bytes have no special meaning in
143 * that case, we have to set su_size correctly to cover only the bytes
144 * that are part of the address. */
145 sstrncpy(su.sun_path, notifysocket, sizeof(su.sun_path));
147 su_size = sizeof(sa_family_t) + strlen(notifysocket);
148 if (su_size > sizeof(su))
149 su_size = sizeof(su);
152 const char buffer[] = "READY=1\n";
153 if (sendto(fd, buffer, strlen(buffer), MSG_NOSIGNAL, (void *)&su,
154 (socklen_t)su_size) < 0) {
155 ERROR("sendto(\"%s\") failed: %s", notifysocket, STRERRNO);
160 unsetenv("NOTIFY_SOCKET");
164 #endif /* KERNEL_LINUX */
166 int main(int argc, char **argv) {
167 struct cmdline_config config = init_config(argc, argv);
173 struct sigaction sig_chld_action = {.sa_handler = SIG_IGN};
175 sigaction(SIGCHLD, &sig_chld_action, NULL);
178 * Only daemonize if we're not being supervised
179 * by upstart or systemd (when using Linux).
183 && notify_upstart() == 0 && notify_systemd() == 0
187 if ((pid = fork()) == -1) {
189 fprintf(stderr, "fork: %s", STRERRNO);
191 } else if (pid != 0) {
193 /* printf ("Running (PID %i)\n", pid); */
197 /* Detach from session */
201 if (pidfile_create())
204 /* close standard descriptors */
209 int status = open("/dev/null", O_RDWR);
211 ERROR("Error: Could not connect `STDIN' to `/dev/null' (status %d)",
218 ERROR("Error: Could not connect `STDOUT' to `/dev/null' (status %d)",
225 ERROR("Error: Could not connect `STDERR' to `/dev/null', (status %d)",
229 } /* if (config.daemonize) */
230 #endif /* COLLECT_DAEMON */
232 struct sigaction sig_pipe_action = {.sa_handler = SIG_IGN};
234 sigaction(SIGPIPE, &sig_pipe_action, NULL);
237 * install signal handlers
239 struct sigaction sig_int_action = {.sa_handler = sig_int_handler};
241 if (sigaction(SIGINT, &sig_int_action, NULL) != 0) {
242 ERROR("Error: Failed to install a signal handler for signal INT: %s",
247 struct sigaction sig_term_action = {.sa_handler = sig_term_handler};
249 if (sigaction(SIGTERM, &sig_term_action, NULL) != 0) {
250 ERROR("Error: Failed to install a signal handler for signal TERM: %s",
255 struct sigaction sig_usr1_action = {.sa_handler = sig_usr1_handler};
257 if (sigaction(SIGUSR1, &sig_usr1_action, NULL) != 0) {
258 ERROR("Error: Failed to install a signal handler for signal USR1: %s",
263 int exit_status = run_loop(config.test_readall);
266 if (config.daemonize)
268 #endif /* COLLECT_DAEMON */