uptime code does not work on FreeBSD with python 3

Bug #1853160 reported by Mina Galić on 2019-11-19
12
This bug affects 2 people
Affects Status Importance Assigned to Milestone
cloud-init
Medium
Mina Galić

Bug Description

The uptime code in cloudinit/util.py does not work for FreeBSD (any more)

https://github.com/canonical/cloud-init/blob/3baabe76a70b28abeee2da77826a35e27cf9019a/cloudinit/util.py#L1806-L1825 (link to the code in question at the time of reporting)

root@container-host-02:~ # python3.6
Python 3.6.9 (default, Oct 24 2019, 01:18:01)
[GCC 4.2.1 Compatible FreeBSD Clang 6.0.1 (tags/RELEASE_601/final 335540)] on freebsd12
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> libc = ctypes.CDLL('/lib/libc.so.7')
>>> import time
>>> size = ctypes.c_size_t()
>>> buf = ctypes.c_int()
>>> size.value = ctypes.sizeof(buf)
>>> libc.sysctlbyname("kern.boottime", ctypes.byref(buf), ctypes.byref(size), None, 0)
-1
>>>
root@container-host-02:~ #

and here's what happens when we ask for kern.boottime via sysctl(8):

root@container-host-02:~ # sysctl kern.boottime
kern.boottime: { sec = 1573656128, usec = 384300 } Wed Nov 13 14:42:08 2019
root@container-host-02:~ #

Mina Galić (minagalic) on 2019-11-19
tags: added: freebsd
Mina Galić (minagalic) wrote :

my current attempt to bring this into the new millenium:

import ctypes
import time
import errno

class timeval(ctypes.Structure):
    _fields_ = [
        ("tv_sec", ctypes.c_int64),
        ("tv_usec", ctypes.c_int64)
    ]

libc = ctypes.CDLL('/lib/libc.so.7', use_errno=True)
boottime = timeval()
if libc.sysctlbyname("kern.boottime", ctypes.byref(boottime), ctypes.sizeof(timeval), None, 0) == -1:
    print(errno.errorcode[ctypes.get_errno()])
    exit(1)

which results in ENOENT

which is rather confusing, given that `sysctl kern.boottime` returns
kern.boottime: { sec = 1573656128, usec = 384300 } Wed Nov 13 14:42:08 2019

Mina Galić (minagalic) wrote :

soooooo!

there are two different issues here at play, which confused me a lot

Let's get the simplest one out of the way: ENOENT is caused by the fact that we're passing a Python String to a C function.

when using b"kern.boottime" + "\x00", it works as expected.

The issue in the original code is that kern.boottime is not an integer (any more… and has not been for a long time…)

There are two ways to unpack it: either by loading the value into a generic string buffer: https://github.com/Cairnarvon/uptime/blob/master/src/__init__.py#L135 and then using struct.unpack

or, as i tried above, by constructing a Structure of our own.

Mina Galić (minagalic) on 2019-11-20
summary: - uptime code does not work on FreeBSD
+ uptime code does not work on FreeBSD with python 3
Ryan Harper (raharper) on 2019-11-20
Changed in cloud-init:
importance: Undecided → Medium
status: New → In Progress
Chad Smith (chad.smith) wrote :
Changed in cloud-init:
status: In Progress → Fix Committed
assignee: nobody → Igor Galić (i.galic)
Dan Watkins (oddbloke) on 2020-02-20
Changed in cloud-init:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers