From feff1f6edd44da252212caa10442b274d4b203c9 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Fri, 14 May 2021 16:55:17 -0700 Subject: [PATCH] check stderr before reporting back error 1 --- README.md | 10 +++++----- errors.go | 2 ++ systemctl.go | 27 ++++++++++++++++++++------- systemctl_test.go | 28 ++++++++++++++++++++++++++++ util.go | 13 +++++++++++++ 5 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 systemctl_test.go diff --git a/README.md b/README.md index 76f7bd7..bc0e166 100644 --- a/README.md +++ b/README.md @@ -40,17 +40,17 @@ import ( "log" "time" - "github.com/taigrr/systemctl/v1" + "github.com/taigrr/systemctl" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - - // Equivalent to `systemctl enable dhcpd` with a 10 second timeout - err := systemctl.Enable(ctx, "dhcpd") + userMode := false + // Equivalent to `systemctl enable nginx` with a 10 second timeout + err := systemctl.Enable(ctx, "nginx", userMode) if err != nil { - log.Fatalf("unable to enable unit %s: %v", "dhcpd", err) + log.Fatalf("unable to enable unit %s: %v", "nginx", err) } } ``` diff --git a/errors.go b/errors.go index 12a9278..b7f1157 100644 --- a/errors.go +++ b/errors.go @@ -17,4 +17,6 @@ var ( // ErrDoesNotExist means the unit specified doesn't exist or can't be found ErrDoesNotExist = errors.New("Unit does not exist") + // ErrUnspecified means something in the stderr output contains the word `Failed`, but not a known case + ErrUnspecified = errors.New("Unknown error") ) diff --git a/systemctl.go b/systemctl.go index 5d4060d..050d42a 100644 --- a/systemctl.go +++ b/systemctl.go @@ -2,8 +2,7 @@ package systemctl import ( "context" - "errors" - "strconv" + "fmt" ) // TODO @@ -44,22 +43,36 @@ func Enable(ctx context.Context, unit string, usermode bool) error { args[1] = "--user" } _, stderr, code, err := execute(ctx, args) - - if err != nil { - return err + customErr := filterErr(stderr) + if customErr != nil { + return customErr } - err = filterErr(stderr) if err != nil { return err } if code != 0 { - return errors.New("received error code " + strconv.Itoa(code)) + return fmt.Errorf("received error code %d for stderr `%s`: %w", code, stderr, ErrUnspecified) } return nil } // TODO func Disable(ctx context.Context, unit string, usermode bool) error { + var args = []string{"disable", "--system", unit} + if usermode { + args[1] = "--user" + } + _, stderr, code, err := execute(ctx, args) + customErr := filterErr(stderr) + if customErr != nil { + return customErr + } + if err != nil { + return err + } + if code != 0 { + return fmt.Errorf("received error code %d for stderr `%s`: %w", code, stderr, ErrUnspecified) + } return nil } diff --git a/systemctl_test.go b/systemctl_test.go new file mode 100644 index 0000000..e20dee4 --- /dev/null +++ b/systemctl_test.go @@ -0,0 +1,28 @@ +package systemctl + +import ( + "context" + "testing" + "time" +) + +func TestEnableNonexistant(t *testing.T) { + unit := "nonexistant" + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + err := Enable(ctx, unit, true) + if err != ErrDoesNotExist { + t.Errorf("error is %v, but should have been %v", err, ErrDoesNotExist) + } + +} +func TestEnableNoPermissions(t *testing.T) { + unit := "nginx" + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + err := Enable(ctx, unit, false) + if err != ErrInsufficientPermissions { + t.Errorf("error is %v, but should have been %v", err, ErrInsufficientPermissions) + } + +} diff --git a/util.go b/util.go index c87b7cc..499490b 100644 --- a/util.go +++ b/util.go @@ -45,6 +45,19 @@ func filterErr(stderr string) error { if matched { return ErrDoesNotExist } + matched, _ = regexp.MatchString(`Interactive authentication required`, stderr) + if matched { + return ErrInsufficientPermissions + } + matched, _ = regexp.MatchString(`Access denied`, stderr) + if matched { + return ErrInsufficientPermissions + } + + matched, _ = regexp.MatchString(`Failed`, stderr) + if matched { + return ErrUnspecified + } return nil }