This is a golang client module which support utmpx
API: which includes utmpx and wtmp. The new API is inspired by libutempter. Currently, The implementation is a golang wrapper for utmpx
C library. On alpine linux (musl based) it will call utmps through utmpx API. On other linux (glibc based) it will call glibc utmpx API.
To use goutmp module in your golang development, you need to provide additional build tags.
go build -tags utmps . # for alpine linux
go build -tags utmp . # for glibc based linux
// called when user login, adds a login utmp/wtmp record to database with the specified
// pseudo-terminal device name, user name, host name and process PID.
// this function will update both utmp and wtmp within one call
func AddRecord(ptsName string, user string, host string, pid int) bool {
// called when user logout, marks a login session as being closed with the specified
// pseudo-terminal device name, process PID.
// this function will update both utmp and wtmp within one call
func RemoveRecord(ptsName string, pid int) bool {
// read the next utmpx record from utmp database
func GetRecord() *Utmpx
// Add a record to last log, with the specified login line, username and
// originating host/IP.
func AddLastLog(line, userName, host string) bool {
To edit or browse source code in this project, you need to set the following environment variable for nvide
export GOFLAGS="-tags=utmps" # for musl based linux, such as: alpine
export GOFLAGS="-tags=utmp" # for glibc based linux, such as: fedora, redhat
Refer to alpine container with openrc support to build the docker image, run the following command to start container.
% docker run --env TZ=Asia/Shanghai --tty --privileged --volume /sys/fs/cgroup:/sys/fs/cgroup:ro \
-h openrc-ssh --name openrc-ssh -d -p 5022:22 openrc-ssh:0.1.0
Install go
SDK and utmps-dev
package to prepare build dependencies. Note, the following command require root privilege.
# apk add go utmps-dev
Run setup-utmp
script to setup utmps
services for the container. Note, this command require root privilege.
# setup-utmp
Restart the container. Run the following command to make sure everything works. pstree
command shows that 3 utmps
related service is ready for us. who
and last
command shows the correct result from utmps
service.
openrc-ssh:~# pstree -p
init(1)-+-s6-ipcserverd(154)
|-s6-ipcserverd(217)
|-s6-ipcserverd(245)
`-sshd(190)---sshd(286)---ash(288)---pstree(292)
openrc-ssh:~# who
root pts/1 00:00 May 29 22:48:09 172.17.0.1
openrc-ssh:~# last
USER TTY HOST LOGIN TIME
root pts/1 172.17.0.1 May 29 22:48
Now, it's time to build your application and run it according to the following section.
Add user ide
into utmp
group. This is required by utmps
. Note, this command require root privilege.
openrc-ssh:~# adduser ide utmp
Set GID for the application. Note, local mounted file system in docker (such as the ~/develop directory) doesn't support set GID application. That is why we move it to the /tmp
directory.
openrc-ssh:~/develop/goutmp$ go build -tags utmps main/test_linux.go
openrc-ssh:~/develop/goutmp$ ls -al
total 2116
drwxr-xr-x 11 ide develop 352 May 29 22:50 .
drwxr-xr-x 24 ide develop 768 May 24 07:00 ..
drwxr-xr-x 16 ide develop 512 May 29 21:59 .git
-rw-r--r-- 1 ide develop 515 May 28 19:16 .gitignore
-rw-r--r-- 1 ide develop 1063 May 21 14:31 LICENSE
-rw-r--r-- 1 ide develop 4651 May 29 22:49 README.md
-rw-r--r-- 1 ide develop 41 May 21 14:34 go.mod
-rw-r--r-- 1 ide develop 4120 May 28 19:13 goutmp_linux.go
drwxr-xr-x 3 ide develop 96 May 28 20:11 main
-rwxr-xr-x 1 ide develop 2137992 May 29 22:50 test_linux
drwxr-xr-x 6 ide develop 192 May 28 19:13 xutmp
openrc-ssh:~/develop/goutmp$ cp test_linux /tmp/
openrc-ssh:~/develop/goutmp$ cd /tmp
openrc-ssh:/tmp$ chgrp utmp test_linux # run as root
openrc-ssh:/tmp$ chmod g+s test_linux # run as root
openrc-ssh:/tmp$ ls -al
total 2096
drwxrwxrwt 1 root root 4096 May 29 22:50 .
drwxr-xr-x 1 root root 4096 May 29 22:41 ..
-rwxr-sr-x 1 ide utmp 2137992 May 29 22:50 test_linux
openrc-ssh:/tmp$ ./test_linux
You has a service and want that service has the privileges to access utmps
service. Then you need to set the effective GID for your service to be utmp
. The utmps
service require effective GID of utmp
. Refer to The utmps-utmpd program for detail.
Let's say your service program is prog2
. You need set GID for prog2
. Let's assume that user ide
belongs to two groups: develop
and utmp
. You can use $ adduser ide utmp
command to achieve it.
- first, change the group of
prog2
toutmp
. - second, set-GID for
prog2
. - finally, if you run the
prog2
program, it's effective GID will beutmp
.
openrc-ssh:/tmp$ ls -al
total 2096
drwxrwxrwt 1 root root 4096 May 27 20:38 .
drwxr-xr-x 1 root root 4096 May 27 18:12 ..
-rwxr-xr-x 1 ide develop 2137512 May 27 20:38 prog2
openrc-ssh:/tmp$ chgrp utmp prog2
openrc-ssh:/tmp$ ls -al
total 2096
drwxrwxrwt 1 root root 4096 May 27 20:38 .
drwxr-xr-x 1 root root 4096 May 27 18:12 ..
-rwxr-xr-x 1 ide utmp 2137512 May 27 20:38 prog2
openrc-ssh:/tmp$ chmod g+s prog2
openrc-ssh:/tmp$ ls -al
total 2096
drwxrwxrwt 1 root root 4096 May 27 20:38 .
drwxr-xr-x 1 root root 4096 May 27 18:12 ..
-rwxr-sr-x 1 ide utmp 2137512 May 27 20:38 prog2
Please refer to s6-setuidgid to accomplish the above work in a single command. Note: in docker environment, mounted local file system does not support set UID/GID operation.
After search the internet, I found RLabs/goutmp and decide to use it to access utmp
and wutmp
database. As I learn more about utmp/utmpx API and RLabs/goutmp
. I found it's time to create an alternative go module.
There are several differences between ericwq/goutmp
and RLabs/goutmp
. ericwq/goutmp
refer to libutempter
and the example from The linux programming interface (P829).
ericwq/goutmp
supportutmpx
API, whileRLabs/goutmp
supportutmp
API.ericwq/goutmp
updatewtmp
when updateutmp
record. This behavior is more reasonable.ericwq/goutmp
supporttty
andpts
device, whileRLabs/goutmp
only supportpts
device.
We use the following cgo directive and inline C functions to implement the wrapper. Inline C functions is more easy to build than stand alone C module.
// #cgo pkg-config: utmps skalibs
Please use the following commands to build the stand alone C module, either staticly or dynamicly.
$ cd ./xutmp/
$ gcc -I/usr/include/utmps -lutmps -lskarnet -c -o xutmp.o xutmp.c
$ ar rcs libxutmp.a xutmp.o
$ gcc -shared -I/usr/include/utmps -lutmps -lskarnet -o libxutmp.so xutmp.c
The following cgo directive is for stand alone C module.
/*
#cgo CFLAGS: -I./xutmp
#cgo LDFLAGS: -L${SRCDIR}/xutmp -lxutmp
#include "xutmp.h"
*/
It's MIT license, please see the LICENSE file.