├── LICENSE ├── README.md └── what /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 MIT PDOS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # what 2 | 3 | what is an improved version of the `w` tool. It finds all processes 4 | associated with a TTY (not just those registered in wtmp), and reports 5 | all users that are running anything. In particular, unlike `w`, `what` 6 | will also shows things running in detached screens/tmuxen. 7 | 8 | Example output: 9 | 10 | ```console 11 | $ ./what 12 | up 23m56s 4 users load 0.65 0.41 0.23 procs 1/403 13 | USER TTY LOGIN INPUT OUTPUT WHAT 14 | root tty1 23m53s 23m53s 23m53s /sbin/agetty --noclear tty1 linux 15 | root tty7 23m53s 23m53s 23m53s /usr/lib/xorg-server/Xorg -nolisten tcp vt07 -auth /var/run/slim.auth 16 | jon pts/0 9m36s 2s 2s python2 ./what 17 | root none 177 more processes 18 | jon none 42 more processes 19 | ``` 20 | -------------------------------------------------------------------------------- /what: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Like "w", but finds all processes associated with a TTY (not just 4 | # those registered in wtmp), and reports all users that are running 5 | # anything. In particular, unlike "w", this will shows things running 6 | # in detached screens/tmuxen. 7 | 8 | import sys, os, glob, pwd, time 9 | 10 | # Find all TTYs 11 | ttys = {} 12 | for tty in glob.glob("/dev/tty*") + glob.glob("/dev/pts/*"): 13 | try: 14 | st = os.stat(tty) 15 | except EnvironmentError: 16 | continue 17 | # atime is time of last input 18 | # mtime is time of last output 19 | # ctime is when it was created 20 | ttys[st.st_rdev] = (tty[5:], st, []) 21 | 22 | # Find all processes and map them to TTYs 23 | notty = {} 24 | uids = set() 25 | for pid in os.listdir("/proc"): 26 | if not pid.isdigit(): 27 | continue 28 | pid = int(pid) 29 | 30 | try: 31 | with open("/proc/%d/stat" % pid, 'r') as statusfile: 32 | status = statusfile.read() 33 | with open("/proc/%d/cmdline" % pid, 'r') as cmdlinefile: 34 | cmdline = cmdlinefile.read() 35 | st = os.stat("/proc/%d" % pid) 36 | except EnvironmentError: 37 | continue 38 | uids.add(st.st_uid) 39 | 40 | parts = status.rsplit(") ", 1)[1].split() 41 | tty_nr = int(parts[4]) 42 | tpgid = int(parts[5]) 43 | if tty_nr == 0 or tpgid == -1: 44 | # No controlling terminal 45 | notty.setdefault(st.st_uid, 0) 46 | notty[st.st_uid] += 1 47 | continue 48 | if cmdline.startswith("/sbin/getty\0"): 49 | # Ignore login terminals 50 | continue 51 | if tpgid == int(pid) and tty_nr in ttys: 52 | ttys[tty_nr][-1].append(cmdline.replace("\0", " ")) 53 | 54 | # Sort TTYs by input time 55 | ttys = sorted(ttys.values(), key=lambda tty: tty[1].st_atime) 56 | 57 | # Print 58 | def pretty_time(ts): 59 | diff = time.time() - ts 60 | days, diff = divmod(diff, 24*60*60) 61 | hours, diff = divmod(diff, 60*60) 62 | mins, secs = divmod(diff, 60) 63 | if days > 99: 64 | return "%5dd" % days 65 | if days: 66 | return "%2dd%02dh" % (days, hours) 67 | if hours: 68 | return "%2dh%02dm" % (hours, mins) 69 | if mins: 70 | return "%2dm%02ds" % (mins, secs) 71 | return "%5ds" % secs 72 | 73 | # Old code for absolute time 74 | lt = time.localtime(ts) 75 | if lt[:3] == time.localtime()[:3]: 76 | return "%02d:%02d" % (lt.tm_hour, lt.tm_min) 77 | return time.strftime("%d%b%g", lt) 78 | 79 | def getTermSize(): 80 | import termios, fcntl, struct, errno, os 81 | 82 | # Try TIOCGWINSZ 83 | try: 84 | s = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, struct.pack("HH", 0, 0)) 85 | h, w = struct.unpack("HH", s) 86 | return w, h 87 | except IOError as e: 88 | if e.errno != errno.EINVAL: 89 | raise 90 | 91 | # Try environment 92 | if "LINES" in os.environ and "COLUMNS" in os.environ: 93 | h, w = int(os.environ["LINES"]), int(os.environ["COLUMNS"]) 94 | return w, h 95 | 96 | # Give up 97 | return 80, 24 98 | 99 | with open("/proc/uptime", 'r') as uptimefile: 100 | uptime = int(float(uptimefile.read().split()[0])) 101 | with open("/proc/loadavg", 'r') as loadavgfile: 102 | loadavg = loadavgfile.read().split() 103 | print(" up %s %2d users load %s %s %s procs %s" % \ 104 | (pretty_time(time.time() - uptime).strip(), len(uids), 105 | loadavg[0], loadavg[1], loadavg[2], loadavg[3])) 106 | 107 | fmt = "%-8.8s %-7s %6s %6s %6s %s" 108 | cols = getTermSize()[0] 109 | uid_colors = {} 110 | colors = [32, 33, 34, 35, 36] 111 | hdr = fmt % tuple("USER TTY LOGIN INPUT OUTPUT WHAT".split()) 112 | hdr = hdr.replace("INPUT", "\033[4mINPUT\033[0m") 113 | print(hdr[:cols]) 114 | for tty, st, cmds in ttys: 115 | uid = st.st_uid 116 | if uid not in uid_colors: 117 | uid_colors[uid] = len(uid_colors) % len(colors) 118 | color = "\033[%dm" % colors[uid_colors[uid]] 119 | for cmd in cmds: 120 | s = fmt % (pwd.getpwuid(st.st_uid)[0], tty, \ 121 | pretty_time(st.st_ctime), \ 122 | pretty_time(st.st_atime), \ 123 | pretty_time(st.st_mtime), cmd) 124 | print(color + s[:cols] + "\033[0m") 125 | 126 | logged_in_uids = set() 127 | for tty in ttys: 128 | logged_in_uids.add(tty[1].st_uid) 129 | for uid, count in notty.items(): 130 | if uid not in logged_in_uids: 131 | continue 132 | print("%-8.8s %-7s %d more processes" % (pwd.getpwuid(uid)[0], "none", count)) 133 | --------------------------------------------------------------------------------