shirou / gopsutil

psutil for golang
Other
10.67k stars 1.59k forks source link

[host][freebsd] Users() returns incorrect "Started" timestamp #709

Closed ppmathis closed 5 years ago

ppmathis commented 5 years ago

Describe the bug Calling host.Users() on a FreeBSD system which uses the utmpx POSIX standard (default since FreeBSD 9.0) returns a slice of UserStat structs, which contains an incorrect value for the Started attribute. Instead of containing a UNIX timestamp representing the start time of the user session, a seemingly random timestamp is being returned.

To Reproduce Start a new user session at a FreeBSD system (e.g. SSH to the machine), then run the following code snippet:

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/host"
)

func main() {
    users, _ := host.Users()
    for _, user := range users {
        fmt.Printf("%s@%s@%s - %d", user.User, user.Terminal, user.Host, user.Started)
    }
}

As an example, this resulted in the following output on my system: root@pts/0@<my reverse dns> - 1732593154 - converting the supposed UNIX timestamp to a human-readable date results in 11/26/2024 @ 3:52am (UTC), which is obviously way off as I am unable to start sessions in the future :)

Expected behavior Calling host.Users() on a FreeBSD system should return a correct UNIX timestamp specifying when the session got started. This behavior would be equivalent to the other supported operating systems, e.g. Linux.

Environment (please complete the following information):

Root cause gopsutil is currently using the C struct declaration utmpx, which is incompatible with the format used by FreeBSD for /var/run/utx.active. While struct utmpx is being represented according to the POSIX standards and used internally in the kernel, FreeBSD chose to use a different representation for the utx.active file.

This can be read in the initial commit which introduced the utmpx implementation to FreeBSD in 2010:

The standard allows the on-disk format to be different than the in-memory representation (struct utmpx). Most operating systems don't do this, but we do. This allows us to keep our ABI more stable, while giving us the opportunity to modify the on-disk format. It also allows us to use a common file format across different architectures (i.e. byte ordering).

The correct structure which should be used for parsing the file is present in lib/libc/gen/utxdb.h, which has some notable differences:

I have already verified that using struct futx would result in the correct timestamp by analyzing a copy of utx.active in a hex editor, which can be seen here: https://zig.pw/3916bfaca6116fe1e5d67b314e6de03c.png

Unfortunately this structure is not being included in the regular header files available in a base FreeBSD installation, so this structure would either have to be manually replicated (without Cgo) or we would have to use the actual C functions to retrieve struct utmpx instances. I couldn't think of a satisfying solution so far, which is why I am opening this as an issue.

shirou commented 5 years ago

Thank you! I will check in this weekend.

Lomanic commented 5 years ago

Thanks for this excellent report. I can reproduce indeed. I tried to regenerate host_freebsd_amd64.go with cgo -godefs types_freebsd.go > host_freebsd_amd64.go on a FreeBSD 12.0 RELEASE VM, but then Utmp was defined as an empty struct and would break the code (and generated types would be sometimes different also).

shirou commented 5 years ago

From this great report, I can create a fix PR #712. please check it and if it works on your environment, I can merge the PR. Thanks!

ppmathis commented 5 years ago

@shirou Thank you very much! I have commented on the PR regarding my test results and can confirm that it does fix this specific issue.

shirou commented 5 years ago

712 is merged. Big thanks for this report and your contribution!