tools/ttysnoop: Add --datasize/--datacount
authorJiri Olsa <jolsa@kernel.org>
Fri, 9 Apr 2021 17:24:12 +0000 (19:24 +0200)
committeryonghong-song <ys114321@gmail.com>
Wed, 26 May 2021 00:21:49 +0000 (17:21 -0700)
Adding the possibility to define transmitting data size
(--datasize option) and number of times we ask for this
amount (--datacount option).

This helps to configure ttysnoop  behaviour for the expected
data in the terminal session. For example ncurses applications
like mc or huge sized terminals need bigger buffer to snoop
everything from the buffer.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
man/man8/ttysnoop.8
tools/ttysnoop.py
tools/ttysnoop_example.txt

index 9f37aaa90a00a17c9805876fe3702e1fca8ceae3..e2ec037fccbd9efaa4d9fcc4898e83bd895a77d7 100644 (file)
@@ -20,6 +20,12 @@ CONFIG_BPF and bcc.
 \-C
 Don't clear the screen.
 .TP
+\-s SIZE , \-\-datasize SIZE
+Size of the transmitting buffer (default 256).
+.TP
+\-c COUNT, \-\-datacount COUNT
+Number of times ttysnop checks for SIZE bytes of data (default 16).
+.TP
 device
 Either a path to a tty device (eg, /dev/tty0) or a pts number (eg, the "3"
 from /dev/pts/3).
index 1249f228e025208aff9513ac7542e2ccdc47f65a..237f333c7f7cff4aa1d2224cb9c24561f51b1c00 100755 (executable)
@@ -28,10 +28,13 @@ def usage():
 
 # arguments
 examples = """examples:
-    ./ttysnoop /dev/pts/2    # snoop output from /dev/pts/2
-    ./ttysnoop 2             # snoop output from /dev/pts/2 (shortcut)
-    ./ttysnoop /dev/console  # snoop output from the system console
-    ./ttysnoop /dev/tty0     # snoop output from /dev/tty0
+    ./ttysnoop /dev/pts/2          # snoop output from /dev/pts/2
+    ./ttysnoop 2                   # snoop output from /dev/pts/2 (shortcut)
+    ./ttysnoop /dev/console        # snoop output from the system console
+    ./ttysnoop /dev/tty0           # snoop output from /dev/tty0
+    ./ttysnoop /dev/pts/2 -s 1024  # snoop output from /dev/pts/2 with data size 1024
+    ./ttysnoop /dev/pts/2 -c 2     # snoop output from /dev/pts/2 with 2 checks for 256 bytes of data in buffer
+                                     (potentially retrieving 512 bytes)
 """
 parser = argparse.ArgumentParser(
     description="Snoop output from a pts or tty device, eg, a shell",
@@ -41,6 +44,10 @@ parser.add_argument("-C", "--noclear", action="store_true",
     help="don't clear the screen")
 parser.add_argument("device", default="-1",
     help="path to a tty device (eg, /dev/tty0) or pts number")
+parser.add_argument("-s", "--datasize", default="256",
+    help="size of the transmitting buffer (default 256)")
+parser.add_argument("-c", "--datacount", default="16",
+    help="number of times we check for 'data-size' data (default 16)")
 parser.add_argument("--ebpf", action="store_true",
     help=argparse.SUPPRESS)
 args = parser.parse_args()
@@ -64,7 +71,7 @@ bpf_text = """
 #include <linux/fs.h>
 #include <linux/uio.h>
 
-#define BUFSIZE 256
+#define BUFSIZE USER_DATASIZE
 struct data_t {
     int count;
     char buf[BUFSIZE];
@@ -75,7 +82,7 @@ BPF_PERF_OUTPUT(events);
 
 static int do_tty_write(void *ctx, const char __user *buf, size_t count)
 {
-    int zero = 0;
+    int zero = 0, i;
     struct data_t *data;
 
 /* We can't read data to map data before v4.11 */
@@ -89,14 +96,22 @@ static int do_tty_write(void *ctx, const char __user *buf, size_t count)
         return 0;
 #endif
 
-    // bpf_probe_read_user() can only use a fixed size, so truncate to count
-    // in user space:
-    bpf_probe_read_user(&data->buf, BUFSIZE, (void *)buf);
-    if (count > BUFSIZE)
-        data->count = BUFSIZE;
-    else
-        data->count = count;
-    events.perf_submit(ctx, data, sizeof(*data));
+    #pragma unroll
+    for (i = 0; i < USER_DATACOUNT; i++) {
+        // bpf_probe_read_user() can only use a fixed size, so truncate to count
+        // in user space:
+        if (bpf_probe_read_user(&data->buf, BUFSIZE, (void *)buf))
+            return 0;
+        if (count > BUFSIZE)
+            data->count = BUFSIZE;
+        else
+            data->count = count;
+        events.perf_submit(ctx, data, sizeof(*data));
+        if (count < BUFSIZE)
+            return 0;
+        count -= BUFSIZE;
+        buf += BUFSIZE;
+    }
 
     return 0;
 };
@@ -142,6 +157,9 @@ if debug or args.ebpf:
     if args.ebpf:
         exit()
 
+bpf_text = bpf_text.replace('USER_DATASIZE', '%s' % args.datasize)
+bpf_text = bpf_text.replace('USER_DATACOUNT', '%s' % args.datacount)
+
 # initialize BPF
 b = BPF(text=bpf_text)
 
index 1c299617e1d7569fde1724ab7e47438ce81ced02..95dbf32ed7e1f515f2288100687dbcedb2dd3a66 100644 (file)
@@ -73,11 +73,16 @@ positional arguments:
   device         path to a tty device (eg, /dev/tty0) or pts number
 
 optional arguments:
-  -h, --help     show this help message and exit
-  -C, --noclear  don't clear the screen
+  -h, --help      show this help message and exit
+  -C, --noclear   don't clear the screen
+  -s, --datasize  size of the transmitting buffer (default 256)
+  -c, --datacount number of times ttysnop checks for data (default 16)
 
 examples:
-    ./ttysnoop /dev/pts/2    # snoop output from /dev/pts/2
-    ./ttysnoop 2             # snoop output from /dev/pts/2 (shortcut)
-    ./ttysnoop /dev/console  # snoop output from the system console
-    ./ttysnoop /dev/tty0     # snoop output from /dev/tty0
+    ./ttysnoop /dev/pts/2          # snoop output from /dev/pts/2
+    ./ttysnoop 2                   # snoop output from /dev/pts/2 (shortcut)
+    ./ttysnoop /dev/console        # snoop output from the system console
+    ./ttysnoop /dev/tty0           # snoop output from /dev/tty0
+    ./ttysnoop /dev/pts/2 -s 1024  # snoop output from /dev/pts/2 with data size 1024
+    ./ttysnoop /dev/pts/2 -c 2     # snoop output from /dev/pts/2 with 2 checks for 256 bytes of data in buffer
+                                     (potentionaly retrieving 512 bytes)