diff options
-rw-r--r-- | examples/plugins/users | 36 | ||||
-rw-r--r-- | src/plugins/users.py | 73 |
2 files changed, 105 insertions, 4 deletions
diff --git a/examples/plugins/users b/examples/plugins/users new file mode 100644 index 0000000..5458b37 --- /dev/null +++ b/examples/plugins/users @@ -0,0 +1,36 @@ +# -*- python -*- + +# A xpybar configuration example testing the features of plugins.xdisplay + +import time +import threading + +from plugins.users import Users +from plugins.clock import Clock + + +OUTPUT, HEIGHT, YPOS, TOP = 0, 12, 24, True + + +clock = Clock(sync_to = Clock.SECONDS) + +start_ = start +def start(): + start_() + async(lambda : clock.continuous_sync(lambda : bar.invalidate())) + + +def redraw(): + you = os.environ['USER'] + def colour(user): + if user == 'root': return '\033[31m%s\033[39m' + elif not user == you: return '\033[33m%s\033[39m' + else: return '%s' + + users = Users(lambda : Users.devfs(True)).users + text = ['%s: %s' % (colour(u) % u, ' '.join(sorted(users[u]))) for u in users] + text = ' │ '.join(text) + + bar.clear() + bar.draw_coloured_text(0, 10, 0, 2, text) + diff --git a/src/plugins/users.py b/src/plugins/users.py index a73939e..85e390c 100644 --- a/src/plugins/users.py +++ b/src/plugins/users.py @@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ''' +import os + from util import * @@ -24,19 +26,82 @@ class Users: ''' Gets the logged in users and what TTY:s they are using - @variable users:dict<str, list<str>> Map from logged in users to acquired TTY:s + @variable users:dict<str, list<str>> Map from logged in users to acquired TTY:s (all might not be listed) ''' - def __init__(self): + def __init__(self, method = 'who'): ''' Constructor + + @param method:str|()→itr<str> The user listing method ''' - users = spawn('w').read().decode('utf-8', 'replace').split('\n')[2 : -1] - users = [list(filter(lambda cell : not cell == '', line.split(' ')))[:2] for line in users] + users = Users.who + if not isinstance(method, str): + users = method + elif method == 'who': users = Users.who + elif method == 'w': users = Users.w + elif method == 'devfs': users = Users.devfs + + users = users() self.users = {} for (user, tty) in users: if user not in self.users: self.users[user] = [] self.users[user].append(tty) + + + @staticmethod + def who(): + ''' + Use Coreutil's `who` command to fetch users and ttys + + @return :list<(user:str, tty:str>) List of user–tty pairs + ''' + users = spawn('who').read().decode('utf-8', 'replace').split('\n')[:-1] + users = [list(filter(lambda cell : not cell == '', line.split(' ')))[:2] for line in users] + return users + + + @staticmethod + def w(): + ''' + Use procps-ng's `w` command to fetch users and ttys + + @return :list<(user:str, tty:str>) List of user–tty pairs + ''' + users = spawn('w').read().decode('utf-8', 'replace').split('\n')[2 : -1] + users = [list(filter(lambda cell : not cell == '', line.split(' ')))[:2] for line in users] + return users + + + @staticmethod + def devfs(try_to_find_root = False): + ''' + Walk /dev to find TTY acquisitions + + @param try_to_find_root:bool Whether to list root for /dev/tty[[:numeric:]]+ if the permission bits looks good + @return :list<(user:str, tty:str>) List of user–tty pairs + ''' + import pwd + + def num(s): + return (not s == '') and (0 == len(list(filter(lambda c : not ('0' <= c <= '9'), s)))) + + ttys = [f for f in os.listdir('/dev') if f.startswith('tty') and num(f[3:])] + ttys += ['pts/' + f for f in os.listdir('/dev/pts') if num(f)] + + users, rc = {}, [] + for tty in ttys: + attr = os.stat('/dev/' + tty) + if ('/' not in tty) and (attr.st_uid == 0): + if not (try_to_find_root and (attr.st_mode == 0o20600)): + continue + user = attr.st_uid + if user in users: + user = users[user] + else: + users[user] = user = pwd.getpwuid(user).pw_name + rc.append((user, tty)) + return rc |