blob: ad08c722b08160e645963d016cea71f9ce24ad78 [file] [log] [blame]
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"log"
"os"
"syscall"
"unsafe"
"github.com/tarm/serial"
)
func init() {
killProcessTree = killProcessTreeWindows
configureSerialLogOutput = configureSerialLogOutputWindows
}
func configureSerialLogOutputWindows() {
c := &serial.Config{Name: "COM1", Baud: 9600}
s, err := serial.OpenPort(c)
if err != nil {
// Oh well, we tried. This empirically works
// on Windows on GCE.
// We can log here anyway and hope somebody sees it
// in a GUI console:
log.Printf("serial.OpenPort: %v", err)
return
}
log.SetOutput(s)
}
// the system process tree
type psTree map[int]int // pid -> parent pid
// findDescendants searches process tree t for pid process children.
// It returns children pids.
func (t psTree) findDescendants(pid int) []int {
var children []int
for child, parent := range t {
if parent == pid {
children = append(children, child)
children = append(children, t.findDescendants(child)...)
}
}
return children
}
func snapshotSysProcesses() (psTree, error) {
ss, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(ss)
ps := make(psTree)
var pe syscall.ProcessEntry32
pe.Size = uint32(unsafe.Sizeof(pe))
if err = syscall.Process32First(ss, &pe); err != nil {
return nil, err
}
for {
ps[int(pe.ProcessID)] = int(pe.ParentProcessID)
err = syscall.Process32Next(ss, &pe)
if err == syscall.ERROR_NO_MORE_FILES {
return ps, nil
}
if err != nil {
return nil, err
}
}
}
func killProcesses(ps []int) {
for _, pid := range ps {
p, err := os.FindProcess(pid)
if err != nil {
continue
}
p.Kill()
p.Release()
}
}
func killProcessTreeWindows(p *os.Process) error {
ps, err := snapshotSysProcesses()
if err != nil {
return err
}
toKill := ps.findDescendants(p.Pid)
toKill = append(toKill, p.Pid)
killProcesses(toKill)
return nil
}