system
packageAPI reference for the system
package.
Imports
(9)GetProcessList
GetProcessList returns a list of all processes running on the system.
Returns
func GetProcessList() ([]types.Process, error)
{
var processes []types.Process
// Read the list of files in the /proc directory
files, err := os.ReadDir("/proc")
if err != nil {
return nil, fmt.Errorf("error reading /proc directory: %v", err)
}
// Iterate over each file in /proc and check if it's a process
for _, file := range files {
pid, err := strconv.Atoi(file.Name())
if err == nil {
// If the file name is a number, it's a process
process, err := GetProcessInfo(pid)
if err == nil {
processes = append(processes, *process)
}
}
}
return processes, nil
}
Example
processes, err := system.GetProcessList()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, process := range processes {
fmt.Printf("PID: %d\n", process.PID)
fmt.Printf("Name: %s\n", process.Name)
fmt.Printf("State: %s\n", process.State)
}
GetProcessInfo
GetProcessInfo returns information about a specific process.
Parameters
Returns
func GetProcessInfo(pid int) (*types.Process, error)
{
process := &types.Process{PID: pid}
// Read information from the /proc/{pid}/stat file
statPath := fmt.Sprintf("/proc/%d/stat", pid)
statContent, err := os.ReadFile(statPath)
if err != nil {
return nil, fmt.Errorf("error reading %s: %v", statPath, err)
}
// Extract information from /proc/{pid}/stat content
fields := strings.Fields(string(statContent))
if len(fields) < 24 {
return nil, fmt.Errorf("insufficient fields in %s", statPath)
}
process.Name = fields[1][1 : len(fields[1])-1]
process.State = fields[2]
process.PPID, _ = strconv.Atoi(fields[3])
process.Priority, _ = strconv.Atoi(fields[17])
process.Nice, _ = strconv.Atoi(fields[18])
process.Threads, _ = strconv.Atoi(fields[19])
// Read information from the /proc/{pid}/status file
statusPath := fmt.Sprintf("/proc/%d/status", pid)
statusContent, err := os.ReadFile(statusPath)
if err != nil {
return nil, fmt.Errorf("error reading %s: %v", statusPath, err)
}
// Extract information from /proc/{pid}/status content
lines := strings.Split(string(statusContent), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 2 {
switch fields[0] {
case "Uid:":
process.UID, _ = strconv.Atoi(fields[1])
case "Gid:":
process.GID, _ = strconv.Atoi(fields[1])
}
}
}
return process, nil
}
Example
process, err := system.GetProcessInfo(1)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("PID: %d\n", process.PID)
fmt.Printf("Name: %s\n", process.Name)
fmt.Printf("State: %s\n", process.State)
KillProcess
KillProcess terminates a process given its PID.
Parameters
Returns
func KillProcess(pid int) error
{
process, err := os.FindProcess(pid)
if err != nil {
return fmt.Errorf("unable to find process with PID %d: %v", pid, err)
}
err = process.Kill()
if err != nil {
return fmt.Errorf("unable to kill process with PID %d: %v", pid, err)
}
return nil
}
Example
err := system.KillProcess(2024)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
GetSystemInfo
GetSystemInfo returns information about the system, such as OS, version,
codename, architecture and machine type. If the machine type cannot be
determined, it will be set to BareMetal. If any error occurs, it will
be returned.
Returns
func GetSystemInfo() (*types.SystemInfo, error)
{
hostInfo, err := host.Info()
if err != nil {
return nil, err
}
osReleaseInfo, err := readOSRelease()
if err != nil {
return nil, err
}
machineType, err := getMachineType()
if err != nil {
return nil, err
}
info := &types.SystemInfo{
OS: osReleaseInfo.Name,
Version: osReleaseInfo.Version,
Codename: osReleaseInfo.Codename,
Arch: hostInfo.KernelArch,
MachineType: machineType,
}
return info, nil
}
Example
info, err := system.GetSystemInfo()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("OS: %s\n", info.OS)
readOSRelease
readOSRelease reads the /etc/os-release file and returns the OS name,
version and codename. In the future releases on Vanilla OS, we may
consider storing this information in a different file, perhaps using
a better format. If any error occurs, it will be returned.
Returns
func readOSRelease() (*types.OSReleaseInfo, error)
{
osReleaseInfo := &types.OSReleaseInfo{}
file, err := os.Open("/etc/os-release")
if err != nil {
return nil, fmt.Errorf("failed to open /etc/os-release: %v", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
switch key {
case "NAME":
osReleaseInfo.Name = value
case "VERSION_ID":
osReleaseInfo.Version = value
case "VERSION_CODENAME":
osReleaseInfo.Codename = value
}
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error reading /etc/os-release: %v", err)
}
if osReleaseInfo.Name == "" || osReleaseInfo.Version == "" {
return nil, fmt.Errorf("missing or invalid information in /etc/os-release")
}
return osReleaseInfo, nil
}
getMachineType
getMachineType returns the machine type, which can be BareMetal, VM or
Container. If any error occurs, it will be returned.
Returns
func getMachineType() (types.MachineType, error)
{
// There are many ways to check if the system is running in a container,
// we have to check multiple methods to be sure.
// Check if /run/.containerenv file exists
if _, err := os.Stat("/run/.containerenv"); err == nil {
return types.Container, nil
}
// Check if /.dockerenv file exists
if _, err := os.Stat("/.dockerenv"); err == nil {
return types.Container, nil
}
// Check if hypervisor information is present in /proc/cpuinfo
cpuInfo, err := os.ReadFile("/proc/cpuinfo")
if err == nil && strings.Contains(string(cpuInfo), "hypervisor") {
return types.VM, nil
}
// No clear indication of VM or Container, assuming BareMetal
return types.BareMetal, nil
}
RunningInVM
RunningInVM returns true if the system is running in a virtual machine,
otherwise it returns false.
Returns
func RunningInVM() bool
{
info, err := getMachineType()
if err != nil {
return false
}
return info == types.VM
}
Example
if system.RunningInVM() {
fmt.Println("Running in a virtual machine")
} else {
fmt.Println("Not running in a virtual machine")
}
RunningInContainer
RunningInContainer returns true if the system is running in a container,
otherwise it returns false.
Returns
func RunningInContainer() bool
{
info, err := getMachineType()
if err != nil {
return false
}
return info == types.Container
}
Example
if system.RunningInContainer() {
fmt.Println("Running in a container")
} else {
fmt.Println("Not running in a container")
}
RunningInBareMetal
RunningInBareMetal returns true if the system is running on bare metal,
otherwise it returns false.
Returns
func RunningInBareMetal() bool
{
info, err := getMachineType()
if err != nil {
return false
}
return info == types.BareMetal
}
Example
if system.RunningInBareMetal() {
fmt.Println("Running on bare metal")
} else {
fmt.Println("Not running on bare metal")
}
RunningInVMOrContainer
RunningInVMOrContainer returns true if the system is running in a virtual
machine or a container, otherwise it returns false.
Returns
func RunningInVMOrContainer() bool
{
info, err := getMachineType()
if err != nil {
return false
}
return info == types.VM || info == types.Container
}
Example
if system.RunningInVMOrContainer() {
fmt.Println("Running in a virtual machine or a container")
} else {
fmt.Println("Not running in a virtual machine or a container")
}
GetSupportedTimezones
GetSupportedTimezones returns a list of supported timezones.
The list is generated by reading the contents of /usr/share/zoneinfo.
Returns
func GetSupportedTimezones() ([]types.Timezone, error)
{
const zoneinfoPath = "/usr/share/zoneinfo"
files, err := os.ReadDir(zoneinfoPath)
if err != nil {
return nil, err
}
var supportedTimezones []types.Timezone
for _, file := range files {
timezonePath := filepath.Join(zoneinfoPath, file.Name())
if file.IsDir() {
subregionFiles, err := os.ReadDir(timezonePath)
if err != nil {
return nil, err
}
for _, subregionFile := range subregionFiles {
subregion := strings.Join([]string{file.Name(), subregionFile.Name()}, "/")
timezone := types.Timezone{
Name: subregion,
Location: filepath.Join("/usr/share/zoneinfo", subregion),
}
supportedTimezones = append(supportedTimezones, timezone)
}
}
}
return supportedTimezones, nil
}
Example
timezones, err := system.GetSupportedTimezones()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, timezone := range timezones {
fmt.Printf("%s\n", timezone.Name)
fmt.Printf("%s\n", timezone.Location)
}
GetAllUsers
GetAllUsers retrieves information about all users on the system by
parsing /etc/passwd. If includeNoLogin is true, users with /usr/sbin/nologin
as their shell will be included.
Parameters
Returns
func GetAllUsers(includeNoLogin bool) ([]types.UserInfo, error)
{
etcPasswd, err := os.ReadFile("/etc/passwd")
if err != nil {
return nil, fmt.Errorf("error reading /etc/passwd: %v", err)
}
var users []types.UserInfo
for _, line := range strings.Split(string(etcPasswd), "\n") {
if line == "" {
continue
}
items := strings.Split(line, ":")
if len(items) < 7 {
continue
}
username := items[0]
hasLogin := items[6] != "/usr/sbin/nologin"
shell := items[6]
if username == "root" || username == "sync" {
continue
}
if !includeNoLogin && !hasLogin {
continue
}
u, err := user.Lookup(username)
if err != nil {
return nil, fmt.Errorf("error looking up user %s: %v", u, err)
}
users = append(users, types.UserInfo{
UID: u.Uid,
GID: u.Gid,
Username: u.Username,
Name: u.Name,
HomeDir: u.HomeDir,
Shell: shell,
})
}
return users, nil
}
Example
users, err := system.GetAllUsers(false)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, user := range users {
fmt.Printf("UID: %s\n", user.UID)
fmt.Printf("Username: %s\n", user.Username)
}
GetUsers
GetUsers retrieves users with the given usernames and UIDs. If useUID is
true, the returned map will use the UID as the key, otherwise it will use
the username as the key.
Parameters
Returns
func GetUsers(usernames []string, uids []string, useUID bool) map[string]types.UserInfo
{
usersMap := make(map[string]types.UserInfo)
for _, username := range usernames {
u, err := user.Lookup(username)
if err != nil {
// If the user doesn't exist, continue
continue
}
key := u.Username
if useUID {
key = u.Uid
}
usersMap[key] = types.UserInfo{
UID: u.Uid,
GID: u.Gid,
Username: u.Username,
Name: u.Name,
HomeDir: u.HomeDir,
Shell: u.HomeDir,
}
}
for _, uid := range uids {
u, err := user.LookupId(uid)
if err != nil {
// If the user doesn't exist, continue
continue
}
// Check if the user already exists from the previous loop, since the
// developer may have passed in a username and UID that refer to the
// same user
exists := false
for _, user := range usersMap {
if useUID && user.UID == u.Uid {
exists = true
break
} else if !useUID && user.Username == u.Username {
exists = true
break
}
}
if exists {
continue
}
key := uid
if !useUID {
key = u.Username
}
usersMap[key] = types.UserInfo{
UID: u.Uid,
GID: u.Gid,
Username: u.Username,
Name: u.Name,
HomeDir: u.HomeDir,
Shell: u.HomeDir,
}
}
return usersMap
}
Example
users, err := system.GetUsers([]string{"john", "jane"}, []string{"1000"})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, user := range users {
fmt.Printf("UID: %s\n", user.UID)
fmt.Printf("Username: %s\n", user.Username)
}
Notes
if a username and UID refer to the same user, the user will only be
returned once. If an user does not match any of the given usernames or UIDs,
it will not be available in the returned map.
GetAllGroups
GetAllGroups retrieves information about all groups on the system by
parsing /etc/group.
Returns
func GetAllGroups() ([]types.GroupInfo, error)
{
etcGroup, err := os.ReadFile("/etc/group")
if err != nil {
return nil, fmt.Errorf("error reading /etc/group: %v", err)
}
var groups []types.GroupInfo
for _, line := range strings.Split(string(etcGroup), "\n") {
if line == "" {
continue
}
items := strings.Split(line, ":")
if len(items) < 3 {
continue
}
gid := items[2]
name := items[0]
if name == "root" {
continue
}
groups = append(groups, types.GroupInfo{
GID: gid,
Name: name,
})
}
return groups, nil
}
Example
groups, err := system.GetGroups()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, group := range groups {
fmt.Printf("GID: %s\n", group.GID)
fmt.Printf("Name: %s\n", group.Name)
}