LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Fork, exec, wait, etc. | 5 // Fork, exec, wait, etc. |
6 | 6 |
7 package syscall | 7 package syscall |
8 | 8 |
9 import ( | 9 import ( |
10 "sync" | 10 "sync" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 // of NUL-terminated byte pointer. | 64 // of NUL-terminated byte pointer. |
65 func StringArrayPtr(ss []string) []*byte { | 65 func StringArrayPtr(ss []string) []*byte { |
66 bb := make([]*byte, len(ss)+1) | 66 bb := make([]*byte, len(ss)+1) |
67 for i := 0; i < len(ss); i++ { | 67 for i := 0; i < len(ss); i++ { |
68 bb[i] = StringBytePtr(ss[i]) | 68 bb[i] = StringBytePtr(ss[i]) |
69 } | 69 } |
70 bb[len(ss)] = nil | 70 bb[len(ss)] = nil |
71 return bb | 71 return bb |
72 } | 72 } |
73 | 73 |
74 // Read a 16-bit numeric value from a 9P | 74 // gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b, |
75 // protocol message b, returning the value | 75 // returning the value and the remaining slice of b. |
76 // and the remaining slice of b. | |
77 func gbit16(b []byte) (uint16, []byte) { | 76 func gbit16(b []byte) (uint16, []byte) { |
78 return uint16(b[0]) | uint16(b[1])<<8, b[2:] | 77 return uint16(b[0]) | uint16(b[1])<<8, b[2:] |
79 } | 78 } |
80 | 79 |
81 // Read a string from a 9P protocol message b, | 80 // gstring reads a string from a 9P protocol message strored in b, |
82 // returning the value and the remaining slice of b. | 81 // returning the value as a Go string and the remaining slice of b. |
83 func gstring(b []byte) (string, []byte) { | 82 func gstring(b []byte) (string, []byte) { |
84 n, b := gbit16(b) | 83 n, b := gbit16(b) |
85 return string(b[0:n]), b[n:] | 84 return string(b[0:n]), b[n:] |
86 } | 85 } |
87 | 86 |
88 // Return file names inside a directory· | 87 // readdirnames returns the names of files inside the directory represented by d
irfd. |
89 // already opened for reading dirfd. | |
90 func readdirnames(dirfd int) (names []string, err Error) { | 88 func readdirnames(dirfd int) (names []string, err Error) { |
91 result := make([]string, 0, 100) | 89 result := make([]string, 0, 100) |
92 var buf [STATMAX]byte | 90 var buf [STATMAX]byte |
93 | 91 |
94 for { | 92 for { |
95 n, e := Read(dirfd, buf[:]) | 93 n, e := Read(dirfd, buf[:]) |
96 if e != nil { | 94 if e != nil { |
97 return []string{}, e | 95 return []string{}, e |
98 } | 96 } |
99 if n == 0 { | 97 if n == 0 { |
(...skipping 10 matching lines...) Expand all Loading... |
110 | 108 |
111 name, _ := gstring(buf[i+41:]) | 109 name, _ := gstring(buf[i+41:]) |
112 result = append(result, name) | 110 result = append(result, name) |
113 | 111 |
114 i += int(m) | 112 i += int(m) |
115 } | 113 } |
116 } | 114 } |
117 return []string{}, nil | 115 return []string{}, nil |
118 } | 116 } |
119 | 117 |
120 // Return a list of currently opened fds (excluding stdin, stdout, stderr) | 118 // readdupdevice returns a list of currently opened fds (excluding stdin, stdout
, stderr) from the dup device #d. |
121 // by reading the special dup device #d. | 119 // ForkLock should be write locked before calling, so that no new fds would be c
reated while the fd list is being read. |
122 // ForkLock should be write locked before calling, | |
123 // so that no new fds would be created while reading the fd list. | |
124 func readdupdevice() (fds []int, err Error) { | 120 func readdupdevice() (fds []int, err Error) { |
125 dupdevfd, err := Open("#d", O_RDONLY) | 121 dupdevfd, err := Open("#d", O_RDONLY) |
126 | 122 |
127 if err != nil { | 123 if err != nil { |
128 return | 124 return |
129 } | 125 } |
130 defer Close(dupdevfd) | 126 defer Close(dupdevfd) |
131 | 127 |
132 » file_names, err := readdirnames(dupdevfd) | 128 » fileNames, err := readdirnames(dupdevfd) |
133 if err != nil { | 129 if err != nil { |
134 return | 130 return |
135 } | 131 } |
136 | 132 |
137 » fds = make([]int, 0, len(file_names)>>1) | 133 » fds = make([]int, 0, len(fileNames)>>1) |
138 » for _, fdstr := range file_names { | 134 » for _, fdstr := range fileNames { |
139 if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] ==
't' && fdstr[l-1] == 'l' { | 135 if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] ==
't' && fdstr[l-1] == 'l' { |
140 continue | 136 continue |
141 } | 137 } |
142 | 138 |
143 fd := int(atoi([]byte(fdstr))) | 139 fd := int(atoi([]byte(fdstr))) |
144 | 140 |
145 if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd { | 141 if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd { |
146 continue | 142 continue |
147 } | 143 } |
148 | 144 |
149 fds = append(fds, fd) | 145 fds = append(fds, fd) |
150 } | 146 } |
151 | 147 |
152 return fds[0:len(fds)], nil | 148 return fds[0:len(fds)], nil |
153 } | 149 } |
154 | 150 |
155 var startup_fds []int | 151 var startupFds []int |
156 | 152 |
157 // Plan 9 does not allow clearing the OCEXEC flag | 153 // Plan 9 does not allow clearing the OCEXEC flag |
158 // from the underlying channel backing an open file descriptor, | 154 // from the underlying channel backing an open file descriptor, |
159 // therefore we store a list of already opened file descriptors | 155 // therefore we store a list of already opened file descriptors |
160 // inside startup_fds, and skip them when manually closing descriptors | 156 // inside startupFds and skip them when manually closing descriptors |
161 // not ment to be passed to a child exec. | 157 // not meant to be passed to a child exec. |
162 func init() { | 158 func init() { |
163 » startup_fds, _ = readdupdevice() | 159 » startupFds, _ = readdupdevice() |
164 } | 160 } |
165 | 161 |
166 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. | 162 // forkAndExecInChild forks the process, calling dup onto 0..len(fd) |
167 // If a dup or exec fails, write the errstr int to pipe. | 163 // and finally invoking exec(argv0, argvv, envv) in the child. |
| 164 // If a dup or exec fails, it writes the error string to pipe. |
168 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) | 165 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) |
| 166 // |
169 // In the child, this function must not acquire any locks, because | 167 // In the child, this function must not acquire any locks, because |
170 // they might have been locked at the time of the fork. This means | 168 // they might have been locked at the time of the fork. This means |
171 // no rescheduling, no malloc calls, and no new stack segments. | 169 // no rescheduling, no malloc calls, and no new stack segments. |
172 // The calls to RawSyscall are okay because they are assembly | 170 // The calls to RawSyscall are okay because they are assembly |
173 // functions that do not grow the stack. | 171 // functions that do not grow the stack. |
174 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
tr *ProcAttr, fdclose []int, pipe int) (pid int, err Error) { | 172 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir *
byte, attr *ProcAttr, fdsToClose []int, pipe int) (pid int, err Error) { |
175 // Declare all variables at top in case any | 173 // Declare all variables at top in case any |
176 // declarations require heap allocation (e.g., errbuf). | 174 // declarations require heap allocation (e.g., errbuf). |
177 var ( | 175 var ( |
178 r1 uintptr | 176 r1 uintptr |
179 nextfd int | 177 nextfd int |
180 i int | 178 i int |
181 clearenv int | 179 clearenv int |
182 envfd int | 180 envfd int |
183 errbuf [ERRMAX]byte | 181 errbuf [ERRMAX]byte |
184 ) | 182 ) |
(...skipping 13 matching lines...) Expand all Loading... |
198 if int(r1) == -1 { | 196 if int(r1) == -1 { |
199 return 0, NewError(errstr()) | 197 return 0, NewError(errstr()) |
200 } | 198 } |
201 // parent; return PID | 199 // parent; return PID |
202 return int(r1), nil | 200 return int(r1), nil |
203 } | 201 } |
204 | 202 |
205 // Fork succeeded, now in child. | 203 // Fork succeeded, now in child. |
206 | 204 |
207 // Close fds we don't need. | 205 // Close fds we don't need. |
208 » for i = 0; i < len(fdclose); i++ { | 206 » for i = 0; i < len(fdsToClose); i++ { |
209 » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdclose[i]), 0, 0) | 207 » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0) |
210 if int(r1) == -1 { | 208 if int(r1) == -1 { |
211 goto childerror | 209 goto childerror |
212 } | 210 } |
213 } | 211 } |
214 | 212 |
215 if envv != nil { | 213 if envv != nil { |
216 // Write new environment variables. | 214 // Write new environment variables. |
217 for i = 0; i < len(envv); i++ { | 215 for i = 0; i < len(envv); i++ { |
218 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer
(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) | 216 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer
(envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) |
219 | 217 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 for { | 307 for { |
310 RawSyscall(SYS_EXITS, 0, 0, 0) | 308 RawSyscall(SYS_EXITS, 0, 0, 0) |
311 } | 309 } |
312 | 310 |
313 // Calling panic is not actually safe, | 311 // Calling panic is not actually safe, |
314 // but the for loop above won't break | 312 // but the for loop above won't break |
315 // and this shuts up the compiler. | 313 // and this shuts up the compiler. |
316 panic("unreached") | 314 panic("unreached") |
317 } | 315 } |
318 | 316 |
319 func itoa(n int) string { | |
320 var buf [64]byte | |
321 j := len(buf) | |
322 for n > 0 { | |
323 j-- | |
324 buf[j] = (byte)((n % 10) + '0') | |
325 n /= 10 | |
326 } | |
327 return string(buf[j:]) | |
328 } | |
329 | |
330 func cexecPipe(p []int) Error { | 317 func cexecPipe(p []int) Error { |
331 e := Pipe(p) | 318 e := Pipe(p) |
332 if e != nil { | 319 if e != nil { |
333 return e | 320 return e |
334 } | 321 } |
335 | 322 |
336 fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC) | 323 fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC) |
337 if e != nil { | 324 if e != nil { |
338 Close(p[0]) | 325 Close(p[0]) |
339 Close(p[1]) | 326 Close(p[1]) |
340 return e | 327 return e |
341 } | 328 } |
342 | 329 |
343 Close(fd) | 330 Close(fd) |
344 return nil | 331 return nil |
345 } | 332 } |
346 | 333 |
347 type envItem struct { | 334 type envItem struct { |
348 name *byte | 335 name *byte |
349 value *byte | 336 value *byte |
350 nvalue int | 337 nvalue int |
351 } | 338 } |
352 | 339 |
353 type ProcAttr struct { | 340 type ProcAttr struct { |
354 » Dir string // Current working directory. | 341 » Dir string // Current working directory. |
355 » Env []string // Environment. | 342 » Env []string // Environment. |
356 » Files []int // File descriptors. | 343 » Files []int // File descriptors. |
| 344 » Chroot string // Chroot. |
357 } | 345 } |
358 | 346 |
359 var zeroAttributes ProcAttr | 347 var zeroAttributes ProcAttr |
360 | 348 |
361 | 349 |
362 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
{ | 350 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
{ |
363 var ( | 351 var ( |
364 p [2]int | 352 p [2]int |
365 n int | 353 n int |
366 errbuf [ERRMAX]byte | 354 errbuf [ERRMAX]byte |
367 wmsg Waitmsg | 355 wmsg Waitmsg |
368 ) | 356 ) |
369 | 357 |
370 if attr == nil { | 358 if attr == nil { |
371 attr = &zeroAttributes | 359 attr = &zeroAttributes |
372 } | 360 } |
373 | 361 |
374 p[0] = -1 | 362 p[0] = -1 |
375 p[1] = -1 | 363 p[1] = -1 |
376 | 364 |
377 // Convert args to C form. | 365 // Convert args to C form. |
378 argv0p := StringBytePtr(argv[0]) | 366 argv0p := StringBytePtr(argv[0]) |
379 argvp := StringArrayPtr(argv) | 367 argvp := StringArrayPtr(argv) |
380 » var envv_parsed []envItem | 368 |
381 | 369 » var chroot *byte |
| 370 » if attr.Chroot != "" { |
| 371 » » chroot = StringBytePtr(attr.Chroot) |
| 372 » } |
382 var dir *byte | 373 var dir *byte |
383 if attr.Dir != "" { | 374 if attr.Dir != "" { |
384 dir = StringBytePtr(attr.Dir) | 375 dir = StringBytePtr(attr.Dir) |
385 } | 376 } |
386 | 377 » var envvParsed []envItem |
387 if attr.Env != nil { | 378 if attr.Env != nil { |
388 » » envv_parsed = make([]envItem, 0, len(attr.Env)) | 379 » » envvParsed = make([]envItem, 0, len(attr.Env)) |
389 for _, v := range attr.Env { | 380 for _, v := range attr.Env { |
390 i := 0 | 381 i := 0 |
391 for i < len(v) && v[i] != '=' { | 382 for i < len(v) && v[i] != '=' { |
392 i++ | 383 i++ |
393 } | 384 } |
394 | 385 |
395 » » » envv_parsed = append(envv_parsed, envItem{StringBytePtr(
"/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i}) | 386 » » » envvParsed = append(envvParsed, envItem{StringBytePtr("/
env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i}) |
396 » » } | 387 » » } |
397 » } | 388 » } |
398 | 389 |
399 » // Acquire the fork lock so that no other threads | 390 » // Acquire the fork lock to prevent other threads from creating new fds
before we fork. |
400 » // create new fds that are not yet close-on-exec | |
401 » // before we fork. | |
402 ForkLock.Lock() | 391 ForkLock.Lock() |
403 | 392 |
404 // get a list of open fds, excluding stdin,stdout and stderr that need t
o be closed in the child. | 393 // get a list of open fds, excluding stdin,stdout and stderr that need t
o be closed in the child. |
405 // no new fds can be created while we hold the ForkLock for writing. | 394 // no new fds can be created while we hold the ForkLock for writing. |
406 » fds_to_close, e := readdupdevice() | 395 » openFds, e := readdupdevice() |
407 | 396 |
408 if e != nil { | 397 if e != nil { |
409 ForkLock.Unlock() | 398 ForkLock.Unlock() |
410 return 0, e | 399 return 0, e |
411 } | 400 } |
412 | 401 |
| 402 fdsToClose := make([]int, 0, len(openFds)) |
413 // exclude fds opened from startup from the list of fds to be closed. | 403 // exclude fds opened from startup from the list of fds to be closed. |
414 » for _, reserved_fd := range startup_fds { | 404 » for _, fd := range openFds { |
415 » » for i := 0; i < len(fds_to_close); i++ { | 405 » » isReserved := false |
416 » » » if reserved_fd == fds_to_close[i] { | 406 » » for _, reservedFd := range startupFds { |
417 » » » » fds_to_close = append(fds_to_close[:i], fds_to_c
lose[i+1:]...) | 407 » » » if fd == reservedFd { |
| 408 » » » » isReserved = true |
418 break | 409 break |
419 } | 410 } |
420 } | 411 } |
| 412 |
| 413 if !isReserved { |
| 414 fdsToClose = append(fdsToClose, fd) |
| 415 } |
421 } | 416 } |
422 | 417 |
423 // exclude fds requested by the caller from the list of fds to be closed
. | 418 // exclude fds requested by the caller from the list of fds to be closed
. |
424 » for _, reserved_fd := range attr.Files { | 419 » for _, fd := range openFds { |
425 » » for i := 0; i < len(fds_to_close); i++ { | 420 » » isReserved := false |
426 » » » if reserved_fd == fds_to_close[i] { | 421 » » for _, reservedFd := range attr.Files { |
427 » » » » fds_to_close = append(fds_to_close[:i], fds_to_c
lose[i+1:]...) | 422 » » » if fd == reservedFd { |
| 423 » » » » isReserved = true |
428 break | 424 break |
429 } | 425 } |
| 426 } |
| 427 |
| 428 if !isReserved { |
| 429 fdsToClose = append(fdsToClose, fd) |
430 } | 430 } |
431 } | 431 } |
432 | 432 |
433 // Allocate child status pipe close on exec.···· | 433 // Allocate child status pipe close on exec.···· |
434 e = cexecPipe(p[:]) | 434 e = cexecPipe(p[:]) |
435 | 435 |
436 if e != nil { | 436 if e != nil { |
437 return 0, e | 437 return 0, e |
438 } | 438 } |
439 » fds_to_close = append(fds_to_close, p[0]) | 439 » fdsToClose = append(fdsToClose, p[0]) |
440 | 440 |
441 // Kick off child. | 441 // Kick off child. |
442 » pid, err = forkAndExecInChild(argv0p, argvp, envv_parsed, dir, attr, fds
_to_close, p[1]) | 442 » pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, chroot, dir, at
tr, fdsToClose, p[1]) |
443 | 443 |
444 if err != nil { | 444 if err != nil { |
445 if p[0] >= 0 { | 445 if p[0] >= 0 { |
446 Close(p[0]) | 446 Close(p[0]) |
447 Close(p[1]) | 447 Close(p[1]) |
448 } | 448 } |
449 ForkLock.Unlock() | 449 ForkLock.Unlock() |
450 return 0, err | 450 return 0, err |
451 } | 451 } |
452 ForkLock.Unlock() | 452 ForkLock.Unlock() |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 if int(r1) == -1 { | 491 if int(r1) == -1 { |
492 return NewError(errstr()) | 492 return NewError(errstr()) |
493 } | 493 } |
494 | 494 |
495 for _, v := range envv { | 495 for _, v := range envv { |
496 i := 0 | 496 i := 0 |
497 for i < len(v) && v[i] != '=' { | 497 for i < len(v) && v[i] != '=' { |
498 i++ | 498 i++ |
499 } | 499 } |
500 | 500 |
501 » » » r1, _, _ := RawSyscall(SYS_CREATE, uintptr(unsafe.Pointe
r(StringBytePtr("/env/"+v[:i]))), | 501 » » » fd, e := Create("/env/"+v[:i], O_WRONLY, 0666) |
502 » » » » uintptr(O_WRONLY), uintptr(0666)) | 502 » » » if e != nil { |
503 » » » if int(r1) == -1 { | 503 » » » » return e |
504 » » » » return NewError(errstr()) | 504 » » » } |
505 » » » } | 505 |
506 | 506 » » » _, e = Write(fd, []byte(v[i+1:])) |
507 » » » envfd := int(r1) | 507 » » » if e != nil { |
508 | 508 » » » » Close(fd) |
509 » » » r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintp
tr(unsafe.Pointer(StringBytePtr(v[i+1:]))), | 509 » » » » return e |
510 » » » » uintptr(len(v)-i), ^uintptr(0), ^uintptr(0), 0) | 510 » » » } |
511 » » » if int(r1) == -1 || int(r1) != (len(v)-i) { | 511 » » » Close(fd) |
512 » » » » return NewError(errstr()) | |
513 » » » } | |
514 | |
515 » » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0) | |
516 » » » if int(r1) == -1 { | |
517 » » » » return NewError(errstr()) | |
518 » » » } | |
519 } | 512 } |
520 } | 513 } |
521 | 514 |
522 _, _, e := Syscall(SYS_EXEC, | 515 _, _, e := Syscall(SYS_EXEC, |
523 uintptr(unsafe.Pointer(StringBytePtr(argv0))), | 516 uintptr(unsafe.Pointer(StringBytePtr(argv0))), |
524 uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), | 517 uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), |
525 0) | 518 0) |
526 | 519 |
527 return NewError(e) | 520 return NewError(e) |
528 } | 521 } |
LEFT | RIGHT |