blob: 117de75e7e2ff86d47fd79652434d52e8a04da7a [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package versioning handles device manager versioning. Device manager
// binaries need to be compatible with the existing device manager installation.
package versioning
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"v.io/v23/context"
"v.io/v23/verror"
"v.io/x/lib/metadata"
"v.io/x/ref/services/device/internal/errors"
)
// Version info for this device manager binary. Increment as appropriate when the binary changes.
// The major version number should be incremented whenever a change to the binary makes it incompatible
// with on-disk state created by a binary from a different major version.
type Version struct{ Major, Minor int }
var CurrentVersion = Version{1, 0}
// CreationInfo holds data about the binary that originally created the device manager on-disk state
type CreatorInfo struct {
Version Version
MetaData string
}
func SaveCreatorInfo(ctx *context.T, dir string) error {
info := CreatorInfo{
Version: CurrentVersion,
MetaData: metadata.ToXML(),
}
jsonInfo, err := json.Marshal(info)
if err != nil {
ctx.Errorf("Marshal(%v) failed: %v", info, err)
return verror.New(errors.ErrOperationFailed, nil)
}
if err := os.MkdirAll(dir, os.FileMode(0700)); err != nil {
ctx.Errorf("MkdirAll(%v) failed: %v", dir, err)
return verror.New(errors.ErrOperationFailed, nil)
}
infoPath := filepath.Join(dir, "creation_info")
if err := ioutil.WriteFile(infoPath, jsonInfo, 0600); err != nil {
ctx.Errorf("WriteFile(%v) failed: %v", infoPath, err)
return verror.New(errors.ErrOperationFailed, nil)
}
// Make the file read-only as we don't want anyone changing it
if err := os.Chmod(infoPath, 0400); err != nil {
ctx.Errorf("Chmod(0400, %v) failed: %v", infoPath, err)
return verror.New(errors.ErrOperationFailed, nil)
}
return nil
}
func loadCreatorInfo(ctx *context.T, dir string) (*CreatorInfo, error) {
infoPath := filepath.Join(dir, "creation_info")
info := new(CreatorInfo)
if infoBytes, err := ioutil.ReadFile(infoPath); err != nil {
ctx.Errorf("ReadFile(%v) failed: %v", infoPath, err)
return nil, verror.New(errors.ErrOperationFailed, nil)
} else if err := json.Unmarshal(infoBytes, info); err != nil {
ctx.Errorf("Unmarshal(%v) failed: %v", infoBytes, err)
return nil, verror.New(errors.ErrOperationFailed, nil)
}
return info, nil
}
// Checks the compatibilty of the running binary against the device manager directory on disk
func CheckCompatibility(ctx *context.T, dir string) error {
if infoOnDisk, err := loadCreatorInfo(ctx, dir); err != nil {
ctx.Errorf("Failed to load creator info from %s", dir)
return verror.New(errors.ErrOperationFailed, nil)
} else if CurrentVersion.Major != infoOnDisk.Version.Major {
ctx.Errorf("Device Manager binary vs disk major version mismatch (%+v vs %+v)",
CurrentVersion, infoOnDisk.Version)
return verror.New(errors.ErrOperationFailed, nil)
}
return nil
}