Skip to content

Commit

Permalink
os rework
Browse files Browse the repository at this point in the history
  • Loading branch information
leongross committed Aug 2, 2024
1 parent 2b0cd9e commit 8cce6c2
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 83 deletions.
36 changes: 5 additions & 31 deletions src/os/exec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ func (p *Process) release() error {
// * No parent-child communication via pipes (TODO)
// * No waiting for crashes child processes to prohibit zombie process accumulation / Wait status checking (TODO)
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
var (
ret uintptr
)

if len(argv) == 0 {
return 0, errors.New("exec: no argv")
}
Expand All @@ -58,40 +54,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
attr = new(ProcAttr)
}

argv0p, err := syscall.BytePtrFromString(argv0)
if err != nil {
return 0, err
}
argvp, err := syscall.SlicePtrFromStrings(argv)
if err != nil {
return 0, err
}
envp, err := syscall.SlicePtrFromStrings(attr.Env)
pid, err = Fork()
if err != nil {
return 0, err
}

if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv) > 0 && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
}

ret = syscall.Fork()
if int(ret) < 0 {
return 0, errors.New("fork failed")
}

if int(ret) != 0 {
// if fd == 0 code runs in parent
return int(ret), nil
} else {
// else code runs in child, which then should exec the new process
ret = syscall.Execve(argv0, argv, envp)
if int(ret) != 0 {
err = Execve(argv0, argv, attr.Env)
if err != nil {
// exec failed
return int(ret), errors.New("exec failed")
return 0, err
}
// 3. TODO: use pipes to communicate back child status
return int(ret), nil
return pid, nil
}
}

Expand Down
56 changes: 56 additions & 0 deletions src/os/osexec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//go:build linux
// +build linux

package os

import (
"errors"
"syscall"
"unsafe"
)

func Fork() (pid int, err error) {
// ret := libc_fork()
// ret, _, _ := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
ret, _, _ := syscall.Syscall(57, 0, 0, 0)
if ret < 0 {
// TODO: parse the syscall return codes
return 0, errors.New("fork failed")
}
return int(ret), nil
}

// the golang standard library does not expose interfaces for execve and fork, so we define them here the same way via the libc wrapper
func Execve(pathname string, argv []string, envv []string) (err error) {
argv0 := cstring(pathname)

// transform argv and envv into the format expected by execve
argv1 := make([]*byte, len(argv)+1)
for i, arg := range argv {
argv1[i] = &cstring(arg)[0]
}
argv1[len(argv)] = nil

env1 := make([]*byte, len(envv)+1)
for i, env := range envv {
env1[i] = &cstring(env)[0]
}
env1[len(envv)] = nil

// fail := libc_execve(&argv0[0], &argv1[0], &env1[0])
// fail, _, _ := syscall.Syscall(syscall.SYS_EXECVE, uintptr(unsafe.Pointer(&argv0[0])), uintptr(unsafe.Pointer(&argv1[0])), uintptr(unsafe.Pointer(&env1[0])))
fail, _, _ := syscall.Syscall(59, uintptr(unsafe.Pointer(&argv0[0])), uintptr(unsafe.Pointer(&argv1[0])), uintptr(unsafe.Pointer(&env1[0])))
if fail < 0 {
// TODO: parse the syscall return codes
return errors.New("execve failed")
}

return nil
}

func cstring(s string) []byte {
data := make([]byte, len(s)+1)
copy(data, s)
// final byte should be zero from the initial allocation
return data
}
56 changes: 4 additions & 52 deletions src/syscall/syscall_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

package syscall

import "errors"

func Exec(argv0 string, argv []string, envv []string) (err error)

// The two SockaddrInet* structs have been copied from the Go source tree.
Expand All @@ -22,53 +20,7 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}

func Fork() (err error) {
fail := int(libc_fork())
if fail < 0 {
// TODO: parse the syscall return codes
return errors.New("fork failed")
}
return
}

// the golang standard library does not expose interfaces for execve and fork, so we define them here the same way via the libc wrapper
func Execve(pathname string, argv []string, envv []string) (err error) {
argv0 := cstring(pathname)

// transform argv and envv into the format expected by execve
argv1 := make([]*byte, len(argv)+1)
for i, arg := range argv {
argv1[i] = &cstring(arg)[0]
}
argv1[len(argv)] = nil

env1 := make([]*byte, len(envv)+1)
for i, env := range envv {
env1[i] = &cstring(env)[0]
}
env1[len(envv)] = nil

fail := int(libc_execve(&argv0[0], &argv1[0], &env1[0]))
if fail < 0 {
// TODO: parse the syscall return codes
return errors.New("fork failed")
}
return
}

func cstring(s string) []byte {
data := make([]byte, len(s)+1)
copy(data, s)
// final byte should be zero from the initial allocation
return data
}

// pid_t fork(void);
//
//export fork
func libc_fork() int32

// int execve(const char *filename, char *const argv[], char *const envp[]);
//
//export execve
func libc_execve(filename *byte, argv **byte, envp **byte) int
const (
SYS_FORK = 57
SYS_EXECVE = 59
)

0 comments on commit 8cce6c2

Please sign in to comment.