-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathutil.n
More file actions
141 lines (110 loc) · 3.3 KB
/
util.n
File metadata and controls
141 lines (110 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import os
import fmt
import parker.cgroup
import path
import time
import syscall
import parker.log as *
import libc
import fs
import strings
string charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
fn arg_version():bool {
var args = os.args()
// 没有参数
if args.len() == 1 {
return true
}
if args.len() == 2 && (args[1] == '-v' || args[1] == '--version') {
return true
}
return false
}
fn arg_verbose():bool {
var flag = syscall.get_env('PARKER_VERBOSE')
return flag != ''
}
// 从 exe_path 中提取完整的数据
fn extract_tgz(string exe_path):[u8]! {
var f = fs.open(exe_path, syscall.O_RDONLY, 0666)
f.seek(-16, syscall.SEEK_END)
var size_buf = vec_new<u8>(0, 16)
var len = f.read(size_buf)
if len != size_buf.len() {
f.close()
throw errorf('read fd len %d exception', len)
}
var size_str = size_buf as string
// atoi
var size = size_str.to_int()
if size == 0 {
throw errorf('extract tgz size is zero')
}
logf('read tgz tail 16 size=%d success', size)
f.seek(-16 - size, syscall.SEEK_END)
// read result
var result = vec_new<u8>(0, size)
len = f.read(result)
if len != size {
throw errorf('read fd result len %d != size %d', len, size)
}
// close fd
f.close()
return result
}
fn rand_letter(int len):string {
var result = vec_new<u8>(0, len)
libc.srand(time.unix() as u32)
for i,v in result {
int char_index = libc.rand() % charset.len()
result[i] = charset[char_index]
}
return result as string
}
// 在 workdir 创建 mount 空间
fn mount_ns(string workdir):void! {
syscall.unshare(syscall.CLONE_NEWNS)
// mount /
syscall.mount('none', '/', '', syscall.MS_REC|syscall.MS_PRIVATE, "")
// mount("tmpfs", workdir, "tmpfs", 0, NULL)
syscall.mount('tmpfs', workdir, 'tmpfs', 0, '')
}
fn read_target(string workdir):string! {
var target_path = path.join(workdir, '.target_name')
var fd = syscall.open(target_path, syscall.O_RDONLY, 0)
var f = fs.from(fd, target_path)
var target_name = f.content()
f.close()
return path.join(workdir, target_name)
}
// gmp 模型中,fork 是不安全的操作,所有的子线程都不会被 fork。
fn run_target(string target_path):int! {
// - fork 默认继承父进程的 mount ns
// - fork, 父进程直接返回 pid 即可
var pid = syscall.fork()
if pid > 0 {
// parent
return pid
}
// sub process
// pdeathsig
// 1 = PR_SET_PDEATHSIG
// 9 = SIGKILL
var result = libc.prctl(1, 9, 0, 0, 0)
if result == -1 {
throw errorf('set pdeathsig err=%s', libc.strerror())
}
// 读取当前进程 id
pid = syscall.getpid()
logf('[child %d] fork success, current is child , syscall.getpid() is %d', pid, pid)
// run target with all args and env
var args = os.args()
// args[0] 是 proc/:pid/comm, 这里替换成 target name
var target_name = path.base(target_path)
args[0] = target_name
// 通过 exec 进行进程启动直接覆盖当前进程
logf('will syscall.exec target_path: %s', target_path)
syscall.exec(target_path, args, syscall.get_envs())
logf('exec cannot execute it here')
return 0 // 正常不会执行到这里了
}