diff --git a/openwrt/executor.go b/openwrt/executor.go index 71d3ae7..bdd4275 100644 --- a/openwrt/executor.go +++ b/openwrt/executor.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "os/exec" + "syscall" ) // Executor interface to describe command runners signature @@ -12,12 +13,22 @@ type Executor interface { Run(command string, params ...string) *CommandResult } +// CommandResult contain all information about a command execution, stdout, stderr +type CommandResult struct { + Stdout string + Stderr string + ReturnCode int +} + type localExecutor struct{} func (e *localExecutor) Run(command string, params ...string) *CommandResult { var out bytes.Buffer var stderr bytes.Buffer + var exitCode int + + defaultFailedCode := 255 exe := exec.Command(command, params...) exe.Stdout = &out @@ -25,14 +36,32 @@ func (e *localExecutor) Run(command string, params ...string) *CommandResult { err := exe.Run() if err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + ws := exitError.Sys().(syscall.WaitStatus) + exitCode = ws.ExitStatus() + } else { + // This will happen (in OSX) if `name` is not available in $PATH, + // in this situation, exit code could not be get, and stderr will be + // empty string very likely, so we use the default fail code, and format err + // to string and set to stderr + log.Printf("Could not get exit code for failed program: %v, %v", command, params) + exitCode = defaultFailedCode + } fmt.Println(fmt.Sprint(err) + ": " + stderr.String()) log.Fatal(err) } + if err != nil { + // try to get the exit code + } else { + // success, exitCode should be 0 if go is ok + ws := exe.ProcessState.Sys().(syscall.WaitStatus) + exitCode = ws.ExitStatus() + } + return &CommandResult{ - Stdout: out.String(), - Stderr: stderr.String(), - // FIXME - ReturnCode: 0, + Stdout: out.String(), + Stderr: stderr.String(), + ReturnCode: exitCode, } } diff --git a/openwrt/executor_test.go b/openwrt/executor_test.go new file mode 100644 index 0000000..3909188 --- /dev/null +++ b/openwrt/executor_test.go @@ -0,0 +1,18 @@ +package openwrt + +import ( + "testing" +) + +func TestRun(t *testing.T) { + exec := &localExecutor{} + res := exec.Run("uname", "-a") + if g, e := res.ReturnCode, 0; g != e { + t.Errorf("Run command failed ! Got bad return code [%d], [%d} is expected\n", g, e) + } + + // res = exec.Run("noCommandWithThisNameExists", "-a") + // if g, e := res.ReturnCode, 127; g != e { + // t.Errorf("Run command failed ! Got bad return code [%d], [%d} is expected\n", g, e) + // } +} diff --git a/openwrt/network.go b/openwrt/network.go new file mode 100644 index 0000000..6505d46 --- /dev/null +++ b/openwrt/network.go @@ -0,0 +1,75 @@ +package openwrt + +import ( + "fmt" + "io/ioutil" + "net" + "strings" +) + +// Network provides a representation of network +type Network struct { + exec Executor +} + +// NewNetwork return an UCI instance to interact with UCI +func NewNetwork() *Network { + exec := &localExecutor{} + return &Network{exec} +} + +// NewNetworkWithExecutor return an UCI instance to interact with UCI +func NewNetworkWithExecutor(exe Executor) *Network { + exec := exe + return &Network{exec} +} + +// ListInterfaces list all available interfaces on a system using "ip" commmand +func (n *Network) ListInterfaces() []net.Interface { + var result []net.Interface + ifaces, err := net.Interfaces() + if err != nil { + fmt.Print(fmt.Errorf("error listing network interfacess: %+v", err.Error())) + return nil + } + for _, i := range ifaces { + result = append(result, i) + } + return result +} + +// ListWirelessInterfaces list all wifi cards +func (n *Network) ListWirelessInterfaces() []net.Interface { + var result []net.Interface + var ifaceNames []string + + wifiFile := "/proc/net/wireless" + + wifiFileContent, err := ioutil.ReadFile(wifiFile) + check(err) + + index := 0 + for _, line := range strings.Split(string(wifiFileContent), "\n") { + if index < 2 { + index++ + continue + } else { + name := strings.Split(line, ":")[0] + ifaceNames = append(ifaceNames, name) + } + } + + ifaces, err := net.Interfaces() + if err != nil { + fmt.Print(fmt.Errorf("error listing network interfaces : %+v", err.Error())) + return nil + } + for _, i := range ifaces { + for _, name := range ifaceNames { + if name == i.Name { + result = append(result, i) + } + } + } + return result +} diff --git a/openwrt/network_test.go b/openwrt/network_test.go new file mode 100644 index 0000000..89b6f1a --- /dev/null +++ b/openwrt/network_test.go @@ -0,0 +1,22 @@ +package openwrt + +import ( + "fmt" + "testing" +) + +func TestNetworkListInterfaces(t *testing.T) { + net := NewNetwork() + iface := net.ListInterfaces() + for _, ife := range iface { + fmt.Printf("%s\n", ife.Name) + } +} + +func TestListWirelessInterfaces(t *testing.T) { + net := NewNetwork() + res := net.ListWirelessInterfaces() + for _, el := range res { + fmt.Printf("%s\n", el.Name) + } +} diff --git a/openwrt/test.go b/openwrt/test.go index 77b3e3a..5f7ff9a 100644 --- a/openwrt/test.go +++ b/openwrt/test.go @@ -5,6 +5,12 @@ import ( "strings" ) +func check(e error) { + if e != nil { + panic(e) + } +} + func createMockExecutor(stdout string, stderr string, returnCode int) Executor { return &mockExecutor{ stdout: stdout, diff --git a/openwrt/utils.go b/openwrt/utils.go deleted file mode 100644 index 6e0dbed..0000000 --- a/openwrt/utils.go +++ /dev/null @@ -1,38 +0,0 @@ -package openwrt - -import ( - "bytes" - "fmt" - "log" - "os/exec" -) - -// CommandResult contain all information about a command execution, stdout, stderr -type CommandResult struct { - Stdout string - Stderr string - ReturnCode int -} - -// Run executes a system command and returns -func run(command string, params ...string) *CommandResult { - var out bytes.Buffer - var stderr bytes.Buffer - - exe := exec.Command(command, params...) - exe.Stdout = &out - exe.Stderr = &stderr - - err := exe.Run() - if err != nil { - fmt.Println(fmt.Sprint(err) + ": " + stderr.String()) - log.Fatal(err) - } - - return &CommandResult{ - Stdout: out.String(), - Stderr: stderr.String(), - // FIXME - ReturnCode: 0, - } -}