config: fix issues with memory-only config file paths

Fixes #5222
This commit is contained in:
albertony 2021-04-08 17:49:47 +02:00
parent b96ebfc40b
commit 23a0d4a1e6
11 changed files with 119 additions and 89 deletions

View file

@ -26,12 +26,12 @@ func TestVersionWorksWithoutAccessibleConfigFile(t *testing.T) {
} }
// re-wire // re-wire
oldOsStdout := os.Stdout oldOsStdout := os.Stdout
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
config.ConfigPath = path assert.NoError(t, config.SetConfigPath(path))
os.Stdout = nil os.Stdout = nil
defer func() { defer func() {
os.Stdout = oldOsStdout os.Stdout = oldOsStdout
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
}() }()
cmd.Root.SetArgs([]string{"version"}) cmd.Root.SetArgs([]string{"version"})

View file

@ -28,6 +28,7 @@ import (
const ( const (
configFileName = "rclone.conf" configFileName = "rclone.conf"
hiddenConfigFileName = "." + configFileName hiddenConfigFileName = "." + configFileName
noConfigFile = "/notfound"
// ConfigToken is the key used to store the token under // ConfigToken is the key used to store the token under
ConfigToken = "token" ConfigToken = "token"
@ -107,17 +108,21 @@ var (
// and any parents. // and any parents.
CacheDir = makeCacheDir() CacheDir = makeCacheDir()
// ConfigPath points to the config file
ConfigPath = makeConfigPath()
// Password can be used to configure the random password generator // Password can be used to configure the random password generator
Password = random.Password Password = random.Password
) )
var (
configPath string
noConfigPath string
)
func init() { func init() {
// Set the function pointers up in fs // Set the function pointers up in fs
fs.ConfigFileGet = FileGetFlag fs.ConfigFileGet = FileGetFlag
fs.ConfigFileSet = SetValueAndSave fs.ConfigFileSet = SetValueAndSave
noConfigPath, _ = filepath.Abs(noConfigFile)
configPath = makeConfigPath()
} }
// Return the path to the configuration file // Return the path to the configuration file
@ -212,18 +217,44 @@ func makeConfigPath() string {
return hiddenConfigFileName return hiddenConfigFileName
} }
// GetConfigPath returns the current config file path
func GetConfigPath() string {
return configPath
}
// SetConfigPath sets new config file path
//
// Checks for empty string, os null device, or special path, all of which indicates in-memory config.
func SetConfigPath(path string) (err error) {
if path == "" || path == os.DevNull {
configPath = ""
} else {
if configPath, err = filepath.Abs(path); err != nil {
return err
}
if configPath == noConfigPath {
configPath = ""
}
}
return nil
}
// LoadConfig loads the config file // LoadConfig loads the config file
func LoadConfig(ctx context.Context) { func LoadConfig(ctx context.Context) {
// Set RCLONE_CONFIG_DIR for backend config and subprocesses // Set RCLONE_CONFIG_DIR for backend config and subprocesses
_ = os.Setenv("RCLONE_CONFIG_DIR", filepath.Dir(ConfigPath)) // If empty configPath (in-memory only) the value will be "."
_ = os.Setenv("RCLONE_CONFIG_DIR", filepath.Dir(configPath))
// Load configuration file. // Load configuration from file (or initialize sensible default if no file or error)
if err := Data.Load(); err == ErrorConfigFileNotFound { if err := Data.Load(); err == ErrorConfigFileNotFound {
fs.Logf(nil, "Config file %q not found - using defaults", ConfigPath) if configPath == "" {
} else if err != nil { fs.Debugf(nil, "Config is memory-only - using defaults")
log.Fatalf("Failed to load config file %q: %v", ConfigPath, err)
} else { } else {
fs.Debugf(nil, "Using config file from %q", ConfigPath) fs.Logf(nil, "Config file %q not found - using defaults", configPath)
}
} else if err != nil {
log.Fatalf("Failed to load config file %q: %v", configPath, err)
} else {
fs.Debugf(nil, "Using config file from %q", configPath)
} }
} }
@ -233,6 +264,10 @@ var ErrorConfigFileNotFound = errors.New("config file not found")
// SaveConfig calling function which saves configuration file. // SaveConfig calling function which saves configuration file.
// if SaveConfig returns error trying again after sleep. // if SaveConfig returns error trying again after sleep.
func SaveConfig() { func SaveConfig() {
if configPath == "" {
fs.Debugf(nil, "Skipping save for memory-only config")
return
}
ctx := context.Background() ctx := context.Background()
ci := fs.GetConfig(ctx) ci := fs.GetConfig(ctx)
var err error var err error
@ -244,7 +279,6 @@ func SaveConfig() {
time.Sleep(time.Duration(waitingTimeMs) * time.Millisecond) time.Sleep(time.Duration(waitingTimeMs) * time.Millisecond)
} }
fs.Errorf(nil, "Failed to save config after %d tries: %v", ci.LowLevelRetries, err) fs.Errorf(nil, "Failed to save config after %d tries: %v", ci.LowLevelRetries, err)
return
} }
// SetValueAndSave sets the key to the value and saves just that // SetValueAndSave sets the key to the value and saves just that

View file

@ -12,10 +12,10 @@ import (
) )
func TestConfigLoad(t *testing.T) { func TestConfigLoad(t *testing.T) {
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
config.ConfigPath = "./testdata/plain.conf" assert.NoError(t, config.SetConfigPath("./testdata/plain.conf"))
defer func() { defer func() {
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
}() }()
config.ClearConfigPassword() config.ClearConfigPassword()
configfile.LoadConfig(context.Background()) configfile.LoadConfig(context.Background())

View file

@ -15,9 +15,6 @@ import (
"github.com/rclone/rclone/fs/config" "github.com/rclone/rclone/fs/config"
) )
// Special value indicating in memory config file. Empty string works also.
const noConfigFile = "/notfound"
// LoadConfig installs the config file handler and calls config.LoadConfig // LoadConfig installs the config file handler and calls config.LoadConfig
func LoadConfig(ctx context.Context) { func LoadConfig(ctx context.Context) {
config.Data = &Storage{} config.Data = &Storage{}
@ -32,22 +29,14 @@ type Storage struct {
fi os.FileInfo // stat of the file when last loaded fi os.FileInfo // stat of the file when last loaded
} }
// Return whether we have a real config file or not
func (s *Storage) noConfig() bool {
return config.ConfigPath == "" || config.ConfigPath == noConfigFile
}
// Check to see if we need to reload the config // Check to see if we need to reload the config
func (s *Storage) check() { func (s *Storage) check() {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if s.noConfig() { if configPath := config.GetConfigPath(); configPath != "" {
return
}
// Check to see if config file has changed since it was last loaded // Check to see if config file has changed since it was last loaded
fi, err := os.Stat(config.ConfigPath) fi, err := os.Stat(configPath)
if err == nil { if err == nil {
// check to see if config file has changed and if it has, reload it // check to see if config file has changed and if it has, reload it
if s.fi == nil || !fi.ModTime().Equal(s.fi.ModTime()) || fi.Size() != s.fi.Size() { if s.fi == nil || !fi.ModTime().Equal(s.fi.ModTime()) || fi.Size() != s.fi.Size() {
@ -58,6 +47,7 @@ func (s *Storage) check() {
} }
} }
} }
}
} }
// _load the config from permanent storage, decrypting if necessary // _load the config from permanent storage, decrypting if necessary
@ -71,11 +61,12 @@ func (s *Storage) _load() (err error) {
} }
}() }()
if s.noConfig() { configPath := config.GetConfigPath()
if configPath == "" {
return config.ErrorConfigFileNotFound return config.ErrorConfigFileNotFound
} }
fd, err := os.Open(config.ConfigPath) fd, err := os.Open(configPath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return config.ErrorConfigFileNotFound return config.ErrorConfigFileNotFound
@ -85,7 +76,7 @@ func (s *Storage) _load() (err error) {
defer fs.CheckClose(fd, &err) defer fs.CheckClose(fd, &err)
// Update s.fi with the current file info // Update s.fi with the current file info
s.fi, _ = os.Stat(config.ConfigPath) s.fi, _ = os.Stat(configPath)
cryptReader, err := config.Decrypt(fd) cryptReader, err := config.Decrypt(fd)
if err != nil { if err != nil {
@ -113,11 +104,12 @@ func (s *Storage) Save() error {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if s.noConfig() { configPath := config.GetConfigPath()
return nil if configPath == "" {
return errors.Errorf("Failed to save config file: Path is empty")
} }
dir, name := filepath.Split(config.ConfigPath) dir, name := filepath.Split(configPath)
err := os.MkdirAll(dir, os.ModePerm) err := os.MkdirAll(dir, os.ModePerm)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create config directory") return errors.Wrap(err, "failed to create config directory")
@ -149,7 +141,7 @@ func (s *Storage) Save() error {
} }
var fileMode os.FileMode = 0600 var fileMode os.FileMode = 0600
info, err := os.Stat(config.ConfigPath) info, err := os.Stat(configPath)
if err != nil { if err != nil {
fs.Debugf(nil, "Using default permissions for config file: %v", fileMode) fs.Debugf(nil, "Using default permissions for config file: %v", fileMode)
} else if info.Mode() != fileMode { } else if info.Mode() != fileMode {
@ -157,25 +149,25 @@ func (s *Storage) Save() error {
fileMode = info.Mode() fileMode = info.Mode()
} }
attemptCopyGroup(config.ConfigPath, f.Name()) attemptCopyGroup(configPath, f.Name())
err = os.Chmod(f.Name(), fileMode) err = os.Chmod(f.Name(), fileMode)
if err != nil { if err != nil {
fs.Errorf(nil, "Failed to set permissions on config file: %v", err) fs.Errorf(nil, "Failed to set permissions on config file: %v", err)
} }
if err = os.Rename(config.ConfigPath, config.ConfigPath+".old"); err != nil && !os.IsNotExist(err) { if err = os.Rename(configPath, configPath+".old"); err != nil && !os.IsNotExist(err) {
return errors.Errorf("Failed to move previous config to backup location: %v", err) return errors.Errorf("Failed to move previous config to backup location: %v", err)
} }
if err = os.Rename(f.Name(), config.ConfigPath); err != nil { if err = os.Rename(f.Name(), configPath); err != nil {
return errors.Errorf("Failed to move newly written config from %s to final location: %v", f.Name(), err) return errors.Errorf("Failed to move newly written config from %s to final location: %v", f.Name(), err)
} }
if err := os.Remove(config.ConfigPath + ".old"); err != nil && !os.IsNotExist(err) { if err := os.Remove(configPath + ".old"); err != nil && !os.IsNotExist(err) {
fs.Errorf(nil, "Failed to remove backup config file: %v", err) fs.Errorf(nil, "Failed to remove backup config file: %v", err)
} }
// Update s.fi with the newly written file // Update s.fi with the newly written file
s.fi, _ = os.Stat(config.ConfigPath) s.fi, _ = os.Stat(configPath)
return nil return nil
} }

View file

@ -39,10 +39,10 @@ func setConfigFile(t *testing.T, data string) func() {
require.NoError(t, out.Close()) require.NoError(t, out.Close())
old := config.ConfigPath old := config.GetConfigPath()
config.ConfigPath = filePath assert.NoError(t, config.SetConfigPath(filePath))
return func() { return func() {
config.ConfigPath = old assert.NoError(t, config.SetConfigPath(old))
_ = os.Remove(filePath) _ = os.Remove(filePath)
} }
} }
@ -160,7 +160,7 @@ type = number3
`, toUnix(buf)) `, toUnix(buf))
t.Run("Save", func(t *testing.T) { t.Run("Save", func(t *testing.T) {
require.NoError(t, data.Save()) require.NoError(t, data.Save())
buf, err := ioutil.ReadFile(config.ConfigPath) buf, err := ioutil.ReadFile(config.GetConfigPath())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, `[one] assert.Equal(t, `[one]
fruit = potato fruit = potato
@ -188,7 +188,7 @@ func TestConfigFileReload(t *testing.T) {
assert.Equal(t, "", value) assert.Equal(t, "", value)
// Now write a new value on the end // Now write a new value on the end
out, err := os.OpenFile(config.ConfigPath, os.O_APPEND|os.O_WRONLY, 0777) out, err := os.OpenFile(config.GetConfigPath(), os.O_APPEND|os.O_WRONLY, 0777)
require.NoError(t, err) require.NoError(t, err)
fmt.Fprintln(out, "appended = what magic") fmt.Fprintln(out, "appended = what magic")
require.NoError(t, out.Close()) require.NoError(t, out.Close())
@ -203,7 +203,7 @@ func TestConfigFileDoesNotExist(t *testing.T) {
defer setConfigFile(t, configData)() defer setConfigFile(t, configData)()
data := &Storage{} data := &Storage{}
require.NoError(t, os.Remove(config.ConfigPath)) require.NoError(t, os.Remove(config.GetConfigPath()))
err := data.Load() err := data.Load()
require.Equal(t, config.ErrorConfigFileNotFound, err) require.Equal(t, config.ErrorConfigFileNotFound, err)
@ -215,7 +215,7 @@ func TestConfigFileDoesNotExist(t *testing.T) {
} }
func testConfigFileNoConfig(t *testing.T, configPath string) { func testConfigFileNoConfig(t *testing.T, configPath string) {
config.ConfigPath = configPath assert.NoError(t, config.SetConfigPath(configPath))
data := &Storage{} data := &Storage{}
err := data.Load() err := data.Load()
@ -227,13 +227,13 @@ func testConfigFileNoConfig(t *testing.T, configPath string) {
assert.Equal(t, "42", value) assert.Equal(t, "42", value)
err = data.Save() err = data.Save()
require.NoError(t, err) require.Error(t, err)
} }
func TestConfigFileNoConfig(t *testing.T) { func TestConfigFileNoConfig(t *testing.T) {
old := config.ConfigPath old := config.GetConfigPath()
defer func() { defer func() {
config.ConfigPath = old assert.NoError(t, config.SetConfigPath(old))
}() }()
t.Run("Empty", func(t *testing.T) { t.Run("Empty", func(t *testing.T) {

View file

@ -6,7 +6,6 @@ package configflags
import ( import (
"log" "log"
"net" "net"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
@ -23,6 +22,7 @@ var (
// these will get interpreted into fs.Config via SetFlags() below // these will get interpreted into fs.Config via SetFlags() below
verbose int verbose int
quiet bool quiet bool
configPath string
dumpHeaders bool dumpHeaders bool
dumpBodies bool dumpBodies bool
deleteBefore bool deleteBefore bool
@ -45,7 +45,7 @@ func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) {
flags.DurationVarP(flagSet, &ci.ModifyWindow, "modify-window", "", ci.ModifyWindow, "Max time diff to be considered the same") flags.DurationVarP(flagSet, &ci.ModifyWindow, "modify-window", "", ci.ModifyWindow, "Max time diff to be considered the same")
flags.IntVarP(flagSet, &ci.Checkers, "checkers", "", ci.Checkers, "Number of checkers to run in parallel.") flags.IntVarP(flagSet, &ci.Checkers, "checkers", "", ci.Checkers, "Number of checkers to run in parallel.")
flags.IntVarP(flagSet, &ci.Transfers, "transfers", "", ci.Transfers, "Number of file transfers to run in parallel.") flags.IntVarP(flagSet, &ci.Transfers, "transfers", "", ci.Transfers, "Number of file transfers to run in parallel.")
flags.StringVarP(flagSet, &config.ConfigPath, "config", "", config.ConfigPath, "Config file.") flags.StringVarP(flagSet, &configPath, "config", "", config.GetConfigPath(), "Config file.")
flags.StringVarP(flagSet, &config.CacheDir, "cache-dir", "", config.CacheDir, "Directory rclone will use for caching.") flags.StringVarP(flagSet, &config.CacheDir, "cache-dir", "", config.CacheDir, "Directory rclone will use for caching.")
flags.BoolVarP(flagSet, &ci.CheckSum, "checksum", "c", ci.CheckSum, "Skip based on checksum (if available) & size, not mod-time & size") flags.BoolVarP(flagSet, &ci.CheckSum, "checksum", "c", ci.CheckSum, "Skip based on checksum (if available) & size, not mod-time & size")
flags.BoolVarP(flagSet, &ci.SizeOnly, "size-only", "", ci.SizeOnly, "Skip based on size only, not mod-time or checksum") flags.BoolVarP(flagSet, &ci.SizeOnly, "size-only", "", ci.SizeOnly, "Skip based on size only, not mod-time or checksum")
@ -267,10 +267,9 @@ func SetFlags(ci *fs.ConfigInfo) {
} }
} }
// Make the config file absolute // Set path to configuration file
configPath, err := filepath.Abs(config.ConfigPath) if err := config.SetConfigPath(configPath); err != nil {
if err == nil { log.Fatalf("--config: Failed to set %q as config path: %v", configPath, err)
config.ConfigPath = configPath
} }
// Set whether multi-thread-streams was set // Set whether multi-thread-streams was set

View file

@ -16,10 +16,10 @@ import (
func TestConfigLoadEncrypted(t *testing.T) { func TestConfigLoadEncrypted(t *testing.T) {
var err error var err error
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
config.ConfigPath = "./testdata/encrypted.conf" assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
defer func() { defer func() {
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
config.ClearConfigPassword() config.ClearConfigPassword()
}() }()
@ -40,13 +40,13 @@ func TestConfigLoadEncrypted(t *testing.T) {
func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) { func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) {
ctx := context.Background() ctx := context.Background()
ci := fs.GetConfig(ctx) ci := fs.GetConfig(ctx)
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
oldConfig := *ci oldConfig := *ci
config.ConfigPath = "./testdata/encrypted.conf" assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
// using ci.PasswordCommand, correct password // using ci.PasswordCommand, correct password
ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf"} ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf"}
defer func() { defer func() {
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
config.ClearConfigPassword() config.ClearConfigPassword()
*ci = oldConfig *ci = oldConfig
ci.PasswordCommand = nil ci.PasswordCommand = nil
@ -69,13 +69,13 @@ func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) {
func TestConfigLoadEncryptedWithInvalidPassCommand(t *testing.T) { func TestConfigLoadEncryptedWithInvalidPassCommand(t *testing.T) {
ctx := context.Background() ctx := context.Background()
ci := fs.GetConfig(ctx) ci := fs.GetConfig(ctx)
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
oldConfig := *ci oldConfig := *ci
config.ConfigPath = "./testdata/encrypted.conf" assert.NoError(t, config.SetConfigPath("./testdata/encrypted.conf"))
// using ci.PasswordCommand, incorrect password // using ci.PasswordCommand, incorrect password
ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf-blurfl"} ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf-blurfl"}
defer func() { defer func() {
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
config.ClearConfigPassword() config.ClearConfigPassword()
*ci = oldConfig *ci = oldConfig
ci.PasswordCommand = nil ci.PasswordCommand = nil
@ -92,24 +92,24 @@ func TestConfigLoadEncryptedFailures(t *testing.T) {
var err error var err error
// This file should be too short to be decoded. // This file should be too short to be decoded.
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
config.ConfigPath = "./testdata/enc-short.conf" assert.NoError(t, config.SetConfigPath("./testdata/enc-short.conf"))
defer func() { config.ConfigPath = oldConfigPath }() defer func() { assert.NoError(t, config.SetConfigPath(oldConfigPath)) }()
err = config.Data.Load() err = config.Data.Load()
require.Error(t, err) require.Error(t, err)
// This file contains invalid base64 characters. // This file contains invalid base64 characters.
config.ConfigPath = "./testdata/enc-invalid.conf" assert.NoError(t, config.SetConfigPath("./testdata/enc-invalid.conf"))
err = config.Data.Load() err = config.Data.Load()
require.Error(t, err) require.Error(t, err)
// This file contains invalid base64 characters. // This file contains invalid base64 characters.
config.ConfigPath = "./testdata/enc-too-new.conf" assert.NoError(t, config.SetConfigPath("./testdata/enc-too-new.conf"))
err = config.Data.Load() err = config.Data.Load()
require.Error(t, err) require.Error(t, err)
// This file does not exist. // This file does not exist.
config.ConfigPath = "./testdata/filenotfound.conf" assert.NoError(t, config.SetConfigPath("./testdata/filenotfound.conf"))
err = config.Data.Load() err = config.Data.Load()
assert.Equal(t, config.ErrorConfigFileNotFound, err) assert.Equal(t, config.ErrorConfigFileNotFound, err)
} }

View file

@ -535,12 +535,16 @@ func CopyRemote(name string) {
// ShowConfigLocation prints the location of the config file in use // ShowConfigLocation prints the location of the config file in use
func ShowConfigLocation() { func ShowConfigLocation() {
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) { if configPath := GetConfigPath(); configPath == "" {
fmt.Println("Configuration is in memory only")
} else {
if _, err := os.Stat(configPath); os.IsNotExist(err) {
fmt.Println("Configuration file doesn't exist, but rclone will use this path:") fmt.Println("Configuration file doesn't exist, but rclone will use this path:")
} else { } else {
fmt.Println("Configuration file is stored at:") fmt.Println("Configuration file is stored at:")
} }
fmt.Printf("%s\n", ConfigPath) fmt.Printf("%s\n", configPath)
}
} }
// ShowConfig prints the (unencrypted) config options // ShowConfig prints the (unencrypted) config options

View file

@ -34,13 +34,13 @@ func testConfigFile(t *testing.T, configFileName string) func() {
// temporarily adapt configuration // temporarily adapt configuration
oldOsStdout := os.Stdout oldOsStdout := os.Stdout
oldConfigPath := config.ConfigPath oldConfigPath := config.GetConfigPath()
oldConfig := *ci oldConfig := *ci
oldConfigFile := config.Data oldConfigFile := config.Data
oldReadLine := config.ReadLine oldReadLine := config.ReadLine
oldPassword := config.Password oldPassword := config.Password
os.Stdout = nil os.Stdout = nil
config.ConfigPath = path assert.NoError(t, config.SetConfigPath(path))
ci = &fs.ConfigInfo{} ci = &fs.ConfigInfo{}
configfile.LoadConfig(ctx) configfile.LoadConfig(ctx)
@ -69,7 +69,7 @@ func testConfigFile(t *testing.T, configFileName string) func() {
assert.NoError(t, err) assert.NoError(t, err)
os.Stdout = oldOsStdout os.Stdout = oldOsStdout
config.ConfigPath = oldConfigPath assert.NoError(t, config.SetConfigPath(oldConfigPath))
config.ReadLine = oldReadLine config.ReadLine = oldReadLine
config.Password = oldPassword config.Password = oldPassword
*ci = oldConfig *ci = oldConfig

View file

@ -1317,7 +1317,8 @@ type setConfigFile string
// Set a config item into the config file // Set a config item into the config file
func (section setConfigFile) Set(key, value string) { func (section setConfigFile) Set(key, value string) {
if strings.HasPrefix(string(section), ":") { if strings.HasPrefix(string(section), ":") {
Errorf(nil, "Can't save config %q = %q for on the fly backend %q", key, value, section) Logf(nil, "Can't save config %q = %q for on the fly backend %q", key, value, section)
return
} }
Debugf(nil, "Saving config %q = %q in section %q of the config file", key, value, section) Debugf(nil, "Saving config %q = %q in section %q of the config file", key, value, section)
err := ConfigFileSet(string(section), key, value) err := ConfigFileSet(string(section), key, value)

View file

@ -69,7 +69,7 @@ func Initialise() {
// parse the flags any more so this doesn't happen // parse the flags any more so this doesn't happen
// automatically // automatically
if envConfig := os.Getenv("RCLONE_CONFIG"); envConfig != "" { if envConfig := os.Getenv("RCLONE_CONFIG"); envConfig != "" {
config.ConfigPath = envConfig _ = config.SetConfigPath(envConfig)
} }
configfile.LoadConfig(ctx) configfile.LoadConfig(ctx)
accounting.Start(ctx) accounting.Start(ctx)