On 2016-12-05 18:26, Wildman via Python-list wrote: > On Mon, 05 Dec 2016 16:08:57 -0600, Tim Chase wrote: > > > On 2016-12-05 14:58, Wildman via Python-list wrote: > >> I there a way to detect what the Linux runlevel is from > >> within a Python program? I would like to be able to do > >> it without the use of an external program such as 'who' > >> or 'runlevel'. > > > > You can use something like > > > > https://gist.github.com/likexian/f9da722585036d372dca > > > > to parse the /var/run/utmp contents. Based on some source-code > > scrounging, it looks like you want the first field to be "1" for > > the "runlevel" account. To extract the actual runlevel, you can > > take the PID value from the second column ("53" in my example > > here) and take it's integer value mod 256 (AKA "& 0xff") to get > > the character value. So chr(int("53") & 0xff) returns "5" in my > > case, which is my runlevel. > > > > Additional links I found helpful while searching: > > > > https://casper.berkeley.edu/svn/trunk/roach/sw/busybox-1.10.1/miscutils/runlevel.c > > https://github.com/garabik/python-utmp > > That is exactly the kind of thing I was looking for. Thank you. > Now all I have to do is get it to work with Python3.
This works based on my poking at it in both Py2 and Py3: import struct from collections import namedtuple try: basestring except NameError: basestring = str UTMP = namedtuple("UTMP", [ "ut_type", # Type of record "ut_pid", # PID of login process "ut_line", # Device name of tty - "/dev/" "ut_id", # Terminal name suffix, or inittab(5) ID "ut_user", # Username "ut_host", # Hostname for remote login, or kernel version for run-level messages "e_termination", # Process termination status "e_exit", # Process exit status "ut_session", # Session ID (getsid(2)), used for windowing "tv_sec", # Seconds "tv_usec", # Microseconds "ut_addr_v6a", # Internet address of remote host; IPv4 address uses just ut_addr_v6[0] "ut_addr_v6b", # Internet address of remote host; IPv4 address uses just ut_addr_v6[0] "ut_addr_v6c", # Internet address of remote host; IPv4 address uses just ut_addr_v6[0] "ut_addr_v6d", # Internet address of remote host; IPv4 address uses just ut_addr_v6[0] #"__unused", # Reserved for future use ]) XTMP_STRUCT = "hi32s4s32s256shhiiiiiii20x" XTMP_STRUCT_SIZE = struct.calcsize(XTMP_STRUCT) # ut_types EMPTY = 0 RUN_LVL = 1 BOOT_TIME = 2 OLD_TIME = 3 NEW_TIME = 4 INIT_PROCESS = 5 # Process spawned by "init" LOGIN_PROCESS = 6 # A "getty" process DEFAULT_UTMP = "/var/run/utmp" def parse_utmp(utmp_fname=DEFAULT_UTMP): with open(utmp_fname, "rb") as f: while True: bytes = f.read(XTMP_STRUCT_SIZE) if not bytes: break bits = struct.unpack(XTMP_STRUCT, bytes) bits = [ bit.rstrip('\0') if isinstance(bit, basestring) else bit for bit in bits ] yield UTMP(*bits) def filter(ut_type, utmp_fname=DEFAULT_UTMP): for utmp in parse_utmp(utmp_fname): if utmp.ut_type == ut_type: yield utmp def get_runlevel(utmp_fname=DEFAULT_UTMP): return chr(next(filter(RUN_LVL, utmp_fname)).ut_pid & 0xFF) if __name__ == "__main__": print("Runlevel: %s" % get_runlevel()) -tkc -- https://mail.python.org/mailman/listinfo/python-list