From: Florian Forster Date: Sun, 1 Apr 2012 10:01:58 +0000 (+0200) Subject: Merge branch 'collectd-4.10' into collectd-5.0 X-Git-Tag: collectd-5.0.4~2 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=483e801902bca3c779793224eddf3bb2749d7288;hp=8991abf98de418b8464aa0f3251b024c9292da96 Merge branch 'collectd-4.10' into collectd-5.0 Conflicts: ChangeLog src/collectd.conf.pod src/common.c src/network.c src/processes.c version-gen.sh --- diff --git a/ChangeLog b/ChangeLog index 4a99a15a..1beef6eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -140,6 +140,35 @@ * v5upgrade target: Target for converting v4 data sets to the v5 schema. +2012-03-23, Version 4.10.7 + * Build system: Fix the use of a libltdl macro. Thanks to Clemens Lang + for fixing this. Adresses some issues with building the iptables + plugin under Gentoo. + * libcollectdclient: A memory leak in the lcc_getval() function has + been fixed. Thanks to Jason Schmidlapp for finding and fixing this + issue. + * bind plugin: The use of 'QType" types has been fixed. + * df plugin: Fixed compiler issue under Mac OS X 10.7. + * conntrack plugin: Support zero as legitimate value. Thanks to Louis + Opter for his patch. + * memcached plugin: Increased the size of a static buffer, which was + truncating status messages form memcached. Thanks to Timon for the + patch. + * network plugin: Forwarding of notifications has been disabled. This + was a contition not checked for before, which may retult in an + endless loop. + * processes plugin: Support for process names with spaces has been + added to the Linux implementation. Thanks to Darrell Bishop for his + patch. + * perl plugin: A race condition in several callbacks, including log and + write callbacks, has been fixed. Thanks to "Rrpv" for reporting this + bug. + * snmp plugin: A bug when casting unsigned integers to gauge values has + been fixed: Unsigned integers would be cast to a signed integer and + then to a gauge, possibly resulting in a negative value. + * tcpconns plugin: Compilation with newer versions of the FreeBSD + runtime has been fixed. + 2012-02-19, Version 4.10.6 * Build system: Fix problems when building the ipvs and iptables plugins. Thanks to Sebastian Harl for his patch. A bashism in the diff --git a/configure.in b/configure.in index e30d0f88..bb26716d 100644 --- a/configure.in +++ b/configure.in @@ -1380,6 +1380,7 @@ AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWAPINFO, test "x$with_kvm_getswapinfo" = "x AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"]) if test "x$with_kvm_nlist" = "xyes" then + AC_CHECK_HEADERS(bsd/nlist.h nlist.h) AC_DEFINE(HAVE_LIBKVM_NLIST, 1, [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)]) with_libkvm="yes" @@ -1853,9 +1854,10 @@ then AC_CHECK_TYPES([iptc_handle_t, ip6tc_handle_t], [], []) fi # Check for the iptc_init symbol in the library. +# This could be in iptc or ip4tc if test "x$with_libiptc" = "xpkgconfig" then - AC_CHECK_LIB(iptc, iptc_init, + AC_SEARCH_LIBS(iptc_init, [iptc ip4tc], [with_libiptc="pkgconfig"], [with_libiptc="no"], [$with_libiptc_libs]) diff --git a/src/Makefile.am b/src/Makefile.am index 259a3816..ba59bf54 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,7 +85,7 @@ endif if BUILD_WITH_OWN_LIBOCONFIG collectd_LDADD += $(LIBLTDL) liboconfig/liboconfig.la -collectd_DEPENDENCIES += $(LIBLTDL) liboconfig/liboconfig.la +collectd_DEPENDENCIES += liboconfig/liboconfig.la else collectd_LDADD += -loconfig endif diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 1b0c2fd9..1c0f4f07 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2654,10 +2654,18 @@ The default IPv6 multicast group is C. The default IPv4 multicast group is C<239.192.74.66>. The default I port is B<25826>. Both, B and B can be used as single option or as block. When -used as block, given options are valid for this socket only. For example: +used as block, given options are valid for this socket only. The following +example will export the metrics twice: Once to an "internal" server (without +encryption and signing) and one to an external server (with cryptographic +signature): + # Export to an internal server + # (demonstrates usage without additional options) Server "collectd.internal.tld" + + # Export to an external server + # (demonstrates usage with signature options) SecurityLevel "sign" Username "myhostname" @@ -4831,6 +4839,170 @@ number. =back +=head1 THRESHOLD CONFIGURATION + +Starting with version C<4.3.0> collectd has support for B. By that +we mean that the values are not only stored or sent somewhere, but that they +are judged and, if a problem is recognized, acted upon. The only action +collectd takes itself is to generate and dispatch a "notification". Plugins can +register to receive notifications and perform appropriate further actions. + +Since systems and what you expect them to do differ a lot, you can configure +B for your values freely. This gives you a lot of flexibility but +also a lot of responsibility. + +Every time a value is out of range a notification is dispatched. This means +that the idle percentage of your CPU needs to be less then the configured +threshold only once for a notification to be generated. There's no such thing +as a moving average or similar - at least not now. + +Also, all values that match a threshold are considered to be relevant or +"interesting". As a consequence collectd will issue a notification if they are +not received for B iterations. The B configuration option is +explained in section L<"GLOBAL OPTIONS">. If, for example, B is set to +"2" (the default) and some hosts sends it's CPU statistics to the server every +60 seconds, a notification will be dispatched after about 120 seconds. It may +take a little longer because the timeout is checked only once each B +on the server. + +When a value comes within range again or is received after it was missing, an +"OKAY-notification" is dispatched. + +Here is a configuration example to get you started. Read below for more +information. + + + + WarningMin 0.00 + WarningMax 1000.00 + FailureMin 0.00 + FailureMax 1200.00 + Invert false + Instance "bar" + + + + Instance "eth0" + + FailureMax 10000000 + DataSource "rx" + + + + + + Instance "idle" + FailureMin 10 + + + + + Instance "cached" + WarningMin 100000000 + + + + + +There are basically two types of configuration statements: The C, +C, and C blocks select the value for which a threshold should be +configured. The C and C blocks may be specified further using the +C option. You can combine the block by nesting the blocks, though +they must be nested in the above order, i.Ee. C may contain either +C and C blocks, C may only contain C blocks and +C may not contain other blocks. If multiple blocks apply to the same +value the most specific block is used. + +The other statements specify the threshold to configure. They B be +included in a C block. Currently the following statements are recognized: + +=over 4 + +=item B I + +=item B I + +Sets the upper bound of acceptable values. If unset defaults to positive +infinity. If a value is greater than B a B notification +will be created. If the value is greater than B but less than (or +equal to) B a B notification will be created. + +=item B I + +=item B I + +Sets the lower bound of acceptable values. If unset defaults to negative +infinity. If a value is less than B a B notification will +be created. If the value is less than B but greater than (or equal +to) B a B notification will be created. + +=item B I + +Some data sets have more than one "data source". Interesting examples are the +C data set, which has received (C) and sent (C) bytes and +the C data set, which holds C and C operations. The +system load data set, C, even has three data sources: C, +C, and C. + +Normally, all data sources are checked against a configured threshold. If this +is undesirable, or if you want to specify different limits for each data +source, you can use the B option to have a threshold apply only to +one data source. + +=item B B|B + +If set to B the range of acceptable values is inverted, i.Ee. +values between B and B (B and +B) are not okay. Defaults to B. + +=item B B|B + +Sets how often notifications are generated. If set to B one notification +will be generated for each value that is out of the acceptable range. If set to +B (the default) then a notification is only generated if a value is out +of range but the previous value was okay. + +This applies to missing values, too: If set to B a notification about a +missing value is generated once every B seconds. If set to B +only one such notification is generated until the value appears again. + +=item B B|B + +If set to B, the minimum and maximum values given are interpreted as +percentage value, relative to the other data sources. This is helpful for +example for the "df" type, where you may want to issue a warning when less than +5E% of the total space is available. Defaults to B. + +=item B I + +Delay creating the notification until the threshold has been passed I +times. When a notification has been generated, or when a subsequent value is +inside the threshold, the counter is reset. If, for example, a value is +collected once every 10Eseconds and B is set to 3, a notification +will be dispatched at most once every 30Eseconds. + +This is useful when short bursts are not a problem. If, for example, 100% CPU +usage for up to a minute is normal (and data is collected every +10Eseconds), you could set B to B<6> to account for this. + +=item B I + +When set to non-zero, a hysteresis value is applied when checking minimum and +maximum bounds. This is useful for values that increase slowly and fluctuate a +bit while doing so. When these values come close to the threshold, they may +"flap", i.e. switch between failure / warning case and okay case repeatedly. + +If, for example, the threshold is configures as + + WarningMax 100.0 + Hysteresis 1.0 + +then a I notification is created when the value exceeds I<101> and the +corresponding I notification is only created once the value falls below +I<99>, thus avoiding the "flapping". + +=back + =head1 FILTER CONFIGURATION Starting with collectd 4.6 there is a powerful filtering infrastructure diff --git a/src/common.c b/src/common.c index 0069a8b6..459c7024 100644 --- a/src/common.c +++ b/src/common.c @@ -953,9 +953,25 @@ int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */ return (0); } /* }}} int parse_identifier_vl */ -int parse_value (const char *value, value_t *ret_value, int ds_type) +int parse_value (const char *value_orig, value_t *ret_value, int ds_type) { + char *value; char *endptr = NULL; + size_t value_len; + + if (value_orig == NULL) + return (EINVAL); + + value = strdup (value_orig); + if (value == NULL) + return (ENOMEM); + value_len = strlen (value); + + while ((value_len > 0) && isspace ((int) value[value_len - 1])) + { + value[value_len - 1] = 0; + value_len--; + } switch (ds_type) { @@ -976,11 +992,13 @@ int parse_value (const char *value, value_t *ret_value, int ds_type) break; default: + sfree (value); ERROR ("parse_value: Invalid data source type: %i.", ds_type); return -1; } if (value == endptr) { + sfree (value); ERROR ("parse_value: Failed to parse string as %s: %s.", DS_TYPE_TO_STRING (ds_type), value); return -1; @@ -988,8 +1006,9 @@ int parse_value (const char *value, value_t *ret_value, int ds_type) else if ((NULL != endptr) && ('\0' != *endptr)) INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. " "Input string was \"%s\".", - endptr, DS_TYPE_TO_STRING (ds_type), value); + endptr, DS_TYPE_TO_STRING (ds_type), value_orig); + sfree (value); return 0; } /* int parse_value */ diff --git a/src/common.h b/src/common.h index e6b899de..6b11b538 100644 --- a/src/common.h +++ b/src/common.h @@ -287,6 +287,7 @@ typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename, void *user_data); int walk_directory (const char *dir, dirwalk_callback_f callback, void *user_data, int hidden); +/* Returns the number of bytes read or negative on error. */ int read_file_contents (const char *filename, char *buf, int bufsize); counter_t counter_diff (counter_t old_value, counter_t new_value); diff --git a/src/conntrack.c b/src/conntrack.c index e70ff5f1..33236c45 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -31,14 +31,11 @@ #define CONNTRACK_FILE "/proc/sys/net/netfilter/nf_conntrack_count" -static void conntrack_submit (double conntrack) +static void conntrack_submit (value_t conntrack) { - value_t values[1]; value_list_t vl = VALUE_LIST_INIT; - values[0].gauge = conntrack; - - vl.values = values; + vl.values = &conntrack; vl.values_len = 1; sstrncpy (vl.host, hostname_g, sizeof (vl.host)); sstrncpy (vl.plugin, "conntrack", sizeof (vl.plugin)); @@ -49,14 +46,16 @@ static void conntrack_submit (double conntrack) static int conntrack_read (void) { - double conntrack; + value_t conntrack; FILE *fh; char buffer[64]; + size_t buffer_len; fh = fopen (CONNTRACK_FILE, "r"); if (fh == NULL) return (-1); + memset (buffer, 0, sizeof (buffer)); if (fgets (buffer, sizeof (buffer), fh) == NULL) { fclose (fh); @@ -64,10 +63,18 @@ static int conntrack_read (void) } fclose (fh); - conntrack = atof (buffer); + /* strip trailing newline. */ + buffer_len = strlen (buffer); + while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1])) + { + buffer[buffer_len - 1] = 0; + buffer_len--; + } + + if (parse_value (buffer, &conntrack, DS_TYPE_GAUGE) != 0) + return (-1); - if (conntrack > 0.0) - conntrack_submit (conntrack); + conntrack_submit (conntrack); return (0); } /* static int conntrack_read */ diff --git a/src/libcollectdclient/client.c b/src/libcollectdclient/client.c index 3eb0d055..f5fe2049 100644 --- a/src/libcollectdclient/client.c +++ b/src/libcollectdclient/client.c @@ -733,6 +733,8 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */ if (ret_values_names != NULL) *ret_values_names = values_names; + lcc_response_free (&res); + return (0); } /* }}} int lcc_getval */ diff --git a/src/memcached.c b/src/memcached.c index ee3dbe12..48fa713b 100644 --- a/src/memcached.c +++ b/src/memcached.c @@ -357,7 +357,7 @@ static void submit_gauge2 (const char *type, const char *type_inst, static int memcached_read (void) /* {{{ */ { - char buf[1024]; + char buf[4096]; char *fields[3]; char *ptr; char *line; diff --git a/src/network.c b/src/network.c index e0c329c6..5fed1b19 100644 --- a/src/network.c +++ b/src/network.c @@ -352,6 +352,43 @@ static _Bool check_send_okay (const value_list_t *vl) /* {{{ */ return (!received); } /* }}} _Bool check_send_okay */ +static _Bool check_notify_received (const notification_t *n) /* {{{ */ +{ + notification_meta_t *ptr; + + for (ptr = n->meta; ptr != NULL; ptr = ptr->next) + if ((strcmp ("network:received", ptr->name) == 0) + && (ptr->type == NM_TYPE_BOOLEAN)) + return ((_Bool) ptr->nm_value.nm_boolean); + + return (0); +} /* }}} _Bool check_notify_received */ + +static _Bool check_send_notify_okay (const notification_t *n) /* {{{ */ +{ + static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC; + _Bool received = 0; + + if (n->meta == NULL) + return (1); + + received = check_notify_received (n); + + if (network_config_forward && received) + { + c_complain_once (LOG_ERR, &complain_forwarding, + "network plugin: A notification has been received via the network " + "forwarding if enabled. Forwarding of notifications is currently " + "not supported, because there is not loop-deteciton available. " + "Please contact the collectd mailing list if you need this " + "feature."); + } + + /* By default, only *send* value lists that were not *received* by the + * network plugin. */ + return (!received); +} /* }}} _Bool check_send_notify_okay */ + static int network_dispatch_values (value_list_t *vl, /* {{{ */ const char *username) { @@ -415,6 +452,29 @@ static int network_dispatch_values (value_list_t *vl, /* {{{ */ return (0); } /* }}} int network_dispatch_values */ +static int network_dispatch_notification (notification_t *n) /* {{{ */ +{ + int status; + + assert (n->meta == NULL); + + status = plugin_notification_meta_add_boolean (n, "network:received", 1); + if (status != 0) + { + ERROR ("network plugin: plugin_notification_meta_add_boolean failed."); + plugin_notification_meta_free (n->meta); + n->meta = NULL; + return (status); + } + + status = plugin_dispatch_notification (n); + + plugin_notification_meta_free (n->meta); + n->meta = NULL; + + return (status); +} /* }}} int network_dispatch_notification */ + #if HAVE_LIBGCRYPT static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */ const void *iv, size_t iv_size, const char *username) @@ -705,7 +765,7 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len, exp_size = 3 * sizeof (uint16_t) + pkg_numval * (sizeof (uint8_t) + sizeof (value_t)); - if ((buffer_len < 0) || (buffer_len < exp_size)) + if (buffer_len < exp_size) { WARNING ("network plugin: parse_part_values: " "Packet too short: " @@ -790,7 +850,7 @@ static int parse_part_number (void **ret_buffer, size_t *ret_buffer_len, uint16_t pkg_length; - if ((buffer_len < 0) || ((size_t) buffer_len < exp_size)) + if (buffer_len < exp_size) { WARNING ("network plugin: parse_part_number: " "Packet too short: " @@ -829,7 +889,7 @@ static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len, uint16_t pkg_length; - if ((buffer_len < 0) || (buffer_len < header_size)) + if (buffer_len < header_size) { WARNING ("network plugin: parse_part_string: " "Packet too short: " @@ -1484,7 +1544,7 @@ static int parse_packet (sockent_t *se, /* {{{ */ } else { - plugin_dispatch_notification (&n); + network_dispatch_notification (&n); } } else if (pkg_type == TYPE_SEVERITY) @@ -3087,14 +3147,17 @@ static int network_config (oconfig_item_t *ci) /* {{{ */ } /* }}} int network_config */ static int network_notification (const notification_t *n, - user_data_t __attribute__((unused)) *user_data) + user_data_t __attribute__((unused)) *user_data) { char buffer[network_config_packet_size]; char *buffer_ptr = buffer; int buffer_free = sizeof (buffer); int status; - memset (buffer, '\0', sizeof (buffer)); + if (!check_send_notify_okay (n)) + return (0); + + memset (buffer, 0, sizeof (buffer)); status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR, (uint64_t) n->time); @@ -3109,7 +3172,7 @@ static int network_notification (const notification_t *n, if (strlen (n->host) > 0) { status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST, - n->host, strlen (n->host)); + n->host, strlen (n->host)); if (status != 0) return (-1); } @@ -3117,7 +3180,7 @@ static int network_notification (const notification_t *n, if (strlen (n->plugin) > 0) { status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN, - n->plugin, strlen (n->plugin)); + n->plugin, strlen (n->plugin)); if (status != 0) return (-1); } @@ -3125,8 +3188,8 @@ static int network_notification (const notification_t *n, if (strlen (n->plugin_instance) > 0) { status = write_part_string (&buffer_ptr, &buffer_free, - TYPE_PLUGIN_INSTANCE, - n->plugin_instance, strlen (n->plugin_instance)); + TYPE_PLUGIN_INSTANCE, + n->plugin_instance, strlen (n->plugin_instance)); if (status != 0) return (-1); } @@ -3134,7 +3197,7 @@ static int network_notification (const notification_t *n, if (strlen (n->type) > 0) { status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE, - n->type, strlen (n->type)); + n->type, strlen (n->type)); if (status != 0) return (-1); } @@ -3142,7 +3205,7 @@ static int network_notification (const notification_t *n, if (strlen (n->type_instance) > 0) { status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE, - n->type_instance, strlen (n->type_instance)); + n->type_instance, strlen (n->type_instance)); if (status != 0) return (-1); } diff --git a/src/perl.c b/src/perl.c index f8a48227..a2568da2 100644 --- a/src/perl.c +++ b/src/perl.c @@ -1929,6 +1929,11 @@ static int perl_read (void) aTHX = t->interp; } + /* Assert that we're not running as the base thread. Otherwise, we might + * run into concurrency issues with c_ithread_create(). See + * https://github.com/collectd/collectd/issues/9 for details. */ + assert (aTHX != perl_threads->head->interp); + log_debug ("perl_read: c_ithread: interp = %p (active threads: %i)", aTHX, perl_threads->number_of_threads); return pplugin_call_all (aTHX_ PLUGIN_READ); @@ -1937,6 +1942,7 @@ static int perl_read (void) static int perl_write (const data_set_t *ds, const value_list_t *vl, user_data_t __attribute__((unused)) *user_data) { + int status; dTHX; if (NULL == perl_threads) @@ -1952,9 +1958,20 @@ static int perl_write (const data_set_t *ds, const value_list_t *vl, aTHX = t->interp; } + /* Lock the base thread if this is not called from one of the read threads + * to avoid race conditions with c_ithread_create(). See + * https://github.com/collectd/collectd/issues/9 for details. */ + if (aTHX == perl_threads->head->interp) + pthread_mutex_lock (&perl_threads->mutex); + log_debug ("perl_write: c_ithread: interp = %p (active threads: %i)", aTHX, perl_threads->number_of_threads); - return pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl); + status = pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl); + + if (aTHX == perl_threads->head->interp) + pthread_mutex_unlock (&perl_threads->mutex); + + return status; } /* static int perl_write (const data_set_t *, const value_list_t *) */ static void perl_log (int level, const char *msg, @@ -1975,7 +1992,17 @@ static void perl_log (int level, const char *msg, aTHX = t->interp; } + /* Lock the base thread if this is not called from one of the read threads + * to avoid race conditions with c_ithread_create(). See + * https://github.com/collectd/collectd/issues/9 for details. */ + if (aTHX == perl_threads->head->interp) + pthread_mutex_lock (&perl_threads->mutex); + pplugin_call_all (aTHX_ PLUGIN_LOG, level, msg); + + if (aTHX == perl_threads->head->interp) + pthread_mutex_unlock (&perl_threads->mutex); + return; } /* static void perl_log (int, const char *) */ diff --git a/src/processes.c b/src/processes.c index 8f4eb88f..8a1436e1 100644 --- a/src/processes.c +++ b/src/processes.c @@ -881,9 +881,12 @@ int ps_read_process (int pid, procstat_t *ps, char *state) char *fields[64]; char fields_len; - int i; + int buffer_len; - int name_len; + char *buffer_ptr; + size_t name_start_pos; + size_t name_end_pos; + size_t name_len; derive_t cpu_user_counter; derive_t cpu_system_counter; @@ -895,33 +898,56 @@ int ps_read_process (int pid, procstat_t *ps, char *state) ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid); - i = read_file_contents (filename, buffer, sizeof(buffer) - 1); - if (i <= 0) + buffer_len = read_file_contents (filename, + buffer, sizeof(buffer) - 1); + if (buffer_len <= 0) return (-1); - buffer[i] = 0; - - fields_len = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields)); - if (fields_len < 24) + buffer[buffer_len] = 0; + + /* The name of the process is enclosed in parens. Since the name can + * contain parens itself, spaces, numbers and pretty much everything + * else, use these to determine the process name. We don't use + * strchr(3) and strrchr(3) to avoid pointer arithmetic which would + * otherwise be required to determine name_len. */ + name_start_pos = 0; + while ((buffer[name_start_pos] != '(') + && (name_start_pos < buffer_len)) + name_start_pos++; + + name_end_pos = buffer_len; + while ((buffer[name_end_pos] != ')') + && (name_end_pos > 0)) + name_end_pos--; + + /* Either '(' or ')' is not found or they are in the wrong order. + * Anyway, something weird that shouldn't happen ever. */ + if (name_start_pos >= name_end_pos) { - DEBUG ("processes plugin: ps_read_process (pid = %i):" - " `%s' has only %i fields..", - (int) pid, filename, fields_len); + ERROR ("processes plugin: name_start_pos = %zu >= name_end_pos = %zu", + name_start_pos, name_end_pos); return (-1); } - /* copy the name, strip brackets in the process */ - name_len = strlen (fields[1]) - 2; - if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')')) + name_len = (name_end_pos - name_start_pos) - 1; + if (name_len >= sizeof (ps->name)) + name_len = sizeof (ps->name) - 1; + + sstrncpy (ps->name, &buffer[name_start_pos + 1], name_len + 1); + + if ((buffer_len - name_end_pos) < 2) + return (-1); + buffer_ptr = &buffer[name_end_pos + 2]; + + fields_len = strsplit (buffer_ptr, fields, STATIC_ARRAY_SIZE (fields)); + if (fields_len < 22) { - DEBUG ("No brackets found in process name: `%s'", fields[1]); + DEBUG ("processes plugin: ps_read_process (pid = %i):" + " `%s' has only %i fields..", + (int) pid, filename, fields_len); return (-1); } - fields[1] = fields[1] + 1; - fields[1][name_len] = '\0'; - strncpy (ps->name, fields[1], PROCSTAT_NAME_LEN); - - *state = fields[2][0]; + *state = fields[0][0]; if (*state == 'Z') { @@ -946,16 +972,16 @@ int ps_read_process (int pid, procstat_t *ps, char *state) return (0); } - cpu_user_counter = atoll (fields[13]); - cpu_system_counter = atoll (fields[14]); - vmem_size = atoll (fields[22]); - vmem_rss = atoll (fields[23]); - ps->vmem_minflt_counter = atoll (fields[9]); - ps->vmem_majflt_counter = atoll (fields[11]); + cpu_user_counter = atoll (fields[11]); + cpu_system_counter = atoll (fields[12]); + vmem_size = atoll (fields[20]); + vmem_rss = atoll (fields[21]); + ps->vmem_minflt_counter = atol (fields[7]); + ps->vmem_majflt_counter = atol (fields[9]); { - unsigned long long stack_start = atoll (fields[27]); - unsigned long long stack_ptr = atoll (fields[28]); + unsigned long long stack_start = atoll (fields[25]); + unsigned long long stack_ptr = atoll (fields[26]); stack_size = (stack_start > stack_ptr) ? stack_start - stack_ptr diff --git a/src/snmp.c b/src/snmp.c index 54bcf672..d24ca2cd 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -708,7 +708,9 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, value_t ret; uint64_t tmp_unsigned = 0; int64_t tmp_signed = 0; - int defined = 1; + _Bool defined = 1; + /* Set to true when the original SNMP type appears to have been signed. */ + _Bool prefer_signed = 0; if ((vl->type == ASN_INTEGER) || (vl->type == ASN_UINTEGER) @@ -720,7 +722,12 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, { tmp_unsigned = (uint32_t) *vl->val.integer; tmp_signed = (int32_t) *vl->val.integer; - DEBUG ("snmp plugin: Parsed int32 value is %"PRIi64".", tmp_signed); + + if ((vl->type == ASN_INTEGER) + || (vl->type == ASN_GAUGE)) + prefer_signed = 1; + + DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", tmp_unsigned); } else if (vl->type == ASN_COUNTER64) { @@ -809,14 +816,24 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, } else if (type == DS_TYPE_GAUGE) { - ret.gauge = NAN; - if (defined != 0) + if (!defined) + ret.gauge = NAN; + else if (prefer_signed) ret.gauge = (scale * tmp_signed) + shift; + else + ret.gauge = (scale * tmp_unsigned) + shift; } else if (type == DS_TYPE_DERIVE) - ret.derive = (derive_t) tmp_signed; + { + if (prefer_signed) + ret.derive = (derive_t) tmp_signed; + else + ret.derive = (derive_t) tmp_unsigned; + } else if (type == DS_TYPE_ABSOLUTE) + { ret.absolute = (absolute_t) tmp_unsigned; + } else { ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source " diff --git a/src/tcpconns.c b/src/tcpconns.c index d68cd096..78c337b7 100644 --- a/src/tcpconns.c +++ b/src/tcpconns.c @@ -116,7 +116,11 @@ # include # include # include -# include +# if !defined(HAVE_BSD_NLIST_H) || !HAVE_BSD_NLIST_H +# include +# else /* HAVE_BSD_NLIST_H */ +# include +# endif # include #endif /* HAVE_LIBKVM_NLIST */