---
id: c90263519492728e7cc2d0ce840057b6
author: Yunjin Lee
title: Közvetlen Linux rendszerhívások tiszta Go-ban a syscall.Syscall és az unsafe.Pointer segítségével
description: Linux-kernel rendszerhívások, például a SYS_SYSINFO közvetlen meghívása tiszta Go kódból, ABI-hoz igazított struktúrák, unsafe.Pointer és a szabványos syscall csomag használatával, cgo nélkül.
language: hu
date: 2025-10-26T12:31:21.655228078Z
path: /blog/posts/go-syscall-is-a-brilliant-replacement-of-low-level-i-o-za50951e1
category: lowlevel
---

## Összefoglalás

Megismerkedünk a közvetlen rendszerhívásokkal Go nyelven.
Mivel a Go szigorú fordítóprogram-hibaüzeneteket és merev szemétgyűjtést (GC) biztosít, előnyösebb az alacsony szintű hívásokat tiszta Go kóddal helyettesíteni.
Szerencsére a C függvényhívások nagy része jó és korszerű módon teljesen újra van implementálva Go nyelven.
Nézzük meg ezt.

## Rendszerhívás

A rendszerhívás közvetlen kérés az operációs rendszer felé.
Mivel a rendszer általában merev, régimódi stílusban íródik, hiszen közvetlenül a hardveren fut, figyelembe kell vennünk, hogy hívásának szigorú és helyes formájú kérést kell közvetítenie.
Ezért még akkor is, ha nincs szükségünk bizonyos változókra, a méretüket akkor is ki kell tölteni, függetlenül attól, hogy használjuk-e őket.
Nézzünk meg egy teljesen működőképes példát.

## Teljes példa

```go
package main
import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	Uptime    int64
	Loads     [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	Procs     uint16
	Pad       uint16
	_         [4]byte
	Totalhigh uint64
	Freehigh  uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	scale := float64(1 << 16)
	fmt.Printf("Uptime: %d seconds\n", info.Uptime)
	fmt.Printf("Load Average: %.2f %.2f %.2f\n",
		float64(info.Loads[0])/scale,
		float64(info.Loads[1])/scale,
		float64(info.Loads[2])/scale)
	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Processes: %d\n", info.Procs)
}
```

Ez a példa minden változót tartalmaz, és kiírja a jelenlegi rendszerinformációk részletes adatait.
Ezt a kódot úgy tekinthetjük, mint egy zárat és egy kulcsot.
A `syscall.SYS_SYSINFO` egy kulcs, amely kinyitja a kernelen belül található zárat.
Ezért fontos, hogy a zárhoz megfelelő kulcsot használjunk.
Mi történik, ha ehhez a híváshoz a `syscall.SYS_GETPID` értéket használjuk?
Ez egy olyan kulcs, amely a folyamatazonosítót tartalmazó zárat nyitja.
Ez arra tesz kísérletet, hogy a PID-et a rendszerinformációk területéről szerezze meg.
Ennek eredményeként az információk egyike sem olvasható helyesen; a hívásnak sikertelen állapotot kell visszaadnia.

Most meg kell tudnunk, milyen elemek vannak benne, és hogyan vannak sorrendbe rendezve.
A zár első rekeszében található az Uptime, 2^64 méretben.
Ha ezt 2^32 mérettel próbáljuk beolvasni, a bitsorozat nem olvasódik be teljesen.
Ilyen részleges bináris adatokat nem használhatunk, hacsak nem alacsony szintű trükköket akarunk írni.

Az 64 bit bináris adat beolvasása után végre a második rekeszben vagyunk.
Csak akkor olvasható pontosan, ha az előző 64 bites egész számot már beolvastuk.

E szigorú és logikus folyamatok ismétlésével a rendszerből megfelelő információt nyerhetünk, és a beolvasott adatokat megfelelően kezelhetjük.

## Hogyan hagyjuk ki a „változónevek” használatát

Bár magukat a változókat nem tudjuk „kihagyni”, fontos megkülönböztetni a használt és az eldobott változókat.
Ha a program használata elég egyértelmű, jobb névtelen változókat használni helyőrzőként, mint minden értéket megcímkézni, még akkor is, ha azokat véglegesen nem használjuk.
Nézzünk erre egy példát, a „Szabad memória ellenőrző” programot.

## Példa – Szabad memória ellenőrző

Szabad memória/swap ellenőrzésekor nincs szükségünk más, különböző erőforrásokat jelölő információkra.
A jobb áttekinthetőség érdekében névtelen változókat hozhatunk létre a konkrét területek tárolására.

```go
package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	_          int64
	_         [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	_         uint16  // névtelen, a nem használt mezőket _ jelöli
	_         uint16
	_         [4]byte
	_         uint64
	_         uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
}
```

Következésképpen a változók címkék nélkül kerülnek beolvasásra.
Bár a névtelen értékek valójában egy struktúrában tárolódnak, a kódon nincsenek címkék vagy olvasható jelölések.

## Következtetés

- A Go `syscall` és `unsafe` csomagjainak használata továbbra is biztonságosabb, mint a C/CGo használata
- Ha egy nagy, könnyen bővíthető projektet írunk:
  - Ne használjunk névtelen változókat; minden tagnak adjunk nevet.
- Ha egy korlátozott felhasználású projektet írunk:
  - Használhatunk névtelen változókat azokon a területeken, amelyek valójában nincsenek használatban.
- A Go `syscall` csomagja erőteljes és modern eszköz az alacsony szintű hívások kezelésére

## További olvasnivaló

[syscall](https://pkg.go.dev/syscall)
[unsafe](https://pkg.go.dev/unsafe)
[x/sys/unix](https://pkg.go.dev/golang.org/x/sys/unix)
