github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/config/configflags/configflags.go (about) 1 // Package configflags defines the flags used by rclone. It is 2 // decoupled into a separate package so it can be replaced. 3 package configflags 4 5 // Options set by command line flags 6 import ( 7 "log" 8 "net" 9 "os" 10 "strconv" 11 "strings" 12 13 "github.com/rclone/rclone/fs" 14 "github.com/rclone/rclone/fs/config" 15 "github.com/rclone/rclone/fs/config/flags" 16 fsLog "github.com/rclone/rclone/fs/log" 17 "github.com/rclone/rclone/fs/rc" 18 "github.com/sirupsen/logrus" 19 "github.com/spf13/pflag" 20 ) 21 22 var ( 23 // these will get interpreted into fs.Config via SetFlags() below 24 verbose int 25 quiet bool 26 configPath string 27 cacheDir string 28 tempDir string 29 dumpHeaders bool 30 dumpBodies bool 31 deleteBefore bool 32 deleteDuring bool 33 deleteAfter bool 34 bindAddr string 35 disableFeatures string 36 dscp string 37 uploadHeaders []string 38 downloadHeaders []string 39 headers []string 40 metadataSet []string 41 partialSuffix string 42 ) 43 44 // AddFlags adds the non filing system specific flags to the command 45 func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) { 46 rc.AddOption("main", ci) 47 // NB defaults which aren't the zero for the type should be set in fs/config.go NewConfig 48 flags.CountVarP(flagSet, &verbose, "verbose", "v", "Print lots more stuff (repeat for more)", "Logging,Important") 49 flags.BoolVarP(flagSet, &quiet, "quiet", "q", false, "Print as little stuff as possible", "Logging") 50 flags.DurationVarP(flagSet, &ci.ModifyWindow, "modify-window", "", ci.ModifyWindow, "Max time diff to be considered the same", "Copy") 51 flags.IntVarP(flagSet, &ci.Checkers, "checkers", "", ci.Checkers, "Number of checkers to run in parallel", "Performance") 52 flags.IntVarP(flagSet, &ci.Transfers, "transfers", "", ci.Transfers, "Number of file transfers to run in parallel", "Performance") 53 flags.StringVarP(flagSet, &configPath, "config", "", config.GetConfigPath(), "Config file", "Config") 54 flags.StringVarP(flagSet, &cacheDir, "cache-dir", "", config.GetCacheDir(), "Directory rclone will use for caching", "Config") 55 flags.StringVarP(flagSet, &tempDir, "temp-dir", "", os.TempDir(), "Directory rclone will use for temporary files", "Config") 56 flags.BoolVarP(flagSet, &ci.CheckSum, "checksum", "c", ci.CheckSum, "Check for changes with size & checksum (if available, or fallback to size only).", "Copy") 57 flags.BoolVarP(flagSet, &ci.SizeOnly, "size-only", "", ci.SizeOnly, "Skip based on size only, not modtime or checksum", "Copy") 58 flags.BoolVarP(flagSet, &ci.IgnoreTimes, "ignore-times", "I", ci.IgnoreTimes, "Don't skip items that match size and time - transfer all unconditionally", "Copy") 59 flags.BoolVarP(flagSet, &ci.IgnoreExisting, "ignore-existing", "", ci.IgnoreExisting, "Skip all files that exist on destination", "Copy") 60 flags.BoolVarP(flagSet, &ci.IgnoreErrors, "ignore-errors", "", ci.IgnoreErrors, "Delete even if there are I/O errors", "Sync") 61 flags.BoolVarP(flagSet, &ci.DryRun, "dry-run", "n", ci.DryRun, "Do a trial run with no permanent changes", "Config,Important") 62 flags.BoolVarP(flagSet, &ci.Interactive, "interactive", "i", ci.Interactive, "Enable interactive mode", "Config,Important") 63 flags.DurationVarP(flagSet, &ci.ConnectTimeout, "contimeout", "", ci.ConnectTimeout, "Connect timeout", "Networking") 64 flags.DurationVarP(flagSet, &ci.Timeout, "timeout", "", ci.Timeout, "IO idle timeout", "Networking") 65 flags.DurationVarP(flagSet, &ci.ExpectContinueTimeout, "expect-continue-timeout", "", ci.ExpectContinueTimeout, "Timeout when using expect / 100-continue in HTTP", "Networking") 66 flags.BoolVarP(flagSet, &dumpHeaders, "dump-headers", "", false, "Dump HTTP headers - may contain sensitive info", "Debugging") 67 flags.BoolVarP(flagSet, &dumpBodies, "dump-bodies", "", false, "Dump HTTP headers and bodies - may contain sensitive info", "Debugging") 68 flags.BoolVarP(flagSet, &ci.InsecureSkipVerify, "no-check-certificate", "", ci.InsecureSkipVerify, "Do not verify the server SSL certificate (insecure)", "Networking") 69 flags.BoolVarP(flagSet, &ci.AskPassword, "ask-password", "", ci.AskPassword, "Allow prompt for password for encrypted configuration", "Config") 70 flags.FVarP(flagSet, &ci.PasswordCommand, "password-command", "", "Command for supplying password for encrypted configuration", "Config") 71 flags.BoolVarP(flagSet, &deleteBefore, "delete-before", "", false, "When synchronizing, delete files on destination before transferring", "Sync") 72 flags.BoolVarP(flagSet, &deleteDuring, "delete-during", "", false, "When synchronizing, delete files during transfer", "Sync") 73 flags.BoolVarP(flagSet, &deleteAfter, "delete-after", "", false, "When synchronizing, delete files on destination after transferring (default)", "Sync") 74 flags.Int64VarP(flagSet, &ci.MaxDelete, "max-delete", "", -1, "When synchronizing, limit the number of deletes", "Sync") 75 flags.FVarP(flagSet, &ci.MaxDeleteSize, "max-delete-size", "", "When synchronizing, limit the total size of deletes", "Sync") 76 flags.BoolVarP(flagSet, &ci.TrackRenames, "track-renames", "", ci.TrackRenames, "When synchronizing, track file renames and do a server-side move if possible", "Sync") 77 flags.StringVarP(flagSet, &ci.TrackRenamesStrategy, "track-renames-strategy", "", ci.TrackRenamesStrategy, "Strategies to use when synchronizing using track-renames hash|modtime|leaf", "Sync") 78 flags.IntVarP(flagSet, &ci.Retries, "retries", "", 3, "Retry operations this many times if they fail", "Config") 79 flags.DurationVarP(flagSet, &ci.RetriesInterval, "retries-sleep", "", 0, "Interval between retrying operations if they fail, e.g. 500ms, 60s, 5m (0 to disable)", "Config") 80 flags.IntVarP(flagSet, &ci.LowLevelRetries, "low-level-retries", "", ci.LowLevelRetries, "Number of low level retries to do", "Config") 81 flags.BoolVarP(flagSet, &ci.UpdateOlder, "update", "u", ci.UpdateOlder, "Skip files that are newer on the destination", "Copy") 82 flags.BoolVarP(flagSet, &ci.UseServerModTime, "use-server-modtime", "", ci.UseServerModTime, "Use server modified time instead of object metadata", "Config") 83 flags.BoolVarP(flagSet, &ci.NoGzip, "no-gzip-encoding", "", ci.NoGzip, "Don't set Accept-Encoding: gzip", "Networking") 84 flags.IntVarP(flagSet, &ci.MaxDepth, "max-depth", "", ci.MaxDepth, "If set limits the recursion depth to this", "Filter") 85 flags.BoolVarP(flagSet, &ci.IgnoreSize, "ignore-size", "", false, "Ignore size when skipping use modtime or checksum", "Copy") 86 flags.BoolVarP(flagSet, &ci.IgnoreChecksum, "ignore-checksum", "", ci.IgnoreChecksum, "Skip post copy check of checksums", "Copy") 87 flags.BoolVarP(flagSet, &ci.IgnoreCaseSync, "ignore-case-sync", "", ci.IgnoreCaseSync, "Ignore case when synchronizing", "Copy") 88 flags.BoolVarP(flagSet, &ci.FixCase, "fix-case", "", ci.FixCase, "Force rename of case insensitive dest to match source", "Sync") 89 flags.BoolVarP(flagSet, &ci.NoTraverse, "no-traverse", "", ci.NoTraverse, "Don't traverse destination file system on copy", "Copy") 90 flags.BoolVarP(flagSet, &ci.CheckFirst, "check-first", "", ci.CheckFirst, "Do all the checks before starting transfers", "Copy") 91 flags.BoolVarP(flagSet, &ci.NoCheckDest, "no-check-dest", "", ci.NoCheckDest, "Don't check the destination, copy regardless", "Copy") 92 flags.BoolVarP(flagSet, &ci.NoUnicodeNormalization, "no-unicode-normalization", "", ci.NoUnicodeNormalization, "Don't normalize unicode characters in filenames", "Config") 93 flags.BoolVarP(flagSet, &ci.NoUpdateModTime, "no-update-modtime", "", ci.NoUpdateModTime, "Don't update destination modtime if files identical", "Copy") 94 flags.BoolVarP(flagSet, &ci.NoUpdateDirModTime, "no-update-dir-modtime", "", ci.NoUpdateModTime, "Don't update directory modification times", "Copy") 95 flags.StringArrayVarP(flagSet, &ci.CompareDest, "compare-dest", "", nil, "Include additional comma separated server-side paths during comparison", "Copy") 96 flags.StringArrayVarP(flagSet, &ci.CopyDest, "copy-dest", "", nil, "Implies --compare-dest but also copies files from paths into destination", "Copy") 97 flags.StringVarP(flagSet, &ci.BackupDir, "backup-dir", "", ci.BackupDir, "Make backups into hierarchy based in DIR", "Sync") 98 flags.StringVarP(flagSet, &ci.Suffix, "suffix", "", ci.Suffix, "Suffix to add to changed files", "Sync") 99 flags.BoolVarP(flagSet, &ci.SuffixKeepExtension, "suffix-keep-extension", "", ci.SuffixKeepExtension, "Preserve the extension when using --suffix", "Sync") 100 flags.BoolVarP(flagSet, &ci.UseListR, "fast-list", "", ci.UseListR, "Use recursive list if available; uses more memory but fewer transactions", "Listing") 101 flags.Float64VarP(flagSet, &ci.TPSLimit, "tpslimit", "", ci.TPSLimit, "Limit HTTP transactions per second to this", "Networking") 102 flags.IntVarP(flagSet, &ci.TPSLimitBurst, "tpslimit-burst", "", ci.TPSLimitBurst, "Max burst of transactions for --tpslimit", "Networking") 103 flags.StringVarP(flagSet, &bindAddr, "bind", "", "", "Local address to bind to for outgoing connections, IPv4, IPv6 or name", "Networking") 104 flags.StringVarP(flagSet, &disableFeatures, "disable", "", "", "Disable a comma separated list of features (use --disable help to see a list)", "Config") 105 flags.StringVarP(flagSet, &ci.UserAgent, "user-agent", "", ci.UserAgent, "Set the user-agent to a specified string", "Networking") 106 flags.BoolVarP(flagSet, &ci.Immutable, "immutable", "", ci.Immutable, "Do not modify files, fail if existing files have been modified", "Copy") 107 flags.BoolVarP(flagSet, &ci.AutoConfirm, "auto-confirm", "", ci.AutoConfirm, "If enabled, do not request console confirmation", "Config") 108 flags.IntVarP(flagSet, &ci.StatsFileNameLength, "stats-file-name-length", "", ci.StatsFileNameLength, "Max file name length in stats (0 for no limit)", "Logging") 109 flags.FVarP(flagSet, &ci.LogLevel, "log-level", "", "Log level DEBUG|INFO|NOTICE|ERROR", "Logging") 110 flags.FVarP(flagSet, &ci.StatsLogLevel, "stats-log-level", "", "Log level to show --stats output DEBUG|INFO|NOTICE|ERROR", "Logging") 111 flags.FVarP(flagSet, &ci.BwLimit, "bwlimit", "", "Bandwidth limit in KiB/s, or use suffix B|K|M|G|T|P or a full timetable", "Networking") 112 flags.FVarP(flagSet, &ci.BwLimitFile, "bwlimit-file", "", "Bandwidth limit per file in KiB/s, or use suffix B|K|M|G|T|P or a full timetable", "Networking") 113 flags.FVarP(flagSet, &ci.BufferSize, "buffer-size", "", "In memory buffer size when reading files for each --transfer", "Performance") 114 flags.FVarP(flagSet, &ci.StreamingUploadCutoff, "streaming-upload-cutoff", "", "Cutoff for switching to chunked upload if file size is unknown, upload starts after reaching cutoff or when file ends", "Copy") 115 flags.FVarP(flagSet, &ci.Dump, "dump", "", "List of items to dump from: "+fs.DumpFlagsList, "Debugging") 116 flags.FVarP(flagSet, &ci.MaxTransfer, "max-transfer", "", "Maximum size of data to transfer", "Copy") 117 flags.DurationVarP(flagSet, &ci.MaxDuration, "max-duration", "", 0, "Maximum duration rclone will transfer data for", "Copy") 118 flags.FVarP(flagSet, &ci.CutoffMode, "cutoff-mode", "", "Mode to stop transfers when reaching the max transfer limit HARD|SOFT|CAUTIOUS", "Copy") 119 flags.IntVarP(flagSet, &ci.MaxBacklog, "max-backlog", "", ci.MaxBacklog, "Maximum number of objects in sync or check backlog", "Copy,Check") 120 flags.IntVarP(flagSet, &ci.MaxStatsGroups, "max-stats-groups", "", ci.MaxStatsGroups, "Maximum number of stats groups to keep in memory, on max oldest is discarded", "Logging") 121 flags.BoolVarP(flagSet, &ci.StatsOneLine, "stats-one-line", "", ci.StatsOneLine, "Make the stats fit on one line", "Logging") 122 flags.BoolVarP(flagSet, &ci.StatsOneLineDate, "stats-one-line-date", "", ci.StatsOneLineDate, "Enable --stats-one-line and add current date/time prefix", "Logging") 123 flags.StringVarP(flagSet, &ci.StatsOneLineDateFormat, "stats-one-line-date-format", "", ci.StatsOneLineDateFormat, "Enable --stats-one-line-date and use custom formatted date: Enclose date string in double quotes (\"), see https://golang.org/pkg/time/#Time.Format", "Logging") 124 flags.BoolVarP(flagSet, &ci.ErrorOnNoTransfer, "error-on-no-transfer", "", ci.ErrorOnNoTransfer, "Sets exit code 9 if no files are transferred, useful in scripts", "Config") 125 flags.BoolVarP(flagSet, &ci.Progress, "progress", "P", ci.Progress, "Show progress during transfer", "Logging") 126 flags.BoolVarP(flagSet, &ci.ProgressTerminalTitle, "progress-terminal-title", "", ci.ProgressTerminalTitle, "Show progress on the terminal title (requires -P/--progress)", "Logging") 127 flags.BoolVarP(flagSet, &ci.Cookie, "use-cookies", "", ci.Cookie, "Enable session cookiejar", "Networking") 128 flags.BoolVarP(flagSet, &ci.UseMmap, "use-mmap", "", ci.UseMmap, "Use mmap allocator (see docs)", "Config") 129 flags.StringArrayVarP(flagSet, &ci.CaCert, "ca-cert", "", ci.CaCert, "CA certificate used to verify servers", "Networking") 130 flags.StringVarP(flagSet, &ci.ClientCert, "client-cert", "", ci.ClientCert, "Client SSL certificate (PEM) for mutual TLS auth", "Networking") 131 flags.StringVarP(flagSet, &ci.ClientKey, "client-key", "", ci.ClientKey, "Client SSL private key (PEM) for mutual TLS auth", "Networking") 132 flags.FVarP(flagSet, &ci.MultiThreadCutoff, "multi-thread-cutoff", "", "Use multi-thread downloads for files above this size", "Copy") 133 flags.IntVarP(flagSet, &ci.MultiThreadStreams, "multi-thread-streams", "", ci.MultiThreadStreams, "Number of streams to use for multi-thread downloads", "Copy") 134 flags.FVarP(flagSet, &ci.MultiThreadWriteBufferSize, "multi-thread-write-buffer-size", "", "In memory buffer size for writing when in multi-thread mode", "Copy") 135 flags.FVarP(flagSet, &ci.MultiThreadChunkSize, "multi-thread-chunk-size", "", "Chunk size for multi-thread downloads / uploads, if not set by filesystem", "Copy") 136 flags.BoolVarP(flagSet, &ci.UseJSONLog, "use-json-log", "", ci.UseJSONLog, "Use json log format", "Logging") 137 flags.StringVarP(flagSet, &ci.OrderBy, "order-by", "", ci.OrderBy, "Instructions on how to order the transfers, e.g. 'size,descending'", "Copy") 138 flags.StringArrayVarP(flagSet, &uploadHeaders, "header-upload", "", nil, "Set HTTP header for upload transactions", "Networking") 139 flags.StringArrayVarP(flagSet, &downloadHeaders, "header-download", "", nil, "Set HTTP header for download transactions", "Networking") 140 flags.StringArrayVarP(flagSet, &headers, "header", "", nil, "Set HTTP header for all transactions", "Networking") 141 flags.StringArrayVarP(flagSet, &metadataSet, "metadata-set", "", nil, "Add metadata key=value when uploading", "Metadata") 142 flags.BoolVarP(flagSet, &ci.RefreshTimes, "refresh-times", "", ci.RefreshTimes, "Refresh the modtime of remote files", "Copy") 143 flags.BoolVarP(flagSet, &ci.NoConsole, "no-console", "", ci.NoConsole, "Hide console window (supported on Windows only)", "Config") 144 flags.StringVarP(flagSet, &dscp, "dscp", "", "", "Set DSCP value to connections, value or name, e.g. CS1, LE, DF, AF21", "Networking") 145 flags.DurationVarP(flagSet, &ci.FsCacheExpireDuration, "fs-cache-expire-duration", "", ci.FsCacheExpireDuration, "Cache remotes for this long (0 to disable caching)", "Config") 146 flags.DurationVarP(flagSet, &ci.FsCacheExpireInterval, "fs-cache-expire-interval", "", ci.FsCacheExpireInterval, "Interval to check for expired remotes", "Config") 147 flags.BoolVarP(flagSet, &ci.DisableHTTP2, "disable-http2", "", ci.DisableHTTP2, "Disable HTTP/2 in the global transport", "Networking") 148 flags.BoolVarP(flagSet, &ci.HumanReadable, "human-readable", "", ci.HumanReadable, "Print numbers in a human-readable format, sizes with suffix Ki|Mi|Gi|Ti|Pi", "Config") 149 flags.DurationVarP(flagSet, &ci.KvLockTime, "kv-lock-time", "", ci.KvLockTime, "Maximum time to keep key-value database locked by process", "Config") 150 flags.BoolVarP(flagSet, &ci.DisableHTTPKeepAlives, "disable-http-keep-alives", "", ci.DisableHTTPKeepAlives, "Disable HTTP keep-alives and use each connection once.", "Networking") 151 flags.BoolVarP(flagSet, &ci.Metadata, "metadata", "M", ci.Metadata, "If set, preserve metadata when copying objects", "Metadata,Copy") 152 flags.BoolVarP(flagSet, &ci.ServerSideAcrossConfigs, "server-side-across-configs", "", ci.ServerSideAcrossConfigs, "Allow server-side operations (e.g. copy) to work across different configs", "Copy") 153 flags.FVarP(flagSet, &ci.TerminalColorMode, "color", "", "When to show colors (and other ANSI codes) AUTO|NEVER|ALWAYS", "Config") 154 flags.FVarP(flagSet, &ci.DefaultTime, "default-time", "", "Time to show if modtime is unknown for files and directories", "Config,Listing") 155 flags.BoolVarP(flagSet, &ci.Inplace, "inplace", "", ci.Inplace, "Download directly to destination file instead of atomic download to temp/rename", "Copy") 156 flags.StringVarP(flagSet, &partialSuffix, "partial-suffix", "", ci.PartialSuffix, "Add partial-suffix to temporary file name when --inplace is not used", "Copy") 157 flags.FVarP(flagSet, &ci.MetadataMapper, "metadata-mapper", "", "Program to run to transforming metadata before upload", "Metadata") 158 } 159 160 // ParseHeaders converts the strings passed in via the header flags into HTTPOptions 161 func ParseHeaders(headers []string) []*fs.HTTPOption { 162 opts := []*fs.HTTPOption{} 163 for _, header := range headers { 164 parts := strings.SplitN(header, ":", 2) 165 if len(parts) == 1 { 166 log.Fatalf("Failed to parse '%s' as an HTTP header. Expecting a string like: 'Content-Encoding: gzip'", header) 167 } 168 option := &fs.HTTPOption{ 169 Key: strings.TrimSpace(parts[0]), 170 Value: strings.TrimSpace(parts[1]), 171 } 172 opts = append(opts, option) 173 } 174 return opts 175 } 176 177 // SetFlags converts any flags into config which weren't straight forward 178 func SetFlags(ci *fs.ConfigInfo) { 179 if dumpHeaders { 180 ci.Dump |= fs.DumpHeaders 181 fs.Logf(nil, "--dump-headers is obsolete - please use --dump headers instead") 182 } 183 if dumpBodies { 184 ci.Dump |= fs.DumpBodies 185 fs.Logf(nil, "--dump-bodies is obsolete - please use --dump bodies instead") 186 } 187 if ci.Dump != 0 && verbose < 2 && ci.LogLevel != fs.LogLevelDebug { 188 fs.Logf(nil, "Automatically setting -vv as --dump is enabled") 189 verbose = 2 190 } 191 192 if verbose >= 2 { 193 ci.LogLevel = fs.LogLevelDebug 194 } else if verbose >= 1 { 195 ci.LogLevel = fs.LogLevelInfo 196 } 197 if (ci.DryRun || ci.Interactive) && ci.StatsLogLevel > fs.LogLevelNotice { 198 ci.StatsLogLevel = fs.LogLevelNotice 199 } 200 if quiet { 201 if verbose > 0 { 202 log.Fatalf("Can't set -v and -q") 203 } 204 ci.LogLevel = fs.LogLevelError 205 } 206 logLevelFlag := pflag.Lookup("log-level") 207 if logLevelFlag != nil && logLevelFlag.Changed { 208 if verbose > 0 { 209 log.Fatalf("Can't set -v and --log-level") 210 } 211 if quiet { 212 log.Fatalf("Can't set -q and --log-level") 213 } 214 } 215 if ci.UseJSONLog { 216 logrus.AddHook(fsLog.NewCallerHook()) 217 logrus.SetFormatter(&logrus.JSONFormatter{ 218 TimestampFormat: "2006-01-02T15:04:05.999999-07:00", 219 }) 220 logrus.SetLevel(logrus.DebugLevel) 221 switch ci.LogLevel { 222 case fs.LogLevelEmergency, fs.LogLevelAlert: 223 logrus.SetLevel(logrus.PanicLevel) 224 case fs.LogLevelCritical: 225 logrus.SetLevel(logrus.FatalLevel) 226 case fs.LogLevelError: 227 logrus.SetLevel(logrus.ErrorLevel) 228 case fs.LogLevelWarning, fs.LogLevelNotice: 229 logrus.SetLevel(logrus.WarnLevel) 230 case fs.LogLevelInfo: 231 logrus.SetLevel(logrus.InfoLevel) 232 case fs.LogLevelDebug: 233 logrus.SetLevel(logrus.DebugLevel) 234 } 235 } 236 237 switch { 238 case deleteBefore && (deleteDuring || deleteAfter), 239 deleteDuring && deleteAfter: 240 log.Fatalf(`Only one of --delete-before, --delete-during or --delete-after can be used.`) 241 case deleteBefore: 242 ci.DeleteMode = fs.DeleteModeBefore 243 case deleteDuring: 244 ci.DeleteMode = fs.DeleteModeDuring 245 case deleteAfter: 246 ci.DeleteMode = fs.DeleteModeAfter 247 default: 248 ci.DeleteMode = fs.DeleteModeDefault 249 } 250 251 if len(ci.CompareDest) > 0 && len(ci.CopyDest) > 0 { 252 log.Fatalf(`Can't use --compare-dest with --copy-dest.`) 253 } 254 255 switch { 256 case len(ci.StatsOneLineDateFormat) > 0: 257 ci.StatsOneLineDate = true 258 ci.StatsOneLine = true 259 case ci.StatsOneLineDate: 260 ci.StatsOneLineDateFormat = "2006/01/02 15:04:05 - " 261 ci.StatsOneLine = true 262 } 263 264 if bindAddr != "" { 265 addrs, err := net.LookupIP(bindAddr) 266 if err != nil { 267 log.Fatalf("--bind: Failed to parse %q as IP address: %v", bindAddr, err) 268 } 269 if len(addrs) != 1 { 270 log.Fatalf("--bind: Expecting 1 IP address for %q but got %d", bindAddr, len(addrs)) 271 } 272 ci.BindAddr = addrs[0] 273 } 274 275 if disableFeatures != "" { 276 if disableFeatures == "help" { 277 log.Fatalf("Possible backend features are: %s\n", strings.Join(new(fs.Features).List(), ", ")) 278 } 279 ci.DisableFeatures = strings.Split(disableFeatures, ",") 280 } 281 282 if len(uploadHeaders) != 0 { 283 ci.UploadHeaders = ParseHeaders(uploadHeaders) 284 } 285 if len(downloadHeaders) != 0 { 286 ci.DownloadHeaders = ParseHeaders(downloadHeaders) 287 } 288 if len(headers) != 0 { 289 ci.Headers = ParseHeaders(headers) 290 } 291 if len(headers) != 0 { 292 ci.Headers = ParseHeaders(headers) 293 } 294 if len(metadataSet) != 0 { 295 ci.MetadataSet = make(fs.Metadata, len(metadataSet)) 296 for _, kv := range metadataSet { 297 equal := strings.IndexRune(kv, '=') 298 if equal < 0 { 299 log.Fatalf("Failed to parse '%s' as metadata key=value.", kv) 300 } 301 ci.MetadataSet[strings.ToLower(kv[:equal])] = kv[equal+1:] 302 } 303 fs.Debugf(nil, "MetadataUpload %v", ci.MetadataSet) 304 } 305 if len(dscp) != 0 { 306 if value, ok := parseDSCP(dscp); ok { 307 ci.TrafficClass = value << 2 308 } else { 309 log.Fatalf("--dscp: Invalid DSCP name: %v", dscp) 310 } 311 } 312 313 // Set path to configuration file 314 if err := config.SetConfigPath(configPath); err != nil { 315 log.Fatalf("--config: Failed to set %q as config path: %v", configPath, err) 316 } 317 318 // Set path to cache dir 319 if err := config.SetCacheDir(cacheDir); err != nil { 320 log.Fatalf("--cache-dir: Failed to set %q as cache dir: %v", cacheDir, err) 321 } 322 323 // Set path to temp dir 324 if err := config.SetTempDir(tempDir); err != nil { 325 log.Fatalf("--temp-dir: Failed to set %q as temp dir: %v", tempDir, err) 326 } 327 328 // Set whether multi-thread-streams was set 329 multiThreadStreamsFlag := pflag.Lookup("multi-thread-streams") 330 ci.MultiThreadSet = multiThreadStreamsFlag != nil && multiThreadStreamsFlag.Changed 331 332 if len(partialSuffix) > 16 { 333 log.Fatalf("--partial-suffix: Expecting suffix length not greater than %d but got %d", 16, len(partialSuffix)) 334 } 335 ci.PartialSuffix = partialSuffix 336 337 // Make sure some values are > 0 338 nonZero := func(pi *int) { 339 if *pi <= 0 { 340 *pi = 1 341 } 342 } 343 nonZero(&ci.LowLevelRetries) 344 nonZero(&ci.Transfers) 345 nonZero(&ci.Checkers) 346 } 347 348 // parseHeaders converts DSCP names to value 349 func parseDSCP(dscp string) (uint8, bool) { 350 if s, err := strconv.ParseUint(dscp, 10, 6); err == nil { 351 return uint8(s), true 352 } 353 dscp = strings.ToUpper(dscp) 354 switch dscp { 355 case "BE": 356 fallthrough 357 case "DF": 358 fallthrough 359 case "CS0": 360 return 0x00, true 361 case "CS1": 362 return 0x08, true 363 case "AF11": 364 return 0x0A, true 365 case "AF12": 366 return 0x0C, true 367 case "AF13": 368 return 0x0E, true 369 case "CS2": 370 return 0x10, true 371 case "AF21": 372 return 0x12, true 373 case "AF22": 374 return 0x14, true 375 case "AF23": 376 return 0x16, true 377 case "CS3": 378 return 0x18, true 379 case "AF31": 380 return 0x1A, true 381 case "AF32": 382 return 0x1C, true 383 case "AF33": 384 return 0x1E, true 385 case "CS4": 386 return 0x20, true 387 case "AF41": 388 return 0x22, true 389 case "AF42": 390 return 0x24, true 391 case "AF43": 392 return 0x26, true 393 case "CS5": 394 return 0x28, true 395 case "EF": 396 return 0x2E, true 397 case "CS6": 398 return 0x30, true 399 case "LE": 400 return 0x01, true 401 default: 402 return 0, false 403 } 404 }