github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/config/config.go (about)

     1  // Package config reads, writes and edits the config file and deals with command line flags
     2  package config
     3  
     4  import (
     5  	"bufio"
     6  	"bytes"
     7  	"crypto/rand"
     8  	"crypto/sha256"
     9  	"encoding/base64"
    10  	"encoding/json"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"log"
    15  	mathrand "math/rand"
    16  	"os"
    17  	"path/filepath"
    18  	"regexp"
    19  	"runtime"
    20  	"sort"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  	"unicode/utf8"
    25  
    26  	"github.com/Unknwon/goconfig"
    27  	homedir "github.com/mitchellh/go-homedir"
    28  	"github.com/ncw/rclone/fs"
    29  	"github.com/ncw/rclone/fs/accounting"
    30  	"github.com/ncw/rclone/fs/config/configmap"
    31  	"github.com/ncw/rclone/fs/config/configstruct"
    32  	"github.com/ncw/rclone/fs/config/obscure"
    33  	"github.com/ncw/rclone/fs/driveletter"
    34  	"github.com/ncw/rclone/fs/fshttp"
    35  	"github.com/ncw/rclone/fs/fspath"
    36  	"github.com/ncw/rclone/fs/rc"
    37  	"github.com/pkg/errors"
    38  	"golang.org/x/crypto/nacl/secretbox"
    39  	"golang.org/x/text/unicode/norm"
    40  )
    41  
    42  const (
    43  	configFileName       = "rclone.conf"
    44  	hiddenConfigFileName = "." + configFileName
    45  
    46  	// ConfigToken is the key used to store the token under
    47  	ConfigToken = "token"
    48  
    49  	// ConfigClientID is the config key used to store the client id
    50  	ConfigClientID = "client_id"
    51  
    52  	// ConfigClientSecret is the config key used to store the client secret
    53  	ConfigClientSecret = "client_secret"
    54  
    55  	// ConfigAuthURL is the config key used to store the auth server endpoint
    56  	ConfigAuthURL = "auth_url"
    57  
    58  	// ConfigTokenURL is the config key used to store the token server endpoint
    59  	ConfigTokenURL = "token_url"
    60  
    61  	// ConfigAuthorize indicates that we just want "rclone authorize"
    62  	ConfigAuthorize = "config_authorize"
    63  )
    64  
    65  // Global
    66  var (
    67  	// configFile is the global config data structure. Don't read it directly, use getConfigData()
    68  	configFile *goconfig.ConfigFile
    69  
    70  	// ConfigPath points to the config file
    71  	ConfigPath = makeConfigPath()
    72  
    73  	// CacheDir points to the cache directory.  Users of this
    74  	// should make a subdirectory and use MkdirAll() to create it
    75  	// and any parents.
    76  	CacheDir = makeCacheDir()
    77  
    78  	// Key to use for password en/decryption.
    79  	// When nil, no encryption will be used for saving.
    80  	configKey []byte
    81  
    82  	// output of prompt for password
    83  	PasswordPromptOutput = os.Stderr
    84  
    85  	// If set to true, the configKey is obscured with obscure.Obscure and saved to a temp file when it is
    86  	// calculated from the password. The path of that temp file is then written to the environment variable
    87  	// `_RCLONE_CONFIG_KEY_FILE`. If `_RCLONE_CONFIG_KEY_FILE` is present, password prompt is skipped and `RCLONE_CONFIG_PASS` ignored.
    88  	// For security reasons, the temp file is deleted once the configKey is successfully loaded.
    89  	// This can be used to pass the configKey to a child process.
    90  	PassConfigKeyForDaemonization = false
    91  )
    92  
    93  func init() {
    94  	// Set the function pointers up in fs
    95  	fs.ConfigFileGet = FileGetFlag
    96  	fs.ConfigFileSet = FileSet
    97  }
    98  
    99  func getConfigData() *goconfig.ConfigFile {
   100  	if configFile == nil {
   101  		LoadConfig()
   102  	}
   103  	return configFile
   104  }
   105  
   106  // Return the path to the configuration file
   107  func makeConfigPath() string {
   108  
   109  	// Use rclone.conf from rclone executable directory if already existing
   110  	exe, err := os.Executable()
   111  	if err == nil {
   112  		exedir := filepath.Dir(exe)
   113  		cfgpath := filepath.Join(exedir, configFileName)
   114  		_, err := os.Stat(cfgpath)
   115  		if err == nil {
   116  			return cfgpath
   117  		}
   118  	}
   119  
   120  	// Find user's home directory
   121  	homeDir, err := homedir.Dir()
   122  
   123  	// Find user's configuration directory.
   124  	// Prefer XDG config path, with fallback to $HOME/.config.
   125  	// See XDG Base Directory specification
   126  	// https://specifications.freedesktop.org/basedir-spec/latest/),
   127  	xdgdir := os.Getenv("XDG_CONFIG_HOME")
   128  	var cfgdir string
   129  	if xdgdir != "" {
   130  		// User's configuration directory for rclone is $XDG_CONFIG_HOME/rclone
   131  		cfgdir = filepath.Join(xdgdir, "rclone")
   132  	} else if homeDir != "" {
   133  		// User's configuration directory for rclone is $HOME/.config/rclone
   134  		cfgdir = filepath.Join(homeDir, ".config", "rclone")
   135  	}
   136  
   137  	// Use rclone.conf from user's configuration directory if already existing
   138  	var cfgpath string
   139  	if cfgdir != "" {
   140  		cfgpath = filepath.Join(cfgdir, configFileName)
   141  		_, err := os.Stat(cfgpath)
   142  		if err == nil {
   143  			return cfgpath
   144  		}
   145  	}
   146  
   147  	// Use .rclone.conf from user's home directory if already existing
   148  	var homeconf string
   149  	if homeDir != "" {
   150  		homeconf = filepath.Join(homeDir, hiddenConfigFileName)
   151  		_, err := os.Stat(homeconf)
   152  		if err == nil {
   153  			return homeconf
   154  		}
   155  	}
   156  
   157  	// Check to see if user supplied a --config variable or environment
   158  	// variable.  We can't use pflag for this because it isn't initialised
   159  	// yet so we search the command line manually.
   160  	_, configSupplied := os.LookupEnv("RCLONE_CONFIG")
   161  	if !configSupplied {
   162  		for _, item := range os.Args {
   163  			if item == "--config" || strings.HasPrefix(item, "--config=") {
   164  				configSupplied = true
   165  				break
   166  			}
   167  		}
   168  	}
   169  
   170  	// If user's configuration directory was found, then try to create it
   171  	// and assume rclone.conf can be written there. If user supplied config
   172  	// then skip creating the directory since it will not be used.
   173  	if cfgpath != "" {
   174  		// cfgpath != "" implies cfgdir != ""
   175  		if configSupplied {
   176  			return cfgpath
   177  		}
   178  		err := os.MkdirAll(cfgdir, os.ModePerm)
   179  		if err == nil {
   180  			return cfgpath
   181  		}
   182  	}
   183  
   184  	// Assume .rclone.conf can be written to user's home directory.
   185  	if homeconf != "" {
   186  		return homeconf
   187  	}
   188  
   189  	// Default to ./.rclone.conf (current working directory) if everything else fails.
   190  	if !configSupplied {
   191  		fs.Errorf(nil, "Couldn't find home directory or read HOME or XDG_CONFIG_HOME environment variables.")
   192  		fs.Errorf(nil, "Defaulting to storing config in current directory.")
   193  		fs.Errorf(nil, "Use --config flag to workaround.")
   194  		fs.Errorf(nil, "Error was: %v", err)
   195  	}
   196  	return hiddenConfigFileName
   197  }
   198  
   199  // LoadConfig loads the config file
   200  func LoadConfig() {
   201  	// Load configuration file.
   202  	var err error
   203  	configFile, err = loadConfigFile()
   204  	if err == errorConfigFileNotFound {
   205  		fs.Logf(nil, "Config file %q not found - using defaults", ConfigPath)
   206  		configFile, _ = goconfig.LoadFromReader(&bytes.Buffer{})
   207  	} else if err != nil {
   208  		log.Fatalf("Failed to load config file %q: %v", ConfigPath, err)
   209  	} else {
   210  		fs.Debugf(nil, "Using config file from %q", ConfigPath)
   211  	}
   212  
   213  	// Start the token bucket limiter
   214  	accounting.StartTokenBucket()
   215  
   216  	// Start the bandwidth update ticker
   217  	accounting.StartTokenTicker()
   218  
   219  	// Start the transactions per second limiter
   220  	fshttp.StartHTTPTokenBucket()
   221  }
   222  
   223  var errorConfigFileNotFound = errors.New("config file not found")
   224  
   225  // loadConfigFile will load a config file, and
   226  // automatically decrypt it.
   227  func loadConfigFile() (*goconfig.ConfigFile, error) {
   228  	envpw := os.Getenv("RCLONE_CONFIG_PASS")
   229  	if len(configKey) == 0 && envpw != "" {
   230  		err := setConfigPassword(envpw)
   231  		if err != nil {
   232  			fs.Errorf(nil, "Using RCLONE_CONFIG_PASS returned: %v", err)
   233  		} else {
   234  			fs.Debugf(nil, "Using RCLONE_CONFIG_PASS password.")
   235  		}
   236  	}
   237  
   238  	b, err := ioutil.ReadFile(ConfigPath)
   239  	if err != nil {
   240  		if os.IsNotExist(err) {
   241  			return nil, errorConfigFileNotFound
   242  		}
   243  		return nil, err
   244  	}
   245  	// Find first non-empty line
   246  	r := bufio.NewReader(bytes.NewBuffer(b))
   247  	for {
   248  		line, _, err := r.ReadLine()
   249  		if err != nil {
   250  			if err == io.EOF {
   251  				return goconfig.LoadFromReader(bytes.NewBuffer(b))
   252  			}
   253  			return nil, err
   254  		}
   255  		l := strings.TrimSpace(string(line))
   256  		if len(l) == 0 || strings.HasPrefix(l, ";") || strings.HasPrefix(l, "#") {
   257  			continue
   258  		}
   259  		// First non-empty or non-comment must be ENCRYPT_V0
   260  		if l == "RCLONE_ENCRYPT_V0:" {
   261  			break
   262  		}
   263  		if strings.HasPrefix(l, "RCLONE_ENCRYPT_V") {
   264  			return nil, errors.New("unsupported configuration encryption - update rclone for support")
   265  		}
   266  		return goconfig.LoadFromReader(bytes.NewBuffer(b))
   267  	}
   268  
   269  	// Encrypted content is base64 encoded.
   270  	dec := base64.NewDecoder(base64.StdEncoding, r)
   271  	box, err := ioutil.ReadAll(dec)
   272  	if err != nil {
   273  		return nil, errors.Wrap(err, "failed to load base64 encoded data")
   274  	}
   275  	if len(box) < 24+secretbox.Overhead {
   276  		return nil, errors.New("Configuration data too short")
   277  	}
   278  
   279  	var out []byte
   280  	for {
   281  		if envKeyFile := os.Getenv("_RCLONE_CONFIG_KEY_FILE"); len(envKeyFile) > 0 {
   282  			fs.Debugf(nil, "attempting to obtain configKey from temp file %s", envKeyFile)
   283  			obscuredKey, err := ioutil.ReadFile(envKeyFile)
   284  			if err != nil {
   285  				errRemove := os.Remove(envKeyFile)
   286  				if errRemove != nil {
   287  					log.Fatalf("unable to read obscured config key and unable to delete the temp file: %v", err)
   288  				}
   289  				log.Fatalf("unable to read obscured config key: %v", err)
   290  			}
   291  			errRemove := os.Remove(envKeyFile)
   292  			if errRemove != nil {
   293  				log.Fatalf("unable to delete temp file with configKey: %v", err)
   294  			}
   295  			configKey = []byte(obscure.MustReveal(string(obscuredKey)))
   296  			fs.Debugf(nil, "using _RCLONE_CONFIG_KEY_FILE for configKey")
   297  		} else {
   298  			if len(configKey) == 0 {
   299  				if !fs.Config.AskPassword {
   300  					return nil, errors.New("unable to decrypt configuration and not allowed to ask for password - set RCLONE_CONFIG_PASS to your configuration password")
   301  				}
   302  				getConfigPassword("Enter configuration password:")
   303  			}
   304  		}
   305  
   306  		// Nonce is first 24 bytes of the ciphertext
   307  		var nonce [24]byte
   308  		copy(nonce[:], box[:24])
   309  		var key [32]byte
   310  		copy(key[:], configKey[:32])
   311  
   312  		// Attempt to decrypt
   313  		var ok bool
   314  		out, ok = secretbox.Open(nil, box[24:], &nonce, &key)
   315  		if ok {
   316  			break
   317  		}
   318  
   319  		// Retry
   320  		fs.Errorf(nil, "Couldn't decrypt configuration, most likely wrong password.")
   321  		configKey = nil
   322  	}
   323  	return goconfig.LoadFromReader(bytes.NewBuffer(out))
   324  }
   325  
   326  // checkPassword normalises and validates the password
   327  func checkPassword(password string) (string, error) {
   328  	if !utf8.ValidString(password) {
   329  		return "", errors.New("password contains invalid utf8 characters")
   330  	}
   331  	// Check for leading/trailing whitespace
   332  	trimmedPassword := strings.TrimSpace(password)
   333  	// Warn user if password has leading+trailing whitespace
   334  	if len(password) != len(trimmedPassword) {
   335  		_, _ = fmt.Fprintln(os.Stderr, "Your password contains leading/trailing whitespace - in previous versions of rclone this was stripped")
   336  	}
   337  	// Normalize to reduce weird variations.
   338  	password = norm.NFKC.String(password)
   339  	if len(password) == 0 || len(trimmedPassword) == 0 {
   340  		return "", errors.New("no characters in password")
   341  	}
   342  	return password, nil
   343  }
   344  
   345  // GetPassword asks the user for a password with the prompt given.
   346  func GetPassword(prompt string) string {
   347  	_, _ = fmt.Fprintln(PasswordPromptOutput, prompt)
   348  	for {
   349  		_, _ = fmt.Fprint(PasswordPromptOutput, "password:")
   350  		password := ReadPassword()
   351  		password, err := checkPassword(password)
   352  		if err == nil {
   353  			return password
   354  		}
   355  		_, _ = fmt.Fprintf(os.Stderr, "Bad password: %v\n", err)
   356  	}
   357  }
   358  
   359  // ChangePassword will query the user twice for the named password. If
   360  // the same password is entered it is returned.
   361  func ChangePassword(name string) string {
   362  	for {
   363  		a := GetPassword(fmt.Sprintf("Enter %s password:", name))
   364  		b := GetPassword(fmt.Sprintf("Confirm %s password:", name))
   365  		if a == b {
   366  			return a
   367  		}
   368  		fmt.Println("Passwords do not match!")
   369  	}
   370  }
   371  
   372  // getConfigPassword will query the user for a password the
   373  // first time it is required.
   374  func getConfigPassword(q string) {
   375  	if len(configKey) != 0 {
   376  		return
   377  	}
   378  	for {
   379  		password := GetPassword(q)
   380  		err := setConfigPassword(password)
   381  		if err == nil {
   382  			return
   383  		}
   384  		_, _ = fmt.Fprintln(os.Stderr, "Error:", err)
   385  	}
   386  }
   387  
   388  // setConfigPassword will set the configKey to the hash of
   389  // the password. If the length of the password is
   390  // zero after trimming+normalization, an error is returned.
   391  func setConfigPassword(password string) error {
   392  	password, err := checkPassword(password)
   393  	if err != nil {
   394  		return err
   395  	}
   396  	// Create SHA256 has of the password
   397  	sha := sha256.New()
   398  	_, err = sha.Write([]byte("[" + password + "][rclone-config]"))
   399  	if err != nil {
   400  		return err
   401  	}
   402  	configKey = sha.Sum(nil)
   403  	if PassConfigKeyForDaemonization {
   404  		tempFile, err := ioutil.TempFile("", "rclone")
   405  		if err != nil {
   406  			log.Fatalf("cannot create temp file to store configKey: %v", err)
   407  		}
   408  		_, err = tempFile.WriteString(obscure.MustObscure(string(configKey)))
   409  		if err != nil {
   410  			errRemove := os.Remove(tempFile.Name())
   411  			if errRemove != nil {
   412  				log.Fatalf("error writing configKey to temp file and also error deleting it: %v", err)
   413  			}
   414  			log.Fatalf("error writing configKey to temp file: %v", err)
   415  		}
   416  		err = tempFile.Close()
   417  		if err != nil {
   418  			errRemove := os.Remove(tempFile.Name())
   419  			if errRemove != nil {
   420  				log.Fatalf("error closing temp file with configKey and also error deleting it: %v", err)
   421  			}
   422  			log.Fatalf("error closing temp file with configKey: %v", err)
   423  		}
   424  		fs.Debugf(nil, "saving configKey to temp file")
   425  		err = os.Setenv("_RCLONE_CONFIG_KEY_FILE", tempFile.Name())
   426  		if err != nil {
   427  			errRemove := os.Remove(tempFile.Name())
   428  			if errRemove != nil {
   429  				log.Fatalf("unable to set environment variable _RCLONE_CONFIG_KEY_FILE and unable to delete the temp file: %v", err)
   430  			}
   431  			log.Fatalf("unable to set environment variable _RCLONE_CONFIG_KEY_FILE: %v", err)
   432  		}
   433  	}
   434  	return nil
   435  }
   436  
   437  // changeConfigPassword will query the user twice
   438  // for a password. If the same password is entered
   439  // twice the key is updated.
   440  func changeConfigPassword() {
   441  	err := setConfigPassword(ChangePassword("NEW configuration"))
   442  	if err != nil {
   443  		fmt.Printf("Failed to set config password: %v\n", err)
   444  		return
   445  	}
   446  }
   447  
   448  // saveConfig saves configuration file.
   449  // if configKey has been set, the file will be encrypted.
   450  func saveConfig() error {
   451  	dir, name := filepath.Split(ConfigPath)
   452  	err := os.MkdirAll(dir, os.ModePerm)
   453  	if err != nil {
   454  		return errors.Wrap(err, "failed to create config directory")
   455  	}
   456  	f, err := ioutil.TempFile(dir, name)
   457  	if err != nil {
   458  		return errors.Errorf("Failed to create temp file for new config: %v", err)
   459  	}
   460  	defer func() {
   461  		if err := os.Remove(f.Name()); err != nil && !os.IsNotExist(err) {
   462  			fs.Errorf(nil, "Failed to remove temp config file: %v", err)
   463  		}
   464  	}()
   465  
   466  	var buf bytes.Buffer
   467  	err = goconfig.SaveConfigData(getConfigData(), &buf)
   468  	if err != nil {
   469  		return errors.Errorf("Failed to save config file: %v", err)
   470  	}
   471  
   472  	if len(configKey) == 0 {
   473  		if _, err := buf.WriteTo(f); err != nil {
   474  			return errors.Errorf("Failed to write temp config file: %v", err)
   475  		}
   476  	} else {
   477  		_, _ = fmt.Fprintln(f, "# Encrypted rclone configuration File")
   478  		_, _ = fmt.Fprintln(f, "")
   479  		_, _ = fmt.Fprintln(f, "RCLONE_ENCRYPT_V0:")
   480  
   481  		// Generate new nonce and write it to the start of the ciphertext
   482  		var nonce [24]byte
   483  		n, _ := rand.Read(nonce[:])
   484  		if n != 24 {
   485  			return errors.Errorf("nonce short read: %d", n)
   486  		}
   487  		enc := base64.NewEncoder(base64.StdEncoding, f)
   488  		_, err = enc.Write(nonce[:])
   489  		if err != nil {
   490  			return errors.Errorf("Failed to write temp config file: %v", err)
   491  		}
   492  
   493  		var key [32]byte
   494  		copy(key[:], configKey[:32])
   495  
   496  		b := secretbox.Seal(nil, buf.Bytes(), &nonce, &key)
   497  		_, err = enc.Write(b)
   498  		if err != nil {
   499  			return errors.Errorf("Failed to write temp config file: %v", err)
   500  		}
   501  		_ = enc.Close()
   502  	}
   503  
   504  	err = f.Close()
   505  	if err != nil {
   506  		return errors.Errorf("Failed to close config file: %v", err)
   507  	}
   508  
   509  	var fileMode os.FileMode = 0600
   510  	info, err := os.Stat(ConfigPath)
   511  	if err != nil {
   512  		fs.Debugf(nil, "Using default permissions for config file: %v", fileMode)
   513  	} else if info.Mode() != fileMode {
   514  		fs.Debugf(nil, "Keeping previous permissions for config file: %v", info.Mode())
   515  		fileMode = info.Mode()
   516  	}
   517  
   518  	attemptCopyGroup(ConfigPath, f.Name())
   519  
   520  	err = os.Chmod(f.Name(), fileMode)
   521  	if err != nil {
   522  		fs.Errorf(nil, "Failed to set permissions on config file: %v", err)
   523  	}
   524  
   525  	if err = os.Rename(ConfigPath, ConfigPath+".old"); err != nil && !os.IsNotExist(err) {
   526  		return errors.Errorf("Failed to move previous config to backup location: %v", err)
   527  	}
   528  	if err = os.Rename(f.Name(), ConfigPath); err != nil {
   529  		return errors.Errorf("Failed to move newly written config from %s to final location: %v", f.Name(), err)
   530  	}
   531  	if err := os.Remove(ConfigPath + ".old"); err != nil && !os.IsNotExist(err) {
   532  		fs.Errorf(nil, "Failed to remove backup config file: %v", err)
   533  	}
   534  	return nil
   535  }
   536  
   537  // SaveConfig calling function which saves configuration file.
   538  // if saveConfig returns error trying again after sleep.
   539  func SaveConfig() {
   540  	var err error
   541  	for i := 0; i < fs.Config.LowLevelRetries+1; i++ {
   542  		if err = saveConfig(); err == nil {
   543  			return
   544  		}
   545  		waitingTimeMs := mathrand.Intn(1000)
   546  		time.Sleep(time.Duration(waitingTimeMs) * time.Millisecond)
   547  	}
   548  	log.Fatalf("Failed to save config after %d tries: %v", fs.Config.LowLevelRetries, err)
   549  
   550  	return
   551  }
   552  
   553  // SetValueAndSave sets the key to the value and saves just that
   554  // value in the config file.  It loads the old config file in from
   555  // disk first and overwrites the given value only.
   556  func SetValueAndSave(name, key, value string) (err error) {
   557  	// Set the value in config in case we fail to reload it
   558  	getConfigData().SetValue(name, key, value)
   559  	// Reload the config file
   560  	reloadedConfigFile, err := loadConfigFile()
   561  	if err == errorConfigFileNotFound {
   562  		// Config file not written yet so ignore reload
   563  		return nil
   564  	} else if err != nil {
   565  		return err
   566  	}
   567  	_, err = reloadedConfigFile.GetSection(name)
   568  	if err != nil {
   569  		// Section doesn't exist yet so ignore reload
   570  		return err
   571  	}
   572  	// Update the config file with the reloaded version
   573  	configFile = reloadedConfigFile
   574  	// Set the value in the reloaded version
   575  	reloadedConfigFile.SetValue(name, key, value)
   576  	// Save it again
   577  	SaveConfig()
   578  	return nil
   579  }
   580  
   581  // FileGetFresh reads the config key under section return the value or
   582  // an error if the config file was not found or that value couldn't be
   583  // read.
   584  func FileGetFresh(section, key string) (value string, err error) {
   585  	reloadedConfigFile, err := loadConfigFile()
   586  	if err != nil {
   587  		return "", err
   588  	}
   589  	return reloadedConfigFile.GetValue(section, key)
   590  }
   591  
   592  // ShowRemotes shows an overview of the config file
   593  func ShowRemotes() {
   594  	remotes := getConfigData().GetSectionList()
   595  	if len(remotes) == 0 {
   596  		return
   597  	}
   598  	sort.Strings(remotes)
   599  	fmt.Printf("%-20s %s\n", "Name", "Type")
   600  	fmt.Printf("%-20s %s\n", "====", "====")
   601  	for _, remote := range remotes {
   602  		fmt.Printf("%-20s %s\n", remote, FileGet(remote, "type"))
   603  	}
   604  }
   605  
   606  // ChooseRemote chooses a remote name
   607  func ChooseRemote() string {
   608  	remotes := getConfigData().GetSectionList()
   609  	sort.Strings(remotes)
   610  	return Choose("remote", remotes, nil, false)
   611  }
   612  
   613  // ReadLine reads some input
   614  var ReadLine = func() string {
   615  	buf := bufio.NewReader(os.Stdin)
   616  	line, err := buf.ReadString('\n')
   617  	if err != nil {
   618  		log.Fatalf("Failed to read line: %v", err)
   619  	}
   620  	return strings.TrimSpace(line)
   621  }
   622  
   623  // Command - choose one
   624  func Command(commands []string) byte {
   625  	opts := []string{}
   626  	for _, text := range commands {
   627  		fmt.Printf("%c) %s\n", text[0], text[1:])
   628  		opts = append(opts, text[:1])
   629  	}
   630  	optString := strings.Join(opts, "")
   631  	optHelp := strings.Join(opts, "/")
   632  	for {
   633  		fmt.Printf("%s> ", optHelp)
   634  		result := strings.ToLower(ReadLine())
   635  		if len(result) != 1 {
   636  			continue
   637  		}
   638  		i := strings.Index(optString, string(result[0]))
   639  		if i >= 0 {
   640  			return result[0]
   641  		}
   642  	}
   643  }
   644  
   645  // Confirm asks the user for Yes or No and returns true or false
   646  //
   647  // If AutoConfirm is set, it will return true
   648  func Confirm() bool {
   649  	return Command([]string{"yYes", "nNo"}) == 'y'
   650  }
   651  
   652  // ConfirmWithConfig asks the user for Yes or No and returns true or
   653  // false.
   654  //
   655  // If AutoConfirm is set, it will look up the value in m and return
   656  // that, but if it isn't set then it will return the Default value
   657  // passed in
   658  func ConfirmWithConfig(m configmap.Getter, configName string, Default bool) bool {
   659  	if fs.Config.AutoConfirm {
   660  		configString, ok := m.Get(configName)
   661  		if ok {
   662  			configValue, err := strconv.ParseBool(configString)
   663  			if err != nil {
   664  				fs.Errorf(nil, "Failed to parse config parameter %s=%q as boolean - using default %v: %v", configName, configString, Default, err)
   665  			} else {
   666  				Default = configValue
   667  			}
   668  		}
   669  		answer := "No"
   670  		if Default {
   671  			answer = "Yes"
   672  		}
   673  		fmt.Printf("Auto confirm is set: answering %s, override by setting config parameter %s=%v\n", answer, configName, !Default)
   674  		return Default
   675  	}
   676  	return Confirm()
   677  }
   678  
   679  // Choose one of the defaults or type a new string if newOk is set
   680  func Choose(what string, defaults, help []string, newOk bool) string {
   681  	valueDescription := "an existing"
   682  	if newOk {
   683  		valueDescription = "your own"
   684  	}
   685  	fmt.Printf("Choose a number from below, or type in %s value\n", valueDescription)
   686  	for i, text := range defaults {
   687  		var lines []string
   688  		if help != nil {
   689  			parts := strings.Split(help[i], "\n")
   690  			lines = append(lines, parts...)
   691  		}
   692  		lines = append(lines, fmt.Sprintf("%q", text))
   693  		pos := i + 1
   694  		if len(lines) == 1 {
   695  			fmt.Printf("%2d > %s\n", pos, text)
   696  		} else {
   697  			mid := (len(lines) - 1) / 2
   698  			for i, line := range lines {
   699  				var sep rune
   700  				switch i {
   701  				case 0:
   702  					sep = '/'
   703  				case len(lines) - 1:
   704  					sep = '\\'
   705  				default:
   706  					sep = '|'
   707  				}
   708  				number := "  "
   709  				if i == mid {
   710  					number = fmt.Sprintf("%2d", pos)
   711  				}
   712  				fmt.Printf("%s %c %s\n", number, sep, line)
   713  			}
   714  		}
   715  	}
   716  	for {
   717  		fmt.Printf("%s> ", what)
   718  		result := ReadLine()
   719  		i, err := strconv.Atoi(result)
   720  		if err != nil {
   721  			if newOk {
   722  				return result
   723  			}
   724  			for _, v := range defaults {
   725  				if result == v {
   726  					return result
   727  				}
   728  			}
   729  			continue
   730  		}
   731  		if i >= 1 && i <= len(defaults) {
   732  			return defaults[i-1]
   733  		}
   734  	}
   735  }
   736  
   737  // ChooseNumber asks the user to enter a number between min and max
   738  // inclusive prompting them with what.
   739  func ChooseNumber(what string, min, max int) int {
   740  	for {
   741  		fmt.Printf("%s> ", what)
   742  		result := ReadLine()
   743  		i, err := strconv.Atoi(result)
   744  		if err != nil {
   745  			fmt.Printf("Bad number: %v\n", err)
   746  			continue
   747  		}
   748  		if i < min || i > max {
   749  			fmt.Printf("Out of range - %d to %d inclusive\n", min, max)
   750  			continue
   751  		}
   752  		return i
   753  	}
   754  }
   755  
   756  // ShowRemote shows the contents of the remote
   757  func ShowRemote(name string) {
   758  	fmt.Printf("--------------------\n")
   759  	fmt.Printf("[%s]\n", name)
   760  	fs := MustFindByName(name)
   761  	for _, key := range getConfigData().GetKeyList(name) {
   762  		isPassword := false
   763  		for _, option := range fs.Options {
   764  			if option.Name == key && option.IsPassword {
   765  				isPassword = true
   766  				break
   767  			}
   768  		}
   769  		value := FileGet(name, key)
   770  		if isPassword && value != "" {
   771  			fmt.Printf("%s = *** ENCRYPTED ***\n", key)
   772  		} else {
   773  			fmt.Printf("%s = %s\n", key, value)
   774  		}
   775  	}
   776  	fmt.Printf("--------------------\n")
   777  }
   778  
   779  // OkRemote prints the contents of the remote and ask if it is OK
   780  func OkRemote(name string) bool {
   781  	ShowRemote(name)
   782  	switch i := Command([]string{"yYes this is OK", "eEdit this remote", "dDelete this remote"}); i {
   783  	case 'y':
   784  		return true
   785  	case 'e':
   786  		return false
   787  	case 'd':
   788  		getConfigData().DeleteSection(name)
   789  		return true
   790  	default:
   791  		fs.Errorf(nil, "Bad choice %c", i)
   792  	}
   793  	return false
   794  }
   795  
   796  // MustFindByName finds the RegInfo for the remote name passed in or
   797  // exits with a fatal error.
   798  func MustFindByName(name string) *fs.RegInfo {
   799  	fsType := FileGet(name, "type")
   800  	if fsType == "" {
   801  		log.Fatalf("Couldn't find type of fs for %q", name)
   802  	}
   803  	return fs.MustFind(fsType)
   804  }
   805  
   806  // RemoteConfig runs the config helper for the remote if needed
   807  func RemoteConfig(name string) {
   808  	fmt.Printf("Remote config\n")
   809  	f := MustFindByName(name)
   810  	if f.Config != nil {
   811  		m := fs.ConfigMap(f, name)
   812  		f.Config(name, m)
   813  	}
   814  }
   815  
   816  // matchProvider returns true if provider matches the providerConfig string.
   817  //
   818  // The providerConfig string can either be a list of providers to
   819  // match, or if it starts with "!" it will be a list of providers not
   820  // to match.
   821  //
   822  // If either providerConfig or provider is blank then it will return true
   823  func matchProvider(providerConfig, provider string) bool {
   824  	if providerConfig == "" || provider == "" {
   825  		return true
   826  	}
   827  	negate := false
   828  	if strings.HasPrefix(providerConfig, "!") {
   829  		providerConfig = providerConfig[1:]
   830  		negate = true
   831  	}
   832  	providers := strings.Split(providerConfig, ",")
   833  	matched := false
   834  	for _, p := range providers {
   835  		if p == provider {
   836  			matched = true
   837  			break
   838  		}
   839  	}
   840  	if negate {
   841  		return !matched
   842  	}
   843  	return matched
   844  }
   845  
   846  // ChooseOption asks the user to choose an option
   847  func ChooseOption(o *fs.Option, name string) string {
   848  	var subProvider = getConfigData().MustValue(name, fs.ConfigProvider, "")
   849  	fmt.Println(o.Help)
   850  	if o.IsPassword {
   851  		actions := []string{"yYes type in my own password", "gGenerate random password"}
   852  		if !o.Required {
   853  			actions = append(actions, "nNo leave this optional password blank")
   854  		}
   855  		var password string
   856  		switch i := Command(actions); i {
   857  		case 'y':
   858  			password = ChangePassword("the")
   859  		case 'g':
   860  			for {
   861  				fmt.Printf("Password strength in bits.\n64 is just about memorable\n128 is secure\n1024 is the maximum\n")
   862  				bits := ChooseNumber("Bits", 64, 1024)
   863  				bytes := bits / 8
   864  				if bits%8 != 0 {
   865  					bytes++
   866  				}
   867  				var pw = make([]byte, bytes)
   868  				n, _ := rand.Read(pw)
   869  				if n != bytes {
   870  					log.Fatalf("password short read: %d", n)
   871  				}
   872  				password = base64.RawURLEncoding.EncodeToString(pw)
   873  				fmt.Printf("Your password is: %s\n", password)
   874  				fmt.Printf("Use this password? Please note that an obscured version of this \npassword (and not the " +
   875  					"password itself) will be stored under your \nconfiguration file, so keep this generated password " +
   876  					"in a safe place.\n")
   877  				if Confirm() {
   878  					break
   879  				}
   880  			}
   881  		case 'n':
   882  			return ""
   883  		default:
   884  			fs.Errorf(nil, "Bad choice %c", i)
   885  		}
   886  		return obscure.MustObscure(password)
   887  	}
   888  	what := fmt.Sprintf("%T value", o.Default)
   889  	switch o.Default.(type) {
   890  	case bool:
   891  		what = "boolean value (true or false)"
   892  	case fs.SizeSuffix:
   893  		what = "size with suffix k,M,G,T"
   894  	case fs.Duration:
   895  		what = "duration s,m,h,d,w,M,y"
   896  	case int, int8, int16, int32, int64:
   897  		what = "signed integer"
   898  	case uint, byte, uint16, uint32, uint64:
   899  		what = "unsigned integer"
   900  	}
   901  	var in string
   902  	for {
   903  		fmt.Printf("Enter a %s. Press Enter for the default (%q).\n", what, fmt.Sprint(o.Default))
   904  		if len(o.Examples) > 0 {
   905  			var values []string
   906  			var help []string
   907  			for _, example := range o.Examples {
   908  				if matchProvider(example.Provider, subProvider) {
   909  					values = append(values, example.Value)
   910  					help = append(help, example.Help)
   911  				}
   912  			}
   913  			in = Choose(o.Name, values, help, true)
   914  		} else {
   915  			fmt.Printf("%s> ", o.Name)
   916  			in = ReadLine()
   917  		}
   918  		if in == "" {
   919  			if o.Required && fmt.Sprint(o.Default) == "" {
   920  				fmt.Printf("This value is required and it has no default.\n")
   921  				continue
   922  			}
   923  			break
   924  		}
   925  		newIn, err := configstruct.StringToInterface(o.Default, in)
   926  		if err != nil {
   927  			fmt.Printf("Failed to parse %q: %v\n", in, err)
   928  			continue
   929  		}
   930  		in = fmt.Sprint(newIn) // canonicalise
   931  		break
   932  	}
   933  	return in
   934  }
   935  
   936  // Suppress the confirm prompts and return a function to undo that
   937  func suppressConfirm() func() {
   938  	old := fs.Config.AutoConfirm
   939  	fs.Config.AutoConfirm = true
   940  	return func() {
   941  		fs.Config.AutoConfirm = old
   942  	}
   943  }
   944  
   945  // UpdateRemote adds the keyValues passed in to the remote of name.
   946  // keyValues should be key, value pairs.
   947  func UpdateRemote(name string, keyValues rc.Params) error {
   948  	defer suppressConfirm()()
   949  
   950  	// Work out which options need to be obscured
   951  	needsObscure := map[string]struct{}{}
   952  	if fsType := FileGet(name, "type"); fsType != "" {
   953  		if ri, err := fs.Find(fsType); err != nil {
   954  			fs.Debugf(nil, "Couldn't find fs for type %q", fsType)
   955  		} else {
   956  			for _, opt := range ri.Options {
   957  				if opt.IsPassword {
   958  					needsObscure[opt.Name] = struct{}{}
   959  				}
   960  			}
   961  		}
   962  	} else {
   963  		fs.Debugf(nil, "UpdateRemote: Couldn't find fs type")
   964  	}
   965  
   966  	// Set the config
   967  	for k, v := range keyValues {
   968  		vStr := fmt.Sprint(v)
   969  		// Obscure parameter if necessary
   970  		if _, ok := needsObscure[k]; ok {
   971  			_, err := obscure.Reveal(vStr)
   972  			if err != nil {
   973  				// If error => not already obscured, so obscure it
   974  				vStr, err = obscure.Obscure(vStr)
   975  				if err != nil {
   976  					return errors.Wrap(err, "UpdateRemote: obscure failed")
   977  				}
   978  			}
   979  		}
   980  		getConfigData().SetValue(name, k, vStr)
   981  	}
   982  	RemoteConfig(name)
   983  	SaveConfig()
   984  	return nil
   985  }
   986  
   987  // CreateRemote creates a new remote with name, provider and a list of
   988  // parameters which are key, value pairs.  If update is set then it
   989  // adds the new keys rather than replacing all of them.
   990  func CreateRemote(name string, provider string, keyValues rc.Params) error {
   991  	// Delete the old config if it exists
   992  	getConfigData().DeleteSection(name)
   993  	// Set the type
   994  	getConfigData().SetValue(name, "type", provider)
   995  	// Set the remaining values
   996  	return UpdateRemote(name, keyValues)
   997  }
   998  
   999  // PasswordRemote adds the keyValues passed in to the remote of name.
  1000  // keyValues should be key, value pairs.
  1001  func PasswordRemote(name string, keyValues rc.Params) error {
  1002  	defer suppressConfirm()()
  1003  	for k, v := range keyValues {
  1004  		keyValues[k] = obscure.MustObscure(fmt.Sprint(v))
  1005  	}
  1006  	return UpdateRemote(name, keyValues)
  1007  }
  1008  
  1009  // JSONListProviders prints all the providers and options in JSON format
  1010  func JSONListProviders() error {
  1011  	b, err := json.MarshalIndent(fs.Registry, "", "    ")
  1012  	if err != nil {
  1013  		return errors.Wrap(err, "failed to marshal examples")
  1014  	}
  1015  	_, err = os.Stdout.Write(b)
  1016  	if err != nil {
  1017  		return errors.Wrap(err, "failed to write providers list")
  1018  	}
  1019  	return nil
  1020  }
  1021  
  1022  // fsOption returns an Option describing the possible remotes
  1023  func fsOption() *fs.Option {
  1024  	o := &fs.Option{
  1025  		Name:    "Storage",
  1026  		Help:    "Type of storage to configure.",
  1027  		Default: "",
  1028  	}
  1029  	for _, item := range fs.Registry {
  1030  		example := fs.OptionExample{
  1031  			Value: item.Name,
  1032  			Help:  item.Description,
  1033  		}
  1034  		o.Examples = append(o.Examples, example)
  1035  	}
  1036  	o.Examples.Sort()
  1037  	return o
  1038  }
  1039  
  1040  // NewRemoteName asks the user for a name for a remote
  1041  func NewRemoteName() (name string) {
  1042  	for {
  1043  		fmt.Printf("name> ")
  1044  		name = ReadLine()
  1045  		parts := fspath.Matcher.FindStringSubmatch(name + ":")
  1046  		switch {
  1047  		case name == "":
  1048  			fmt.Printf("Can't use empty name.\n")
  1049  		case driveletter.IsDriveLetter(name):
  1050  			fmt.Printf("Can't use %q as it can be confused with a drive letter.\n", name)
  1051  		case parts == nil:
  1052  			fmt.Printf("Can't use %q as it has invalid characters in it.\n", name)
  1053  		default:
  1054  			return name
  1055  		}
  1056  	}
  1057  }
  1058  
  1059  // editOptions edits the options.  If new is true then it just allows
  1060  // entry and doesn't show any old values.
  1061  func editOptions(ri *fs.RegInfo, name string, isNew bool) {
  1062  	fmt.Printf("** See help for %s backend at: https://rclone.org/%s/ **\n\n", ri.Name, ri.FileName())
  1063  	hasAdvanced := false
  1064  	for _, advanced := range []bool{false, true} {
  1065  		if advanced {
  1066  			if !hasAdvanced {
  1067  				break
  1068  			}
  1069  			fmt.Printf("Edit advanced config? (y/n)\n")
  1070  			if !Confirm() {
  1071  				break
  1072  			}
  1073  		}
  1074  		for _, option := range ri.Options {
  1075  			hasAdvanced = hasAdvanced || option.Advanced
  1076  			if option.Advanced != advanced {
  1077  				continue
  1078  			}
  1079  			subProvider := getConfigData().MustValue(name, fs.ConfigProvider, "")
  1080  			if matchProvider(option.Provider, subProvider) {
  1081  				if !isNew {
  1082  					fmt.Printf("Value %q = %q\n", option.Name, FileGet(name, option.Name))
  1083  					fmt.Printf("Edit? (y/n)>\n")
  1084  					if !Confirm() {
  1085  						continue
  1086  					}
  1087  				}
  1088  				if option.Hide&fs.OptionHideConfigurator == 0 {
  1089  					FileSet(name, option.Name, ChooseOption(&option, name))
  1090  				}
  1091  			}
  1092  		}
  1093  	}
  1094  }
  1095  
  1096  // NewRemote make a new remote from its name
  1097  func NewRemote(name string) {
  1098  	var (
  1099  		newType string
  1100  		ri      *fs.RegInfo
  1101  		err     error
  1102  	)
  1103  
  1104  	// Set the type first
  1105  	for {
  1106  		newType = ChooseOption(fsOption(), name)
  1107  		ri, err = fs.Find(newType)
  1108  		if err != nil {
  1109  			fmt.Printf("Bad remote %q: %v\n", newType, err)
  1110  			continue
  1111  		}
  1112  		break
  1113  	}
  1114  	getConfigData().SetValue(name, "type", newType)
  1115  
  1116  	editOptions(ri, name, true)
  1117  	RemoteConfig(name)
  1118  	if OkRemote(name) {
  1119  		SaveConfig()
  1120  		return
  1121  	}
  1122  	EditRemote(ri, name)
  1123  }
  1124  
  1125  // EditRemote gets the user to edit a remote
  1126  func EditRemote(ri *fs.RegInfo, name string) {
  1127  	ShowRemote(name)
  1128  	fmt.Printf("Edit remote\n")
  1129  	for {
  1130  		editOptions(ri, name, false)
  1131  		if OkRemote(name) {
  1132  			break
  1133  		}
  1134  	}
  1135  	SaveConfig()
  1136  	RemoteConfig(name)
  1137  }
  1138  
  1139  // DeleteRemote gets the user to delete a remote
  1140  func DeleteRemote(name string) {
  1141  	getConfigData().DeleteSection(name)
  1142  	SaveConfig()
  1143  }
  1144  
  1145  // copyRemote asks the user for a new remote name and copies name into
  1146  // it. Returns the new name.
  1147  func copyRemote(name string) string {
  1148  	newName := NewRemoteName()
  1149  	// Copy the keys
  1150  	for _, key := range getConfigData().GetKeyList(name) {
  1151  		value := getConfigData().MustValue(name, key, "")
  1152  		getConfigData().SetValue(newName, key, value)
  1153  	}
  1154  	return newName
  1155  }
  1156  
  1157  // RenameRemote renames a config section
  1158  func RenameRemote(name string) {
  1159  	fmt.Printf("Enter new name for %q remote.\n", name)
  1160  	newName := copyRemote(name)
  1161  	if name != newName {
  1162  		getConfigData().DeleteSection(name)
  1163  		SaveConfig()
  1164  	}
  1165  }
  1166  
  1167  // CopyRemote copies a config section
  1168  func CopyRemote(name string) {
  1169  	fmt.Printf("Enter name for copy of %q remote.\n", name)
  1170  	copyRemote(name)
  1171  	SaveConfig()
  1172  }
  1173  
  1174  // ShowConfigLocation prints the location of the config file in use
  1175  func ShowConfigLocation() {
  1176  	if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
  1177  		fmt.Println("Configuration file doesn't exist, but rclone will use this path:")
  1178  	} else {
  1179  		fmt.Println("Configuration file is stored at:")
  1180  	}
  1181  	fmt.Printf("%s\n", ConfigPath)
  1182  }
  1183  
  1184  // ShowConfig prints the (unencrypted) config options
  1185  func ShowConfig() {
  1186  	var buf bytes.Buffer
  1187  	if err := goconfig.SaveConfigData(getConfigData(), &buf); err != nil {
  1188  		log.Fatalf("Failed to serialize config: %v", err)
  1189  	}
  1190  	str := buf.String()
  1191  	if str == "" {
  1192  		str = "; empty config\n"
  1193  	}
  1194  	fmt.Printf("%s", str)
  1195  }
  1196  
  1197  // EditConfig edits the config file interactively
  1198  func EditConfig() {
  1199  	for {
  1200  		haveRemotes := len(getConfigData().GetSectionList()) != 0
  1201  		what := []string{"eEdit existing remote", "nNew remote", "dDelete remote", "rRename remote", "cCopy remote", "sSet configuration password", "qQuit config"}
  1202  		if haveRemotes {
  1203  			fmt.Printf("Current remotes:\n\n")
  1204  			ShowRemotes()
  1205  			fmt.Printf("\n")
  1206  		} else {
  1207  			fmt.Printf("No remotes found - make a new one\n")
  1208  			// take 2nd item and last 2 items of menu list
  1209  			what = append(what[1:2], what[len(what)-2:]...)
  1210  		}
  1211  		switch i := Command(what); i {
  1212  		case 'e':
  1213  			name := ChooseRemote()
  1214  			fs := MustFindByName(name)
  1215  			EditRemote(fs, name)
  1216  		case 'n':
  1217  			NewRemote(NewRemoteName())
  1218  		case 'd':
  1219  			name := ChooseRemote()
  1220  			DeleteRemote(name)
  1221  		case 'r':
  1222  			RenameRemote(ChooseRemote())
  1223  		case 'c':
  1224  			CopyRemote(ChooseRemote())
  1225  		case 's':
  1226  			SetPassword()
  1227  		case 'q':
  1228  			return
  1229  
  1230  		}
  1231  	}
  1232  }
  1233  
  1234  // SetPassword will allow the user to modify the current
  1235  // configuration encryption settings.
  1236  func SetPassword() {
  1237  	for {
  1238  		if len(configKey) > 0 {
  1239  			fmt.Println("Your configuration is encrypted.")
  1240  			what := []string{"cChange Password", "uUnencrypt configuration", "qQuit to main menu"}
  1241  			switch i := Command(what); i {
  1242  			case 'c':
  1243  				changeConfigPassword()
  1244  				SaveConfig()
  1245  				fmt.Println("Password changed")
  1246  				continue
  1247  			case 'u':
  1248  				configKey = nil
  1249  				SaveConfig()
  1250  				continue
  1251  			case 'q':
  1252  				return
  1253  			}
  1254  
  1255  		} else {
  1256  			fmt.Println("Your configuration is not encrypted.")
  1257  			fmt.Println("If you add a password, you will protect your login information to cloud services.")
  1258  			what := []string{"aAdd Password", "qQuit to main menu"}
  1259  			switch i := Command(what); i {
  1260  			case 'a':
  1261  				changeConfigPassword()
  1262  				SaveConfig()
  1263  				fmt.Println("Password set")
  1264  				continue
  1265  			case 'q':
  1266  				return
  1267  			}
  1268  		}
  1269  	}
  1270  }
  1271  
  1272  // Authorize is for remote authorization of headless machines.
  1273  //
  1274  // It expects 1 or 3 arguments
  1275  //
  1276  //   rclone authorize "fs name"
  1277  //   rclone authorize "fs name" "client id" "client secret"
  1278  func Authorize(args []string) {
  1279  	defer suppressConfirm()()
  1280  	switch len(args) {
  1281  	case 1, 3:
  1282  	default:
  1283  		log.Fatalf("Invalid number of arguments: %d", len(args))
  1284  	}
  1285  	newType := args[0]
  1286  	f := fs.MustFind(newType)
  1287  	if f.Config == nil {
  1288  		log.Fatalf("Can't authorize fs %q", newType)
  1289  	}
  1290  	// Name used for temporary fs
  1291  	name := "**temp-fs**"
  1292  
  1293  	// Make sure we delete it
  1294  	defer DeleteRemote(name)
  1295  
  1296  	// Indicate that we are running rclone authorize
  1297  	getConfigData().SetValue(name, ConfigAuthorize, "true")
  1298  	if len(args) == 3 {
  1299  		getConfigData().SetValue(name, ConfigClientID, args[1])
  1300  		getConfigData().SetValue(name, ConfigClientSecret, args[2])
  1301  	}
  1302  	m := fs.ConfigMap(f, name)
  1303  	f.Config(name, m)
  1304  }
  1305  
  1306  // FileGetFlag gets the config key under section returning the
  1307  // the value and true if found and or ("", false) otherwise
  1308  func FileGetFlag(section, key string) (string, bool) {
  1309  	newValue, err := getConfigData().GetValue(section, key)
  1310  	return newValue, err == nil
  1311  }
  1312  
  1313  // FileGet gets the config key under section returning the
  1314  // default or empty string if not set.
  1315  //
  1316  // It looks up defaults in the environment if they are present
  1317  func FileGet(section, key string, defaultVal ...string) string {
  1318  	envKey := fs.ConfigToEnv(section, key)
  1319  	newValue, found := os.LookupEnv(envKey)
  1320  	if found {
  1321  		defaultVal = []string{newValue}
  1322  	}
  1323  	return getConfigData().MustValue(section, key, defaultVal...)
  1324  }
  1325  
  1326  // FileSet sets the key in section to value.  It doesn't save
  1327  // the config file.
  1328  func FileSet(section, key, value string) {
  1329  	if value != "" {
  1330  		getConfigData().SetValue(section, key, value)
  1331  	} else {
  1332  		FileDeleteKey(section, key)
  1333  	}
  1334  }
  1335  
  1336  // FileDeleteKey deletes the config key in the config file.
  1337  // It returns true if the key was deleted,
  1338  // or returns false if the section or key didn't exist.
  1339  func FileDeleteKey(section, key string) bool {
  1340  	return getConfigData().DeleteKey(section, key)
  1341  }
  1342  
  1343  var matchEnv = regexp.MustCompile(`^RCLONE_CONFIG_(.*?)_TYPE=.*$`)
  1344  
  1345  // FileRefresh ensures the latest configFile is loaded from disk
  1346  func FileRefresh() error {
  1347  	reloadedConfigFile, err := loadConfigFile()
  1348  	if err != nil {
  1349  		return err
  1350  	}
  1351  	configFile = reloadedConfigFile
  1352  	return nil
  1353  }
  1354  
  1355  // FileSections returns the sections in the config file
  1356  // including any defined by environment variables.
  1357  func FileSections() []string {
  1358  	sections := getConfigData().GetSectionList()
  1359  	for _, item := range os.Environ() {
  1360  		matches := matchEnv.FindStringSubmatch(item)
  1361  		if len(matches) == 2 {
  1362  			sections = append(sections, strings.ToLower(matches[1]))
  1363  		}
  1364  	}
  1365  	return sections
  1366  }
  1367  
  1368  // DumpRcRemote dumps the config for a single remote
  1369  func DumpRcRemote(name string) (dump rc.Params) {
  1370  	params := rc.Params{}
  1371  	for _, key := range getConfigData().GetKeyList(name) {
  1372  		params[key] = FileGet(name, key)
  1373  	}
  1374  	return params
  1375  }
  1376  
  1377  // DumpRcBlob dumps all the config as an unstructured blob suitable
  1378  // for the rc
  1379  func DumpRcBlob() (dump rc.Params) {
  1380  	dump = rc.Params{}
  1381  	for _, name := range getConfigData().GetSectionList() {
  1382  		dump[name] = DumpRcRemote(name)
  1383  	}
  1384  	return dump
  1385  }
  1386  
  1387  // Dump dumps all the config as a JSON file
  1388  func Dump() error {
  1389  	dump := DumpRcBlob()
  1390  	b, err := json.MarshalIndent(dump, "", "    ")
  1391  	if err != nil {
  1392  		return errors.Wrap(err, "failed to marshal config dump")
  1393  	}
  1394  	_, err = os.Stdout.Write(b)
  1395  	if err != nil {
  1396  		return errors.Wrap(err, "failed to write config dump")
  1397  	}
  1398  	return nil
  1399  }
  1400  
  1401  // makeCacheDir returns a directory to use for caching.
  1402  //
  1403  // Code borrowed from go stdlib until it is made public
  1404  func makeCacheDir() (dir string) {
  1405  	// Compute default location.
  1406  	switch runtime.GOOS {
  1407  	case "windows":
  1408  		dir = os.Getenv("LocalAppData")
  1409  
  1410  	case "darwin":
  1411  		dir = os.Getenv("HOME")
  1412  		if dir != "" {
  1413  			dir += "/Library/Caches"
  1414  		}
  1415  
  1416  	case "plan9":
  1417  		dir = os.Getenv("home")
  1418  		if dir != "" {
  1419  			// Plan 9 has no established per-user cache directory,
  1420  			// but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix.
  1421  			dir += "/lib/cache"
  1422  		}
  1423  
  1424  	default: // Unix
  1425  		// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
  1426  		dir = os.Getenv("XDG_CACHE_HOME")
  1427  		if dir == "" {
  1428  			dir = os.Getenv("HOME")
  1429  			if dir != "" {
  1430  				dir += "/.cache"
  1431  			}
  1432  		}
  1433  	}
  1434  
  1435  	// if no dir found then use TempDir - we will have a cachedir!
  1436  	if dir == "" {
  1437  		dir = os.TempDir()
  1438  	}
  1439  	return filepath.Join(dir, "rclone")
  1440  }