no_headings: 1,
no_wrap : 1;
+ dev_t nsfs_dev;
struct libmnt_table *tab;
struct libscols_filter *filter;
snprintf(path, sizeof(path), "ns/%s", nsname);
+ *ino = 0;
if (ul_path_stat(pc, &st, 0, path) != 0)
return -errno;
*ino = st.st_ino;
return -errno;
if (strcmp(nsname, "pid") == 0 || strcmp(nsname, "user") == 0) {
if ((pfd = lsns_ioctl(fd, NS_GET_PARENT)) < 0) {
- if (errno == EPERM)
+ if (errno == EPERM
+ /* On the test platforms, "build (qemu-user, s390x)" and
+ * "build (qemu-user, riscv64)", the ioctl reported ENOSYS.
+ */
+ || errno == ENOSYS)
goto user;
close(fd);
return -errno;
}
user:
if ((ofd = lsns_ioctl(fd, NS_GET_USERNS)) < 0) {
- if (errno == EPERM)
+ if (errno == EPERM
+ /* On the test platforms, "build (qemu-user, s390x)" and
+ * "build (qemu-user, riscv64)", the ioctl reported ENOSYS.
+ */
+ || errno == ENOSYS)
goto out;
close(fd);
return -errno;
}
#endif /* HAVE_LINUX_NET_NAMESPACE_H */
+static struct lsns_namespace *add_namespace_for_nsfd(struct lsns *ls, int fd, ino_t ino);
+
+static void read_open_ns_inos(struct lsns *ls, struct path_cxt *pc)
+{
+ DIR *sub = NULL;
+ struct dirent *d = NULL;
+ char path[sizeof("fd/") + sizeof(stringify_value(UINT64_MAX))];
+
+ while (ul_path_next_dirent(pc, &sub, "fd", &d) == 0) {
+ uint64_t num;
+ struct stat st;
+
+ if (ul_strtou64(d->d_name, &num, 10) != 0) /* only numbers */
+ continue;
+
+ snprintf(path, sizeof(path), "fd/%ju", (uintmax_t) num);
+
+ if (ul_path_stat(pc, &st, 0, path) == 0
+ && st.st_dev == ls->nsfs_dev) {
+ int fd = ul_path_open(pc, O_RDONLY, path);
+ if (fd >= 0) {
+ add_namespace_for_nsfd(ls, fd, st.st_ino);
+ close(fd);
+ }
+ }
+ }
+}
+
static int read_process(struct lsns *ls, struct path_cxt *pc)
{
struct lsns_process *p = NULL;
if (procfs_process_get_uid(pc, &p->uid) == 0)
add_uid(uid_cache, p->uid);
- if ((rc = procfs_process_get_stat(pc, buf, sizeof(buf))) < 0)
+ if ((rc = procfs_process_get_stat(pc, buf, sizeof(buf))) < 0) {
+ DBG(PROC, ul_debug("failed in procfs_process_get_stat() (rc: %d)", rc));
goto done;
- if ((rc = parse_proc_stat(buf, &p->pid, &p->state, &p->ppid)) < 0)
+ }
+ if ((rc = parse_proc_stat(buf, &p->pid, &p->state, &p->ppid)) < 0) {
+ DBG(PROC, ul_debug("failed in parse_proc_stat() (rc: %d)", rc));
goto done;
+ }
rc = 0;
for (i = 0; i < ARRAY_SIZE(p->ns_ids); i++) {
rc = get_ns_ino(pc, ns_names[i], &p->ns_ids[i],
&p->ns_pids[i], &p->ns_oids[i]);
- if (rc && rc != -EACCES && rc != -ENOENT)
+ if (rc && rc != -EACCES && rc != -ENOENT) {
+ DBG(PROC, ul_debug("failed in get_ns_ino (rc: %d)", rc));
goto done;
- if (i == LSNS_ID_NET)
+ }
+ if (p->ns_ids[i] && i == LSNS_ID_NET)
p->netnsid = get_netnsid(pc, p->ns_ids[i]);
rc = 0;
}
DBG(PROC, ul_debugobj(p, "new pid=%d", p->pid));
list_add_tail(&p->processes, &ls->processes);
+
+ read_open_ns_inos(ls, pc);
done:
if (rc)
free(p);
DBG(PROC, ul_debug("reading %d", (int) pid));
rc = procfs_process_init_path(pc, pid);
if (rc < 0) {
- DBG(PROC, ul_debug("failed in reading /proc/%d", (int) pid));
+ DBG(PROC, ul_debug("failed in initializing path_cxt for /proc/%d (rc: %d)", (int) pid, rc));
+ /* This failure is acceptable. If a process ($pid) owning
+ * a namespace is gone while running this lsns process,
+ * procfs_process_init_path(pc, $pid) may fail.
+ *
+ * We must reset this `rc' here. If this `d' is the last
+ * dentry in `dir', this read_processes() invocation
+ * returns this `rc'. In the caller context, the
+ * non-zero value returned from read_processes() makes
+ * lsns prints nothing. We should avoid the behavior. */
+ rc = 0;
continue;
}
rc = read_process(ls, pc);
- if (rc && rc != -EACCES && rc != -ENOENT)
+ if (rc && rc != -EACCES && rc != -ENOENT) {
+ DBG(PROC, ul_debug("failed in read_process() (pid: %d, rc: %d)", (int) pid, rc));
break;
+ }
rc = 0;
}
exit(EXIT_SUCCESS);
}
+static dev_t read_nsfs_dev(void)
+{
+ struct stat st;
+
+ if (stat("/proc/self/ns/user", &st) < 0)
+ err(EXIT_FAILURE, _("failed to do stat /proc/self/ns/user"));
+
+ return st.st_dev;
+}
+
int main(int argc, char *argv[])
{
struct lsns ls;
if (!ls.tab)
err(MNT_EX_FAIL, _("failed to parse %s"), _PATH_PROC_MOUNTINFO);
+ ls.nsfs_dev = read_nsfs_dev();
+
r = read_processes(&ls);
if (!r)
r = read_namespaces(&ls);