Blame dnf/cli/utils.py

Packit Service 21c75c
# Copyright (C) 2016  Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
# This program is free software; you can redistribute it and/or modify
Packit Service 21c75c
# it under the terms of the GNU General Public License as published by
Packit Service 21c75c
# the Free Software Foundation; either version 2 of the License, or
Packit Service 21c75c
# (at your option) any later version.
Packit Service 21c75c
#
Packit Service 21c75c
# This program is distributed in the hope that it will be useful,
Packit Service 21c75c
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 21c75c
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 21c75c
# GNU Library General Public License for more details.
Packit Service 21c75c
#
Packit Service 21c75c
# You should have received a copy of the GNU General Public License
Packit Service 21c75c
# along with this program; if not, write to the Free Software
Packit Service 21c75c
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 21c75c
Packit Service 21c75c
"""Various utility functions, and a utility class."""
Packit Service 21c75c
Packit Service 21c75c
from __future__ import absolute_import
Packit Service 21c75c
from __future__ import unicode_literals
Packit Service 21c75c
from dnf.cli.format import format_number
Packit Service 21c75c
from dnf.i18n import _
Packit Service 21c75c
import dnf.util
Packit Service 21c75c
import logging
Packit Service 21c75c
import os
Packit Service 21c75c
import time
Packit Service 21c75c
Packit Service 21c75c
_USER_HZ = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
Packit Service 21c75c
logger = logging.getLogger('dnf')
Packit Service 21c75c
Packit Service 21c75c
def jiffies_to_seconds(jiffies):
Packit Service 21c75c
    """Convert a number of jiffies to seconds. How many jiffies are in a second
Packit Service 21c75c
    is system-dependent, e.g. 100 jiffies = 1 second is common.
Packit Service 21c75c
Packit Service 21c75c
    :param jiffies: a number of jiffies
Packit Service 21c75c
    :return: the equivalent number of seconds
Packit Service 21c75c
    """
Packit Service 21c75c
    return int(jiffies) / _USER_HZ
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def seconds_to_ui_time(seconds):
Packit Service 21c75c
    """Return a human-readable string representation of the length of
Packit Service 21c75c
    a time interval given in seconds.
Packit Service 21c75c
Packit Service 21c75c
    :param seconds: the length of the time interval in seconds
Packit Service 21c75c
    :return: a human-readable string representation of the length of
Packit Service 21c75c
      the time interval
Packit Service 21c75c
    """
Packit Service 21c75c
    if seconds >= 60 * 60 * 24:
Packit Service 21c75c
        return "%d day(s) %d:%02d:%02d" % (seconds // (60 * 60 * 24),
Packit Service 21c75c
                                           (seconds // (60 * 60)) % 24,
Packit Service 21c75c
                                           (seconds // 60) % 60,
Packit Service 21c75c
                                           seconds % 60)
Packit Service 21c75c
    if seconds >= 60 * 60:
Packit Service 21c75c
        return "%d:%02d:%02d" % (seconds // (60 * 60), (seconds // 60) % 60,
Packit Service 21c75c
                                 (seconds % 60))
Packit Service 21c75c
    return "%02d:%02d" % ((seconds // 60), seconds % 60)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def get_process_info(pid):
Packit Service 21c75c
    """Return info dict about a process."""
Packit Service 21c75c
Packit Service 21c75c
    pid = int(pid)
Packit Service 21c75c
Packit Service 21c75c
    # Maybe true if /proc isn't mounted, or not Linux ... or something.
Packit Service 21c75c
    if (not os.path.exists("/proc/%d/status" % pid) or
Packit Service 21c75c
        not os.path.exists("/proc/stat") or
Packit Service 21c75c
        not os.path.exists("/proc/%d/stat" % pid)):
Packit Service 21c75c
        return
Packit Service 21c75c
Packit Service 21c75c
    ps = {}
Packit Service 21c75c
    with open("/proc/%d/status" % pid) as status_file:
Packit Service 21c75c
        for line in status_file:
Packit Service 21c75c
            if line[-1] != '\n':
Packit Service 21c75c
                continue
Packit Service 21c75c
            data = line[:-1].split(':\t', 1)
Packit Service 21c75c
            if len(data) < 2:
Packit Service 21c75c
                continue
Packit Service 21c75c
            data[1] = dnf.util.rtrim(data[1], ' kB')
Packit Service 21c75c
            ps[data[0].strip().lower()] = data[1].strip()
Packit Service 21c75c
    if 'vmrss' not in ps:
Packit Service 21c75c
        return
Packit Service 21c75c
    if 'vmsize' not in ps:
Packit Service 21c75c
        return
Packit Service 21c75c
Packit Service 21c75c
    boot_time = None
Packit Service 21c75c
    with open("/proc/stat") as stat_file:
Packit Service 21c75c
        for line in stat_file:
Packit Service 21c75c
            if line.startswith("btime "):
Packit Service 21c75c
                boot_time = int(line[len("btime "):-1])
Packit Service 21c75c
                break
Packit Service 21c75c
    if boot_time is None:
Packit Service 21c75c
        return
Packit Service 21c75c
Packit Service 21c75c
    with open('/proc/%d/stat' % pid) as stat_file:
Packit Service 21c75c
        ps_stat = stat_file.read().split()
Packit Service 21c75c
        ps['start_time'] = boot_time + jiffies_to_seconds(ps_stat[21])
Packit Service 21c75c
        ps['state'] = {'R' : _('Running'),
Packit Service 21c75c
                       'S' : _('Sleeping'),
Packit Service 21c75c
                       'D' : _('Uninterruptible'),
Packit Service 21c75c
                       'Z' : _('Zombie'),
Packit Service 21c75c
                       'T' : _('Traced/Stopped')
Packit Service 21c75c
                       }.get(ps_stat[2], _('Unknown'))
Packit Service 21c75c
Packit Service 21c75c
    return ps
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def show_lock_owner(pid):
Packit Service 21c75c
    """Output information about process holding a lock."""
Packit Service 21c75c
Packit Service 21c75c
    ps = get_process_info(pid)
Packit Service 21c75c
    if not ps:
Packit Service 21c75c
        msg = _('Unable to find information about the locking process (PID %d)')
Packit Service 21c75c
        logger.critical(msg, pid)
Packit Service 21c75c
        return
Packit Service 21c75c
Packit Service 21c75c
    msg = _('  The application with PID %d is: %s') % (pid, ps['name'])
Packit Service 21c75c
Packit Service 21c75c
    logger.critical("%s", msg)
Packit Service 21c75c
    logger.critical(_("    Memory : %5s RSS (%5sB VSZ)"),
Packit Service 21c75c
                    format_number(int(ps['vmrss']) * 1024),
Packit Service 21c75c
                    format_number(int(ps['vmsize']) * 1024))
Packit Service 21c75c
Packit Service 21c75c
    ago = seconds_to_ui_time(int(time.time()) - ps['start_time'])
Packit Service 21c75c
    logger.critical(_('    Started: %s - %s ago'),
Packit Service 21c75c
                    dnf.util.normalize_time(ps['start_time']), ago)
Packit Service 21c75c
    logger.critical(_('    State  : %s'), ps['state'])
Packit Service 21c75c
Packit Service 21c75c
    return