diff options
Diffstat (limited to 'src/mod_rrdtool.c')
-rw-r--r-- | src/mod_rrdtool.c | 123 |
1 files changed, 84 insertions, 39 deletions
diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c index 28003c4..2cb4640 100644 --- a/src/mod_rrdtool.c +++ b/src/mod_rrdtool.c @@ -92,11 +92,11 @@ FREE_FUNC(mod_rrd_free) { } int mod_rrd_create_pipe(server *srv, plugin_data *p) { +#ifdef HAVE_FORK pid_t pid; int to_rrdtool_fds[2]; int from_rrdtool_fds[2]; -#ifdef HAVE_FORK if (pipe(to_rrdtool_fds)) { log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno)); @@ -132,13 +132,6 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { /* not needed */ close(to_rrdtool_fds[1]); - close(STDERR_FILENO); - - if (srv->errorlog_mode == ERRORLOG_FILE) { - dup2(srv->errorlog_fd, STDERR_FILENO); - close(srv->errorlog_fd); - } - /* set up args */ argc = 3; args = malloc(sizeof(*args) * argc); @@ -148,6 +141,8 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { args[i++] = dash; args[i++] = NULL; + openDevNull(STDERR_FILENO); + /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); @@ -156,7 +151,7 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { /* exec the cgi */ execv(args[0], args); - log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]); + /* log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]); */ /* */ SEGFAULT(); @@ -177,6 +172,11 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { p->read_fd = from_rrdtool_fds[0]; p->rrdtool_pid = pid; +#ifdef FD_CLOEXEC + fcntl(p->write_fd, F_SETFD, FD_CLOEXEC); + fcntl(p->read_fd, F_SETFD, FD_CLOEXEC); +#endif + break; } } @@ -187,6 +187,47 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { #endif } +/* read/write wrappers to catch EINTR */ + +/* write to blocking socket; blocks until all data is sent, write returns 0 or an error (apart from EINTR) occurs. */ +static ssize_t safe_write(int fd, const void *buf, size_t count) { + ssize_t res, sum = 0; + + for (;;) { + res = write(fd, buf, count); + if (res >= 0) { + sum += res; + /* do not try again if res == 0 */ + if (res == 0 || (size_t) res == count) return sum; + count -= res; + buf = (const char*) buf + res; + continue; + } + switch (errno) { + case EINTR: + continue; + default: + return -1; + } + } +} + +/* this assumes we get enough data on a successful read */ +static ssize_t safe_read(int fd, void *buf, size_t count) { + ssize_t res; + + for (;;) { + res = read(fd, buf, count); + if (res >= 0) return res; + switch (errno) { + case EINTR: + continue; + default: + return -1; + } + } +} + static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) { struct stat st; @@ -202,26 +243,27 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) int r ; /* create a new one */ - BUFFER_COPY_STRING_CONST(p->cmd, "create "); + buffer_copy_string_len(p->cmd, CONST_STR_LEN("create ")); buffer_append_string_buffer(p->cmd, s->path_rrd); - buffer_append_string(p->cmd, " --step 60 "); - buffer_append_string(p->cmd, "DS:InOctets:ABSOLUTE:600:U:U "); - buffer_append_string(p->cmd, "DS:OutOctets:ABSOLUTE:600:U:U "); - buffer_append_string(p->cmd, "DS:Requests:ABSOLUTE:600:U:U "); - buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:1:600 "); - buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:6:700 "); - buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:24:775 "); - buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:288:797 "); - buffer_append_string(p->cmd, "RRA:MAX:0.5:1:600 "); - buffer_append_string(p->cmd, "RRA:MAX:0.5:6:700 "); - buffer_append_string(p->cmd, "RRA:MAX:0.5:24:775 "); - buffer_append_string(p->cmd, "RRA:MAX:0.5:288:797 "); - buffer_append_string(p->cmd, "RRA:MIN:0.5:1:600 "); - buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 "); - buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 "); - buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n"); - - if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { + buffer_append_string_len(p->cmd, CONST_STR_LEN( + " --step 60 " + "DS:InOctets:ABSOLUTE:600:U:U " + "DS:OutOctets:ABSOLUTE:600:U:U " + "DS:Requests:ABSOLUTE:600:U:U " + "RRA:AVERAGE:0.5:1:600 " + "RRA:AVERAGE:0.5:6:700 " + "RRA:AVERAGE:0.5:24:775 " + "RRA:AVERAGE:0.5:288:797 " + "RRA:MAX:0.5:1:600 " + "RRA:MAX:0.5:6:700 " + "RRA:MAX:0.5:24:775 " + "RRA:MAX:0.5:288:797 " + "RRA:MIN:0.5:1:600 " + "RRA:MIN:0.5:6:700 " + "RRA:MIN:0.5:24:775 " + "RRA:MIN:0.5:288:797\n")); + + if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-write: failed", strerror(errno)); @@ -229,7 +271,7 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) } buffer_prepare_copy(p->resp, 4096); - if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) { + if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) { log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-read: failed", strerror(errno)); @@ -372,17 +414,17 @@ TRIGGER_FUNC(mod_rrd_trigger) { if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR; - BUFFER_COPY_STRING_CONST(p->cmd, "update "); + buffer_copy_string_len(p->cmd, CONST_STR_LEN("update ")); buffer_append_string_buffer(p->cmd, s->path_rrd); - BUFFER_APPEND_STRING_CONST(p->cmd, " N:"); + buffer_append_string_len(p->cmd, CONST_STR_LEN(" N:")); buffer_append_off_t(p->cmd, s->bytes_read); - BUFFER_APPEND_STRING_CONST(p->cmd, ":"); + buffer_append_string_len(p->cmd, CONST_STR_LEN(":")); buffer_append_off_t(p->cmd, s->bytes_written); - BUFFER_APPEND_STRING_CONST(p->cmd, ":"); + buffer_append_string_len(p->cmd, CONST_STR_LEN(":")); buffer_append_long(p->cmd, s->requests); - BUFFER_APPEND_STRING_CONST(p->cmd, "\n"); + buffer_append_string_len(p->cmd, CONST_STR_LEN("\n")); - if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { + if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { p->rrdtool_running = 0; log_error_write(srv, __FILE__, __LINE__, "ss", @@ -392,7 +434,7 @@ TRIGGER_FUNC(mod_rrd_trigger) { } buffer_prepare_copy(p->resp, 4096); - if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) { + if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) { p->rrdtool_running = 0; log_error_write(srv, __FILE__, __LINE__, "ss", @@ -405,12 +447,15 @@ TRIGGER_FUNC(mod_rrd_trigger) { if (p->resp->ptr[0] != 'O' || p->resp->ptr[1] != 'K') { - p->rrdtool_running = 0; + /* don't fail on this error if we just started (graceful restart, the old one might have just updated too) */ + if (!(strstr(p->resp->ptr, "(minimum one second step)") && (srv->cur_ts - srv->startup_ts < 3))) { + p->rrdtool_running = 0; - log_error_write(srv, __FILE__, __LINE__, "sbb", + log_error_write(srv, __FILE__, __LINE__, "sbb", "rrdtool-response:", p->cmd, p->resp); - return HANDLER_ERROR; + return HANDLER_ERROR; + } } s->requests = 0; s->bytes_written = 0; |