Jon Marnock <[email protected]> writes:

> I know this is an ancient thread, but I just got weewx up and running on 
> OpenBSD and found the FreeBSD kern.boottime thing didn't work for system 
> uptime because the sysctlbyname doesn't exist there.

The try block that has a comment about FreeBSD works on NetBSD also,
which has sysctlbyname.  I would expect it to also work on Dragonfly.

(On NetBSD, it seems /proc/uptime is there with a Linux-compatible value,
so the first method works, if /proc is mounted.)

> I've never programmed in python before, so I'm sure this is horrible, but 
> following the example of the FreeBSD sysctlbyname modification, I've 
> created one that works in OpenBSD:

Most of the complexity seems unavoidable.  I might consider hoisting the
cyptes/libc up a level, but I think it's better to have each try block
be logically self-contained.

> bin/weewx/station.py
> @@ -118,7 +118,22 @@
>                      libc.sysctlbyname("kern.boottime", ctypes.byref(buf), 
> ctypes.byref(size), None, 0)
>                      os_uptime_secs = time.time() - float(buf.value)
>                  except (AttributeError, IOError, NameError):
> -                    pass
> +                    try:
> +                        # for OpenBSD
> +                        import ctypes
> +                        from ctypes.util import find_library
> +                        libc = ctypes.CDLL(find_library('c'))
> +                        # Confession: I don't know how to get a ctype 
> struct for timeval. It's just two longs stacked next to each other and we 
> only care about the first, so this currently works:
> +                        boottime = (ctypes.c_long*2)(0, 0)
> +                        size = ctypes.c_size_t()
> +                        size.value = ctypes.sizeof(boottime)
> +                        CTL_KERN = 1
> +                        KERN_BOOTTIME = 21
> +                        mibs = (ctypes.c_int*2)(CTL_KERN, KERN_BOOTTIME)
> +                        libc.sysctl(ctypes.byref(mibs), len(mibs), 
> ctypes.byref(boottime), ctypes.byref(size), None, 0)
> +                        os_uptime_secs = time.time() - float(boottime[0])
> +                    except:
> +                        pass
>
>          return weewx.units.ValueHelper(value_t=(os_uptime_secs, "second", 
> "group_deltatime"),
>                                         formatter=self.formatter,

Is it really still two longs?  On NetBSD it seems to be struct timespec,
which is a time_t and a long, and time_t is int64_t.

> As this uses a more generic sysctl call it's possible this will also work 
> in FreeBSD and possibly more generally for other unixes that don't have 
> procfs available handy, so it's entirely possible this could replace the 
> current FreeBSD block.

There are two problems with this being a generic approach.  One is the
numeric codepoints.  On NetBSD 21 is OBOOTTIME, which returns struct
timeval50 which is two longs -- but only if COMPAT50 is defined in the
kernel config.  KERN_BOOTTIME is 83, which returns struct timespec.

The other problem already exists, which is that the return types are not
necessarily the same on various systems.

> I don't have FreeBSD handy to test though, so... YMMV :)

Odds are that it might work as a compat call, but that shouldn't be
used.


Overall, I would want to replace the try/except/try notion with a switch
on os type and helper functions for groups of systems that have common
behavior.   That's perhaps a bias on my part not to use exceptions for
things that could avoid them, and partly because this seems to be
getting to be a long list.

Also, I wonder about using a library.  I realize adding a dependency vs
a bit of icky code is a hard call.  And, I didn't quickly find a
maintained library for this.  So I'd change the code to try
/proc/uptime, or at least on Linux and NetBSD, and then have a switch on
OS type with whatever that OS needs.



Reply via email to