2012-01-13 20:52:35 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/stat.h>
|
2012-01-27 21:37:13 +04:00
|
|
|
#include <string.h>
|
2012-05-13 08:30:06 +04:00
|
|
|
#include <linux/fs.h>
|
2012-01-14 01:48:29 +04:00
|
|
|
|
2012-01-13 20:52:35 +04:00
|
|
|
#include "types.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "util.h"
|
2012-01-14 01:48:29 +04:00
|
|
|
#include "crtools.h"
|
2012-08-09 16:27:30 +04:00
|
|
|
#include "mount.h"
|
2012-01-14 01:48:29 +04:00
|
|
|
|
2012-01-13 20:52:35 +04:00
|
|
|
#include "proc_parse.h"
|
2012-07-17 07:25:42 +04:00
|
|
|
#include "protobuf.h"
|
2012-07-19 10:18:37 +04:00
|
|
|
#include "protobuf/fdinfo.pb-c.h"
|
2012-01-13 20:52:35 +04:00
|
|
|
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2012-05-02 15:22:00 +04:00
|
|
|
struct buffer {
|
|
|
|
char buf[PAGE_SIZE];
|
|
|
|
char end; /* '\0' */
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct buffer __buf;
|
|
|
|
static char *buf = __buf.buf;
|
|
|
|
|
|
|
|
#define BUF_SIZE sizeof(__buf.buf)
|
|
|
|
|
2012-05-10 21:07:00 +04:00
|
|
|
/* check the @line starts with "%lx-%lx" format */
|
|
|
|
static bool is_vma_range_fmt(char *line)
|
|
|
|
{
|
|
|
|
while (*line && is_hex_digit(*line))
|
|
|
|
line++;
|
|
|
|
|
|
|
|
if (*line++ != '-')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
while (*line && is_hex_digit(*line))
|
|
|
|
line++;
|
|
|
|
|
|
|
|
if (*line++ != ' ')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_smaps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
|
2012-01-13 20:52:35 +04:00
|
|
|
{
|
|
|
|
struct vma_area *vma_area = NULL;
|
|
|
|
u64 start, end, pgoff;
|
|
|
|
unsigned long ino;
|
2012-08-11 22:19:34 +04:00
|
|
|
char r, w, x, s;
|
2012-01-13 20:52:35 +04:00
|
|
|
int dev_maj, dev_min;
|
2012-03-02 19:28:46 +04:00
|
|
|
int ret = -1, nr = 0;
|
2012-01-13 20:52:35 +04:00
|
|
|
|
|
|
|
DIR *map_files_dir = NULL;
|
2012-05-10 21:07:00 +04:00
|
|
|
FILE *smaps = NULL;
|
2012-01-13 20:52:35 +04:00
|
|
|
|
2012-05-10 21:07:00 +04:00
|
|
|
smaps = fopen_proc(pid, "smaps");
|
|
|
|
if (!smaps)
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (use_map_files) {
|
2012-02-17 01:39:36 +04:00
|
|
|
map_files_dir = opendir_proc(pid, "map_files");
|
2012-02-17 01:39:35 +04:00
|
|
|
if (!map_files_dir) /* old kernel? */
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-05-10 21:07:00 +04:00
|
|
|
while (fgets(buf, BUF_SIZE, smaps)) {
|
2012-01-13 20:52:35 +04:00
|
|
|
int num;
|
2012-02-14 20:19:49 +03:00
|
|
|
char file_path[6];
|
2012-01-13 20:52:35 +04:00
|
|
|
|
2012-05-10 21:07:00 +04:00
|
|
|
if (!is_vma_range_fmt(buf)) {
|
|
|
|
if (!strncmp(buf, "Nonlinear", 9)) {
|
|
|
|
BUG_ON(!vma_area);
|
|
|
|
pr_err("Nonlinear mapping found %016lx-%016lx\n",
|
|
|
|
vma_area->vma.start, vma_area->vma.end);
|
|
|
|
/*
|
|
|
|
* VMA is already on list and will be
|
|
|
|
* freed later as list get destroyed.
|
|
|
|
*/
|
|
|
|
vma_area = NULL;
|
|
|
|
goto err;
|
|
|
|
} else
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
vma_area = alloc_vma_area();
|
|
|
|
if (!vma_area)
|
|
|
|
goto err;
|
2012-02-14 20:19:49 +03:00
|
|
|
|
|
|
|
memset(file_path, 0, 6);
|
2012-05-02 15:22:00 +04:00
|
|
|
num = sscanf(buf, "%lx-%lx %c%c%c%c %lx %02x:%02x %lu %5s",
|
2012-01-13 20:52:35 +04:00
|
|
|
&start, &end, &r, &w, &x, &s, &pgoff, &dev_maj,
|
2012-02-14 20:19:49 +03:00
|
|
|
&dev_min, &ino, file_path);
|
|
|
|
if (num < 10) {
|
2012-05-02 15:22:00 +04:00
|
|
|
pr_err("Can't parse: %s", buf);
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (map_files_dir) {
|
|
|
|
char path[32];
|
|
|
|
|
|
|
|
/* Figure out if it's file mapping */
|
|
|
|
snprintf(path, sizeof(path), "%lx-%lx", start, end);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that we "open" it in dumper process space
|
|
|
|
* so later we might refer to it via /proc/self/fd/vm_file_fd
|
|
|
|
* if needed.
|
|
|
|
*/
|
|
|
|
vma_area->vm_file_fd = openat(dirfd(map_files_dir), path, O_RDONLY);
|
|
|
|
if (vma_area->vm_file_fd < 0) {
|
|
|
|
if (errno != ENOENT) {
|
2012-02-01 02:08:04 +04:00
|
|
|
pr_perror("Can't open %d's map %lu", pid, start);
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vma_area->vma.start = start;
|
|
|
|
vma_area->vma.end = end;
|
|
|
|
vma_area->vma.pgoff = pgoff;
|
|
|
|
vma_area->vma.prot = PROT_NONE;
|
|
|
|
|
|
|
|
if (r == 'r')
|
|
|
|
vma_area->vma.prot |= PROT_READ;
|
|
|
|
if (w == 'w')
|
|
|
|
vma_area->vma.prot |= PROT_WRITE;
|
|
|
|
if (x == 'x')
|
|
|
|
vma_area->vma.prot |= PROT_EXEC;
|
|
|
|
|
|
|
|
if (s == 's')
|
|
|
|
vma_area->vma.flags = MAP_SHARED;
|
|
|
|
else if (s == 'p')
|
|
|
|
vma_area->vma.flags = MAP_PRIVATE;
|
2012-03-03 19:35:10 +03:00
|
|
|
else {
|
|
|
|
pr_err("Unexpected VMA met (%c)\n", s);
|
|
|
|
goto err;
|
|
|
|
}
|
2012-01-13 20:52:35 +04:00
|
|
|
|
2012-09-07 18:21:04 +04:00
|
|
|
if (strstr(buf, "[vsyscall]")) {
|
2012-01-13 20:52:35 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_VSYSCALL;
|
2012-05-02 15:22:00 +04:00
|
|
|
} else if (strstr(buf, "[vdso]")) {
|
2012-01-13 20:52:35 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
|
2012-05-02 15:22:00 +04:00
|
|
|
} else if (strstr(buf, "[heap]")) {
|
2012-01-13 20:52:35 +04:00
|
|
|
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_HEAP;
|
|
|
|
} else {
|
|
|
|
vma_area->vma.status = VMA_AREA_REGULAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some mapping hints for restore, we save this on
|
|
|
|
* disk and restore might need to analyze it.
|
|
|
|
*/
|
|
|
|
if (vma_area->vm_file_fd >= 0) {
|
2012-03-17 01:22:18 +04:00
|
|
|
struct stat st_buf;
|
2012-01-13 20:52:35 +04:00
|
|
|
|
|
|
|
if (fstat(vma_area->vm_file_fd, &st_buf) < 0) {
|
2012-01-31 15:31:23 +04:00
|
|
|
pr_perror("Failed fstat on %d's map %lu", pid, start);
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!S_ISREG(st_buf.st_mode)) {
|
2012-01-31 15:31:23 +04:00
|
|
|
pr_err("Can't handle non-regular mapping on %d's map %lu\n", pid, start);
|
2012-01-13 20:52:35 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* /dev/zero stands for anon-shared mapping
|
|
|
|
* otherwise it's some file mapping.
|
|
|
|
*/
|
|
|
|
if (MAJOR(st_buf.st_dev) == 0) {
|
|
|
|
if (!(vma_area->vma.flags & MAP_SHARED))
|
|
|
|
goto err_bogus_mapping;
|
|
|
|
vma_area->vma.flags |= MAP_ANONYMOUS;
|
|
|
|
vma_area->vma.status |= VMA_ANON_SHARED;
|
2012-03-21 10:11:00 +04:00
|
|
|
vma_area->vma.shmid = st_buf.st_ino;
|
2012-02-14 20:19:49 +03:00
|
|
|
|
|
|
|
if (!strcmp(file_path, "/SYSV")) {
|
2012-03-17 01:22:18 +04:00
|
|
|
pr_info("path: %s\n", file_path);
|
2012-02-14 20:19:49 +03:00
|
|
|
vma_area->vma.status |= VMA_AREA_SYSVIPC;
|
|
|
|
}
|
2012-01-13 20:52:35 +04:00
|
|
|
} else {
|
|
|
|
if (vma_area->vma.flags & MAP_PRIVATE)
|
|
|
|
vma_area->vma.status |= VMA_FILE_PRIVATE;
|
|
|
|
else
|
|
|
|
vma_area->vma.status |= VMA_FILE_SHARED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No file but mapping -- anonymous one.
|
|
|
|
*/
|
|
|
|
if (vma_area->vma.flags & MAP_SHARED) {
|
|
|
|
vma_area->vma.status |= VMA_ANON_SHARED;
|
2012-03-21 10:11:00 +04:00
|
|
|
vma_area->vma.shmid = ino;
|
2012-01-13 20:52:35 +04:00
|
|
|
} else {
|
|
|
|
vma_area->vma.status |= VMA_ANON_PRIVATE;
|
|
|
|
}
|
|
|
|
vma_area->vma.flags |= MAP_ANONYMOUS;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_tail(&vma_area->list, vma_area_list);
|
2012-03-02 19:28:46 +04:00
|
|
|
nr++;
|
2012-01-13 20:52:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
vma_area = NULL;
|
2012-03-02 19:28:46 +04:00
|
|
|
ret = nr;
|
2012-01-13 20:52:35 +04:00
|
|
|
|
|
|
|
err:
|
2012-05-10 21:07:00 +04:00
|
|
|
if (smaps)
|
|
|
|
fclose(smaps);
|
2012-01-13 20:52:35 +04:00
|
|
|
|
|
|
|
if (map_files_dir)
|
|
|
|
closedir(map_files_dir);
|
|
|
|
|
|
|
|
xfree(vma_area);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err_bogus_mapping:
|
2012-04-24 15:20:24 +04:00
|
|
|
pr_err("Bogus mapping 0x%lx-0x%lx (flags: %#x vm_file_fd: %d)\n",
|
2012-01-13 20:52:35 +04:00
|
|
|
vma_area->vma.start, vma_area->vma.end,
|
|
|
|
vma_area->vma.flags, vma_area->vm_file_fd);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s)
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
{
|
2012-04-17 11:41:00 +04:00
|
|
|
char *tok, *p;
|
|
|
|
int fd;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
int n;
|
|
|
|
|
2012-04-17 11:41:00 +04:00
|
|
|
fd = open_proc(pid, "stat");
|
|
|
|
if (fd < 0)
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-05-02 15:22:00 +04:00
|
|
|
n = read(fd, buf, BUF_SIZE);
|
2012-04-17 11:41:00 +04:00
|
|
|
if (n < 1) {
|
|
|
|
pr_err("stat for %d is corrupted\n", pid);
|
|
|
|
close(fd);
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-04-17 11:41:00 +04:00
|
|
|
close(fd);
|
|
|
|
|
|
|
|
memset(s, 0, sizeof(*s));
|
|
|
|
|
|
|
|
tok = strchr(buf, ' ');
|
|
|
|
if (!tok)
|
|
|
|
goto err;
|
|
|
|
*tok++ = '\0';
|
|
|
|
if (*tok != '(')
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
s->pid = atoi(buf);
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
|
2012-04-17 11:41:00 +04:00
|
|
|
p = strrchr(tok + 1, ')');
|
|
|
|
if (!p)
|
|
|
|
goto err;
|
|
|
|
*tok = '\0';
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
strncpy(s->comm, tok + 1, sizeof(s->comm));
|
|
|
|
|
|
|
|
n = sscanf(p + 1, " %c %d %d %d", &s->state, &s->ppid, &s->pgid, &s->sid);
|
|
|
|
if (n < 4)
|
|
|
|
goto err;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
|
|
|
|
return 0;
|
2012-04-17 11:41:00 +04:00
|
|
|
|
|
|
|
err:
|
|
|
|
pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
|
|
|
|
return -1;
|
ctrools: Rewrite task/threads stopping engine is back
This commit brings the former "Rewrite task/threads stopping engine"
commit back. Handling it separately is too complex so better try
to handle it in-place.
Note some tests might fault, it's expected.
---
Stopping tasks with STOP and proceeding with SEIZE is actually excessive --
the SEIZE if enough. Moreover, just killing a task with STOP is also racy,
since task should be given some time to come to sleep before its proc
can be parsed.
Rewrite all this code to SEIZE task and all its threads from the very beginning.
With this we can distinguish stopped task state and migrate it properly (not
supported now, need to implement).
This thing however has one BIG problem -- after we SEIZE-d a task we should
seize
it's threads, but we should do it in a loop -- reading /proc/pid/task and
seizing
them again and again, until the contents of this dir stops changing (not done
now).
Besides, after we seized a task and all its threads we cannot scan it's children
list once -- task can get reparented to init and any task's child can call clone
with CLONE_PARENT flag thus repopulating the children list of the already seized
task (not done also)
This patch is ugly, yes, but splitting it doesn't help to review it much, sorry
:(
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-02-01 19:45:31 +04:00
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
int parse_pid_stat(pid_t pid, struct proc_pid_stat *s)
|
2012-01-13 20:54:08 +04:00
|
|
|
{
|
2012-04-17 11:41:00 +04:00
|
|
|
char *tok, *p;
|
|
|
|
int fd;
|
2012-01-15 02:20:57 +04:00
|
|
|
int n;
|
2012-01-13 20:54:08 +04:00
|
|
|
|
2012-04-17 11:41:00 +04:00
|
|
|
fd = open_proc(pid, "stat");
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-05-02 15:22:00 +04:00
|
|
|
n = read(fd, buf, BUF_SIZE);
|
2012-04-17 11:41:00 +04:00
|
|
|
if (n < 1) {
|
|
|
|
pr_err("stat for %d is corrupted\n", pid);
|
|
|
|
close(fd);
|
2012-01-13 20:54:08 +04:00
|
|
|
return -1;
|
2012-04-17 11:41:00 +04:00
|
|
|
}
|
|
|
|
close(fd);
|
2012-01-13 20:54:08 +04:00
|
|
|
|
|
|
|
memset(s, 0, sizeof(*s));
|
2012-04-17 11:41:00 +04:00
|
|
|
|
|
|
|
tok = strchr(buf, ' ');
|
|
|
|
if (!tok)
|
|
|
|
goto err;
|
|
|
|
*tok++ = '\0';
|
|
|
|
if (*tok != '(')
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
s->pid = atoi(buf);
|
|
|
|
|
|
|
|
p = strrchr(tok + 1, ')');
|
|
|
|
if (!p)
|
|
|
|
goto err;
|
|
|
|
*tok = '\0';
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
strncpy(s->comm, tok + 1, sizeof(s->comm));
|
|
|
|
|
|
|
|
n = sscanf(p + 1,
|
|
|
|
" %c %d %d %d %d %d %u %lu %lu %lu %lu "
|
2012-01-14 01:58:36 +04:00
|
|
|
"%lu %lu %ld %ld %ld %ld %d %d %llu %lu %ld %lu %lu %lu %lu "
|
|
|
|
"%lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld "
|
2012-01-23 15:18:31 +04:00
|
|
|
"%lu %lu %lu %lu %lu %lu %lu %d",
|
2012-01-13 20:54:08 +04:00
|
|
|
&s->state,
|
|
|
|
&s->ppid,
|
|
|
|
&s->pgid,
|
|
|
|
&s->sid,
|
|
|
|
&s->tty_nr,
|
|
|
|
&s->tty_pgrp,
|
|
|
|
&s->flags,
|
|
|
|
&s->min_flt,
|
|
|
|
&s->cmin_flt,
|
|
|
|
&s->maj_flt,
|
|
|
|
&s->cmaj_flt,
|
|
|
|
&s->utime,
|
|
|
|
&s->stime,
|
|
|
|
&s->cutime,
|
|
|
|
&s->cstime,
|
|
|
|
&s->priority,
|
|
|
|
&s->nice,
|
|
|
|
&s->num_threads,
|
|
|
|
&s->zero0,
|
|
|
|
&s->start_time,
|
|
|
|
&s->vsize,
|
|
|
|
&s->mm_rss,
|
|
|
|
&s->rsslim,
|
|
|
|
&s->start_code,
|
|
|
|
&s->end_code,
|
|
|
|
&s->start_stack,
|
|
|
|
&s->esp,
|
|
|
|
&s->eip,
|
|
|
|
&s->sig_pending,
|
|
|
|
&s->sig_blocked,
|
|
|
|
&s->sig_ignored,
|
|
|
|
&s->sig_handled,
|
|
|
|
&s->wchan,
|
|
|
|
&s->zero1,
|
|
|
|
&s->zero2,
|
|
|
|
&s->exit_signal,
|
|
|
|
&s->task_cpu,
|
|
|
|
&s->rt_priority,
|
|
|
|
&s->policy,
|
|
|
|
&s->delayacct_blkio_ticks,
|
|
|
|
&s->gtime,
|
|
|
|
&s->cgtime,
|
|
|
|
&s->start_data,
|
|
|
|
&s->end_data,
|
2012-01-22 20:22:40 +04:00
|
|
|
&s->start_brk,
|
2012-01-23 15:18:31 +04:00
|
|
|
&s->arg_start,
|
|
|
|
&s->arg_end,
|
|
|
|
&s->env_start,
|
|
|
|
&s->env_end,
|
2012-01-22 20:22:40 +04:00
|
|
|
&s->exit_code);
|
2012-04-17 11:41:00 +04:00
|
|
|
if (n < 50)
|
|
|
|
goto err;
|
2012-01-14 01:48:29 +04:00
|
|
|
|
2012-01-13 20:54:08 +04:00
|
|
|
return 0;
|
2012-04-17 11:41:00 +04:00
|
|
|
|
|
|
|
err:
|
|
|
|
pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
|
|
|
|
return -1;
|
2012-01-13 20:54:08 +04:00
|
|
|
}
|
2012-01-27 21:37:13 +04:00
|
|
|
|
|
|
|
static int ids_parse(char *str, unsigned int *arr)
|
|
|
|
{
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
arr[0] = strtol(str, &end, 10);
|
|
|
|
arr[1] = strtol(end + 1, &end, 10);
|
|
|
|
arr[2] = strtol(end + 1, &end, 10);
|
|
|
|
arr[3] = strtol(end + 1, &end, 10);
|
|
|
|
if (*end != '\n')
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cap_parse(char *str, unsigned int *res)
|
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
for (i = 0; i < PROC_CAP_SIZE; i++) {
|
|
|
|
ret = sscanf(str, "%08x", &res[PROC_CAP_SIZE - 1 - i]);
|
|
|
|
if (ret != 1)
|
|
|
|
return -1;
|
|
|
|
str += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
int parse_pid_status(pid_t pid, struct proc_status_creds *cr)
|
2012-01-27 21:37:13 +04:00
|
|
|
{
|
|
|
|
int done = 0;
|
|
|
|
FILE *f;
|
|
|
|
char str[64];
|
|
|
|
|
2012-02-17 01:39:36 +04:00
|
|
|
f = fopen_proc(pid, "status");
|
2012-01-27 21:37:13 +04:00
|
|
|
if (f == NULL) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't open proc status");
|
2012-01-27 21:37:13 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (done < 6 && fgets(str, sizeof(str), f)) {
|
|
|
|
if (!strncmp(str, "Uid:", 4)) {
|
|
|
|
if (ids_parse(str + 5, cr->uids))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(str, "Gid:", 4)) {
|
|
|
|
if (ids_parse(str + 5, cr->gids))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(str, "CapInh:", 7)) {
|
|
|
|
if (cap_parse(str + 8, cr->cap_inh))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(str, "CapEff:", 7)) {
|
|
|
|
if (cap_parse(str + 8, cr->cap_eff))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(str, "CapPrm:", 7)) {
|
|
|
|
if (cap_parse(str + 8, cr->cap_prm))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(str, "CapBnd:", 7)) {
|
|
|
|
if (cap_parse(str + 8, cr->cap_bnd))
|
|
|
|
goto err_parse;
|
|
|
|
|
|
|
|
done++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (done != 6) {
|
|
|
|
err_parse:
|
|
|
|
pr_err("Error parsing proc status file\n");
|
|
|
|
fclose(f);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-05-13 08:30:06 +04:00
|
|
|
struct opt2flag {
|
|
|
|
char *opt;
|
|
|
|
unsigned flag;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int do_opt2flag(char *opt, unsigned *flags,
|
|
|
|
const struct opt2flag *opts, char *unknown)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
end = strchr(opt, ',');
|
|
|
|
if (end)
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
for (i = 0; opts[i].opt != NULL; i++)
|
|
|
|
if (!strcmp(opts[i].opt, opt)) {
|
|
|
|
(*flags) |= opts[i].flag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts[i].opt == NULL) {
|
|
|
|
if (!unknown) {
|
|
|
|
pr_err("Unknown option [%s]\n", opt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(unknown, opt);
|
|
|
|
unknown += strlen(opt);
|
|
|
|
*unknown = ',';
|
|
|
|
unknown++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!end) {
|
|
|
|
if (unknown)
|
|
|
|
*unknown = '\0';
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
opt = end + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_mnt_flags(char *opt, unsigned *flags)
|
|
|
|
{
|
|
|
|
const struct opt2flag mnt_opt2flag[] = {
|
|
|
|
{ "rw", 0, },
|
|
|
|
{ "ro", MS_RDONLY, },
|
|
|
|
{ "nosuid", MS_NOSUID, },
|
|
|
|
{ "nodev", MS_NODEV, } ,
|
|
|
|
{ "noexec", MS_NOEXEC, },
|
|
|
|
{ "noatime", MS_NOATIME, },
|
|
|
|
{ "nodiratime", MS_NODIRATIME, },
|
|
|
|
{ "relatime", MS_RELATIME, },
|
|
|
|
{ },
|
|
|
|
};
|
|
|
|
|
|
|
|
return do_opt2flag(opt, flags, mnt_opt2flag, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_sb_opt(char *opt, unsigned *flags, char *uopt)
|
|
|
|
{
|
|
|
|
const struct opt2flag sb_opt2flag[] = {
|
|
|
|
{ "rw", 0, },
|
|
|
|
{ "ro", MS_RDONLY, },
|
|
|
|
{ "sync", MS_SYNC, },
|
|
|
|
{ "dirsync", MS_DIRSYNC, },
|
|
|
|
{ "mad", MS_MANDLOCK, },
|
|
|
|
{ },
|
|
|
|
};
|
|
|
|
|
|
|
|
return do_opt2flag(opt, flags, sb_opt2flag, uopt);
|
|
|
|
}
|
|
|
|
|
2012-06-27 20:57:30 +04:00
|
|
|
static int parse_mnt_opt(char *str, struct mount_info *mi, int *off)
|
2012-05-13 08:30:06 +04:00
|
|
|
{
|
|
|
|
char *istr = str, *end;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
end = strchr(str, ' ');
|
|
|
|
if (!end) {
|
|
|
|
pr_err("Error parsing mount options");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*end = '\0';
|
|
|
|
if (!strncmp(str, "-", 1))
|
|
|
|
break;
|
|
|
|
else if (!strncmp(str, "shared:", 7)) {
|
|
|
|
mi->flags |= MS_SHARED;
|
|
|
|
mi->shared_id = atoi(str + 7);
|
|
|
|
} else if (!strncmp(str, "master:", 7)) {
|
|
|
|
mi->flags |= MS_SLAVE;
|
|
|
|
mi->master_id = atoi(str + 7);
|
|
|
|
} else if (!strncmp(str, "propagate_from:", 15)) {
|
|
|
|
/* skip */;
|
|
|
|
} else if (!strncmp(str, "unbindable", 11))
|
|
|
|
mi->flags |= MS_UNBINDABLE;
|
|
|
|
else {
|
|
|
|
pr_err("Unknown option [%s]\n", str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
str = end + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*off = end - istr + 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-27 20:57:30 +04:00
|
|
|
static int parse_mountinfo_ent(char *str, struct mount_info *new)
|
2012-05-13 03:41:56 +04:00
|
|
|
{
|
|
|
|
unsigned int kmaj, kmin;
|
2012-05-13 08:30:06 +04:00
|
|
|
int ret, n;
|
2012-06-27 20:57:29 +04:00
|
|
|
char *opt;
|
2012-08-09 16:27:30 +04:00
|
|
|
char *fstype;
|
2012-05-13 03:41:56 +04:00
|
|
|
|
2012-06-27 20:57:29 +04:00
|
|
|
ret = sscanf(str, "%i %i %u:%u %ms %ms %ms %n",
|
2012-05-13 03:41:56 +04:00
|
|
|
&new->mnt_id, &new->parent_mnt_id,
|
2012-06-27 20:57:29 +04:00
|
|
|
&kmaj, &kmin, &new->root, &new->mountpoint,
|
|
|
|
&opt, &n);
|
2012-05-13 08:30:06 +04:00
|
|
|
if (ret != 7)
|
2012-05-13 03:41:56 +04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
new->s_dev = MKKDEV(kmaj, kmin);
|
2012-05-13 08:30:06 +04:00
|
|
|
new->flags = 0;
|
|
|
|
if (parse_mnt_flags(opt, &new->flags))
|
|
|
|
return -1;
|
|
|
|
|
2012-06-27 20:57:29 +04:00
|
|
|
free(opt); /* after %ms scanf */
|
|
|
|
|
2012-05-13 08:30:06 +04:00
|
|
|
str += n;
|
|
|
|
if (parse_mnt_opt(str, new, &n))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
str += n;
|
2012-08-09 16:27:30 +04:00
|
|
|
ret = sscanf(str, "%ms %ms %ms", &fstype, &new->source, &opt);
|
2012-05-13 08:30:06 +04:00
|
|
|
if (ret != 3)
|
|
|
|
return -1;
|
|
|
|
|
2012-08-09 16:27:30 +04:00
|
|
|
new->fstype = find_fstype_by_name(fstype);
|
|
|
|
free(fstype);
|
|
|
|
|
2012-06-27 20:57:29 +04:00
|
|
|
new->options = xmalloc(strlen(opt));
|
|
|
|
if (!new->options)
|
|
|
|
return -1;
|
|
|
|
|
2012-05-13 08:30:06 +04:00
|
|
|
if (parse_sb_opt(opt, &new->flags, new->options))
|
|
|
|
return -1;
|
|
|
|
|
2012-06-27 20:57:29 +04:00
|
|
|
free(opt);
|
|
|
|
|
2012-05-13 03:41:56 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-27 20:57:30 +04:00
|
|
|
struct mount_info *parse_mountinfo(pid_t pid)
|
2012-05-04 13:38:00 +04:00
|
|
|
{
|
2012-06-27 20:57:30 +04:00
|
|
|
struct mount_info *list = NULL;
|
2012-05-13 00:07:11 +04:00
|
|
|
FILE *f;
|
2012-05-04 13:38:00 +04:00
|
|
|
char str[256];
|
|
|
|
|
|
|
|
snprintf(str, sizeof(str), "/proc/%d/mountinfo", pid);
|
|
|
|
f = fopen(str, "r");
|
|
|
|
if (!f) {
|
|
|
|
pr_perror("Can't open %d mountinfo", pid);
|
2012-05-13 00:07:11 +04:00
|
|
|
return NULL;
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(str, sizeof(str), f)) {
|
2012-06-27 20:57:30 +04:00
|
|
|
struct mount_info *new;
|
2012-05-04 13:38:00 +04:00
|
|
|
int ret;
|
|
|
|
|
2012-05-13 00:07:11 +04:00
|
|
|
new = xmalloc(sizeof(*new));
|
|
|
|
if (!new)
|
|
|
|
goto err;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-06-27 20:57:34 +04:00
|
|
|
mnt_entry_init(new);
|
|
|
|
|
2012-05-13 03:41:56 +04:00
|
|
|
ret = parse_mountinfo_ent(str, new);
|
|
|
|
if (ret < 0) {
|
2012-05-04 13:38:00 +04:00
|
|
|
pr_err("Bad format in %d mountinfo\n", pid);
|
2012-05-13 00:07:11 +04:00
|
|
|
goto err;
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
2012-05-13 08:30:06 +04:00
|
|
|
pr_info("\ttype %s source %s %x %s @ %s flags %x options %s\n",
|
2012-08-09 16:27:30 +04:00
|
|
|
new->fstype->name, new->source,
|
2012-05-13 08:30:06 +04:00
|
|
|
new->s_dev, new->root, new->mountpoint,
|
|
|
|
new->flags, new->options);
|
|
|
|
|
2012-05-13 00:07:11 +04:00
|
|
|
new->next = list;
|
|
|
|
list = new;
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
out:
|
2012-05-13 00:07:11 +04:00
|
|
|
fclose(f);
|
|
|
|
return list;
|
|
|
|
|
|
|
|
err:
|
|
|
|
while (list) {
|
2012-06-27 20:57:30 +04:00
|
|
|
struct mount_info *next = list->next;
|
2012-05-13 00:07:11 +04:00
|
|
|
xfree(list);
|
|
|
|
list = next;
|
|
|
|
}
|
|
|
|
goto out;
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
2012-07-11 09:22:38 +04:00
|
|
|
|
2012-07-11 09:35:36 +04:00
|
|
|
static char nybble(const char n)
|
|
|
|
{
|
2012-08-11 22:03:11 +04:00
|
|
|
if (n >= '0' && n <= '9')
|
|
|
|
return n - '0';
|
|
|
|
else if (n >= 'A' && n <= 'F')
|
|
|
|
return n - ('A' - 10);
|
|
|
|
else if (n >= 'a' && n <= 'f')
|
|
|
|
return n - ('a' - 10);
|
2012-08-11 21:36:03 +04:00
|
|
|
return 0;
|
2012-07-11 09:35:36 +04:00
|
|
|
}
|
|
|
|
|
2012-07-17 07:25:42 +04:00
|
|
|
static void parse_fhandle_encoded(char *tok, FhEntry *fh)
|
2012-07-11 09:35:36 +04:00
|
|
|
{
|
2012-07-17 07:25:42 +04:00
|
|
|
char *d = (char *)fh->handle;
|
2012-07-11 09:35:36 +04:00
|
|
|
int i = 0;
|
|
|
|
|
2012-07-17 07:25:42 +04:00
|
|
|
memzero(d, pb_repeated_size(fh, handle));
|
2012-07-11 09:35:36 +04:00
|
|
|
|
|
|
|
while (*tok == ' ')
|
|
|
|
tok++;
|
|
|
|
|
|
|
|
while (*tok) {
|
2012-07-17 07:25:42 +04:00
|
|
|
if (i >= pb_repeated_size(fh, handle))
|
2012-07-11 09:35:36 +04:00
|
|
|
break;
|
|
|
|
d[i++] = (nybble(tok[0]) << 4) | nybble(tok[1]);
|
|
|
|
if (tok[1])
|
|
|
|
tok += 2;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-11 09:22:38 +04:00
|
|
|
#define fdinfo_field(str, field) !strncmp(str, field":", sizeof(field))
|
|
|
|
|
|
|
|
int parse_fdinfo(int fd, int type,
|
|
|
|
int (*cb)(union fdinfo_entries *e, void *arg), void *arg)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char str[256];
|
2012-08-01 07:41:19 +04:00
|
|
|
bool entry_met = false;
|
2012-07-11 09:22:38 +04:00
|
|
|
|
|
|
|
sprintf(str, "/proc/self/fdinfo/%d", fd);
|
|
|
|
f = fopen(str, "r");
|
|
|
|
if (!f) {
|
|
|
|
pr_perror("Can't open fdinfo to parse");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(str, sizeof(str), f)) {
|
|
|
|
int ret;
|
|
|
|
union fdinfo_entries entry;
|
|
|
|
|
|
|
|
if (fdinfo_field(str, "pos") || fdinfo_field(str, "counter"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fdinfo_field(str, "eventfd-count")) {
|
2012-07-17 07:24:54 +04:00
|
|
|
eventfd_file_entry__init(&entry.efd);
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
if (type != FD_TYPES__EVENTFD)
|
2012-07-11 09:22:38 +04:00
|
|
|
goto parse_err;
|
|
|
|
ret = sscanf(str, "eventfd-count: %lx",
|
|
|
|
&entry.efd.counter);
|
|
|
|
if (ret != 1)
|
|
|
|
goto parse_err;
|
|
|
|
ret = cb(&entry, arg);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2012-08-01 07:41:19 +04:00
|
|
|
|
|
|
|
entry_met = true;
|
2012-07-11 09:22:38 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (fdinfo_field(str, "tfd")) {
|
2012-07-17 07:25:40 +04:00
|
|
|
eventpoll_tfd_entry__init(&entry.epl);
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
if (type != FD_TYPES__EVENTPOLL)
|
2012-07-11 09:22:38 +04:00
|
|
|
goto parse_err;
|
|
|
|
ret = sscanf(str, "tfd: %d events: %x data: %lx",
|
|
|
|
&entry.epl.tfd, &entry.epl.events, &entry.epl.data);
|
|
|
|
if (ret != 3)
|
|
|
|
goto parse_err;
|
|
|
|
ret = cb(&entry, arg);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2012-08-01 07:41:19 +04:00
|
|
|
|
|
|
|
entry_met = true;
|
2012-07-11 09:22:38 +04:00
|
|
|
continue;
|
|
|
|
}
|
2012-08-02 12:25:18 +04:00
|
|
|
if (fdinfo_field(str, "sigmask")) {
|
|
|
|
signalfd_entry__init(&entry.sfd);
|
|
|
|
|
|
|
|
if (type != FD_TYPES__SIGNALFD)
|
|
|
|
goto parse_err;
|
|
|
|
ret = sscanf(str, "sigmask: %Lx",
|
|
|
|
(unsigned long long *)&entry.sfd.sigmask);
|
|
|
|
if (ret != 1)
|
|
|
|
goto parse_err;
|
|
|
|
ret = cb(&entry, arg);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
entry_met = true;
|
|
|
|
continue;
|
|
|
|
}
|
2012-07-11 09:35:36 +04:00
|
|
|
if (fdinfo_field(str, "inotify wd")) {
|
2012-07-17 07:25:42 +04:00
|
|
|
FhEntry f_handle = FH_ENTRY__INIT;
|
2012-07-11 09:35:36 +04:00
|
|
|
int hoff;
|
|
|
|
|
2012-07-17 07:25:42 +04:00
|
|
|
inotify_wd_entry__init(&entry.ify);
|
|
|
|
entry.ify.f_handle = &f_handle;
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
if (type != FD_TYPES__INOTIFY)
|
2012-07-11 09:35:36 +04:00
|
|
|
goto parse_err;
|
|
|
|
ret = sscanf(str,
|
|
|
|
"inotify wd: %8d ino: %16lx sdev: %8x "
|
|
|
|
"mask: %8x ignored_mask: %8x "
|
|
|
|
"fhandle-bytes: %8x fhandle-type: %8x "
|
|
|
|
"f_handle: %n",
|
|
|
|
&entry.ify.wd, &entry.ify.i_ino, &entry.ify.s_dev,
|
|
|
|
&entry.ify.mask, &entry.ify.ignored_mask,
|
2012-07-17 07:25:42 +04:00
|
|
|
&entry.ify.f_handle->bytes, &entry.ify.f_handle->type,
|
2012-07-11 09:35:36 +04:00
|
|
|
&hoff);
|
|
|
|
if (ret != 7)
|
|
|
|
goto parse_err;
|
2012-07-17 07:25:42 +04:00
|
|
|
|
|
|
|
f_handle.n_handle = FH_ENTRY_SIZES__min_entries;
|
|
|
|
f_handle.handle = xmalloc(pb_repeated_size(&f_handle, handle));
|
|
|
|
if (!f_handle.handle)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
parse_fhandle_encoded(str + hoff, entry.ify.f_handle);
|
2012-07-11 09:35:36 +04:00
|
|
|
|
|
|
|
ret = cb(&entry, arg);
|
2012-07-17 07:25:42 +04:00
|
|
|
|
|
|
|
xfree(f_handle.handle);
|
|
|
|
|
2012-07-11 09:35:36 +04:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2012-08-01 07:41:19 +04:00
|
|
|
|
|
|
|
entry_met = true;
|
2012-07-11 09:35:36 +04:00
|
|
|
continue;
|
|
|
|
}
|
2012-07-11 09:22:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
2012-08-01 07:41:19 +04:00
|
|
|
if (!entry_met) {
|
|
|
|
pr_err("No records of type %d found in fdinfo file\n", type);
|
|
|
|
goto parse_err;
|
|
|
|
}
|
|
|
|
|
2012-07-11 09:22:38 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
parse_err:
|
|
|
|
pr_perror("%s: error parsing [%s] for %d\n", __func__, str, type);
|
|
|
|
return -1;
|
|
|
|
}
|