utmp

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 2, 2026 License: MPL-2.0 Imports: 11 Imported by: 0

README

go-utmp

Pure-Go parser and analysis library for Linux utmp, wtmp, and btmp records.

The package decodes the 384-byte glibc struct utmp on-disk layout, streams plain or gzip-compressed files, and reconstructs sessions, uptime windows, failed logins, and live users.

records, err := utmp.ReadFile("/var/log/wtmp")
if err != nil {
	return err
}

for _, session := range utmp.Sessions(records) {
	fmt.Println(session.User, session.Line, session.Login, session.EndReason)
}

Documentation

Overview

Package utmp decodes Linux glibc utmp, wtmp, and btmp records and builds higher-level login analysis from those records.

The package is file-oriented and pure Go. It decodes the 384-byte on-disk struct utmp layout, supports plain and gzip-compressed files, and can reconstruct sessions, uptime windows, failed login attempts, and currently live users from decoded records.

By default, records are decoded with the host's native byte order, which is the normal case for files written and read on the same machine. Use WithByteOrder when reading files captured from a different architecture.

Index

Constants

View Source
const RecordSize = 384

RecordSize is the size in bytes of one glibc struct utmp record on disk.

Variables

View Source
var ErrInvalidRecordSize = errors.New("invalid utmp record size")

ErrInvalidRecordSize is returned when a record buffer is not exactly RecordSize bytes, or when a stream ends in the middle of a record.

Functions

This section is empty.

Types

type EndReason

type EndReason string

EndReason explains why a reconstructed session ended.

const (
	// Logout means a DEAD_PROCESS record closed the session.
	Logout EndReason = "logout"
	// Replaced means a newer login reused the same tty before a logout record
	// was observed.
	Replaced EndReason = "replaced"
	// Shutdown means a RUN_LVL shutdown record closed the session.
	Shutdown EndReason = "shutdown"
	// Reboot means a BOOT_TIME record closed the session.
	Reboot EndReason = "reboot"
	// StillLoggedIn means the session remained open at the end of the input.
	StillLoggedIn EndReason = "still_logged_in"
)

type ExitStatus

type ExitStatus struct {
	Termination int16
	Exit        int16
}

ExitStatus is the ut_exit status embedded in a utmp record.

type FailedLogin

type FailedLogin struct {
	User string
	Line string
	Host string
	Addr netip.Addr
	Time time.Time
}

FailedLogin is one failed login attempt decoded from btmp records.

type FailedLoginList

type FailedLoginList []FailedLogin

FailedLoginList is a collection of failed login attempts with aggregation helpers.

func FailedLogins

func FailedLogins(records []Record) FailedLoginList

FailedLogins extracts failed login attempts from btmp-style records. Results are returned in reverse input order, matching lastb's newest-appended-first display without sorting records by timestamp.

func (FailedLoginList) ByAddr

func (f FailedLoginList) ByAddr() map[netip.Addr]int

ByAddr counts failed login attempts by valid source address.

func (FailedLoginList) ByHost

func (f FailedLoginList) ByHost() map[string]int

ByHost counts failed login attempts by hostname.

func (FailedLoginList) ByUser

func (f FailedLoginList) ByUser() map[string]int

ByUser counts failed login attempts by username.

type FileError

type FileError struct {
	Path string
	Err  error
}

FileError reports an error reading one input path.

func (FileError) Error

func (e FileError) Error() string

func (FileError) Unwrap

func (e FileError) Unwrap() error

type FileErrors

type FileErrors []FileError

FileErrors reports one or more file-specific errors from ReadFiles. Successful records are still returned alongside this error.

func (FileErrors) Error

func (e FileErrors) Error() string

func (FileErrors) Unwrap

func (e FileErrors) Unwrap() []error

type Option

type Option func(*config)

Option configures record decoding and file readers.

func WithByteOrder

func WithByteOrder(order binary.ByteOrder) Option

WithByteOrder overrides the byte order used for fixed-width numeric fields. The default is binary.NativeEndian.

func WithFilter

func WithFilter(filter func(Record) bool) Option

WithFilter keeps only records for which filter returns true when reading through Reader, Open, ReadFile.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader streams decoded utmp records from an io.Reader.

func NewReader

func NewReader(r io.Reader, opts ...Option) *Reader

NewReader creates a streaming record reader.

func Open

func Open(path string, opts ...Option) (*Reader, error)

Open opens a utmp, wtmp, or btmp file for streaming. Files ending in .gz are decompressed transparently.

func (*Reader) Close

func (r *Reader) Close() error

Close closes resources opened by Open.

func (*Reader) Next

func (r *Reader) Next() (Record, error)

Next returns the next decoded record, or io.EOF at the end of the stream.

type Record

type Record struct {
	Type    Type
	PID     int32
	Line    string
	ID      string
	User    string
	Host    string
	Exit    ExitStatus
	Session int32
	Time    time.Time
	// Addr is the normalized remote address from ut_addr_v6. Linux stores IPv4
	// addresses in only the first 4 bytes; when the remaining 12 bytes are zero
	// this field is decoded as IPv4. Use RawAddr when that heuristic is ambiguous.
	Addr netip.Addr
	// RawAddr is the exact 16 bytes stored in ut_addr_v6.
	RawAddr [16]byte
}

Record is one decoded glibc struct utmp record.

func DecodeRecord

func DecodeRecord(b []byte, opts ...Option) (Record, error)

DecodeRecord decodes one RecordSize-byte glibc utmp record.

func ReadFile

func ReadFile(path string, opts ...Option) (records []Record, err error)

ReadFile reads all records from one utmp, wtmp, or btmp file.

func ReadFiles

func ReadFiles(paths []string, opts ...Option) ([]Record, error)

ReadFiles reads records from multiple files in caller-provided path order. It returns successfully decoded records even when one or more files fail; in that case the error is FileErrors.

type Session

type Session struct {
	User        string
	Line        string
	ID          string
	Host        string
	Addr        netip.Addr
	PID         int32
	UtmpSession int32
	Login       time.Time
	Logout      time.Time
	EndReason   EndReason
}

Session is a reconstructed user login session.

func LiveUsers

func LiveUsers(records []Record) []Session

LiveUsers returns currently logged-in users from a live utmp snapshot.

The input is expected to be a live utmp snapshot, not a historical wtmp log. If duplicate slots are present, the latest UserProcess or DeadProcess record for each slot wins. Boot and shutdown records are ignored because a live utmp file is a current-state table, not an append-only event stream. Results are ordered by login time, most recent first.

func Sessions

func Sessions(records []Record) []Session

Sessions reconstructs login sessions from decoded wtmp-style records. Results are ordered by login record input position, newest appended first.

func (Session) Duration

func (s Session) Duration() time.Duration

Duration returns the elapsed time between Login and Logout. Active sessions have zero duration because Logout is not known.

func (Session) IsActive

func (s Session) IsActive() bool

IsActive reports whether the session is still open.

type Type

type Type int16

Type is the ut_type field from a utmp record.

const (
	// Empty marks an unused record slot.
	Empty Type = iota
	// RunLevel records a run-level change, including shutdown markers.
	RunLevel
	// BootTime records a system boot.
	BootTime
	// NewTime records the time after a manual clock change.
	NewTime
	// OldTime records the time before a manual clock change.
	OldTime
	// InitProcess records a process spawned by init.
	InitProcess
	// LoginProcess records a getty/login prompt process.
	LoginProcess
	// UserProcess records a logged-in user or btmp failed login attempt.
	UserProcess
	// DeadProcess records a logout or terminated login process.
	DeadProcess
	// Accounting is reserved for accounting records.
	Accounting
)

type Window

type Window struct {
	Start  time.Time
	End    time.Time
	Active bool
}

Window is one system uptime interval.

func Windows

func Windows(records []Record) []Window

Windows reconstructs uptime windows from boot records and shutdown run-level records. Results are returned in reconstructed input order. Clock changes can make End appear before Start; Windows preserves log order and does not normalize wall-clock jumps.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL