Skip to content

Instantly share code, notes, and snippets.

@ssokolow
Last active January 8, 2022 17:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ssokolow/9833321 to your computer and use it in GitHub Desktop.
Save ssokolow/9833321 to your computer and use it in GitHub Desktop.
"wineserver -k" wrapper which kills every WINEPREFIX the user has running (Very useful for killing misbehaving games in PlayOnLinux)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
`wineserver -k` wrapper which kills every WINEPREFIX the user has running
(Very useful for killing misbehaving games in PlayOnLinux)
Known Bugs:
- The script will miss wineserver instances where the WINESERVER environment
variable was used to specify a wineserver binary not named "wineserver"
"""
__appname__ = "Blanket Wineserver Killer for Linux"
__author__ = "Stephan Sokolow (deitarion/SSokolow)"
__version__ = "0.2"
__license__ = "MIT"
import glob, os, subprocess, sys
def parse_procfile(path):
"""Parse a file containing a null-separated text list or return [].
NOTE: Strips blank fields.
"""
try:
with file(path) as fh:
return [x for x in fh.read().split('\0') if x.strip()]
except:
return []
def pfind(command):
"""Return PIDs where argv[0] ends with the given string.
(Reinvent part of pgrep so we don't have it as an external dependency.)
"""
pids = []
for path in glob.glob('/proc/*/cmdline'):
cmd = parse_procfile(path)
if cmd and cmd[0].endswith(command):
pid = os.path.split(os.path.split(path)[0])[1]
try:
pids.append(int(pid, 10))
except ValueError: # Catch failed int() conversions
print "ERROR: Skipping invalid PID: %s" % pid
continue
return pids
def env_for(pid):
"""Retrieve the environment for a PID or return []."""
env = parse_procfile('/proc/%d/environ' % pid)
if env: # If we managed to retrieve the environment, parse it
env = dict(x.split('=', 1) for x in env if '=' in x)
return env
if __name__ == '__main__':
# Query the list of running wineserver instances
pids = pfind('wineserver')
if pids:
print "Found PIDs: %s" % ' '.join(str(x) for x in pids)
else:
print "No wineserver instances found"
sys.exit(1)
# Resolve PIDs to WINEPREFIX values
environs = {}
for pid in pids:
# Retrieve the environment for the process
env = env_for(pid)
if env is None:
print "WARNING: Skipping wineserver we can't kill: %d" % pid
continue
# Store the environments, indexed by WINEPREFIX
fallback_prefix = os.path.join(env.get('HOME', '~'), '.wine')
prefix = env.get('WINEPREFIX', fallback_prefix)
environs[prefix] = env # deduplicate
print "Found prefixes:\n\t%s" % '\n\t'.join(environs.keys())
# Actually kill them
print "Killing processes:"
for prefix, env in environs.items():
print "\t%s" % prefix
subprocess.call(['wineserver', '-k'], env=env)
print "Done."
#TODO: Research how to query the default monitor resolution so we can call
# xrandr in a non-site-specific manner.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment