From 6f268906ea332e7d473b8ce91044cfc2f5f90fc1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 13 Mar 2019 09:40:36 +0100 Subject: [PATCH] Update updates package to support pmctl --- updates/fetch.go | 6 +-- updates/file.go | 2 +- updates/filename.go | 4 +- updates/get.go | 18 ++++--- updates/latest.go | 29 ++++------- updates/main.go | 70 ++++++++++++--------------- updates/notify.go | 4 +- updates/updater.go | 8 +-- updates/upgrade.go | 115 -------------------------------------------- 9 files changed, 66 insertions(+), 190 deletions(-) delete mode 100644 updates/upgrade.go diff --git a/updates/fetch.go b/updates/fetch.go index 9330d0c5..ccdeac65 100644 --- a/updates/fetch.go +++ b/updates/fetch.go @@ -34,9 +34,9 @@ func fetchFile(realFilepath, updateFilepath string, tries int) error { return fmt.Errorf("error build url (%s + %s): %s", updateURLs[tries%len(updateURLs)], updateFilepath, err) } - // create destination dir + // check destination dir dirPath := filepath.Dir(realFilepath) - err = os.MkdirAll(dirPath, 0755) + err = CheckDir(dirPath) if err != nil { return fmt.Errorf("updates: could not create updates folder: %s", dirPath) } @@ -75,7 +75,7 @@ func fetchFile(realFilepath, updateFilepath string, tries int) error { log.Warningf("updates: failed to set permissions on downloaded file %s: %s", realFilepath, err) } - log.Infof("update: fetched %s (stored to %s)", downloadURL, realFilepath) + log.Infof("updates: fetched %s (stored to %s)", downloadURL, realFilepath) return nil } diff --git a/updates/file.go b/updates/file.go index 3f0d133a..4850dc58 100644 --- a/updates/file.go +++ b/updates/file.go @@ -7,7 +7,7 @@ type File struct { stable bool } -func newFile(filepath string, version string, stable bool) *File { +func NewFile(filepath string, version string, stable bool) *File { return &File{ filepath: filepath, version: version, diff --git a/updates/filename.go b/updates/filename.go index cca6cc4f..ae565c24 100644 --- a/updates/filename.go +++ b/updates/filename.go @@ -8,7 +8,7 @@ import ( var versionRegex = regexp.MustCompile("_v[0-9]+-[0-9]+-[0-9]+b?") -func getIdentifierAndVersion(versionedPath string) (identifier, version string, ok bool) { +func GetIdentifierAndVersion(versionedPath string) (identifier, version string, ok bool) { // extract version rawVersion := versionRegex.FindString(versionedPath) if rawVersion == "" { @@ -27,7 +27,7 @@ func getIdentifierAndVersion(versionedPath string) (identifier, version string, return versionedPath[:i] + versionedPath[i+len(rawVersion):], version, true } -func getVersionedPath(identifier, version string) (versionedPath string) { +func GetVersionedPath(identifier, version string) (versionedPath string) { // split in half splittedFilePath := strings.SplitN(identifier, ".", 2) // replace . with - diff --git a/updates/get.go b/updates/get.go index 7f3a2160..c37c2577 100644 --- a/updates/get.go +++ b/updates/get.go @@ -31,6 +31,8 @@ func GetFile(identifier string) (*File, error) { func getLatestFilePath(identifier string) (versionedFilePath, version string, stable bool, ok bool) { updatesLock.RLock() + defer updatesLock.RUnlock() + version, ok = stableUpdates[identifier] if !ok { version, ok = localUpdates[identifier] @@ -41,10 +43,9 @@ func getLatestFilePath(identifier string) (versionedFilePath, version string, st // err := reloadLatest() } } - updatesLock.RUnlock() // TODO: Fix for stable release - return getVersionedPath(identifier, version), version, false, true + return GetVersionedPath(identifier, version), version, false, true } func loadOrFetchFile(identifier string) (*File, error) { @@ -59,19 +60,24 @@ func loadOrFetchFile(identifier string) (*File, error) { if _, err := os.Stat(realFilePath); err == nil { // file exists updateUsedStatus(identifier, version) - return newFile(realFilePath, version, stable), nil + return NewFile(realFilePath, version, stable), nil + } + + // check download dir + err := CheckDir(filepath.Join(updateStoragePath, "tmp")) + if err != nil { + return nil, fmt.Errorf("could not prepare tmp directory for download: %s", err) } // download file log.Tracef("updates: starting download of %s", versionedFilePath) - var err error for tries := 0; tries < 5; tries++ { - err := fetchFile(realFilePath, versionedFilePath, tries) + err = fetchFile(realFilePath, versionedFilePath, tries) if err != nil { log.Tracef("updates: failed to download %s: %s, retrying (%d)", versionedFilePath, err, tries+1) } else { updateUsedStatus(identifier, version) - return newFile(realFilePath, version, stable), nil + return NewFile(realFilePath, version, stable), nil } } log.Warningf("updates: failed to download %s: %s", versionedFilePath, err) diff --git a/updates/latest.go b/updates/latest.go index d77c529d..0e6628bc 100644 --- a/updates/latest.go +++ b/updates/latest.go @@ -21,8 +21,8 @@ var ( updatesLock sync.RWMutex ) -// ReloadLatest reloads available updates from disk. -func ReloadLatest() error { +// LoadLatest (re)loads the latest available updates from disk. +func LoadLatest() error { newLocalUpdates := make(map[string]string) // all @@ -55,13 +55,6 @@ func ReloadLatest() error { log.Tracef("updates: load complete") - if len(stableUpdates) == 0 { - err := loadIndexesFromDisk() - if err != nil { - return err - } - } - // update version status updatesLock.RLock() defer updatesLock.RUnlock() @@ -76,11 +69,13 @@ func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, las filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error { if err != nil { - lastError = err - if hardFail { - return err + if !os.IsNotExist(err) { + lastError = err + if hardFail { + return err + } + log.Warningf("updates: could not read %s", path) } - log.Warningf("updates: could not read %s", path) return nil } if !info.IsDir() { @@ -88,7 +83,7 @@ func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, las } relativePath := strings.TrimLeft(strings.TrimPrefix(path, baseDir), "/") - identifierPath, version, ok := getIdentifierAndVersion(relativePath) + identifierPath, version, ok := GetIdentifierAndVersion(relativePath) if !ok { return nil } @@ -118,13 +113,9 @@ func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, las return latest, nil } -func loadIndexesFromDisk() error { +func LoadIndexes() error { data, err := ioutil.ReadFile(filepath.Join(updateStoragePath, "stable.json")) if err != nil { - if os.IsNotExist(err) { - log.Infof("updates: stable.json does not yet exist, waiting for first update cycle") - return nil - } return err } diff --git a/updates/main.go b/updates/main.go index 45027d39..f9d32467 100644 --- a/updates/main.go +++ b/updates/main.go @@ -1,40 +1,45 @@ package updates import ( + "errors" "fmt" "os" "path/filepath" - "runtime" "github.com/Safing/portbase/database" "github.com/Safing/portbase/info" + "github.com/Safing/portbase/log" "github.com/Safing/portbase/modules" - - // module dependencies - _ "github.com/Safing/portmaster/core" ) var ( updateStoragePath string ) +// SetDatabaseRoot tells the updates module where the database is - and where to put its stuff. +func SetDatabaseRoot(path string) { + if updateStoragePath == "" { + updateStoragePath = filepath.Join(path, "updates") + } +} + func init() { modules.Register("updates", prep, start, nil, "core") } func prep() error { + dbRoot := database.GetDatabaseRoot() + if dbRoot == "" { + return errors.New("database root is not set") + } + updateStoragePath = filepath.Join(dbRoot, "updates") + + err := CheckDir(updateStoragePath) + if err != nil { + return err + } + status.Core = info.GetInfo() - updateStoragePath = filepath.Join(database.GetDatabaseRoot(), "updates") - - err := checkUpdateDirs() - if err != nil { - return err - } - - err = upgradeByFlag() - if err != nil { - return err - } return nil } @@ -45,7 +50,16 @@ func start() error { return err } - err = ReloadLatest() + err = LoadIndexes() + if err != nil { + if os.IsNotExist(err) { + log.Infof("updates: stable.json does not yet exist, waiting for first update cycle") + } else { + return err + } + } + + err = LoadLatest() if err != nil { return err } @@ -59,29 +73,7 @@ func stop() error { return os.RemoveAll(filepath.Join(updateStoragePath, "tmp")) } -func checkUpdateDirs() error { - // all - err := checkDir(filepath.Join(updateStoragePath, "all")) - if err != nil { - return err - } - - // os_platform - err = checkDir(filepath.Join(updateStoragePath, fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))) - if err != nil { - return err - } - - // tmp - err = checkDir(filepath.Join(updateStoragePath, "tmp")) - if err != nil { - return err - } - - return nil -} - -func checkDir(dirPath string) error { +func CheckDir(dirPath string) error { f, err := os.Stat(dirPath) if err == nil { // file exists diff --git a/updates/notify.go b/updates/notify.go index 9a599b62..f944cf51 100644 --- a/updates/notify.go +++ b/updates/notify.go @@ -7,6 +7,8 @@ import ( "github.com/Safing/portbase/notifications" ) +const coreIdentifier = "core/portmaster" + var lastNotified time.Time func updateNotifier() { @@ -24,7 +26,7 @@ func updateNotifier() { // 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), + Message: fmt.Sprintf("There is an update available for the Portmaster core (v%s), please restart the Portmaster to apply the update.", version), Type: notifications.Info, Expires: time.Now().Add(1 * time.Minute).Unix(), }).Init().Save() diff --git a/updates/updater.go b/updates/updater.go index 91769679..a6a86710 100644 --- a/updates/updater.go +++ b/updates/updater.go @@ -13,7 +13,7 @@ import ( func updater() { time.Sleep(10 * time.Second) for { - err := checkForUpdates() + err := CheckForUpdates() if err != nil { log.Warningf("updates: failed to check for updates: %s", err) } @@ -21,7 +21,7 @@ func updater() { } } -func checkForUpdates() error { +func CheckForUpdates() error { // download new index var data []byte @@ -46,7 +46,7 @@ func checkForUpdates() error { return errors.New("stable.json is empty") } - // FIXINSTABLE: correct log line + // FIXME IN STABLE: correct log line log.Infof("updates: downloaded new update index: stable.json (alpha until we actually reach stable)") // update existing files @@ -56,7 +56,7 @@ func checkForUpdates() error { oldVersion, ok := localUpdates[identifier] if ok && newVersion != oldVersion { - filePath := getVersionedPath(identifier, newVersion) + filePath := GetVersionedPath(identifier, newVersion) realFilePath := filepath.Join(updateStoragePath, filePath) for tries := 0; tries < 3; tries++ { err := fetchFile(realFilePath, filePath, tries) diff --git a/updates/upgrade.go b/updates/upgrade.go deleted file mode 100644 index c070e60b..00000000 --- a/updates/upgrade.go +++ /dev/null @@ -1,115 +0,0 @@ -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 -}