summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/probemanager/manager.go38
-rw-r--r--internal/probemanager/manager_test.go31
-rw-r--r--internal/tui/probes/model.go24
3 files changed, 83 insertions, 10 deletions
diff --git a/internal/probemanager/manager.go b/internal/probemanager/manager.go
index 5a7e85d..65dd52b 100644
--- a/internal/probemanager/manager.go
+++ b/internal/probemanager/manager.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"sort"
+ "strings"
"sync"
)
@@ -179,25 +180,44 @@ func (m *Manager) Detach(syscall string) error {
}
enterLink := entry.enterLink
exitLink := entry.exitLink
- entry.enterLink = nil
- entry.exitLink = nil
- entry.active = false
m.mu.Unlock()
+ var errs []string
+ enterErr := error(nil)
if enterLink != nil {
if err := enterLink.Destroy(); err != nil {
- m.setLastError(syscall, fmt.Errorf("detach enter %s: %w", syscall, err))
- return err
+ enterErr = err
+ errs = append(errs, fmt.Sprintf("detach enter %s: %v", syscall, err))
}
}
+ exitErr := error(nil)
if exitLink != nil {
if err := exitLink.Destroy(); err != nil {
- m.setLastError(syscall, fmt.Errorf("detach exit %s: %w", syscall, err))
- return err
+ exitErr = err
+ errs = append(errs, fmt.Sprintf("detach exit %s: %v", syscall, err))
}
}
- m.setLastError(syscall, nil)
- return nil
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ entry, err = m.entryLocked(syscall)
+ if err != nil {
+ return err
+ }
+ if enterErr == nil {
+ entry.enterLink = nil
+ }
+ if exitErr == nil {
+ entry.exitLink = nil
+ }
+ entry.active = entry.enterLink != nil || entry.exitLink != nil
+ if len(errs) == 0 {
+ entry.lastErr = nil
+ return nil
+ }
+ combined := errors.New(strings.Join(errs, "; "))
+ entry.lastErr = combined
+ return combined
}
func (m *Manager) States() []ProbeState {
diff --git a/internal/probemanager/manager_test.go b/internal/probemanager/manager_test.go
index f610ea3..1fcce6d 100644
--- a/internal/probemanager/manager_test.go
+++ b/internal/probemanager/manager_test.go
@@ -114,6 +114,37 @@ func TestManagerDetachDestroysLinks(t *testing.T) {
}
}
+func TestManagerDetachFailureKeepsActiveStateForUndetachedLink(t *testing.T) {
+ enter := &fakeLink{err: errors.New("destroy failed")}
+ exit := &fakeLink{}
+ attacher := &fakeAttacher{
+ programs: map[string]*fakeProgram{
+ "handle_sys_enter_close": {link: enter},
+ "handle_sys_exit_close": {link: exit},
+ },
+ errs: map[string]error{},
+ }
+ mgr := NewManager(attacher)
+ if err := mgr.AttachAll(nil, []string{"sys_enter_close", "sys_exit_close"}); err != nil {
+ t.Fatalf("AttachAll returned error: %v", err)
+ }
+
+ err := mgr.Detach("close")
+ if err == nil {
+ t.Fatalf("expected detach error")
+ }
+ states := mgr.States()
+ if len(states) != 1 {
+ t.Fatalf("expected one state, got %+v", states)
+ }
+ if !states[0].Active {
+ t.Fatalf("expected probe to remain active when one link failed to detach")
+ }
+ if states[0].Error == "" {
+ t.Fatalf("expected error to be recorded after detach failure")
+ }
+}
+
func TestManagerClosePreventsFurtherOperations(t *testing.T) {
attacher := &fakeAttacher{
programs: map[string]*fakeProgram{
diff --git a/internal/tui/probes/model.go b/internal/tui/probes/model.go
index 5715d03..dffa30f 100644
--- a/internal/tui/probes/model.go
+++ b/internal/tui/probes/model.go
@@ -4,6 +4,7 @@ import (
"fmt"
"ior/internal/probemanager"
"strings"
+ "unicode/utf8"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
@@ -266,7 +267,7 @@ func (m Model) View(width, height int) string {
}
line := fmt.Sprintf("%s%s %-24s", prefix, check, p.Syscall)
if p.Error != "" {
- line += " ! " + p.Error
+ line += " ! " + truncateText(sanitizeOneLine(p.Error), 28)
}
lines = append(lines, line)
}
@@ -313,3 +314,24 @@ func bulkToggleCmd(manager Manager, probes []probemanager.ProbeState, sourceActi
return ProbeToggledMsg{Err: firstErr}
}
}
+
+func sanitizeOneLine(s string) string {
+ s = strings.ReplaceAll(s, "\n", " ")
+ s = strings.ReplaceAll(s, "\r", " ")
+ s = strings.ReplaceAll(s, "\t", " ")
+ return s
+}
+
+func truncateText(s string, limit int) string {
+ if limit <= 0 {
+ return ""
+ }
+ if utf8.RuneCountInString(s) <= limit {
+ return s
+ }
+ runes := []rune(s)
+ if limit <= 3 {
+ return string(runes[:limit])
+ }
+ return string(runes[:limit-3]) + "..."
+}