blob: 03b9b2d798cb06976e0f2ecdd0680ed69d541c51 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package sysutil provides utilities for getting system-related information.
package sysutil
import (
"bytes"
"os/user"
"strconv"
"strings"
"golang.org/x/sys/unix"
"chromiumos/tast/errors"
)
const (
// ChronosUID is the UID of the user "chronos".
// A constant is defined since this is unlikely to be changed and since
// it simplifies tests.
ChronosUID uint32 = 1000
// ChronosGID is the GID of the group "chronos", similar to ChronosUID.
ChronosGID uint32 = 1000
)
// GetUID returns the UID corresponding to username.
func GetUID(username string) (uint32, error) {
u, err := user.Lookup(username)
if err != nil {
return 0, errors.Wrapf(err, "failed to look up user %q", username)
}
uid, err := strconv.ParseInt(u.Uid, 10, 64)
if err != nil {
return 0, errors.Wrapf(err, "failed to parse UID %q for user %q", u.Uid, username)
}
return uint32(uid), nil
}
// GetGID returns the GID corresponding to group.
func GetGID(group string) (uint32, error) {
g, err := user.LookupGroup(group)
if err != nil {
return 0, errors.Wrapf(err, "failed to look up group %q", group)
}
gid, err := strconv.ParseInt(g.Gid, 10, 64)
if err != nil {
return 0, errors.Wrapf(err, "failed to parse GID %q for group %q", g.Gid, group)
}
return uint32(gid), nil
}
// Utsname contains system information.
type Utsname struct {
// Sysname is the operating system name (e.g., "Linux").
// Corresponds to `uname -s`.
Sysname string
// Nodename is the name within "some implementation-defined network".
// Corresponds to `uname -n`.
Nodename string
// Release is the operating system release (e.g., "2.6.28").
// Corresponds to `uname -r`.
Release string
// Version is the operating system version.
// Corresponds to `uname -v`.
Version string
// Machine is the hardware identifier (e.g., "x86_64").
// Corresponds to `uname -m`.
Machine string
// Domainname is the NIS or YP domain name. This is nonstandard GNU/Linux extension.
Domainname string
}
// Uname is a wrapper of uname system call. See man 2 uname.
func Uname() (*Utsname, error) {
u := &unix.Utsname{}
if err := unix.Uname(u); err != nil {
return nil, err
}
return convertUtsname(u), nil
}
func convertUtsname(u *unix.Utsname) *Utsname {
convert := func(b []byte) string {
return string(bytes.TrimRight(b, "\x00"))
}
return &Utsname{
Sysname: convert(u.Sysname[:]),
Nodename: convert(u.Nodename[:]),
Release: convert(u.Release[:]),
Version: convert(u.Version[:]),
Machine: convert(u.Machine[:]),
Domainname: convert(u.Domainname[:]),
}
}
// KernelVersion contains the Linux kernel major and minor revisions.
type KernelVersion struct {
major, minor int
}
// Is returns true if the kernel version is major.minor else false.
func (v *KernelVersion) Is(major, minor int) bool {
return v.major == major && v.minor == minor
}
// IsOrLater returns true if the kernel version is at least major.minor else false.
func (v *KernelVersion) IsOrLater(major, minor int) bool {
return v.major > major || v.major == major && v.minor >= minor
}
// IsOrLess returns true if the kernel version is at most major.minor else false.
func (v *KernelVersion) IsOrLess(major, minor int) bool {
return v.major < major || v.major == major && v.minor <= minor
}
// KernelVersionAndArch reads the Linux kernel version and arch of the system.
func KernelVersionAndArch() (*KernelVersion, string, error) {
u, err := Uname()
if err != nil {
return nil, "", errors.Wrap(err, "failed to get uname")
}
t := strings.SplitN(u.Release, ".", 3)
major, err := strconv.Atoi(t[0])
if err != nil {
return nil, "", errors.Wrapf(err, "wrong release format %q", u.Release)
}
minor, err := strconv.Atoi(t[1])
if err != nil {
return nil, "", errors.Wrapf(err, "wrong release format %q", u.Release)
}
return &KernelVersion{major: major, minor: minor}, u.Machine, nil
}