github.com/safing/portbase@v0.19.5/utils/osdetail/svchost_windows.go (about) 1 package osdetail 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "fmt" 8 "os/exec" 9 "strconv" 10 "strings" 11 "sync" 12 ) 13 14 var ( 15 serviceNames map[int32][]string 16 serviceNamesLock sync.Mutex 17 ) 18 19 // Errors 20 var ( 21 ErrServiceNotFound = errors.New("no service with the given PID was found") 22 ) 23 24 // GetServiceNames returns all service names assosicated with a svchost.exe process on Windows. 25 func GetServiceNames(pid int32) ([]string, error) { 26 serviceNamesLock.Lock() 27 defer serviceNamesLock.Unlock() 28 29 if serviceNames != nil { 30 names, ok := serviceNames[pid] 31 if ok { 32 return names, nil 33 } 34 } 35 36 serviceNames, err := GetAllServiceNames() 37 if err != nil { 38 return nil, err 39 } 40 41 names, ok := serviceNames[pid] 42 if ok { 43 return names, nil 44 } 45 46 return nil, ErrServiceNotFound 47 } 48 49 // GetAllServiceNames returns a list of service names assosicated with svchost.exe processes on Windows. 50 func GetAllServiceNames() (map[int32][]string, error) { 51 output, err := exec.Command("tasklist", "/svc", "/fi", "imagename eq svchost.exe").Output() 52 if err != nil { 53 return nil, fmt.Errorf("failed to get svchost tasklist: %s", err) 54 } 55 56 // file scanner 57 scanner := bufio.NewScanner(bytes.NewReader(output)) 58 scanner.Split(bufio.ScanLines) 59 60 // skip output header 61 for scanner.Scan() { 62 if strings.HasPrefix(scanner.Text(), "=") { 63 break 64 } 65 } 66 67 var ( 68 pid int32 69 services []string 70 collection = make(map[int32][]string) 71 ) 72 73 for scanner.Scan() { 74 // get fields of line 75 fields := strings.Fields(scanner.Text()) 76 77 // check fields length 78 if len(fields) == 0 { 79 continue 80 } 81 82 // new entry 83 if fields[0] == "svchost.exe" { 84 // save old entry 85 if pid != 0 { 86 collection[pid] = services 87 } 88 // reset PID 89 pid = 0 90 services = make([]string, 0, len(fields)) 91 92 // check fields length 93 if len(fields) < 3 { 94 continue 95 } 96 97 // get pid 98 i, err := strconv.ParseInt(fields[1], 10, 32) 99 if err != nil { 100 continue 101 } 102 pid = int32(i) 103 104 // skip used fields 105 fields = fields[2:] 106 } 107 108 // add service names 109 for _, field := range fields { 110 services = append(services, strings.Trim(strings.TrimSpace(field), ",")) 111 } 112 } 113 114 if pid != 0 { 115 // save last entry 116 collection[pid] = services 117 } 118 119 return collection, nil 120 }