Skip to content

Instantly share code, notes, and snippets.

@hitalos
Last active November 6, 2024 17:53
Show Gist options
  • Save hitalos/b67024ea505a33fd429b51f25ab74fa2 to your computer and use it in GitHub Desktop.
Save hitalos/b67024ea505a33fd429b51f25ab74fa2 to your computer and use it in GitHub Desktop.
Get system info from linux files
module sysfetch
go 1.23.2
package main
import (
"bufio"
"bytes"
"fmt"
"os"
"strconv"
"strings"
"time"
)
type Item struct {
title string
info func() string
}
var (
shell string
items = []Item{
{"User", func() (user string) { user, shell = userInfo(); return }},
{"OS", osInfo},
{"Shell", func() string { return shell }},
{"Kernel", kernel},
{"Host", host},
{"CPU", cpu},
{"Uptime", uptime},
{"Memory", memory},
}
)
func maxLength(items []Item) int {
max := 0
for _, item := range items {
if len(item.title) > max {
max = len(item.title)
}
}
return max
}
func printInfo(title string, info string) {
os.Stdout.WriteString(title + ": " + strings.Repeat(" ", maxLength(items)-len(title)) + info + "\n")
}
func userInfo() (string, string) {
hostnameContent, _ := os.ReadFile("/etc/hostname")
statusContent, _ := os.ReadFile(fmt.Sprintf("/proc/%d/status", os.Getpid()))
passwdContent, _ := os.ReadFile("/etc/passwd")
var uid, user, shell string
for _, line := range strings.Split(string(statusContent), "\n") {
if strings.HasPrefix(line, "Uid:") {
uid = strings.Split(strings.Split(line, ":")[1], "\t")[1]
break
}
}
for _, line := range strings.Split(string(passwdContent), "\n") {
parts := strings.Split(line, ":")
if parts[2] == uid {
user = parts[0] + "@" + strings.TrimSpace(string(hostnameContent))
shell = parts[6]
break
}
}
return user, shell
}
func osInfo() string {
osRelease, _ := os.ReadFile("/etc/os-release")
for _, line := range strings.Split(string(osRelease), "\n") {
if strings.Contains(line, "PRETTY_NAME") {
return string(osRelease)[len(`PRETTY_NAME="`) : len(line)-1]
}
}
return ""
}
func kernel() string {
kernelVersion, _ := os.ReadFile("/proc/sys/kernel/osrelease")
kernelArch, _ := os.ReadFile("/proc/sys/kernel/arch")
return fmt.Sprintf("%s %s", bytes.TrimSpace(kernelVersion), bytes.TrimSpace(kernelArch))
}
func host() string {
hostVendor, _ := os.ReadFile("/sys/devices/virtual/dmi/id/board_vendor")
hostBoard, _ := os.ReadFile("/sys/devices/virtual/dmi/id/board_name")
return fmt.Sprintf("%s (%s)", bytes.TrimSpace(hostVendor), bytes.TrimSpace(hostBoard))
}
func cpu() string {
f, _ := os.Open("/proc/cpuinfo")
defer f.Close()
scan := bufio.NewScanner(f)
var line, cpuModel, cpuCores string
for scan.Scan() {
line = scan.Text()
if strings.Contains(line, "model name") {
cpuModel = strings.TrimSpace(strings.Split(line, ":")[1])
continue
}
if strings.Contains(line, "cpu cores") {
cpuCores = strings.TrimSpace(strings.Split(line, ":")[1])
break
}
}
return cpuModel + " (x" + cpuCores + ")"
}
func uptime() string {
uptimeContent, _ := os.ReadFile("/proc/uptime")
uptimeSeconds := uptimeContent[:bytes.Index(uptimeContent, []byte("."))]
uptimeDuration, _ := time.ParseDuration(string(uptimeSeconds) + "s")
daysCount := uptimeDuration / (24 * time.Hour)
hoursCount := int(uptimeDuration.Hours()) % 24
minutesCount := int(uptimeDuration.Minutes()) % 60
days := ""
switch daysCount {
case 1:
days = "1 dia, "
default:
days = fmt.Sprintf("%d dias, ", daysCount)
}
hours := ""
switch hoursCount {
case 1:
hours = "1 hora e "
default:
hours = fmt.Sprintf("%d horas e ", hoursCount)
}
minutes := ""
switch minutesCount {
case 1:
minutes = "1 minuto"
default:
minutes = fmt.Sprintf("%d minutos", minutesCount)
}
return days + hours + minutes
}
func formatBytes(val int) string {
bytes := float64(val)
unit := "B"
if bytes >= 1024 {
bytes /= 1024
unit = "KB"
}
if bytes >= 1024 {
bytes /= 1024
unit = "MB"
}
if bytes >= 1024 {
bytes /= 1024
unit = "GB"
}
return fmt.Sprintf("%.3f %s", bytes, unit)
}
func memory() string {
f, _ := os.Open("/proc/meminfo")
defer f.Close()
scan := bufio.NewScanner(f)
var line, memory, free string
for scan.Scan() {
line = scan.Text()
if strings.Contains(line, "MemTotal") {
memory = strings.TrimSpace(strings.Split(line, ":")[1])
continue
}
if strings.Contains(line, "MemAvailable") {
free = strings.TrimSpace(strings.Split(line, ":")[1])
break
}
}
memoryTotal, _ := strconv.Atoi(memory[:strings.Index(memory, " ")])
memoryFree, _ := strconv.Atoi(free[:strings.Index(free, " ")])
percUsed := (float64(memoryTotal - memoryFree)) / float64(memoryTotal) * 100
return fmt.Sprintf("%s / %s (%.2f%%)", formatBytes(1024*memoryFree), formatBytes(1024*memoryTotal), percUsed)
}
func main() {
for _, item := range items {
printInfo(item.title, item.info())
}
}
const { readFile } = require('fs/promises')
const items = ['User', 'OS', 'Shell', 'Kernel', 'Host', 'CPU', 'Uptime', 'Memory']
const max_length = items.reduce((a, b) => a.length > b.length ? a : b).length
const print_info = (title, info) => {
const spaces = ' '.repeat(max_length - title.length)
process.stdout.write(`${title}: ${spaces}${info}\n`)
}
const format_bytes = (val) => {
let bytes = val
let unit = bytes >= 1024 ? ((bytes /= 1024), 'KB') : 'B'
unit = bytes >= 1024 ? ((bytes /= 1024), 'MB') : unit
unit = bytes >= 1024 ? ((bytes /= 1024), 'GB') : unit
return `${bytes.toFixed(3)} ${unit}`
}
const format_time = (time) => {
const seconds = parseInt(time.trim())
const out = {
days: Math.floor(seconds / 86400),
hours: Math.floor((seconds % 86400) / 3600),
minutes: Math.floor(((seconds % 86400) % 3600) / 60),
}
switch (out.days) {
case 0: out.days = ''; break
case 1: out.days = '1 dia, '; break
default: out.days = `${out.days} dias, `
}
switch (out.hours) {
case 0: out.hours = ''; break
case 1: out.hours = '1 hora e '; break
default: out.hours = `${out.hours} horas e `
}
switch (out.minutes) {
case 1: out.minutes = '1 minuto'; break
default: out.minutes = `${out.minutes} minutos`
}
return `${out.days}${out.hours}${out.minutes}`
}
const userinfo = (hostnameContent, statusContent, passwdContent) => {
const uid = /Uid:\s+(\d+)\s/.exec(statusContent)[1]
const passwdLine = passwdContent.split('\n').filter((line) => line.split(':')[2] === uid)[0].split(':')
return { user: `${passwdLine[0]}@${hostnameContent.trim()}`, shell: passwdLine[6] }
}
const cpu = (content) => {
const lines = content.split('\n')
const model = lines.filter((l) => l.includes('model name'))[0].split(': ')[1].trim()
const cores = lines.filter((l) => l.includes('cpu cores'))[0].split(': ')[1].trim()
return `${model} (x${cores})`
}
const memory = (content) => {
const lines = content.split('\n')
const total = parseInt(lines.filter((l) => l.includes('MemTotal'))[0].split(': ')[1].trim()) * 1024
const free = parseInt(lines.filter((l) => l.includes('MemAvailable'))[0].split(': ')[1].trim()) * 1024
const percUsed = ((total-free)/total)*100
return `${format_bytes(free)} / ${format_bytes(total)} (${percUsed.toFixed(2)}%)`
}
Promise.all([
readFile('/etc/hostname', 'utf-8'),
readFile(`/proc/${process.pid}/status`, 'utf-8'),
readFile('/etc/passwd', 'utf-8'),
readFile('/etc/os-release', 'utf-8'),
readFile('/proc/sys/kernel/osrelease', 'utf-8'),
readFile('/proc/sys/kernel/arch', 'utf-8'),
readFile('/sys/devices/virtual/dmi/id/board_vendor', 'utf-8'),
readFile('/sys/devices/virtual/dmi/id/board_name', 'utf-8'),
readFile('/proc/cpuinfo', 'utf-8'),
readFile('/proc/uptime', 'utf-8'),
readFile('/proc/meminfo', 'utf-8'),
]).then((results) => {
const info = userinfo(results[0], results[1], results[2])
return {
User: info.user,
OS: /PRETTY_NAME="(.+)"/.exec(results[3])[1],
Shell: info.shell,
Kernel: `${results[4].trim()} ${results[5].trim()}`,
Host: `${results[6].trim()} (${results[7].trim()})`,
CPU: cpu(results[8]),
Uptime: format_time(results[9]),
Memory: memory(results[10]),
}
}).then((result) => items.forEach((item) => print_info(item, result[item])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment