mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
Update updates package to support pmctl
This commit is contained in:
parent
e07a2a058a
commit
6f268906ea
9 changed files with 66 additions and 190 deletions
|
@ -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)
|
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)
|
dirPath := filepath.Dir(realFilepath)
|
||||||
err = os.MkdirAll(dirPath, 0755)
|
err = CheckDir(dirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("updates: could not create updates folder: %s", dirPath)
|
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.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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ type File struct {
|
||||||
stable bool
|
stable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFile(filepath string, version string, stable bool) *File {
|
func NewFile(filepath string, version string, stable bool) *File {
|
||||||
return &File{
|
return &File{
|
||||||
filepath: filepath,
|
filepath: filepath,
|
||||||
version: version,
|
version: version,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
var versionRegex = regexp.MustCompile("_v[0-9]+-[0-9]+-[0-9]+b?")
|
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
|
// extract version
|
||||||
rawVersion := versionRegex.FindString(versionedPath)
|
rawVersion := versionRegex.FindString(versionedPath)
|
||||||
if rawVersion == "" {
|
if rawVersion == "" {
|
||||||
|
@ -27,7 +27,7 @@ func getIdentifierAndVersion(versionedPath string) (identifier, version string,
|
||||||
return versionedPath[:i] + versionedPath[i+len(rawVersion):], version, true
|
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
|
// split in half
|
||||||
splittedFilePath := strings.SplitN(identifier, ".", 2)
|
splittedFilePath := strings.SplitN(identifier, ".", 2)
|
||||||
// replace . with -
|
// replace . with -
|
||||||
|
|
|
@ -31,6 +31,8 @@ func GetFile(identifier string) (*File, error) {
|
||||||
|
|
||||||
func getLatestFilePath(identifier string) (versionedFilePath, version string, stable bool, ok bool) {
|
func getLatestFilePath(identifier string) (versionedFilePath, version string, stable bool, ok bool) {
|
||||||
updatesLock.RLock()
|
updatesLock.RLock()
|
||||||
|
defer updatesLock.RUnlock()
|
||||||
|
|
||||||
version, ok = stableUpdates[identifier]
|
version, ok = stableUpdates[identifier]
|
||||||
if !ok {
|
if !ok {
|
||||||
version, ok = localUpdates[identifier]
|
version, ok = localUpdates[identifier]
|
||||||
|
@ -41,10 +43,9 @@ func getLatestFilePath(identifier string) (versionedFilePath, version string, st
|
||||||
// err := reloadLatest()
|
// err := reloadLatest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatesLock.RUnlock()
|
|
||||||
|
|
||||||
// TODO: Fix for stable release
|
// 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) {
|
func loadOrFetchFile(identifier string) (*File, error) {
|
||||||
|
@ -59,19 +60,24 @@ func loadOrFetchFile(identifier string) (*File, error) {
|
||||||
if _, err := os.Stat(realFilePath); err == nil {
|
if _, err := os.Stat(realFilePath); err == nil {
|
||||||
// file exists
|
// file exists
|
||||||
updateUsedStatus(identifier, version)
|
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
|
// download file
|
||||||
log.Tracef("updates: starting download of %s", versionedFilePath)
|
log.Tracef("updates: starting download of %s", versionedFilePath)
|
||||||
var err error
|
|
||||||
for tries := 0; tries < 5; tries++ {
|
for tries := 0; tries < 5; tries++ {
|
||||||
err := fetchFile(realFilePath, versionedFilePath, tries)
|
err = fetchFile(realFilePath, versionedFilePath, tries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Tracef("updates: failed to download %s: %s, retrying (%d)", versionedFilePath, err, tries+1)
|
log.Tracef("updates: failed to download %s: %s, retrying (%d)", versionedFilePath, err, tries+1)
|
||||||
} else {
|
} else {
|
||||||
updateUsedStatus(identifier, version)
|
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)
|
log.Warningf("updates: failed to download %s: %s", versionedFilePath, err)
|
||||||
|
|
|
@ -21,8 +21,8 @@ var (
|
||||||
updatesLock sync.RWMutex
|
updatesLock sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReloadLatest reloads available updates from disk.
|
// LoadLatest (re)loads the latest available updates from disk.
|
||||||
func ReloadLatest() error {
|
func LoadLatest() error {
|
||||||
newLocalUpdates := make(map[string]string)
|
newLocalUpdates := make(map[string]string)
|
||||||
|
|
||||||
// all
|
// all
|
||||||
|
@ -55,13 +55,6 @@ func ReloadLatest() error {
|
||||||
|
|
||||||
log.Tracef("updates: load complete")
|
log.Tracef("updates: load complete")
|
||||||
|
|
||||||
if len(stableUpdates) == 0 {
|
|
||||||
err := loadIndexesFromDisk()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update version status
|
// update version status
|
||||||
updatesLock.RLock()
|
updatesLock.RLock()
|
||||||
defer updatesLock.RUnlock()
|
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 {
|
filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastError = err
|
if !os.IsNotExist(err) {
|
||||||
if hardFail {
|
lastError = err
|
||||||
return err
|
if hardFail {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Warningf("updates: could not read %s", path)
|
||||||
}
|
}
|
||||||
log.Warningf("updates: could not read %s", path)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !info.IsDir() {
|
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), "/")
|
relativePath := strings.TrimLeft(strings.TrimPrefix(path, baseDir), "/")
|
||||||
identifierPath, version, ok := getIdentifierAndVersion(relativePath)
|
identifierPath, version, ok := GetIdentifierAndVersion(relativePath)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -118,13 +113,9 @@ func ScanForLatest(baseDir string, hardFail bool) (latest map[string]string, las
|
||||||
return latest, nil
|
return latest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadIndexesFromDisk() error {
|
func LoadIndexes() error {
|
||||||
data, err := ioutil.ReadFile(filepath.Join(updateStoragePath, "stable.json"))
|
data, err := ioutil.ReadFile(filepath.Join(updateStoragePath, "stable.json"))
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,45 @@
|
||||||
package updates
|
package updates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/Safing/portbase/database"
|
"github.com/Safing/portbase/database"
|
||||||
"github.com/Safing/portbase/info"
|
"github.com/Safing/portbase/info"
|
||||||
|
"github.com/Safing/portbase/log"
|
||||||
"github.com/Safing/portbase/modules"
|
"github.com/Safing/portbase/modules"
|
||||||
|
|
||||||
// module dependencies
|
|
||||||
_ "github.com/Safing/portmaster/core"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
updateStoragePath string
|
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() {
|
func init() {
|
||||||
modules.Register("updates", prep, start, nil, "core")
|
modules.Register("updates", prep, start, nil, "core")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
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()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -45,7 +50,16 @@ func start() error {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -59,29 +73,7 @@ func stop() error {
|
||||||
return os.RemoveAll(filepath.Join(updateStoragePath, "tmp"))
|
return os.RemoveAll(filepath.Join(updateStoragePath, "tmp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkUpdateDirs() error {
|
func CheckDir(dirPath string) 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 {
|
|
||||||
f, err := os.Stat(dirPath)
|
f, err := os.Stat(dirPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// file exists
|
// file exists
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"github.com/Safing/portbase/notifications"
|
"github.com/Safing/portbase/notifications"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const coreIdentifier = "core/portmaster"
|
||||||
|
|
||||||
var lastNotified time.Time
|
var lastNotified time.Time
|
||||||
|
|
||||||
func updateNotifier() {
|
func updateNotifier() {
|
||||||
|
@ -24,7 +26,7 @@ func updateNotifier() {
|
||||||
// create notification
|
// create notification
|
||||||
(¬ifications.Notification{
|
(¬ifications.Notification{
|
||||||
ID: "updates-core-update-available",
|
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,
|
Type: notifications.Info,
|
||||||
Expires: time.Now().Add(1 * time.Minute).Unix(),
|
Expires: time.Now().Add(1 * time.Minute).Unix(),
|
||||||
}).Init().Save()
|
}).Init().Save()
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
func updater() {
|
func updater() {
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
for {
|
for {
|
||||||
err := checkForUpdates()
|
err := CheckForUpdates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("updates: failed to check for updates: %s", err)
|
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
|
// download new index
|
||||||
var data []byte
|
var data []byte
|
||||||
|
@ -46,7 +46,7 @@ func checkForUpdates() error {
|
||||||
return errors.New("stable.json is empty")
|
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)")
|
log.Infof("updates: downloaded new update index: stable.json (alpha until we actually reach stable)")
|
||||||
|
|
||||||
// update existing files
|
// update existing files
|
||||||
|
@ -56,7 +56,7 @@ func checkForUpdates() error {
|
||||||
oldVersion, ok := localUpdates[identifier]
|
oldVersion, ok := localUpdates[identifier]
|
||||||
if ok && newVersion != oldVersion {
|
if ok && newVersion != oldVersion {
|
||||||
|
|
||||||
filePath := getVersionedPath(identifier, newVersion)
|
filePath := GetVersionedPath(identifier, newVersion)
|
||||||
realFilePath := filepath.Join(updateStoragePath, filePath)
|
realFilePath := filepath.Join(updateStoragePath, filePath)
|
||||||
for tries := 0; tries < 3; tries++ {
|
for tries := 0; tries < 3; tries++ {
|
||||||
err := fetchFile(realFilePath, filePath, tries)
|
err := fetchFile(realFilePath, filePath, tries)
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue