Skip to content

Commit ffe6df6

Browse files
authored
Merge pull request #925 from devlights/add-syscall6-example
2 parents 28bd7ac + af8ecce commit ffe6df6

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

examples/syscall/syscall6/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app

examples/syscall/syscall6/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# これは何?
2+
3+
[unix](https://pkg.go.dev/golang.org/x/sys/unix) パッケージの
4+
5+
- Syscall6()
6+
7+
を使っているサンプルです。
8+
9+
```sh
10+
$ task
11+
task: [default] rm -f ./app
12+
task: [default] go build -o app .
13+
task: [default] ./app
14+
# Kubernetes-managed hosts file.
15+
127.0.0.1 localho
16+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# https://taskfile.dev
2+
3+
version: '3'
4+
5+
tasks:
6+
default:
7+
cmds:
8+
- rm -f ./app
9+
- go build -o app .
10+
- ./app

examples/syscall/syscall6/main.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"unsafe"
6+
7+
"golang.org/x/sys/unix"
8+
)
9+
10+
func main() {
11+
log.SetFlags(0)
12+
13+
if err := run(); err != nil {
14+
log.Fatal(err)
15+
}
16+
}
17+
18+
func run() error {
19+
//
20+
// unix.Syscall6()を使って mmap(2) を呼び出し
21+
//
22+
23+
// ファイルディスクリプタを取得
24+
var (
25+
fileName = "/etc/hosts"
26+
fd int
27+
err error
28+
)
29+
fd, err = unix.Open(fileName, unix.O_RDONLY, 0)
30+
if err != nil {
31+
return err
32+
}
33+
defer unix.Close(fd)
34+
35+
// ファイルサイズを取得
36+
var (
37+
stat unix.Stat_t
38+
fsize int64
39+
)
40+
err = unix.Fstat(fd, &stat)
41+
if err != nil {
42+
return err
43+
}
44+
45+
fsize = stat.Size
46+
47+
// mmap(2)を利用してメモリにマッピング
48+
// 引数については man 2 mmap で調べられる
49+
//
50+
// そもそも、unixパッケージには
51+
// - unix.Mmap()
52+
// - unix.Munmap()
53+
// が存在するので、それを利用するのが普通です。
54+
//
55+
// 本サンプルは、unix.Syscall6()を試す為の実装です。
56+
var (
57+
trap = uintptr(unix.SYS_MMAP)
58+
addr = uintptr(0) // アドレスヒント(0は自動割当)
59+
length = uintptr(fsize) // ファイルサイズ
60+
prot = uintptr(unix.PROT_READ) // 読み取り専用
61+
flags = uintptr(unix.MAP_SHARED) // マッピングフラグ(共有)
62+
fdptr = uintptr(fd) // ファイルディスクリプタ
63+
offset = uintptr(0) // オフセット
64+
errno unix.Errno
65+
66+
unmap = func(addr uintptr) {
67+
unix.Syscall(unix.SYS_MUNMAP, addr, length, uintptr(0))
68+
}
69+
)
70+
addr, _, errno = unix.Syscall6(trap, addr, length, prot, flags, fdptr, offset)
71+
if errno != 0 {
72+
err = errno
73+
return err
74+
}
75+
defer unmap(addr)
76+
77+
// 先頭 Nバイト 分を見る
78+
const (
79+
dispSize = 50
80+
)
81+
var (
82+
// VSCodeなどで作業していると「possible misuse of unsafe.Pointer」という警告が出るが
83+
// mmapの戻り値はメモリアドレスを表すuintptr値なので、以下のunsafe.Pointerへの変換は安全です。
84+
ptr = (*byte)(unsafe.Pointer(addr))
85+
data = unsafe.Slice(ptr, int(fsize))
86+
)
87+
if fsize >= dispSize {
88+
log.Println(string(data[:dispSize]))
89+
} else {
90+
log.Println(string(data))
91+
}
92+
93+
94+
95+
return nil
96+
}

0 commit comments

Comments
 (0)