36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
82 lines
1.9 KiB
Go
82 lines
1.9 KiB
Go
//go:build darwin
|
|
|
|
package source
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pranshuparmar/witr/internal/launchd"
|
|
"github.com/pranshuparmar/witr/pkg/model"
|
|
)
|
|
|
|
func detectLaunchd(ancestry []model.Process) *model.Source {
|
|
// Check if the ancestry includes launchd (PID 1)
|
|
hasLaunchd := false
|
|
for _, p := range ancestry {
|
|
if p.PID == 1 && p.Command == "launchd" {
|
|
hasLaunchd = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasLaunchd {
|
|
return nil
|
|
}
|
|
|
|
// Get the target process (last in ancestry)
|
|
if len(ancestry) == 0 {
|
|
return nil
|
|
}
|
|
target := ancestry[len(ancestry)-1]
|
|
|
|
// Try to get detailed launchd info for the target process
|
|
info, err := launchd.GetLaunchdInfo(target.PID)
|
|
if err != nil {
|
|
// Fall back to basic launchd detection
|
|
return &model.Source{
|
|
Type: model.SourceLaunchd,
|
|
Name: "launchd",
|
|
}
|
|
}
|
|
|
|
// Build the source with details
|
|
source := &model.Source{
|
|
Type: model.SourceLaunchd,
|
|
Name: info.Label,
|
|
Description: info.Comment,
|
|
Details: make(map[string]string),
|
|
}
|
|
|
|
// Add domain description (Launch Agent vs Launch Daemon)
|
|
source.Details["type"] = info.DomainDescription()
|
|
|
|
// Add plist path if found
|
|
if info.PlistPath != "" {
|
|
source.UnitFile = info.PlistPath
|
|
source.Details["plist"] = info.PlistPath
|
|
}
|
|
|
|
// Separate schedule triggers from non-schedule triggers
|
|
var scheduleParts, triggerParts []string
|
|
for _, t := range info.FormatTriggers() {
|
|
if strings.HasPrefix(t, "StartInterval") || strings.HasPrefix(t, "StartCalendarInterval") {
|
|
scheduleParts = append(scheduleParts, t)
|
|
} else {
|
|
triggerParts = append(triggerParts, t)
|
|
}
|
|
}
|
|
if len(scheduleParts) > 0 {
|
|
source.Details["schedule"] = strings.Join(scheduleParts, "; ")
|
|
}
|
|
if len(triggerParts) > 0 {
|
|
source.Details["triggers"] = strings.Join(triggerParts, "; ")
|
|
}
|
|
|
|
// Add KeepAlive status
|
|
if info.KeepAlive {
|
|
source.Details["keepalive"] = "Yes (restarts if killed)"
|
|
}
|
|
|
|
return source
|
|
}
|