]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lsfd: add KTHREAD column
authorMasatake YAMATO <yamato@redhat.com>
Tue, 19 Oct 2021 08:05:08 +0000 (17:05 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Thu, 21 Oct 2021 12:10:44 +0000 (21:10 +0900)
Signed-off-by: Masatake YAMATO <yamato@redhat.com>
include/procfs.h
lib/procfs.c
misc-utils/lsfd-file.c
misc-utils/lsfd.1.adoc
misc-utils/lsfd.c
misc-utils/lsfd.h
tests/expected/lsfd/column-kthread [new file with mode: 0644]
tests/ts/lsfd/column-kthread [new file with mode: 0755]

index 55cebce50d9749680c3d30f10996128c5b269129..5a730c94caf09ef218922abba18f2ae2788edd7a 100644 (file)
@@ -28,6 +28,7 @@ extern int procfs_process_init_path(struct path_cxt *pc, pid_t pid);
 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)
index 8173d6274c5f120150f37cf54f5b4cd99e966592..4d6d25b6d78eba56aada4cd9acacee4d2e69f656 100644 (file)
@@ -138,9 +138,10 @@ static ssize_t read_procfs_file(int fd, 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);
@@ -150,16 +151,19 @@ ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t 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)
index ea1410e6af611a8e810f09859e71b84a91da7c00..e08b6349c4b42e2bcac96159911f8a67611242e7 100644 (file)
@@ -297,6 +297,9 @@ static bool file_fill_column(struct proc *proc,
        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;
index a81befc8c3d9f8d29404ad9939128c31154a8fca..8549c335532c3a842132f36eb9a3190e840c3dc7 100644 (file)
@@ -104,6 +104,9 @@ User ID number of the file's owner.
 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.
 
index 8c703d411ed48cd5468bf4c283504dd729d6f09f..247c678ee03358906c4aafeef5a439ca14486548 100644 (file)
@@ -30,6 +30,7 @@
 #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,
@@ -38,6 +39,10 @@ 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"
@@ -108,6 +113,8 @@ static struct colinfo infos[] = {
                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,
@@ -195,6 +202,9 @@ struct lsfd_control {
        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;
@@ -381,6 +391,7 @@ static struct proc *new_process(pid_t pid, struct proc *leader)
        INIT_LIST_HEAD(&proc->files);
        INIT_LIST_HEAD(&proc->procs);
 
+       proc->kthread = 0;
        return proc;
 }
 
@@ -867,6 +878,25 @@ static void read_process(struct lsfd_control *ctl, struct path_cxt *pc,
                        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
@@ -987,6 +1017,12 @@ static void xstrappend(char **a, const char *b)
                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'};
index 59cba6ea4ded4dfe7a0b531dfb1ff8e80ed02011..9b0e3aef2488854127f0943ac94dd9bcb2a1194a 100644 (file)
@@ -44,6 +44,7 @@ enum {
        COL_FD,
        COL_FLAGS,
        COL_INODE,
+       COL_KTHREAD,
        COL_MAJMIN,
        COL_MAPLEN,
        COL_MISCDEV,
@@ -97,6 +98,7 @@ struct proc {
        ino_t ns_mnt;
        struct list_head procs;
        struct list_head files;
+       unsigned int kthread: 1;
 };
 
 /*
diff --git a/tests/expected/lsfd/column-kthread b/tests/expected/lsfd/column-kthread
new file mode 100644 (file)
index 0000000..98b0354
--- /dev/null
@@ -0,0 +1,6 @@
+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
diff --git a/tests/ts/lsfd/column-kthread b/tests/ts/lsfd/column-kthread
new file mode 100755 (executable)
index 0000000..1cf8fdb
--- /dev/null
@@ -0,0 +1,42 @@
+#!/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
+
+