# define ARG_MAX 4096
#endif
-static const char *config_keys[] =
-{
- "Process",
- "ProcessMatch"
-};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-
typedef struct procstat_entry_s
{
unsigned long id;
}
/* put all pre-defined 'Process' names from config to list_head_g tree */
-static int ps_config (const char *key, const char *value)
+static int ps_config (oconfig_item_t *ci)
{
- if (strcasecmp (key, "Process") == 0)
- {
- ps_list_register (value, NULL);
- }
- else if (strcasecmp (key, "ProcessMatch") == 0)
- {
- char *new_val;
- char *fields[3];
- int fields_num;
-
- new_val = strdup (value);
- if (new_val == NULL) {
- ERROR ("processes plugin: strdup failed when processing "
- "`ProcessMatch %s'.", value);
- return (1);
+ int i;
+
+ for (i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
+
+ if (strcasecmp (c->key, "Process") == 0)
+ {
+ if ((c->values_num != 1)
+ || (OCONFIG_TYPE_STRING != c->values[0].type)) {
+ ERROR ("processes plugin: `Process' expects exactly "
+ "one string argument (got %i).",
+ c->values_num);
+ continue;
+ }
+
+ if (c->children_num != 0) {
+ WARNING ("processes plugin: the `Process' config option "
+ "does not expect any child elements -- ignoring "
+ "content (%i elements) of the <Process '%s'> block.",
+ c->children_num, c->values[0].value.string);
+ }
+
+ ps_list_register (c->values[0].value.string, NULL);
}
+ else if (strcasecmp (c->key, "ProcessMatch") == 0)
+ {
+ if ((c->values_num != 2)
+ || (OCONFIG_TYPE_STRING != c->values[0].type)
+ || (OCONFIG_TYPE_STRING != c->values[1].type))
+ {
+ ERROR ("processes plugin: `ProcessMatch' needs exactly "
+ "two string arguments (got %i).",
+ c->values_num);
+ continue;
+ }
- fields_num = strsplit (new_val, fields,
- STATIC_ARRAY_SIZE (fields));
- if (fields_num != 2)
+ if (c->children_num != 0) {
+ WARNING ("processes plugin: the `ProcessMatch' config option "
+ "does not expect any child elements -- ignoring "
+ "content (%i elements) of the <ProcessMatch '%s' '%s'> "
+ "block.", c->children_num, c->values[0].value.string,
+ c->values[1].value.string);
+ }
+
+ ps_list_register (c->values[0].value.string,
+ c->values[1].value.string);
+ }
+ else
{
- ERROR ("processes plugin: `ProcessMatch' needs exactly "
- "two string arguments.");
- sfree (new_val);
- return (1);
+ ERROR ("processes plugin: The `%s' configuration option is not "
+ "understood and will be ignored.", c->key);
+ continue;
}
- ps_list_register (fields[0], fields[1]);
- sfree (new_val);
- }
- else
- {
- ERROR ("processes plugin: The `%s' configuration option is not "
- "understood and will be ignored.", key);
- return (-1);
}
return (0);
char *fields[64];
char fields_len;
- int i;
+ int buffer_len;
- int ppid;
- int name_len;
+ char *buffer_ptr;
+ size_t name_start_pos;
+ size_t name_end_pos;
+ size_t name_len;
long long unsigned cpu_user_counter;
long long unsigned cpu_system_counter;
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);
-
- ppid = atoi (fields[3]);
- *state = fields[2][0];
+ *state = fields[0][0];
if (*state == 'Z')
{
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 = atol (fields[9]);
- ps->vmem_majflt_counter = atol (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
void module_register (void)
{
- plugin_register_config ("processes", ps_config,
- config_keys, config_keys_num);
+ plugin_register_complex_config ("processes", ps_config);
plugin_register_init ("processes", ps_init);
plugin_register_read ("processes", ps_read);
} /* void module_register */