extern int procfs_process_get_uid(struct path_cxt *pc, uid_t *uid);
extern ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t bufsz);
extern ssize_t procfs_process_get_cmdname(struct path_cxt *pc, char *buf, size_t bufsz);
+extern ssize_t procfs_process_get_stat(struct path_cxt *pc, char *buf, size_t bufsz);
static inline ssize_t procfs_process_get_exe(struct path_cxt *pc, char *buf, size_t bufsz)
return sz;
}
-ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t bufsz)
+static ssize_t procfs_process_get_line_for(struct path_cxt *pc, char *buf, size_t bufsz,
+ const char *fname)
{
- int fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, "cmdline");
+ int fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, fname);
if (fd >= 0) {
ssize_t sz = read_procfs_file(fd, buf, bufsz);
return -errno;
}
+ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t bufsz)
+{
+ return procfs_process_get_line_for(pc, buf, bufsz, "cmdline");
+}
+
ssize_t procfs_process_get_cmdname(struct path_cxt *pc, char *buf, size_t bufsz)
{
- int fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, "comm");
+ return procfs_process_get_line_for(pc, buf, bufsz, "comm");
+}
- if (fd >= 0) {
- ssize_t sz = read_procfs_file(fd, buf, bufsz);
- close(fd);
- return sz;
- }
- return -errno;
+ssize_t procfs_process_get_stat(struct path_cxt *pc, char *buf, size_t bufsz)
+{
+ return procfs_process_get_line_for(pc, buf, bufsz, "stat");
}
int procfs_process_get_uid(struct path_cxt *pc, uid_t *uid)
case COL_DELETED:
xasprintf(&str, "%d", file->stat.st_nlink == 0);
break;
+ case COL_KTHREAD:
+ xasprintf(&str, "%u", proc->kthread);
+ break;
case COL_MNT_ID:
xasprintf(&str, "%d", file->association < 0? 0: file->mnt_id);
break;
INODE <__number__>::
Inode number.
+KTHREAD <__boolean__>::
+Whether the process is a kernel thread or not.
+
MAJ:MIN <__string__>::
Device ID for special, or ID of device containing file.
#include <unistd.h>
#include <getopt.h>
+#include <linux/sched.h>
#include <sys/syscall.h>
#include <linux/kcmp.h>
static int kcmp(pid_t pid1, pid_t pid2, int type,
return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2);
}
+/* See proc(5).
+ * Defined in linux/include/linux/sched.h private header file. */
+#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
+
#include "c.h"
#include "nls.h"
#include "xalloc.h"
N_("user ID number of the file's owner") },
[COL_INODE] = { "INODE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER,
N_("inode number") },
+ [COL_KTHREAD] = { "KTHREAD", 0, SCOLS_FL_RIGHT, SCOLS_JSON_BOOLEAN,
+ N_("opened by a kernel thread") },
[COL_MAJMIN] = { "MAJ:MIN", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING,
N_("device ID for special, or ID of device containing file") },
[COL_MAPLEN] = { "MAPLEN", 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER,
struct lsfd_filter *filter;
};
+static void xstrappend(char **a, const char *b);
+static void xstrputc(char **a, char c);
+
static int column_name_to_id(const char *name, size_t namesz)
{
size_t i;
INIT_LIST_HEAD(&proc->files);
INIT_LIST_HEAD(&proc->procs);
+ proc->kthread = 0;
return proc;
}
xstrdup(buf) : xstrdup(_("(unknown)"));
procfs_process_get_uid(pc, &proc->uid);
+ if (procfs_process_get_stat(pc, buf, sizeof(buf)) > 0) {
+ char *p;
+ unsigned int flags;
+ char *pat = NULL;
+
+ /* See proc(5) about the column in the line. */
+ xstrappend(&pat, "%*d (");
+ for (p = proc->command; *p != '\0'; p++) {
+ if (*p == '%')
+ xstrappend(&pat, "%%");
+ else
+ xstrputc(&pat, *p);
+ }
+ xstrappend(&pat, ") %*c %*d %*d %*d %*d %*d %u %*[^\n]");
+ if (sscanf(buf, pat, &flags) == 1)
+ proc->kthread = !!(flags & PF_KTHREAD);
+ free(pat);
+ }
+
collect_execve_file(pc, proc);
if (proc->pid == proc->leader->pid
err(EXIT_FAILURE, _("failed to allocate memory for string"));
}
+static void xstrputc(char **a, char c)
+{
+ char b[] = {c, '\0'};
+ xstrappend(a, b);
+}
+
static char * quote_filter_expr(char *expr)
{
char c[] = {'\0', '\0'};
COL_FD,
COL_FLAGS,
COL_INODE,
+ COL_KTHREAD,
COL_MAJMIN,
COL_MAPLEN,
COL_MISCDEV,
ino_t ns_mnt;
struct list_head procs;
struct list_head files;
+ unsigned int kthread: 1;
};
/*
--- /dev/null
+COMMAND PID USER MODE TYPE INODE NAME KTHREAD
+systemd 1 root --- DIR 2 / 0
+systemd 1 root --- DIR 2 / 0
+kthreadd 2 root --- DIR 2 / 1
+kthreadd 2 root --- DIR 2 / 1
+0
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2021 Masatake YAMATO <yamato@redhat.com>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="directory"
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_LSFD"
+ts_check_prog "ps"
+
+ts_skip_nonroot
+
+[ "$(ps --no-headers -o comm 1)" = 'systemd' ] || ts_skip "pid 1 is not systemd"
+[ "$(ps --no-headers -o comm 2)" = 'kthreadd' ] || ts_skip "pid 2 is not kthreadd"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ "$TS_CMD_LSFD" -o COMMAND,PID,USER,MODE,TYPE,INODE,NAME,KTHREAD \
+ -Q '(PID < 3) and ((ASSOC == "cwd") or (ASSOC == "rtd"))'
+ echo $?
+} > $TS_OUTPUT 2>&1
+
+ts_finalize
+
+