Commit f4269504 authored by Sophie Brun's avatar Sophie Brun

New upstream version 2.21.1

parent d3fa11ec
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
revision = "2ce16c963a8ac5bd6af851d4877e38701346983f" revision = "2ce16c963a8ac5bd6af851d4877e38701346983f"
[[projects]] [[projects]]
digest = "1:da1be9af4c3f262bd385cc722b08d98d4a47ddea57731e98b85c7ba21b35bc31" digest = "1:5247f5757ba31623c464db149dc272a37604516d8fbae1561b36e0d7cee070a5"
name = "github.com/evilsocket/islazy" name = "github.com/evilsocket/islazy"
packages = [ packages = [
"data", "data",
...@@ -96,8 +96,8 @@ ...@@ -96,8 +96,8 @@
"zip", "zip",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "6ef79e84ded205e48f296d21e3bc65d1cf4f5c78" revision = "c5c7a41bb1c20e6df409825ed24af8de5fb7fb70"
version = "v1.10.3" version = "v1.10.4"
[[projects]] [[projects]]
branch = "master" branch = "master"
......
...@@ -2,7 +2,7 @@ package core ...@@ -2,7 +2,7 @@ package core
const ( const (
Name = "bettercap" Name = "bettercap"
Version = "2.20" Version = "2.21.1"
Author = "Simone 'evilsocket' Margaritelli" Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/" Website = "https://bettercap.org/"
) )
...@@ -22,7 +22,7 @@ func ParseOptions() (Options, error) { ...@@ -22,7 +22,7 @@ func ParseOptions() (Options, error) {
o := Options{ o := Options{
InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."), InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."),
Gateway: flag.String("gateway-override", "", "Use the provided IP address instead of the default gateway. If not specified or invalid, the default gateway will be used."), Gateway: flag.String("gateway-override", "", "Use the provided IP address instead of the default gateway. If not specified or invalid, the default gateway will be used."),
AutoStart: flag.String("autostart", "events.stream, net.recon", "Comma separated list of modules to auto start."), AutoStart: flag.String("autostart", "events.stream", "Comma separated list of modules to auto start."),
Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."), Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."),
Debug: flag.Bool("debug", false, "Print debug messages."), Debug: flag.Bool("debug", false, "Print debug messages."),
PrintVersion: flag.Bool("version", false, "Print the version and exit."), PrintVersion: flag.Bool("version", false, "Print the version and exit."),
......
...@@ -80,7 +80,7 @@ func (mod *AnyProxy) Configure() error { ...@@ -80,7 +80,7 @@ func (mod *AnyProxy) Configure() error {
var dstAddress string var dstAddress string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, iface = mod.StringParam("any.proxy.iface"); err != nil { } else if err, iface = mod.StringParam("any.proxy.iface"); err != nil {
return err return err
} else if err, protocol = mod.StringParam("any.proxy.protocol"); err != nil { } else if err, protocol = mod.StringParam("any.proxy.protocol"); err != nil {
......
...@@ -126,7 +126,7 @@ func (mod *RestAPI) Configure() error { ...@@ -126,7 +126,7 @@ func (mod *RestAPI) Configure() error {
var port int var port int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, ip = mod.StringParam("api.rest.address"); err != nil { } else if err, ip = mod.StringParam("api.rest.address"); err != nil {
return err return err
} else if err, port = mod.IntParam("api.rest.port"); err != nil { } else if err, port = mod.IntParam("api.rest.port"); err != nil {
......
...@@ -140,7 +140,7 @@ func (w dummyWriter) Write(p []byte) (n int, err error) { ...@@ -140,7 +140,7 @@ func (w dummyWriter) Write(p []byte) (n int, err error) {
func (mod *BLERecon) Configure() (err error) { func (mod *BLERecon) Configure() (err error) {
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if mod.gattDevice == nil { } else if mod.gattDevice == nil {
mod.Debug("initializing device ...") mod.Debug("initializing device ...")
...@@ -239,7 +239,7 @@ func (mod *BLERecon) enumAllTheThings(mac string) error { ...@@ -239,7 +239,7 @@ func (mod *BLERecon) enumAllTheThings(mac string) error {
} }
mod.setCurrentDevice(dev) mod.setCurrentDevice(dev)
if err := mod.Configure(); err != nil && err != session.ErrAlreadyStarted { if err := mod.Configure(); err != nil && err.Error() != session.ErrAlreadyStarted("ble.recon").Error() {
return err return err
} }
......
...@@ -78,7 +78,7 @@ func (mod *DHCP6Spoofer) Configure() error { ...@@ -78,7 +78,7 @@ func (mod *DHCP6Spoofer) Configure() error {
var err error var err error
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} }
if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
......
...@@ -87,7 +87,7 @@ func (mod *DNSSpoofer) Configure() error { ...@@ -87,7 +87,7 @@ func (mod *DNSSpoofer) Configure() error {
var address net.IP var address net.IP
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { } else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
return err return err
} else if err = mod.Handle.SetBPFFilter("udp"); err != nil { } else if err = mod.Handle.SetBPFFilter("udp"); err != nil {
......
...@@ -72,7 +72,7 @@ func (mod *GPS) Author() string { ...@@ -72,7 +72,7 @@ func (mod *GPS) Author() string {
func (mod *GPS) Configure() (err error) { func (mod *GPS) Configure() (err error) {
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.serialPort = mod.StringParam("gps.device"); err != nil { } else if err, mod.serialPort = mod.StringParam("gps.device"); err != nil {
return err return err
} else if err, mod.baudRate = mod.IntParam("gps.baudrate"); err != nil { } else if err, mod.baudRate = mod.IntParam("gps.baudrate"); err != nil {
......
...@@ -163,7 +163,7 @@ func (mod *HIDRecon) Configure() error { ...@@ -163,7 +163,7 @@ func (mod *HIDRecon) Configure() error {
var n int var n int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} }
if err, mod.useLNA = mod.BoolParam("hid.lna"); err != nil { if err, mod.useLNA = mod.BoolParam("hid.lna"); err != nil {
......
...@@ -89,7 +89,7 @@ func (mod *HttpProxy) Configure() error { ...@@ -89,7 +89,7 @@ func (mod *HttpProxy) Configure() error {
var whitelist string var whitelist string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("http.proxy.address"); err != nil { } else if err, address = mod.StringParam("http.proxy.address"); err != nil {
return err return err
} else if err, proxyPort = mod.IntParam("http.proxy.port"); err != nil { } else if err, proxyPort = mod.IntParam("http.proxy.port"); err != nil {
......
...@@ -71,7 +71,7 @@ func (mod *HttpServer) Configure() error { ...@@ -71,7 +71,7 @@ func (mod *HttpServer) Configure() error {
var port int var port int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} }
if err, path = mod.StringParam("http.server.path"); err != nil { if err, path = mod.StringParam("http.server.path"); err != nil {
...@@ -82,7 +82,7 @@ func (mod *HttpServer) Configure() error { ...@@ -82,7 +82,7 @@ func (mod *HttpServer) Configure() error {
fileServer := http.FileServer(http.Dir(path)) fileServer := http.FileServer(http.Dir(path))
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mod.Info("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path) mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
fileServer.ServeHTTP(w, r) fileServer.ServeHTTP(w, r)
})) }))
......
...@@ -106,7 +106,7 @@ func (mod *HttpsProxy) Configure() error { ...@@ -106,7 +106,7 @@ func (mod *HttpsProxy) Configure() error {
var blacklist string var blacklist string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("https.proxy.address"); err != nil { } else if err, address = mod.StringParam("https.proxy.address"); err != nil {
return err return err
} else if err, proxyPort = mod.IntParam("https.proxy.port"); err != nil { } else if err, proxyPort = mod.IntParam("https.proxy.port"); err != nil {
......
...@@ -89,7 +89,7 @@ func (mod *HttpsServer) Configure() error { ...@@ -89,7 +89,7 @@ func (mod *HttpsServer) Configure() error {
var keyFile string var keyFile string
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} }
if err, path = mod.StringParam("https.server.path"); err != nil { if err, path = mod.StringParam("https.server.path"); err != nil {
...@@ -100,7 +100,7 @@ func (mod *HttpsServer) Configure() error { ...@@ -100,7 +100,7 @@ func (mod *HttpsServer) Configure() error {
fileServer := http.FileServer(http.Dir(path)) fileServer := http.FileServer(http.Dir(path))
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mod.Info("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path) mod.Debug("%s %s %s%s", tui.Bold(strings.Split(r.RemoteAddr, ":")[0]), r.Method, r.Host, r.URL.Path)
fileServer.ServeHTTP(w, r) fileServer.ServeHTTP(w, r)
})) }))
......
...@@ -103,7 +103,7 @@ func (mod *MacChanger) setMac(mac net.HardwareAddr) error { ...@@ -103,7 +103,7 @@ func (mod *MacChanger) setMac(mac net.HardwareAddr) error {
func (mod *MacChanger) Start() error { func (mod *MacChanger) Start() error {
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err := mod.Configure(); err != nil { } else if err := mod.Configure(); err != nil {
return err return err
} else if err := mod.setMac(mod.fakeMac); err != nil { } else if err := mod.setMac(mod.fakeMac); err != nil {
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"github.com/bettercap/bettercap/modules/syn_scan" "github.com/bettercap/bettercap/modules/syn_scan"
"github.com/bettercap/bettercap/modules/tcp_proxy" "github.com/bettercap/bettercap/modules/tcp_proxy"
"github.com/bettercap/bettercap/modules/ticker" "github.com/bettercap/bettercap/modules/ticker"
"github.com/bettercap/bettercap/modules/ui"
"github.com/bettercap/bettercap/modules/update" "github.com/bettercap/bettercap/modules/update"
"github.com/bettercap/bettercap/modules/wifi" "github.com/bettercap/bettercap/modules/wifi"
"github.com/bettercap/bettercap/modules/wol" "github.com/bettercap/bettercap/modules/wol"
...@@ -36,7 +37,6 @@ func LoadModules(sess *session.Session) { ...@@ -36,7 +37,6 @@ func LoadModules(sess *session.Session) {
sess.Register(arp_spoof.NewArpSpoofer(sess)) sess.Register(arp_spoof.NewArpSpoofer(sess))
sess.Register(api_rest.NewRestAPI(sess)) sess.Register(api_rest.NewRestAPI(sess))
sess.Register(ble.NewBLERecon(sess)) sess.Register(ble.NewBLERecon(sess))
sess.Register(caplets.NewCapletsModule(sess))
sess.Register(dhcp6_spoof.NewDHCP6Spoofer(sess)) sess.Register(dhcp6_spoof.NewDHCP6Spoofer(sess))
sess.Register(net_recon.NewDiscovery(sess)) sess.Register(net_recon.NewDiscovery(sess))
sess.Register(dns_spoof.NewDNSSpoofer(sess)) sess.Register(dns_spoof.NewDNSSpoofer(sess))
...@@ -54,8 +54,11 @@ func LoadModules(sess *session.Session) { ...@@ -54,8 +54,11 @@ func LoadModules(sess *session.Session) {
sess.Register(syn_scan.NewSynScanner(sess)) sess.Register(syn_scan.NewSynScanner(sess))
sess.Register(tcp_proxy.NewTcpProxy(sess)) sess.Register(tcp_proxy.NewTcpProxy(sess))
sess.Register(ticker.NewTicker(sess)) sess.Register(ticker.NewTicker(sess))
sess.Register(update.NewUpdateModule(sess))
sess.Register(wifi.NewWiFiModule(sess)) sess.Register(wifi.NewWiFiModule(sess))
sess.Register(wol.NewWOL(sess)) sess.Register(wol.NewWOL(sess))
sess.Register(hid.NewHIDRecon(sess)) sess.Register(hid.NewHIDRecon(sess))
sess.Register(caplets.NewCapletsModule(sess))
sess.Register(update.NewUpdateModule(sess))
sess.Register(ui.NewUIModule(sess))
} }
...@@ -79,7 +79,7 @@ func (mod *MySQLServer) Configure() error { ...@@ -79,7 +79,7 @@ func (mod *MySQLServer) Configure() error {
var port int var port int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.infile = mod.StringParam("mysql.server.infile"); err != nil { } else if err, mod.infile = mod.StringParam("mysql.server.infile"); err != nil {
return err return err
} else if err, mod.outfile = mod.StringParam("mysql.server.outfile"); err != nil { } else if err, mod.outfile = mod.StringParam("mysql.server.outfile"); err != nil {
......
...@@ -146,7 +146,7 @@ func (mod *Sniffer) Configure() error { ...@@ -146,7 +146,7 @@ func (mod *Sniffer) Configure() error {
var err error var err error
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, mod.Ctx = mod.GetContext(); err != nil { } else if err, mod.Ctx = mod.GetContext(); err != nil {
if mod.Ctx != nil { if mod.Ctx != nil {
mod.Ctx.Close() mod.Ctx.Close()
......
...@@ -190,7 +190,7 @@ func dummyCallback(payload *nfqueue.Payload) int { ...@@ -190,7 +190,7 @@ func dummyCallback(payload *nfqueue.Payload) int {
func (mod *PacketProxy) Start() error { func (mod *PacketProxy) Start() error {
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err := mod.Configure(); err != nil { } else if err := mod.Configure(); err != nil {
return err return err
} }
......
...@@ -95,7 +95,7 @@ func (mod *TcpProxy) Configure() error { ...@@ -95,7 +95,7 @@ func (mod *TcpProxy) Configure() error {
var tunnelPort int var tunnelPort int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, address = mod.StringParam("tcp.address"); err != nil { } else if err, address = mod.StringParam("tcp.address"); err != nil {
return err return err
} else if err, proxyAddress = mod.StringParam("tcp.proxy.address"); err != nil { } else if err, proxyAddress = mod.StringParam("tcp.proxy.address"); err != nil {
......
...@@ -59,7 +59,7 @@ func (mod *Ticker) Configure() error { ...@@ -59,7 +59,7 @@ func (mod *Ticker) Configure() error {
var period int var period int
if mod.Running() { if mod.Running() {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} else if err, commands = mod.StringParam("ticker.commands"); err != nil { } else if err, commands = mod.StringParam("ticker.commands"); err != nil {
return err return err
} else if err, period = mod.IntParam("ticker.period"); err != nil { } else if err, period = mod.IntParam("ticker.period"); err != nil {
......
package ui
import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"regexp"
"github.com/bettercap/bettercap/session"
"github.com/google/go-github/github"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/tui"
"github.com/evilsocket/islazy/zip"
)
var versionParser = regexp.MustCompile(`name:"ui",version:"([^"]+)"`)
type UIModule struct {
session.SessionModule
client *github.Client
tmpFile string
basePath string
uiPath string
}
func NewUIModule(s *session.Session) *UIModule {
mod := &UIModule{
SessionModule: session.NewSessionModule("ui", s),
client: github.NewClient(nil),
}
mod.AddParam(session.NewStringParameter("ui.basepath",
"/usr/local/share/bettercap/",
"",
"UI base installation path."))
mod.AddParam(session.NewStringParameter("ui.tmpfile",
filepath.Join(os.TempDir(), "ui.zip"),
"",
"Temporary file to use while downloading UI updates."))
mod.AddHandler(session.NewModuleHandler("ui.version", "",
"Print the currently installed UI version.",
func(args []string) error {
return mod.showVersion()
}))
mod.AddHandler(session.NewModuleHandler("ui.update", "",
"Download the latest available version of the UI and install it.",
func(args []string) error {
return mod.Start()
}))
return mod
}
func (mod *UIModule) Name() string {
return "ui"
}
func (mod *UIModule) Description() string {
return "A module to manage bettercap's UI updates and installed version."
}
func (mod *UIModule) Author() string {
return "Simone Margaritelli <evilsocket@gmail.com>"
}
func (mod *UIModule) Configure() (err error) {
if err, mod.basePath = mod.StringParam("ui.basepath"); err != nil {
return err
} else {
mod.uiPath = filepath.Join(mod.basePath, "ui")
}
if err, mod.tmpFile = mod.StringParam("ui.tmpfile"); err != nil {
return err
}
return nil
}
func (mod *UIModule) Stop() error {
return nil
}
func (mod *UIModule) download(version, url string) error {
if !fs.Exists(mod.basePath) {
mod.Warning("creating ui install path %s ...", mod.basePath)
if err := os.MkdirAll(mod.basePath, os.ModePerm); err != nil {
return err
}
}
out, err := os.Create(mod.tmpFile)
if err != nil {
return err
}
defer out.Close()
defer os.Remove(mod.tmpFile)
mod.Info("downloading ui %s from %s ...", tui.Bold(version), url)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if _, err := io.Copy(out, resp.Body); err != nil {
return err
}
if fs.Exists(mod.uiPath) {
mod.Warning("removing previously installed UI from %s ...", mod.uiPath)
if err := os.RemoveAll(mod.uiPath); err != nil {
return err
}
}
mod.Info("installing to %s ...", mod.uiPath)
if _, err = zip.Unzip(mod.tmpFile, mod.basePath); err != nil {
return err
}
mod.Info("installation complete, you can now run the %s (or https-ui) caplet to start the UI.", tui.Bold("http-ui"))
return nil
}
func (mod *UIModule) showVersion() error {
if err := mod.Configure(); err != nil {
return err
}
if !fs.Exists(mod.uiPath) {
return fmt.Errorf("path %s does not exist, ui not installed", mod.uiPath)
}
search := filepath.Join(mod.uiPath, "/main.*.js")
matches, err := filepath.Glob(search)
if err != nil {
return err
} else if len(matches) == 0 {
return fmt.Errorf("can't find any main.*.js files in %s", mod.uiPath)
}
for _, filename := range matches {
if raw, err := ioutil.ReadFile(filename); err != nil {
return err
} else if m := versionParser.FindStringSubmatch(string(raw)); m != nil {
version := m[1]
mod.Info("v%s", version)
return nil
}
}
return fmt.Errorf("can't parse version from %s", search)
}
func (mod *UIModule) Start() error {
if err := mod.Configure(); err != nil {
return err
} else if err := mod.SetRunning(true, nil); err != nil {
return err
}
defer mod.SetRunning(false, nil)
mod.Info("checking latest stable release ...")
if releases, _, err := mod.client.Repositories.ListReleases(context.Background(), "bettercap", "ui", nil); err == nil {
latest := releases[0]
for _, a := range latest.Assets {
if *a.Name == "ui.zip" {
return mod.download(*latest.TagName, *a.BrowserDownloadURL)
}
}
} else {
mod.Error("error while fetching latest release info from GitHub: %s", err)
}
return nil
}
...@@ -35,7 +35,7 @@ func (mod *WiFiModule) startAp() error { ...@@ -35,7 +35,7 @@ func (mod *WiFiModule) startAp() error {
if !mod.Running() { if !mod.Running() {
return errNoRecon return errNoRecon
} else if mod.apRunning { } else if mod.apRunning {
return session.ErrAlreadyStarted return session.ErrAlreadyStarted(mod.Name())
} }
go func() { go func() {
......
...@@ -230,9 +230,9 @@ func (m *SessionModule) Running() bool { ...@@ -230,9 +230,9 @@ func (m *SessionModule) Running() bool {
func (m *SessionModule) SetRunning(running bool, cb func()) error { func (m *SessionModule) SetRunning(running bool, cb func()) error {
if running == m.Running() { if running == m.Running() {
if m.Started { if m.Started {
return ErrAlreadyStarted return ErrAlreadyStarted(m.Name)
} else { } else {
return ErrAlreadyStopped return ErrAlreadyStopped(m.Name)
} }
} }
......
...@@ -35,14 +35,20 @@ const ( ...@@ -35,14 +35,20 @@ const (
var ( var (
I = (*Session)(nil) I = (*Session)(nil)
ErrAlreadyStarted = errors.New("module is already running") ErrNotSupported = errors.New("this component is not supported on this OS")
ErrAlreadyStopped = errors.New("module is not running")
ErrNotSupported = errors.New("this component is not supported on this OS")
reCmdSpaceCleaner = regexp.MustCompile(`^([^\s]+)\s+(.+)$`) reCmdSpaceCleaner = regexp.MustCompile(`^([^\s]+)\s+(.+)$`)
reEnvVarCapture = regexp.MustCompile(`{env\.([^}]+)}`) reEnvVarCapture = regexp.MustCompile(`{env\.([^}]+)}`)
) )
func ErrAlreadyStarted(name string) error {
return fmt.Errorf("module %s is already running", name)
}
func ErrAlreadyStopped(name string) error {
return fmt.Errorf("module %s is not running", name)
}
type UnknownCommandCallback func(cmd string) bool type UnknownCommandCallback func(cmd string) bool
type GPS struct { type GPS struct {
......
...@@ -13,6 +13,8 @@ import ( ...@@ -13,6 +13,8 @@ import (
// within the zip file (parameter 1) to an output directory (parameter 2). // within the zip file (parameter 1) to an output directory (parameter 2).
// Credits to https://golangcode.com/unzip-files-in-go/ // Credits to https://golangcode.com/unzip-files-in-go/
func Unzip(src string, dest string) ([]string, error) { func Unzip(src string, dest string) ([]string, error) {
var outFile *os.File
var zipFile io.ReadCloser
var filenames []string var filenames []string
r, err := zip.OpenReader(src) r, err := zip.OpenReader(src)
...@@ -21,33 +23,55 @@ func Unzip(src string, dest string) ([]string, error) { ...@@ -21,33 +23,55 @@ func Unzip(src string, dest string) ([]string, error) {
} }
defer r.Close() defer r.Close()
clean := func() {
if outFile != nil {
outFile.Close()
outFile = nil
}
if zipFile != nil {
zipFile.Close()
zipFile = nil
}
}
for _, f := range r.File { for _, f := range r.File {
rc, err := f.Open() zipFile, err = f.Open()
if err != nil { if