mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-06 09:20:57 +01:00
commit
c8c8f5df5c
11 changed files with 434 additions and 20 deletions
|
@ -1,6 +1,7 @@
|
||||||
machine:
|
machine:
|
||||||
environment:
|
environment:
|
||||||
PATH: /home/ubuntu/miniconda/envs/test_env/bin:/home/ubuntu/miniconda/bin:$PATH
|
PATH: /home/ubuntu/miniconda/envs/test_env/bin:/home/ubuntu/miniconda/bin:$PATH
|
||||||
|
XONSH_DEBUG: 1
|
||||||
post:
|
post:
|
||||||
- pyenv global 3.4.4 3.5.2
|
- pyenv global 3.4.4 3.5.2
|
||||||
|
|
||||||
|
|
17
news/uptime.rst
Normal file
17
news/uptime.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
**Added:**
|
||||||
|
|
||||||
|
* Uptime module added to ``xonsh.xoreutils``. This can report the system
|
||||||
|
boot time and up time.
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
|
||||||
|
* The JSON history backend will now unlock history files that were created
|
||||||
|
prior to the last reboot.
|
||||||
|
|
||||||
|
**Deprecated:** None
|
||||||
|
|
||||||
|
**Removed:** None
|
||||||
|
|
||||||
|
**Fixed:** None
|
||||||
|
|
||||||
|
**Security:** None
|
|
@ -2,6 +2,7 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from xonsh.xoreutils import _which
|
from xonsh.xoreutils import _which
|
||||||
|
from xonsh.xoreutils import uptime
|
||||||
from xonsh.tools import ON_WINDOWS
|
from xonsh.tools import ON_WINDOWS
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,3 +86,17 @@ class TestWhich:
|
||||||
return path1 == path2
|
return path1 == path2
|
||||||
else:
|
else:
|
||||||
return os.path.samefile(path1, path2)
|
return os.path.samefile(path1, path2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_uptime():
|
||||||
|
up = uptime.uptime()
|
||||||
|
assert up is not None
|
||||||
|
assert up > 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_boottime():
|
||||||
|
bt = uptime.boottime()
|
||||||
|
assert bt is not None
|
||||||
|
assert bt > 0.0
|
||||||
|
assert uptime._BOOTTIME is not None
|
||||||
|
assert uptime._BOOTTIME > 0.0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
__version__ = '0.5.3'
|
__version__ = '0.5.3'
|
||||||
|
|
||||||
# amalgamate exclude jupyter_kernel parser_table parser_test_table pyghooks
|
# amalgamate exclude jupyter_kernel parser_table parser_test_table pyghooks
|
||||||
# amalgamate exclude winutils wizard pytest_plugin fs
|
# amalgamate exclude winutils wizard pytest_plugin fs macutils
|
||||||
import os as _os
|
import os as _os
|
||||||
if _os.getenv('XONSH_DEBUG', ''):
|
if _os.getenv('XONSH_DEBUG', ''):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -10,6 +10,7 @@ import collections.abc as cabc
|
||||||
from xonsh.history.base import History
|
from xonsh.history.base import History
|
||||||
import xonsh.tools as xt
|
import xonsh.tools as xt
|
||||||
import xonsh.lazyjson as xlj
|
import xonsh.lazyjson as xlj
|
||||||
|
import xonsh.xoreutils.uptime as uptime
|
||||||
|
|
||||||
|
|
||||||
def _xhj_gc_commands_to_rmfiles(hsize, files):
|
def _xhj_gc_commands_to_rmfiles(hsize, files):
|
||||||
|
@ -122,7 +123,7 @@ class JsonHistoryGC(threading.Thread):
|
||||||
env = getattr(builtins, '__xonsh_env__', None)
|
env = getattr(builtins, '__xonsh_env__', None)
|
||||||
if env is None:
|
if env is None:
|
||||||
return []
|
return []
|
||||||
|
boot = uptime.boottime()
|
||||||
fs = _xhj_get_history_files(sort=False)
|
fs = _xhj_get_history_files(sort=False)
|
||||||
files = []
|
files = []
|
||||||
for f in fs:
|
for f in fs:
|
||||||
|
@ -132,10 +133,19 @@ class JsonHistoryGC(threading.Thread):
|
||||||
files.append((time.time(), 0, f))
|
files.append((time.time(), 0, f))
|
||||||
continue
|
continue
|
||||||
lj = xlj.LazyJSON(f, reopen=False)
|
lj = xlj.LazyJSON(f, reopen=False)
|
||||||
|
if lj['locked'] and lj['ts'][0] < boot:
|
||||||
|
# computer was rebooted between when this history was created
|
||||||
|
# and now and so this history should be unlocked.
|
||||||
|
hist = lj.load()
|
||||||
|
lj.close()
|
||||||
|
hist['locked'] = False
|
||||||
|
with open(f, 'w', newline='\n') as fp:
|
||||||
|
xlj.ljdump(hist, fp, sort_keys=True)
|
||||||
|
lj = xlj.LazyJSON(f, reopen=False)
|
||||||
if only_unlocked and lj['locked']:
|
if only_unlocked and lj['locked']:
|
||||||
continue
|
continue
|
||||||
# info: closing timestamp, number of commands, filename
|
# info: closing timestamp, number of commands, filename
|
||||||
files.append((lj['ts'][1] or time.time(),
|
files.append((lj['ts'][1] or lj['ts'][0],
|
||||||
len(lj.sizes['cmds']) - 1,
|
len(lj.sizes['cmds']) - 1,
|
||||||
f))
|
f))
|
||||||
lj.close()
|
lj.close()
|
||||||
|
|
|
@ -11,7 +11,7 @@ import subprocess
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
from xonsh.lazyasd import LazyObject
|
from xonsh.lazyasd import LazyObject
|
||||||
from xonsh.platform import ON_DARWIN, ON_WINDOWS, ON_CYGWIN
|
from xonsh.platform import ON_DARWIN, ON_WINDOWS, ON_CYGWIN, LIBC
|
||||||
|
|
||||||
|
|
||||||
tasks = LazyObject(collections.deque, globals(), 'tasks')
|
tasks = LazyObject(collections.deque, globals(), 'tasks')
|
||||||
|
@ -134,9 +134,6 @@ else:
|
||||||
# give_terminal_to from bash 4.3 source, jobs.c, line 4030
|
# give_terminal_to from bash 4.3 source, jobs.c, line 4030
|
||||||
# this will give the terminal to the process group pgid
|
# this will give the terminal to the process group pgid
|
||||||
if ON_CYGWIN:
|
if ON_CYGWIN:
|
||||||
_libc = LazyObject(lambda: ctypes.CDLL('cygwin1.dll'),
|
|
||||||
globals(), '_libc')
|
|
||||||
|
|
||||||
# on cygwin, signal.pthread_sigmask does not exist in Python, even
|
# on cygwin, signal.pthread_sigmask does not exist in Python, even
|
||||||
# though pthread_sigmask is defined in the kernel. thus, we use
|
# though pthread_sigmask is defined in the kernel. thus, we use
|
||||||
# ctypes to mimic the calls in the "normal" version below.
|
# ctypes to mimic the calls in the "normal" version below.
|
||||||
|
@ -145,16 +142,16 @@ else:
|
||||||
if st is not None and os.isatty(st):
|
if st is not None and os.isatty(st):
|
||||||
omask = ctypes.c_ulong()
|
omask = ctypes.c_ulong()
|
||||||
mask = ctypes.c_ulong()
|
mask = ctypes.c_ulong()
|
||||||
_libc.sigemptyset(ctypes.byref(mask))
|
LIBC.sigemptyset(ctypes.byref(mask))
|
||||||
for i in _block_when_giving:
|
for i in _block_when_giving:
|
||||||
_libc.sigaddset(ctypes.byref(mask), ctypes.c_int(i))
|
LIBC.sigaddset(ctypes.byref(mask), ctypes.c_int(i))
|
||||||
_libc.sigemptyset(ctypes.byref(omask))
|
LIBC.sigemptyset(ctypes.byref(omask))
|
||||||
_libc.sigprocmask(ctypes.c_int(signal.SIG_BLOCK),
|
LIBC.sigprocmask(ctypes.c_int(signal.SIG_BLOCK),
|
||||||
ctypes.byref(mask),
|
ctypes.byref(mask),
|
||||||
ctypes.byref(omask))
|
ctypes.byref(omask))
|
||||||
_libc.tcsetpgrp(ctypes.c_int(st), ctypes.c_int(pgid))
|
LIBC.tcsetpgrp(ctypes.c_int(st), ctypes.c_int(pgid))
|
||||||
_libc.sigprocmask(ctypes.c_int(signal.SIG_SETMASK),
|
LIBC.sigprocmask(ctypes.c_int(signal.SIG_SETMASK),
|
||||||
ctypes.byref(omask), None)
|
ctypes.byref(omask), None)
|
||||||
else:
|
else:
|
||||||
def _give_terminal_to(pgid):
|
def _give_terminal_to(pgid):
|
||||||
st = _shell_tty()
|
st = _shell_tty()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Lazy imports that may apply across the xonsh package."""
|
"""Lazy imports that may apply across the xonsh package."""
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
from xonsh.platform import ON_WINDOWS
|
from xonsh.platform import ON_WINDOWS, ON_DARWIN
|
||||||
from xonsh.lazyasd import LazyObject, lazyobject
|
from xonsh.lazyasd import LazyObject, lazyobject
|
||||||
|
|
||||||
pygments = LazyObject(lambda: importlib.import_module('pygments'),
|
pygments = LazyObject(lambda: importlib.import_module('pygments'),
|
||||||
|
@ -69,6 +69,15 @@ def winutils():
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
@lazyobject
|
||||||
|
def macutils():
|
||||||
|
if ON_DARWIN:
|
||||||
|
import xonsh.macutils as m
|
||||||
|
else:
|
||||||
|
m = None
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
@lazyobject
|
@lazyobject
|
||||||
def terminal256():
|
def terminal256():
|
||||||
return importlib.import_module('pygments.formatters.terminal256')
|
return importlib.import_module('pygments.formatters.terminal256')
|
||||||
|
|
22
xonsh/macutils.py
Normal file
22
xonsh/macutils.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Provides some Mac / Darwin based utility functions for xonsh."""
|
||||||
|
from ctypes import c_uint, byref, create_string_buffer
|
||||||
|
|
||||||
|
from xonsh.platform import LIBC
|
||||||
|
|
||||||
|
|
||||||
|
def sysctlbyname(name, return_str=True):
|
||||||
|
"""Gets a sysctrl value by name. If return_str is true, this will return
|
||||||
|
a string representation, else it will return the raw value.
|
||||||
|
"""
|
||||||
|
# forked from https://gist.github.com/pudquick/581a71425439f2cf8f09
|
||||||
|
size = c_uint(0)
|
||||||
|
# Find out how big our buffer will be
|
||||||
|
LIBC.sysctlbyname(name, None, byref(size), None, 0)
|
||||||
|
# Make the buffer
|
||||||
|
buf = create_string_buffer(size.value)
|
||||||
|
# Re-run, but provide the buffer
|
||||||
|
LIBC.sysctlbyname(name, buf, byref(size), None, 0)
|
||||||
|
if return_str:
|
||||||
|
return buf.value
|
||||||
|
else:
|
||||||
|
return buf.raw
|
|
@ -4,6 +4,7 @@ on a platform.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import ctypes
|
||||||
import signal
|
import signal
|
||||||
import pathlib
|
import pathlib
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -51,9 +52,18 @@ ON_FREEBSD = LazyBool(lambda: (sys.platform.startswith('freebsd')),
|
||||||
ON_NETBSD = LazyBool(lambda: (sys.platform.startswith('netbsd')),
|
ON_NETBSD = LazyBool(lambda: (sys.platform.startswith('netbsd')),
|
||||||
globals(), 'ON_NETBSD')
|
globals(), 'ON_NETBSD')
|
||||||
"""``True`` if on a NetBSD operating system, else ``False``."""
|
"""``True`` if on a NetBSD operating system, else ``False``."""
|
||||||
ON_BSD = LazyBool(lambda: ON_FREEBSD or ON_NETBSD,
|
|
||||||
globals(), 'ON_BSD')
|
|
||||||
"""``True`` if on a BSD operating system, else ``False``."""
|
@lazybool
|
||||||
|
def ON_BSD():
|
||||||
|
"""``True`` if on a BSD operating system, else ``False``."""
|
||||||
|
return bool(ON_FREEBSD) or bool(ON_NETBSD)
|
||||||
|
|
||||||
|
|
||||||
|
@lazybool
|
||||||
|
def ON_BEOS():
|
||||||
|
"""True if we are on BeOS or Haiku."""
|
||||||
|
return sys.platform == 'beos5' or sys.platform == 'haiku1'
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -361,3 +371,60 @@ def PATH_DEFAULT():
|
||||||
else:
|
else:
|
||||||
pd = ()
|
pd = ()
|
||||||
return pd
|
return pd
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# libc
|
||||||
|
#
|
||||||
|
@lazyobject
|
||||||
|
def LIBC():
|
||||||
|
"""The platform dependent libc implementation."""
|
||||||
|
if ON_DARWIN:
|
||||||
|
libc = ctypes.CDLL(ctypes.util.find_library("c"))
|
||||||
|
elif ON_CYGWIN:
|
||||||
|
libc = ctypes.CDLL('cygwin1.dll')
|
||||||
|
elif ON_BSD:
|
||||||
|
try:
|
||||||
|
libc = ctypes.CDLL('libc.so')
|
||||||
|
except AttributeError:
|
||||||
|
libc = None
|
||||||
|
except OSError:
|
||||||
|
# OS X; can't use ctypes.util.find_library because that creates
|
||||||
|
# a new process on Linux, which is undesirable.
|
||||||
|
try:
|
||||||
|
libc = ctypes.CDLL('libc.dylib')
|
||||||
|
except OSError:
|
||||||
|
libc = None
|
||||||
|
elif ON_POSIX:
|
||||||
|
try:
|
||||||
|
libc = ctypes.CDLL('libc.so')
|
||||||
|
except AttributeError:
|
||||||
|
libc = None
|
||||||
|
except OSError:
|
||||||
|
# Debian and derivatives do the wrong thing because /usr/lib/libc.so
|
||||||
|
# is a GNU ld script rather than an ELF object. To get around this, we
|
||||||
|
# have to be more specific.
|
||||||
|
# We don't want to use ctypes.util.find_library because that creates a
|
||||||
|
# new process on Linux. We also don't want to try too hard because at
|
||||||
|
# this point we're already pretty sure this isn't Linux.
|
||||||
|
try:
|
||||||
|
libc = ctypes.CDLL('libc.so.6')
|
||||||
|
except OSError:
|
||||||
|
libc = None
|
||||||
|
if not hasattr(libc, 'sysinfo'):
|
||||||
|
# Not Linux.
|
||||||
|
libc = None
|
||||||
|
elif ON_WINDOWS:
|
||||||
|
if hasattr(ctypes, 'windll') and hasattr(ctypes.windll, 'kernel32'):
|
||||||
|
libc = ctypes.windll.kernel32
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# Windows CE uses the cdecl calling convention.
|
||||||
|
libc = ctypes.CDLL('coredll.lib')
|
||||||
|
except (AttributeError, OSError):
|
||||||
|
libc = None
|
||||||
|
elif ON_BEOS:
|
||||||
|
libc = ctypes.CDLL('libroot.so')
|
||||||
|
else:
|
||||||
|
libc = None
|
||||||
|
return libc
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
# amalgamate
|
||||||
|
# amalgamate end
|
274
xonsh/xoreutils/uptime.py
Normal file
274
xonsh/xoreutils/uptime.py
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
"""
|
||||||
|
Provides a cross-platform way to figure out the system uptime.
|
||||||
|
|
||||||
|
Should work on damned near any operating system you can realistically expect
|
||||||
|
to be asked to write Python code for.
|
||||||
|
If this module is invoked as a stand-alone script, it will print the current
|
||||||
|
uptime in a human-readable format, or display an error message if it can't,
|
||||||
|
to standard output.
|
||||||
|
|
||||||
|
This file was forked from the uptime project: https://github.com/Cairnarvon/uptime
|
||||||
|
Copyright (c) 2012, Koen Crolla, All rights reserved.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import ctypes
|
||||||
|
import struct
|
||||||
|
|
||||||
|
import xonsh.platform as xp
|
||||||
|
import xonsh.lazyimps as xlimps
|
||||||
|
import xonsh.lazyasd as xl
|
||||||
|
|
||||||
|
|
||||||
|
_BOOTTIME = None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_osx():
|
||||||
|
"""Returns the uptime on mac / darwin."""
|
||||||
|
global _BOOTTIME
|
||||||
|
bt = xlimps.macutils.sysctlbyname(b"kern.boottime", return_str=False)
|
||||||
|
if len(bt) == 4:
|
||||||
|
bt = struct.unpack_from('@hh', bt)
|
||||||
|
elif len(bt) == 8:
|
||||||
|
bt = struct.unpack_from('@ii', bt)
|
||||||
|
elif len(bt) == 16:
|
||||||
|
bt = struct.unpack_from('@qq', bt)
|
||||||
|
else:
|
||||||
|
raise ValueError('length of boot time not understood: ' + repr(bt))
|
||||||
|
bt = bt[0] + bt[1]*1e-6
|
||||||
|
if bt == 0.0:
|
||||||
|
return None
|
||||||
|
_BOOTTIME = bt
|
||||||
|
return time.time() - bt
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_linux():
|
||||||
|
"""Returns uptime in seconds or None, on Linux."""
|
||||||
|
# With procfs
|
||||||
|
try:
|
||||||
|
with open('/proc/uptime', 'r') as f:
|
||||||
|
up = float(f.readline().split()[0])
|
||||||
|
return up
|
||||||
|
except (IOError, ValueError):
|
||||||
|
pass
|
||||||
|
buf = ctypes.create_string_buffer(128) # 64 suffices on 32-bit, whatever.
|
||||||
|
if xp.LIBC.sysinfo(buf) < 0:
|
||||||
|
return None
|
||||||
|
up = struct.unpack_from('@l', buf.raw)[0]
|
||||||
|
if up < 0:
|
||||||
|
up = None
|
||||||
|
return up
|
||||||
|
|
||||||
|
|
||||||
|
def _boottime_linux():
|
||||||
|
"""A way to figure out the boot time directly on Linux."""
|
||||||
|
global _BOOTTIME
|
||||||
|
try:
|
||||||
|
with open('/proc/stat', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('btime'):
|
||||||
|
_BOOTTIME = float(line.split()[1])
|
||||||
|
return _BOOTTIME
|
||||||
|
except (IOError, IndexError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_amiga():
|
||||||
|
"""Returns uptime in seconds or None, on AmigaOS."""
|
||||||
|
global _BOOTTIME
|
||||||
|
try:
|
||||||
|
_BOOTTIME = os.stat('RAM:').st_ctime
|
||||||
|
return time.time() - _BOOTTIME
|
||||||
|
except (NameError, OSError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_beos():
|
||||||
|
"""Returns uptime in seconds on None, on BeOS/Haiku."""
|
||||||
|
if not hasattr(xp.LIBC, 'system_time'):
|
||||||
|
return None
|
||||||
|
xp.LIBC.system_time.restype = ctypes.c_int64
|
||||||
|
return xp.LIBC.system_time() / 1000000.
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_bsd():
|
||||||
|
"""Returns uptime in seconds or None, on BSD (including OS X)."""
|
||||||
|
global _BOOTTIME
|
||||||
|
if not hasattr(xp.LIBC, 'sysctlbyname'):
|
||||||
|
# Not BSD.
|
||||||
|
return None
|
||||||
|
# Determine how much space we need for the response.
|
||||||
|
sz = ctypes.c_uint(0)
|
||||||
|
xp.LIBC.sysctlbyname('kern.boottime', None, ctypes.byref(sz), None, 0)
|
||||||
|
if sz.value != struct.calcsize('@LL'):
|
||||||
|
# Unexpected, let's give up.
|
||||||
|
return None
|
||||||
|
# For real now.
|
||||||
|
buf = ctypes.create_string_buffer(sz.value)
|
||||||
|
xp.LIBC.sysctlbyname('kern.boottime', buf, ctypes.byref(sz), None, 0)
|
||||||
|
sec, usec = struct.unpack_from('@LL', buf.raw)
|
||||||
|
# OS X disagrees what that second value is.
|
||||||
|
if usec > 1000000:
|
||||||
|
usec = 0.
|
||||||
|
_BOOTTIME = sec + usec / 1000000.
|
||||||
|
up = time.time() - _BOOTTIME
|
||||||
|
if up < 0:
|
||||||
|
up = None
|
||||||
|
return up
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_minix():
|
||||||
|
"""Returns uptime in seconds or None, on MINIX."""
|
||||||
|
try:
|
||||||
|
with open('/proc/uptime', 'r') as f:
|
||||||
|
up = float(f.read())
|
||||||
|
return up
|
||||||
|
except (IOError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_plan9():
|
||||||
|
"""Returns uptime in seconds or None, on Plan 9."""
|
||||||
|
# Apparently Plan 9 only has Python 2.2, which I'm not prepared to
|
||||||
|
# support. Maybe some Linuxes implement /dev/time, though, someone was
|
||||||
|
# talking about it somewhere.
|
||||||
|
try:
|
||||||
|
# The time file holds one 32-bit number representing the sec-
|
||||||
|
# onds since start of epoch and three 64-bit numbers, repre-
|
||||||
|
# senting nanoseconds since start of epoch, clock ticks, and
|
||||||
|
# clock frequency.
|
||||||
|
# -- cons(3)
|
||||||
|
with open('/dev/time', 'r') as f:
|
||||||
|
s, ns, ct, cf = f.read().split()
|
||||||
|
return float(ct) / float(cf)
|
||||||
|
except (IOError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_solaris():
|
||||||
|
"""Returns uptime in seconds or None, on Solaris."""
|
||||||
|
global _BOOTTIME
|
||||||
|
try:
|
||||||
|
kstat = ctypes.CDLL('libkstat.so')
|
||||||
|
except (AttributeError, OSError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# kstat doesn't have uptime, but it does have boot time.
|
||||||
|
# Unfortunately, getting at it isn't perfectly straightforward.
|
||||||
|
# First, let's pretend to be kstat.h
|
||||||
|
|
||||||
|
# Constant
|
||||||
|
KSTAT_STRLEN = 31 # According to every kstat.h I could find.
|
||||||
|
|
||||||
|
# Data structures
|
||||||
|
class anon_union(ctypes.Union):
|
||||||
|
# The ``value'' union in kstat_named_t actually has a bunch more
|
||||||
|
# members, but we're only using it for boot_time, so we only need
|
||||||
|
# the padding and the one we're actually using.
|
||||||
|
_fields_ = [('c', ctypes.c_char * 16),
|
||||||
|
('time', ctypes.c_int)]
|
||||||
|
|
||||||
|
class kstat_named_t(ctypes.Structure):
|
||||||
|
_fields_ = [('name', ctypes.c_char * KSTAT_STRLEN),
|
||||||
|
('data_type', ctypes.c_char),
|
||||||
|
('value', anon_union)]
|
||||||
|
|
||||||
|
# Function signatures
|
||||||
|
kstat.kstat_open.restype = ctypes.c_void_p
|
||||||
|
kstat.kstat_lookup.restype = ctypes.c_void_p
|
||||||
|
kstat.kstat_lookup.argtypes = [ctypes.c_void_p,
|
||||||
|
ctypes.c_char_p,
|
||||||
|
ctypes.c_int,
|
||||||
|
ctypes.c_char_p]
|
||||||
|
kstat.kstat_read.restype = ctypes.c_int
|
||||||
|
kstat.kstat_read.argtypes = [ctypes.c_void_p,
|
||||||
|
ctypes.c_void_p,
|
||||||
|
ctypes.c_void_p]
|
||||||
|
kstat.kstat_data_lookup.restype = ctypes.POINTER(kstat_named_t)
|
||||||
|
kstat.kstat_data_lookup.argtypes = [ctypes.c_void_p,
|
||||||
|
ctypes.c_char_p]
|
||||||
|
|
||||||
|
# Now, let's do something useful.
|
||||||
|
# Initialise kstat control structure.
|
||||||
|
kc = kstat.kstat_open()
|
||||||
|
if not kc:
|
||||||
|
return None
|
||||||
|
# We're looking for unix:0:system_misc:boot_time.
|
||||||
|
ksp = kstat.kstat_lookup(kc, 'unix', 0, 'system_misc')
|
||||||
|
if ksp and kstat.kstat_read(kc, ksp, None) != -1:
|
||||||
|
data = kstat.kstat_data_lookup(ksp, 'boot_time')
|
||||||
|
if data:
|
||||||
|
_BOOTTIME = data.contents.value.time
|
||||||
|
# Clean-up.
|
||||||
|
kstat.kstat_close(kc)
|
||||||
|
if _BOOTTIME is not None:
|
||||||
|
return time.time() - _BOOTTIME
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_syllable():
|
||||||
|
"""Returns uptime in seconds or None, on Syllable."""
|
||||||
|
global _BOOTTIME
|
||||||
|
try:
|
||||||
|
_BOOTTIME = os.stat('/dev/pty/mst/pty0').st_mtime
|
||||||
|
return time.time() - _BOOTTIME
|
||||||
|
except (NameError, OSError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uptime_windows():
|
||||||
|
"""
|
||||||
|
Returns uptime in seconds or None, on Windows. Warning: may return
|
||||||
|
incorrect answers after 49.7 days on versions older than Vista.
|
||||||
|
"""
|
||||||
|
if hasattr(xp.LIBC, 'GetTickCount64'):
|
||||||
|
# Vista/Server 2008 or later.
|
||||||
|
xp.LIBC.GetTickCount64.restype = ctypes.c_uint64
|
||||||
|
return xp.LIBC.GetTickCount64() / 1000.
|
||||||
|
if hasattr(xp.LIBC, 'GetTickCount'):
|
||||||
|
# WinCE and Win2k or later; gives wrong answers after 49.7 days.
|
||||||
|
xp.LIBC.GetTickCount.restype = ctypes.c_uint32
|
||||||
|
return xp.LIBC.GetTickCount() / 1000.
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@xl.lazyobject
|
||||||
|
def _UPTIME_FUNCS():
|
||||||
|
return {'amiga': _uptime_amiga,
|
||||||
|
'aros12': _uptime_amiga,
|
||||||
|
'beos5': _uptime_beos,
|
||||||
|
'cygwin': _uptime_linux,
|
||||||
|
'darwin': _uptime_osx,
|
||||||
|
'haiku1': _uptime_beos,
|
||||||
|
'linux': _uptime_linux,
|
||||||
|
'linux-armv71': _uptime_linux,
|
||||||
|
'linux2': _uptime_linux,
|
||||||
|
'minix3': _uptime_minix,
|
||||||
|
'sunos5': _uptime_solaris,
|
||||||
|
'syllable': _uptime_syllable,
|
||||||
|
'win32': _uptime_windows,
|
||||||
|
'wince': _uptime_windows}
|
||||||
|
|
||||||
|
|
||||||
|
def uptime():
|
||||||
|
"""Returns uptime in seconds if even remotely possible, or None if not."""
|
||||||
|
if _BOOTTIME is not None:
|
||||||
|
return time.time() - _BOOTTIME
|
||||||
|
up = _UPTIME_FUNCS.get(sys.platform, _uptime_bsd)()
|
||||||
|
if up is None:
|
||||||
|
up = (_uptime_bsd() or _uptime_plan9() or _uptime_linux() or
|
||||||
|
_uptime_windows() or _uptime_solaris() or _uptime_beos() or
|
||||||
|
_uptime_amiga() or _uptime_syllable() or _uptime_osx())
|
||||||
|
return up
|
||||||
|
|
||||||
|
|
||||||
|
def boottime():
|
||||||
|
"""Returns boot time if remotely possible, or None if not."""
|
||||||
|
global _BOOTTIME
|
||||||
|
if _BOOTTIME is None:
|
||||||
|
up = uptime()
|
||||||
|
if up is None:
|
||||||
|
return None
|
||||||
|
_BOOTTIME = time.time() - up
|
||||||
|
return _BOOTTIME
|
Loading…
Add table
Reference in a new issue