github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/plugin/builtin/shell/subtree_darwin.go (about) 1 package shell 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "strconv" 8 "strings" 9 10 "github.com/evergreen-ci/evergreen/plugin" 11 "github.com/mongodb/grip/slogger" 12 ) 13 14 func trackProcess(key string, pid int, log plugin.Logger) { 15 // trackProcess is a noop on OSX, because we detect all the processes to be killed in 16 // cleanup() and we don't need to do any special bookkeeping up-front. 17 } 18 19 func cleanup(key string, log plugin.Logger) error { 20 /* 21 Usage of ps on OSX for extracting environment variables: 22 -E: print the environment of the process (VAR1=FOO VAR2=BAR ...) 23 -e: list *all* processes, not just ones that we own 24 -o: print output according to the given format. We supply 'pid,command' so that 25 only those two columns are printed, and then we extract their values using the regexes. 26 27 Each line of output has a format with the pid, command, and environment, e.g.: 28 1084 foo.sh PATH=/usr/bin/sbin TMPDIR=/tmp LOGNAME=xxx 29 */ 30 31 out, err := exec.Command("ps", "-E", "-e", "-o", "pid,command").CombinedOutput() 32 if err != nil { 33 log.LogSystem(slogger.ERROR, "cleanup failed to get output of 'ps': %v", err) 34 return err 35 } 36 myPid := fmt.Sprintf("%v", os.Getpid()) 37 38 pidsToKill := []int{} 39 lines := strings.Split(string(out), "\n") 40 41 // Look through the output of the "ps" command and find the processes we need to kill. 42 for _, line := range lines { 43 if len(line) == 0 { 44 continue 45 } 46 splitLine := strings.Fields(line) 47 pid := splitLine[0] 48 env := splitLine[2:] 49 pidMarker := fmt.Sprintf("EVR_AGENT_PID=%v", os.Getpid()) 50 taskMarker := fmt.Sprintf("EVR_TASK_ID=%v", key) 51 52 if pid != myPid && envHasMarkers(env, pidMarker, taskMarker) { 53 // add it to the list of processes to clean up 54 pidAsInt, err := strconv.Atoi(pid) 55 if err != nil { 56 log.LogSystem(slogger.ERROR, "Cleaup failed to convert from string to int: %v", err) 57 continue 58 } 59 pidsToKill = append(pidsToKill, pidAsInt) 60 } 61 } 62 63 // Iterate through the list of processes to kill that we just built, and actually kill them. 64 for _, pid := range pidsToKill { 65 p := os.Process{} 66 p.Pid = pid 67 err := p.Kill() 68 if err != nil { 69 log.LogSystem(slogger.ERROR, "Cleanup got error killing pid %v: %v", pid, err) 70 } else { 71 log.LogSystem(slogger.INFO, "Cleanup killed pid %v", pid) 72 } 73 } 74 return nil 75 76 }