Detect Linux Runlevel

Tim Chase python.list at tim.thechases.com
Mon Dec 5 22:42:52 EST 2016


On 2016年12月05日 18:26, Wildman via Python-list wrote:
> On 2016年12月05日 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


More information about the Python-list mailing list

AltStyle によって変換されたページ (->オリジナル) /