forked from xujianming2017/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e822a81
commit 6049d3f
Showing
4 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
.TH ttysnoop 8 "2016-02-08" "USER COMMANDS" | ||
.SH NAME | ||
ttysnoop \- Watch output from a tty or pts device. Uses Linux eBPF/bcc. | ||
.SH SYNOPSIS | ||
.B ttysnoop [\-h] [\-C] device | ||
.SH DESCRIPTION | ||
ttysnoop watches a tty or pts device, and prints the same output that is | ||
appearing on that device. It can be used to mirror the output from a shell | ||
session, or the system console. | ||
|
||
This works by use of kernel dynamic tracing of the tty_write() function. | ||
This tool will need updating in case that kernel function changes in a future | ||
kernel version. | ||
|
||
Since this uses BPF, only the root user can use this tool. | ||
.SH REQUIREMENTS | ||
CONFIG_BPF and bcc. | ||
.SH OPTIONS | ||
.TP | ||
\-C | ||
Don't clear the screen. | ||
.TP | ||
device | ||
Either a path to a tty device (eg, /dev/tty0) or a pts number (eg, the "3" | ||
from /dev/pts/3). | ||
.SH EXAMPLES | ||
.TP | ||
Snoop output from /dev/pts/2 | ||
# | ||
.B ttysnoop /dev/pts/2 | ||
.TP | ||
Snoop output from /dev/pts/2 (shortcut) | ||
# | ||
.B ttysnoop 2 | ||
.TP | ||
Snoop output from the system console | ||
# | ||
.B ttysnoop /dev/console | ||
.TP | ||
Snoop output from /dev/tty0 | ||
# | ||
.B ttysnoop /dev/tty0 | ||
.SH OVERHEAD | ||
As the rate of tty_write() is expected to be very low (<100/s), the overhead | ||
of this tool is expected to be negligible. | ||
.SH SOURCE | ||
This is from bcc. | ||
.IP | ||
https://github.com/iovisor/bcc | ||
.PP | ||
Also look in the bcc distribution for a companion _examples.txt file containing | ||
example usage, output, and commentary for this tool. | ||
.SH OS | ||
Linux | ||
.SH STABILITY | ||
Unstable - in development. | ||
.SH AUTHOR | ||
Brendan Gregg | ||
.SH SEE ALSO | ||
opensnoop(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#!/usr/bin/python | ||
# @lint-avoid-python-3-compatibility-imports | ||
# | ||
# ttysnoop Watch live output from a tty or pts device. | ||
# For Linux, uses BCC, eBPF. Embedded C. | ||
# | ||
# Due to a limited buffer size (see BUFSIZE), some commands (eg, a vim | ||
# session) are likely to be printed a little messed up. | ||
# | ||
# Copyright (c) 2016 Brendan Gregg. | ||
# Licensed under the Apache License, Version 2.0 (the "License") | ||
# | ||
# Idea: from ttywatcher. | ||
# | ||
# 15-Oct-2016 Brendan Gregg Created this. | ||
|
||
from __future__ import print_function | ||
from bcc import BPF | ||
import ctypes as ct | ||
from subprocess import call | ||
import argparse | ||
from sys import argv | ||
import sys | ||
from os import stat | ||
|
||
def usage(): | ||
print("USAGE: %s [-Ch] {PTS | /dev/ttydev} # try -h for help" % argv[0]) | ||
exit() | ||
|
||
# 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 | ||
""" | ||
parser = argparse.ArgumentParser( | ||
description="Snoop output from a pts or tty device, eg, a shell", | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
epilog=examples) | ||
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") | ||
args = parser.parse_args() | ||
debug = 0 | ||
|
||
if args.device == "-1": | ||
usage() | ||
|
||
path = args.device | ||
if path.find('/') != 0: | ||
path = "/dev/pts/" + path | ||
try: | ||
pi = stat(path) | ||
except: | ||
print("Unable to read device %s. Exiting." % path) | ||
exit() | ||
|
||
# define BPF program | ||
bpf_text = """ | ||
#include <uapi/linux/ptrace.h> | ||
#include <linux/fs.h> | ||
#define BUFSIZE 256 | ||
struct data_t { | ||
int count; | ||
char buf[BUFSIZE]; | ||
}; | ||
BPF_PERF_OUTPUT(events); | ||
int kprobe__tty_write(struct pt_regs *ctx, struct file *file, | ||
const char __user *buf, size_t count) | ||
{ | ||
if (file->f_inode->i_ino != PTS) | ||
return 0; | ||
// bpf_probe_read() can only use a fixed size, so truncate to count | ||
// in user space: | ||
struct data_t data = {}; | ||
bpf_probe_read(&data.buf, BUFSIZE, (void *)buf); | ||
if (count > BUFSIZE) | ||
data.count = BUFSIZE; | ||
else | ||
data.count = count; | ||
events.perf_submit(ctx, &data, sizeof(data)); | ||
return 0; | ||
}; | ||
""" | ||
|
||
bpf_text = bpf_text.replace('PTS', str(pi.st_ino)) | ||
if debug: | ||
print(bpf_text) | ||
|
||
# initialize BPF | ||
b = BPF(text=bpf_text) | ||
|
||
BUFSIZE = 256 | ||
|
||
class Data(ct.Structure): | ||
_fields_ = [ | ||
("count", ct.c_int), | ||
("buf", ct.c_char * BUFSIZE) | ||
] | ||
|
||
if not args.noclear: | ||
call("clear") | ||
|
||
# process event | ||
def print_event(cpu, data, size): | ||
event = ct.cast(data, ct.POINTER(Data)).contents | ||
print("%s" % event.buf[0:event.count], end="") | ||
sys.stdout.flush() | ||
|
||
# loop with callback to print_event | ||
b["events"].open_perf_buffer(print_event) | ||
while 1: | ||
b.kprobe_poll() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
Demonstrations of ttysnoop, the Linux eBPF/bcc version. | ||
|
||
|
||
ttysnoop watches a tty or pts device, and prints the same output that is | ||
appearing on that device. It can be used to mirror the output from a shell | ||
session, or the system console. | ||
|
||
Let's snoop /dev/pts/2: | ||
|
||
# ./ttysnoop 2 | ||
<screen clears> | ||
date | ||
Sun Oct 16 01:28:47 UTC 2016 | ||
# uname -a | ||
Linux bgregg-xenial-bpf-i-xxx 4.8.0-rc4-virtual #1 SMP Wed Aug 31 22:54:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux | ||
# df -h | ||
Filesystem Size Used Avail Use% Mounted on | ||
udev 7.4G 0 7.4G 0% /dev | ||
tmpfs 1.5G 89M 1.4G 6% /run | ||
/dev/xvda1 7.8G 4.5G 3.3G 59% / | ||
tmpfs 7.4G 0 7.4G 0% /dev/shm | ||
tmpfs 5.0M 0 5.0M 0% /run/lock | ||
tmpfs 7.4G 0 7.4G 0% /sys/fs/cgroup | ||
tmpfs 250M 0 250M 0% /run/shm | ||
/dev/md0 160G 20G 141G 13% /mnt | ||
tmpfs 1.5G 0 1.5G 0% /run/user/0 | ||
# ^C | ||
|
||
What we're seeing is another shell session. The first line was "date" without | ||
the shell prompt ("#") because we began tracing after the prompt was printed. | ||
The other commands appeared, keystroke by keystroke, as the user was typing | ||
them. Spooky! | ||
|
||
Remember to Ctrl-C to exit ttysnoop. | ||
|
||
|
||
To figure out which pts device number to use, you can check your own with "ps" | ||
and other's with "w". For example: | ||
|
||
# ps -p $$ | ||
PID TTY TIME CMD | ||
9605 pts/1 00:00:00 bash | ||
# w | ||
01:26:37 up 9 days, 35 min, 2 users, load average: 0.22, 0.22, 0.15 | ||
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT | ||
root pts/1 100.127.65.241 00:39 2.00s 0.33s 0.33s -bash | ||
root pts/2 100.127.65.241 00:40 16.00s 1.06s 1.06s -bash | ||
|
||
So I'm pts/1, and there's another session that's pts/2. | ||
|
||
|
||
This can also snoop tty devices using their full path. Eg, snooping the system | ||
console: | ||
|
||
# ./ttysnoop /dev/console | ||
Oct 16 01:32:06 bgregg-xenial-bpf-i-xxx kernel: [780087.407428] bash (9888): drop_caches: 1 | ||
Oct 16 01:32:38 bgregg-xenial-bpf-i-xxx snmpd[2708]: Cannot statfs /sys/kernel/debug/tracing: Permission denied | ||
Oct 16 01:33:32 bgregg-xenial-bpf-i-xxx snmpd[2708]: Cannot statfs /sys/kernel/debug/tracing: Permission denied | ||
Oct 16 01:34:26 bgregg-xenial-bpf-i-xxx snmpd[2708]: Cannot statfs /sys/kernel/debug/tracing: Permission denied | ||
^C | ||
|
||
Neat! | ||
|
||
|
||
USAGE: | ||
|
||
# ./ttysnoop.py -h | ||
usage: ttysnoop.py [-h] [-C] device | ||
|
||
Snoop output from a pts or tty device, eg, a shell | ||
|
||
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 | ||
|
||
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 |