-static procstat_t *ps_read_status (long pid, procstat_t *ps)
-{
- FILE *fh;
- char buffer[1024];
- char filename[64];
- unsigned long lib = 0;
- unsigned long exe = 0;
- unsigned long data = 0;
- unsigned long threads = 0;
- char *fields[8];
- int numfields;
-
- ssnprintf (filename, sizeof (filename), "/proc/%li/status", pid);
- if ((fh = fopen (filename, "r")) == NULL)
- return (NULL);
-
- while (fgets (buffer, sizeof(buffer), fh) != NULL)
- {
- unsigned long tmp;
- char *endptr;
-
- if (strncmp (buffer, "Vm", 2) != 0
- && strncmp (buffer, "Threads", 7) != 0)
- continue;
-
- numfields = strsplit (buffer, fields,
- STATIC_ARRAY_SIZE (fields));
-
- if (numfields < 2)
- continue;
-
- errno = 0;
- endptr = NULL;
- tmp = strtoul (fields[1], &endptr, /* base = */ 10);
- if ((errno == 0) && (endptr != fields[1]))
- {
- if (strncmp (buffer, "VmData", 6) == 0)
- {
- data = tmp;
- }
- else if (strncmp (buffer, "VmLib", 5) == 0)
- {
- lib = tmp;
- }
- else if (strncmp(buffer, "VmExe", 5) == 0)
- {
- exe = tmp;
- }
- else if (strncmp(buffer, "Threads", 7) == 0)
- {
- threads = tmp;
- }
- }
- } /* while (fgets) */
-
- if (fclose (fh))
- {
- char errbuf[1024];
- WARNING ("processes: fclose: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
-
- ps->vmem_data = data * 1024;
- ps->vmem_code = (exe + lib) * 1024;
- if (threads != 0)
- ps->num_lwp = threads;
-
- return (ps);
-} /* procstat_t *ps_read_vmem */
-
-static procstat_t *ps_read_io (long pid, procstat_t *ps)
-{
- FILE *fh;
- char buffer[1024];
- char filename[64];
-
- char *fields[8];
- int numfields;
-
- ssnprintf (filename, sizeof (filename), "/proc/%li/io", pid);
- if ((fh = fopen (filename, "r")) == NULL)
- return (NULL);
-
- while (fgets (buffer, sizeof (buffer), fh) != NULL)
- {
- derive_t *val = NULL;
- long long tmp;
- char *endptr;
-
- if (strncasecmp (buffer, "rchar:", 6) == 0)
- val = &(ps->io_rchar);
- else if (strncasecmp (buffer, "wchar:", 6) == 0)
- val = &(ps->io_wchar);
- else if (strncasecmp (buffer, "syscr:", 6) == 0)
- val = &(ps->io_syscr);
- else if (strncasecmp (buffer, "syscw:", 6) == 0)
- val = &(ps->io_syscw);
- else
- continue;
-
- numfields = strsplit (buffer, fields,
- STATIC_ARRAY_SIZE (fields));
-
- if (numfields < 2)
- continue;
-
- errno = 0;
- endptr = NULL;
- tmp = strtoll (fields[1], &endptr, /* base = */ 10);
- if ((errno != 0) || (endptr == fields[1]))
- *val = -1;
- else
- *val = (derive_t) tmp;
- } /* while (fgets) */
-
- if (fclose (fh))
- {
- char errbuf[1024];
- WARNING ("processes: fclose: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
-
- return (ps);
-} /* procstat_t *ps_read_io */
-
-static int ps_read_process (long pid, procstat_t *ps, char *state)
-{
- char filename[64];
- char buffer[1024];
-
- char *fields[64];
- char fields_len;
-
- size_t buffer_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;
- long long unsigned vmem_size;
- long long unsigned vmem_rss;
- long long unsigned stack_size;
-
- ssize_t status;
-
- memset (ps, 0, sizeof (procstat_t));
-
- ssnprintf (filename, sizeof (filename), "/proc/%li/stat", pid);
-
- status = read_file_contents (filename, buffer, sizeof(buffer) - 1);
- if (status <= 0)
- return (-1);
- buffer_len = (size_t) status;
- 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 (name_start_pos < buffer_len && buffer[name_start_pos] != '(')
- name_start_pos++;
-
- name_end_pos = buffer_len;
- while (name_end_pos > 0 && buffer[name_end_pos] != ')')
- 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)
- {
- ERROR ("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
- name_start_pos, name_end_pos);
- return (-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 ("processes plugin: ps_read_process (pid = %li):"
- " `%s' has only %i fields..",
- pid, filename, fields_len);
- return (-1);
- }
-
- *state = fields[0][0];
-
- if (*state == 'Z')
- {
- ps->num_lwp = 0;
- ps->num_proc = 0;
- }
- else
- {
- ps->num_lwp = strtoul (fields[17], /* endptr = */ NULL, /* base = */ 10);
- if ((ps_read_status(pid, ps)) == NULL)
- {
- /* No VMem data */
- ps->vmem_data = -1;
- ps->vmem_code = -1;
- DEBUG("ps_read_process: did not get vmem data for pid %li", pid);
- }
- if (ps->num_lwp == 0)
- ps->num_lwp = 1;
- ps->num_proc = 1;
- }
-
- /* Leave the rest at zero if this is only a zombi */
- if (ps->num_proc == 0)
- {
- DEBUG ("processes plugin: This is only a zombie: pid = %li; "
- "name = %s;", pid, ps->name);
- return (0);
- }
-
- 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[25]);
- unsigned long long stack_ptr = atoll (fields[26]);
-
- stack_size = (stack_start > stack_ptr)
- ? stack_start - stack_ptr
- : stack_ptr - stack_start;
- }
-
- /* Convert jiffies to useconds */
- cpu_user_counter = cpu_user_counter * 1000000 / CONFIG_HZ;
- cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
- vmem_rss = vmem_rss * pagesize_g;
-
- ps->cpu_user_counter = cpu_user_counter;
- ps->cpu_system_counter = cpu_system_counter;
- ps->vmem_size = (unsigned long) vmem_size;
- ps->vmem_rss = (unsigned long) vmem_rss;
- ps->stack_size = (unsigned long) stack_size;
-
- if ( (ps_read_io (pid, ps)) == NULL)
- {
- /* no io data */
- ps->io_rchar = -1;
- ps->io_wchar = -1;
- ps->io_syscr = -1;
- ps->io_syscw = -1;
-
- DEBUG("ps_read_process: not get io data for pid %li", pid);
- }
-
- if ( report_ctx_switch )
- {
- if ( (ps_read_tasks_status(pid, ps)) == NULL)
- {
- ps->cswitch_vol = -1;
- ps->cswitch_invol = -1;
-
- DEBUG("ps_read_tasks_status: not get context "
- "switch data for pid %li", pid);
- }
- }
-
- /* success */
- return (0);
+static int ps_read_status(long pid, process_entry_t *ps) {
+ FILE *fh;
+ char buffer[1024];
+ char filename[64];
+ unsigned long lib = 0;
+ unsigned long exe = 0;
+ unsigned long data = 0;
+ unsigned long threads = 0;
+ char *fields[8];
+ int numfields;
+
+ snprintf(filename, sizeof(filename), "/proc/%li/status", pid);
+ if ((fh = fopen(filename, "r")) == NULL)
+ return -1;
+
+ while (fgets(buffer, sizeof(buffer), fh) != NULL) {
+ unsigned long tmp;
+ char *endptr;
+
+ if (strncmp(buffer, "Vm", 2) != 0 && strncmp(buffer, "Threads", 7) != 0)
+ continue;
+
+ numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
+
+ if (numfields < 2)
+ continue;
+
+ errno = 0;
+ endptr = NULL;
+ tmp = strtoul(fields[1], &endptr, /* base = */ 10);
+ if ((errno == 0) && (endptr != fields[1])) {
+ if (strncmp(buffer, "VmData", 6) == 0) {
+ data = tmp;
+ } else if (strncmp(buffer, "VmLib", 5) == 0) {
+ lib = tmp;
+ } else if (strncmp(buffer, "VmExe", 5) == 0) {
+ exe = tmp;
+ } else if (strncmp(buffer, "Threads", 7) == 0) {
+ threads = tmp;
+ }
+ }
+ } /* while (fgets) */
+
+ if (fclose(fh)) {
+ char errbuf[1024];
+ WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ }
+
+ ps->vmem_data = data * 1024;
+ ps->vmem_code = (exe + lib) * 1024;
+ if (threads != 0)
+ ps->num_lwp = threads;
+
+ return 0;
+} /* int *ps_read_status */
+
+static int ps_read_io(process_entry_t *ps) {
+ FILE *fh;
+ char buffer[1024];
+ char filename[64];
+
+ char *fields[8];
+ int numfields;
+
+ snprintf(filename, sizeof(filename), "/proc/%li/io", ps->id);
+ if ((fh = fopen(filename, "r")) == NULL) {
+ DEBUG("ps_read_io: Failed to open file `%s'", filename);
+ return -1;
+ }
+
+ while (fgets(buffer, sizeof(buffer), fh) != NULL) {
+ derive_t *val = NULL;
+ long long tmp;
+ char *endptr;
+
+ if (strncasecmp(buffer, "rchar:", 6) == 0)
+ val = &(ps->io_rchar);
+ else if (strncasecmp(buffer, "wchar:", 6) == 0)
+ val = &(ps->io_wchar);
+ else if (strncasecmp(buffer, "syscr:", 6) == 0)
+ val = &(ps->io_syscr);
+ else if (strncasecmp(buffer, "syscw:", 6) == 0)
+ val = &(ps->io_syscw);
+ else if (strncasecmp(buffer, "read_bytes:", 11) == 0)
+ val = &(ps->io_diskr);
+ else if (strncasecmp(buffer, "write_bytes:", 12) == 0)
+ val = &(ps->io_diskw);
+ else
+ continue;
+
+ numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
+
+ if (numfields < 2)
+ continue;
+
+ errno = 0;
+ endptr = NULL;
+ tmp = strtoll(fields[1], &endptr, /* base = */ 10);
+ if ((errno != 0) || (endptr == fields[1]))
+ *val = -1;
+ else
+ *val = (derive_t)tmp;
+ } /* while (fgets) */
+
+ if (fclose(fh)) {
+ char errbuf[1024];
+ WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ }
+ return 0;
+} /* int ps_read_io (...) */
+
+static int ps_count_maps(pid_t pid) {
+ FILE *fh;
+ char buffer[1024];
+ char filename[64];
+ int count = 0;
+
+ snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
+ if ((fh = fopen(filename, "r")) == NULL) {
+ DEBUG("ps_count_maps: Failed to open file `%s'", filename);
+ return -1;
+ }
+
+ while (fgets(buffer, sizeof(buffer), fh) != NULL) {
+ if (strchr(buffer, '\n')) {
+ count++;
+ }
+ } /* while (fgets) */
+
+ if (fclose(fh)) {
+ char errbuf[1024];
+ WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ }
+ return count;
+} /* int ps_count_maps (...) */
+
+static int ps_count_fd(int pid) {
+ char dirname[64];
+ DIR *dh;
+ struct dirent *ent;
+ int count = 0;
+
+ snprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid);
+
+ if ((dh = opendir(dirname)) == NULL) {
+ DEBUG("Failed to open directory `%s'", dirname);
+ return -1;
+ }
+ while ((ent = readdir(dh)) != NULL) {
+ if (!isdigit((int)ent->d_name[0]))
+ continue;
+ else
+ count++;
+ }
+ closedir(dh);
+
+ return (count >= 1) ? count : 1;
+} /* int ps_count_fd (pid) */
+
+static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) {
+ if (entry->has_io == 0) {
+ ps_read_io(entry);
+ entry->has_io = 1;
+ }
+
+ if (ps->report_ctx_switch) {
+ if (entry->has_cswitch == 0) {
+ ps_read_tasks_status(entry);
+ entry->has_cswitch = 1;
+ }
+ }
+
+ if (ps->report_maps_num) {
+ int num_maps;
+ if (entry->has_maps == 0 && (num_maps = ps_count_maps(entry->id)) > 0) {
+ entry->num_maps = num_maps;
+ }
+ entry->has_maps = 1;
+ }
+
+ if (ps->report_fd_num) {
+ int num_fd;
+ if (entry->has_fd == 0 && (num_fd = ps_count_fd(entry->id)) > 0) {
+ entry->num_fd = num_fd;
+ }
+ entry->has_fd = 1;
+ }
+} /* void ps_fill_details (...) */
+
+static int ps_read_process(long pid, process_entry_t *ps, char *state) {
+ char filename[64];
+ char buffer[1024];
+
+ char *fields[64];
+ char fields_len;
+
+ size_t buffer_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;
+ long long unsigned vmem_size;
+ long long unsigned vmem_rss;
+ long long unsigned stack_size;
+
+ ssize_t status;
+
+ snprintf(filename, sizeof(filename), "/proc/%li/stat", pid);
+
+ status = read_file_contents(filename, buffer, sizeof(buffer) - 1);
+ if (status <= 0)
+ return -1;
+ buffer_len = (size_t)status;
+ 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 (name_start_pos < buffer_len && buffer[name_start_pos] != '(')
+ name_start_pos++;
+
+ name_end_pos = buffer_len;
+ while (name_end_pos > 0 && buffer[name_end_pos] != ')')
+ 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) {
+ ERROR("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
+ name_start_pos, name_end_pos);
+ return -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("processes plugin: ps_read_process (pid = %li):"
+ " `%s' has only %i fields..",
+ pid, filename, fields_len);
+ return -1;
+ }
+
+ *state = fields[0][0];
+
+ if (*state == 'Z') {
+ ps->num_lwp = 0;
+ ps->num_proc = 0;
+ } else {
+ ps->num_lwp = strtoul(fields[17], /* endptr = */ NULL, /* base = */ 10);
+ if ((ps_read_status(pid, ps)) != 0) {
+ /* No VMem data */
+ ps->vmem_data = -1;
+ ps->vmem_code = -1;
+ DEBUG("ps_read_process: did not get vmem data for pid %li", pid);
+ }
+ if (ps->num_lwp == 0)
+ ps->num_lwp = 1;
+ ps->num_proc = 1;
+ }
+
+ /* Leave the rest at zero if this is only a zombi */
+ if (ps->num_proc == 0) {
+ DEBUG("processes plugin: This is only a zombie: pid = %li; "
+ "name = %s;",
+ pid, ps->name);
+ return 0;
+ }
+
+ 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[25]);
+ unsigned long long stack_ptr = atoll(fields[26]);
+
+ stack_size = (stack_start > stack_ptr) ? stack_start - stack_ptr
+ : stack_ptr - stack_start;
+ }
+
+ /* Convert jiffies to useconds */
+ cpu_user_counter = cpu_user_counter * 1000000 / CONFIG_HZ;
+ cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
+ vmem_rss = vmem_rss * pagesize_g;
+
+ ps->cpu_user_counter = cpu_user_counter;
+ ps->cpu_system_counter = cpu_system_counter;
+ ps->vmem_size = (unsigned long)vmem_size;
+ ps->vmem_rss = (unsigned long)vmem_rss;
+ ps->stack_size = (unsigned long)stack_size;
+
+ /* no data by default. May be filled by ps_fill_details () */
+ ps->io_rchar = -1;
+ ps->io_wchar = -1;
+ ps->io_syscr = -1;
+ ps->io_syscw = -1;
+ ps->io_diskr = -1;
+ ps->io_diskw = -1;
+
+ ps->cswitch_vol = -1;
+ ps->cswitch_invol = -1;
+
+ /* success */
+ return 0;