blob: 577071464c8b1473ba49d54376a301875081a017 [file] [log] [blame]
# Copyright 2016 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Terminal Freezer utility"""
from __future__ import print_function
import logging
import os
import re
import signal
import subprocess
import time
def CheckForPIDNamespace():
"""Checks to see if we are running with PID namespaces.
Raises:
OSError if we are running within the chroot with PID namespaces.
"""
with open('/proc/1/cmdline') as f:
if 'cros_sdk' in f.readline():
raise OSError('You must run this tool in a chroot that was entered'
' with "cros_sdk --no-ns-pid" (see crbug.com/444931 for'
' details)')
class TerminalFreezer(object):
"""SIGSTOP all processes (and their parents) that have the TTY open."""
def __init__(self, tty):
self._tty = tty
self._logger = logging.getLogger('Terminal Freezer (%s)' % self._tty)
self._processes = None
CheckForPIDNamespace()
def __enter__(self):
ret = ''
try:
ret = subprocess.check_output(['lsof', '-FR', self._tty],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
# Ignore non-zero return codes.
pass
self._processes = re.findall(r'^(?:R|p)(\d+)$', ret, re.MULTILINE)
# Don't kill servod, we need that.
servod_processes = []
for p in self._processes:
with open('/proc/%s/cmdline' % p) as f:
if 'servod' in f.readline():
servod_processes.append(p)
self._logger.debug('servod processes: %r', servod_processes)
for p in servod_processes:
self._processes.remove(p)
# SIGSTOP parents before children.
try:
for p in reversed(self._processes):
self._logger.debug('Sending SIGSTOP to process %s!', p)
time.sleep(0.02)
os.kill(int(p), signal.SIGSTOP)
except OSError:
self.__exit__(None, None, None)
raise
def __exit__(self, _t, _v, _b):
# ...and wake 'em up again in reverse order.
for p in self._processes:
self._logger.debug('Sending SIGCONT to process %s!', p)
try:
os.kill(int(p), signal.SIGCONT)
except OSError as e:
self._logger.error('Error when trying to unfreeze process %s: %s', p, e)