From e07a2a058ad3fdfc9643736eb2d87a783d935c81 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Mar 2019 23:05:25 +0100 Subject: [PATCH] Add self upgrade and notifications to updates module --- updates/main.go | 6 +++ updates/notify.go | 37 +++++++++++++++ updates/upgrade.go | 115 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 updates/notify.go create mode 100644 updates/upgrade.go diff --git a/updates/main.go b/updates/main.go index 0a168b61..45027d39 100644 --- a/updates/main.go +++ b/updates/main.go @@ -31,6 +31,11 @@ func prep() error { return err } + err = upgradeByFlag() + if err != nil { + return err + } + return nil } @@ -46,6 +51,7 @@ func start() error { } go updater() + go updateNotifier() return nil } diff --git a/updates/notify.go b/updates/notify.go new file mode 100644 index 00000000..9a599b62 --- /dev/null +++ b/updates/notify.go @@ -0,0 +1,37 @@ +package updates + +import ( + "fmt" + "time" + + "github.com/Safing/portbase/notifications" +) + +var lastNotified time.Time + +func updateNotifier() { + time.Sleep(30 * time.Second) + for { + + _, version, _, ok := getLatestFilePath(coreIdentifier) + if ok { + status.Lock() + liveVersion := status.Core.Version + status.Unlock() + + if version != liveVersion { + + // create notification + (¬ifications.Notification{ + ID: "updates-core-update-available", + Message: fmt.Sprintf("There is an update available for the portmaster core (%s), you may apply the update with the -upgrade flag.", version), + Type: notifications.Info, + Expires: time.Now().Add(1 * time.Minute).Unix(), + }).Init().Save() + + } + } + + time.Sleep(1 * time.Hour) + } +} diff --git a/updates/upgrade.go b/updates/upgrade.go new file mode 100644 index 00000000..c070e60b --- /dev/null +++ b/updates/upgrade.go @@ -0,0 +1,115 @@ +package updates + +import ( + "flag" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/Safing/portbase/modules" +) + +const ( + coreIdentifier = "core/portmaster" +) + +var ( + upgradeSelf bool +) + +func init() { + flag.BoolVar(&upgradeSelf, "upgrade", false, "upgrade to newest portmaster core binary") +} + +func upgradeByFlag() error { + if !upgradeSelf { + return nil + } + + err := ReloadLatest() + if err != nil { + return err + } + + return doSelfUpgrade() +} + +func doSelfUpgrade() error { + + // get source + file, err := GetPlatformFile(coreIdentifier) + if err != nil { + return fmt.Errorf("%s currently not available: %s - you may need to first start portmaster and wait for it to fetch the update index", coreIdentifier, err) + } + + // get destination + dst, err := os.Executable() + if err != nil { + return err + } + dst, err = filepath.EvalSymlinks(dst) + if err != nil { + return err + } + + // mv destination + err = os.Rename(dst, dst+"_old") + if err != nil { + return err + } + + // hard link + err = os.Link(file.Path(), dst) + if err != nil { + fmt.Printf("failed to hardlink: %s, will copy...\n", err) + err = copyFile(file.Path(), dst) + if err != nil { + return err + } + } + + // check permission + info, err := os.Stat(dst) + if info.Mode() != 0755 { + err := os.Chmod(dst, 0755) + if err != nil { + return fmt.Errorf("failed to set permissions on %s: %s", dst, err) + } + } + + // delete old + err = os.Remove(dst + "_old") + if err != nil { + return err + } + + // gracefully exit portmaster + return modules.ErrCleanExit +} + +func copyFile(srcPath, dstPath string) (err error) { + srcFile, err := os.Open(srcPath) + if err != nil { + return + } + defer srcFile.Close() + + dstFile, err := os.Create(dstPath) + if err != nil { + return + } + defer func() { + closeErr := dstFile.Close() + if err == nil { + err = closeErr + } + }() + + _, err = io.Copy(dstFile, srcFile) + if err != nil { + return + } + err = dstFile.Sync() + return +}