Initial commit
This commit is contained in:
		
							
								
								
									
										114
									
								
								internal/shutils/handlers/fakeroot.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								internal/shutils/handlers/fakeroot.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| package handlers | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
|  | ||||
| 	"lure.sh/fakeroot" | ||||
| 	"mvdan.cc/sh/v3/expand" | ||||
| 	"mvdan.cc/sh/v3/interp" | ||||
| ) | ||||
|  | ||||
| // FakerootExecHandler was extracted from github.com/mvdan/sh/interp/handler.go | ||||
| // and modified to run commands in a fakeroot environent. | ||||
| func FakerootExecHandler(killTimeout time.Duration) interp.ExecHandlerFunc { | ||||
| 	return func(ctx context.Context, args []string) error { | ||||
| 		hc := interp.HandlerCtx(ctx) | ||||
| 		path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0]) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintln(hc.Stderr, err) | ||||
| 			return interp.NewExitStatus(127) | ||||
| 		} | ||||
| 		cmd := &exec.Cmd{ | ||||
| 			Path:   path, | ||||
| 			Args:   args, | ||||
| 			Env:    execEnv(hc.Env), | ||||
| 			Dir:    hc.Dir, | ||||
| 			Stdin:  hc.Stdin, | ||||
| 			Stdout: hc.Stdout, | ||||
| 			Stderr: hc.Stderr, | ||||
| 		} | ||||
|  | ||||
| 		err = fakeroot.Apply(cmd) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		err = cmd.Start() | ||||
| 		if err == nil { | ||||
| 			if done := ctx.Done(); done != nil { | ||||
| 				go func() { | ||||
| 					<-done | ||||
|  | ||||
| 					if killTimeout <= 0 || runtime.GOOS == "windows" { | ||||
| 						_ = cmd.Process.Signal(os.Kill) | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					// TODO: don't temporarily leak this goroutine | ||||
| 					// if the program stops itself with the | ||||
| 					// interrupt. | ||||
| 					go func() { | ||||
| 						time.Sleep(killTimeout) | ||||
| 						_ = cmd.Process.Signal(os.Kill) | ||||
| 					}() | ||||
| 					_ = cmd.Process.Signal(os.Interrupt) | ||||
| 				}() | ||||
| 			} | ||||
|  | ||||
| 			err = cmd.Wait() | ||||
| 		} | ||||
|  | ||||
| 		switch x := err.(type) { | ||||
| 		case *exec.ExitError: | ||||
| 			// started, but errored - default to 1 if OS | ||||
| 			// doesn't have exit statuses | ||||
| 			if status, ok := x.Sys().(syscall.WaitStatus); ok { | ||||
| 				if status.Signaled() { | ||||
| 					if ctx.Err() != nil { | ||||
| 						return ctx.Err() | ||||
| 					} | ||||
| 					return interp.NewExitStatus(uint8(128 + status.Signal())) | ||||
| 				} | ||||
| 				return interp.NewExitStatus(uint8(status.ExitStatus())) | ||||
| 			} | ||||
| 			return interp.NewExitStatus(1) | ||||
| 		case *exec.Error: | ||||
| 			// did not start | ||||
| 			fmt.Fprintf(hc.Stderr, "%v\n", err) | ||||
| 			return interp.NewExitStatus(127) | ||||
| 		default: | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // execEnv was extracted from github.com/mvdan/sh/interp/vars.go | ||||
| func execEnv(env expand.Environ) []string { | ||||
| 	list := make([]string, 0, 64) | ||||
| 	env.Each(func(name string, vr expand.Variable) bool { | ||||
| 		if !vr.IsSet() { | ||||
| 			// If a variable is set globally but unset in the | ||||
| 			// runner, we need to ensure it's not part of the final | ||||
| 			// list. Seems like zeroing the element is enough. | ||||
| 			// This is a linear search, but this scenario should be | ||||
| 			// rare, and the number of variables shouldn't be large. | ||||
| 			for i, kv := range list { | ||||
| 				if strings.HasPrefix(kv, name+"=") { | ||||
| 					list[i] = "" | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if vr.Exported && vr.Kind == expand.String { | ||||
| 			list = append(list, name+"="+vr.String()) | ||||
| 		} | ||||
| 		return true | ||||
| 	}) | ||||
| 	return list | ||||
| } | ||||
		Reference in New Issue
	
	Block a user