1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/command_line.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,424 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/command_line.h" 1.9 + 1.10 +#include <algorithm> 1.11 +#include <ostream> 1.12 + 1.13 +#include "base/basictypes.h" 1.14 +#include "base/files/file_path.h" 1.15 +#include "base/logging.h" 1.16 +#include "base/strings/string_split.h" 1.17 +#include "base/strings/string_util.h" 1.18 +#include "base/strings/utf_string_conversions.h" 1.19 +#include "build/build_config.h" 1.20 + 1.21 +#if defined(OS_WIN) 1.22 +#include <windows.h> 1.23 +#include <shellapi.h> 1.24 +#endif 1.25 + 1.26 +using base::FilePath; 1.27 + 1.28 +CommandLine* CommandLine::current_process_commandline_ = NULL; 1.29 + 1.30 +namespace { 1.31 +const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--"); 1.32 +const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("="); 1.33 +// Since we use a lazy match, make sure that longer versions (like "--") are 1.34 +// listed before shorter versions (like "-") of similar prefixes. 1.35 +#if defined(OS_WIN) 1.36 +const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; 1.37 +#elif defined(OS_POSIX) 1.38 +// Unixes don't use slash as a switch. 1.39 +const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"}; 1.40 +#endif 1.41 + 1.42 +size_t GetSwitchPrefixLength(const CommandLine::StringType& string) { 1.43 + for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { 1.44 + CommandLine::StringType prefix(kSwitchPrefixes[i]); 1.45 + if (string.compare(0, prefix.length(), prefix) == 0) 1.46 + return prefix.length(); 1.47 + } 1.48 + return 0; 1.49 +} 1.50 + 1.51 +// Fills in |switch_string| and |switch_value| if |string| is a switch. 1.52 +// This will preserve the input switch prefix in the output |switch_string|. 1.53 +bool IsSwitch(const CommandLine::StringType& string, 1.54 + CommandLine::StringType* switch_string, 1.55 + CommandLine::StringType* switch_value) { 1.56 + switch_string->clear(); 1.57 + switch_value->clear(); 1.58 + size_t prefix_length = GetSwitchPrefixLength(string); 1.59 + if (prefix_length == 0 || prefix_length == string.length()) 1.60 + return false; 1.61 + 1.62 + const size_t equals_position = string.find(kSwitchValueSeparator); 1.63 + *switch_string = string.substr(0, equals_position); 1.64 + if (equals_position != CommandLine::StringType::npos) 1.65 + *switch_value = string.substr(equals_position + 1); 1.66 + return true; 1.67 +} 1.68 + 1.69 +// Append switches and arguments, keeping switches before arguments. 1.70 +void AppendSwitchesAndArguments(CommandLine& command_line, 1.71 + const CommandLine::StringVector& argv) { 1.72 + bool parse_switches = true; 1.73 + for (size_t i = 1; i < argv.size(); ++i) { 1.74 + CommandLine::StringType arg = argv[i]; 1.75 + TrimWhitespace(arg, TRIM_ALL, &arg); 1.76 + 1.77 + CommandLine::StringType switch_string; 1.78 + CommandLine::StringType switch_value; 1.79 + parse_switches &= (arg != kSwitchTerminator); 1.80 + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { 1.81 +#if defined(OS_WIN) 1.82 + command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value); 1.83 +#elif defined(OS_POSIX) 1.84 + command_line.AppendSwitchNative(switch_string, switch_value); 1.85 +#endif 1.86 + } else { 1.87 + command_line.AppendArgNative(arg); 1.88 + } 1.89 + } 1.90 +} 1.91 + 1.92 +// Lowercase switches for backwards compatiblity *on Windows*. 1.93 +std::string LowerASCIIOnWindows(const std::string& string) { 1.94 +#if defined(OS_WIN) 1.95 + return StringToLowerASCII(string); 1.96 +#elif defined(OS_POSIX) 1.97 + return string; 1.98 +#endif 1.99 +} 1.100 + 1.101 + 1.102 +#if defined(OS_WIN) 1.103 +// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. 1.104 +std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) { 1.105 + // We follow the quoting rules of CommandLineToArgvW. 1.106 + // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx 1.107 + if (arg.find_first_of(L" \\\"") == std::wstring::npos) { 1.108 + // No quoting necessary. 1.109 + return arg; 1.110 + } 1.111 + 1.112 + std::wstring out; 1.113 + out.push_back(L'"'); 1.114 + for (size_t i = 0; i < arg.size(); ++i) { 1.115 + if (arg[i] == '\\') { 1.116 + // Find the extent of this run of backslashes. 1.117 + size_t start = i, end = start + 1; 1.118 + for (; end < arg.size() && arg[end] == '\\'; ++end) 1.119 + /* empty */; 1.120 + size_t backslash_count = end - start; 1.121 + 1.122 + // Backslashes are escapes only if the run is followed by a double quote. 1.123 + // Since we also will end the string with a double quote, we escape for 1.124 + // either a double quote or the end of the string. 1.125 + if (end == arg.size() || arg[end] == '"') { 1.126 + // To quote, we need to output 2x as many backslashes. 1.127 + backslash_count *= 2; 1.128 + } 1.129 + for (size_t j = 0; j < backslash_count; ++j) 1.130 + out.push_back('\\'); 1.131 + 1.132 + // Advance i to one before the end to balance i++ in loop. 1.133 + i = end - 1; 1.134 + } else if (arg[i] == '"') { 1.135 + out.push_back('\\'); 1.136 + out.push_back('"'); 1.137 + } else { 1.138 + out.push_back(arg[i]); 1.139 + } 1.140 + } 1.141 + out.push_back('"'); 1.142 + 1.143 + return out; 1.144 +} 1.145 +#endif 1.146 + 1.147 +} // namespace 1.148 + 1.149 +CommandLine::CommandLine(NoProgram no_program) 1.150 + : argv_(1), 1.151 + begin_args_(1) { 1.152 +} 1.153 + 1.154 +CommandLine::CommandLine(const FilePath& program) 1.155 + : argv_(1), 1.156 + begin_args_(1) { 1.157 + SetProgram(program); 1.158 +} 1.159 + 1.160 +CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) 1.161 + : argv_(1), 1.162 + begin_args_(1) { 1.163 + InitFromArgv(argc, argv); 1.164 +} 1.165 + 1.166 +CommandLine::CommandLine(const StringVector& argv) 1.167 + : argv_(1), 1.168 + begin_args_(1) { 1.169 + InitFromArgv(argv); 1.170 +} 1.171 + 1.172 +CommandLine::~CommandLine() { 1.173 +} 1.174 + 1.175 +// static 1.176 +bool CommandLine::Init(int argc, const char* const* argv) { 1.177 + if (current_process_commandline_) { 1.178 + // If this is intentional, Reset() must be called first. If we are using 1.179 + // the shared build mode, we have to share a single object across multiple 1.180 + // shared libraries. 1.181 + return false; 1.182 + } 1.183 + 1.184 + current_process_commandline_ = new CommandLine(NO_PROGRAM); 1.185 +#if defined(OS_WIN) 1.186 + current_process_commandline_->ParseFromString(::GetCommandLineW()); 1.187 +#elif defined(OS_POSIX) 1.188 + current_process_commandline_->InitFromArgv(argc, argv); 1.189 +#endif 1.190 + 1.191 + return true; 1.192 +} 1.193 + 1.194 +// static 1.195 +void CommandLine::Reset() { 1.196 + DCHECK(current_process_commandline_); 1.197 + delete current_process_commandline_; 1.198 + current_process_commandline_ = NULL; 1.199 +} 1.200 + 1.201 +// static 1.202 +CommandLine* CommandLine::ForCurrentProcess() { 1.203 + DCHECK(current_process_commandline_); 1.204 + return current_process_commandline_; 1.205 +} 1.206 + 1.207 +// static 1.208 +bool CommandLine::InitializedForCurrentProcess() { 1.209 + return !!current_process_commandline_; 1.210 +} 1.211 + 1.212 +#if defined(OS_WIN) 1.213 +// static 1.214 +CommandLine CommandLine::FromString(const std::wstring& command_line) { 1.215 + CommandLine cmd(NO_PROGRAM); 1.216 + cmd.ParseFromString(command_line); 1.217 + return cmd; 1.218 +} 1.219 +#endif 1.220 + 1.221 +void CommandLine::InitFromArgv(int argc, 1.222 + const CommandLine::CharType* const* argv) { 1.223 + StringVector new_argv; 1.224 + for (int i = 0; i < argc; ++i) 1.225 + new_argv.push_back(argv[i]); 1.226 + InitFromArgv(new_argv); 1.227 +} 1.228 + 1.229 +void CommandLine::InitFromArgv(const StringVector& argv) { 1.230 + argv_ = StringVector(1); 1.231 + switches_.clear(); 1.232 + begin_args_ = 1; 1.233 + SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); 1.234 + AppendSwitchesAndArguments(*this, argv); 1.235 +} 1.236 + 1.237 +CommandLine::StringType CommandLine::GetCommandLineString() const { 1.238 + StringType string(argv_[0]); 1.239 +#if defined(OS_WIN) 1.240 + string = QuoteForCommandLineToArgvW(string); 1.241 +#endif 1.242 + StringType params(GetArgumentsString()); 1.243 + if (!params.empty()) { 1.244 + string.append(StringType(FILE_PATH_LITERAL(" "))); 1.245 + string.append(params); 1.246 + } 1.247 + return string; 1.248 +} 1.249 + 1.250 +CommandLine::StringType CommandLine::GetArgumentsString() const { 1.251 + StringType params; 1.252 + // Append switches and arguments. 1.253 + bool parse_switches = true; 1.254 + for (size_t i = 1; i < argv_.size(); ++i) { 1.255 + StringType arg = argv_[i]; 1.256 + StringType switch_string; 1.257 + StringType switch_value; 1.258 + parse_switches &= arg != kSwitchTerminator; 1.259 + if (i > 1) 1.260 + params.append(StringType(FILE_PATH_LITERAL(" "))); 1.261 + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { 1.262 + params.append(switch_string); 1.263 + if (!switch_value.empty()) { 1.264 +#if defined(OS_WIN) 1.265 + switch_value = QuoteForCommandLineToArgvW(switch_value); 1.266 +#endif 1.267 + params.append(kSwitchValueSeparator + switch_value); 1.268 + } 1.269 + } 1.270 + else { 1.271 +#if defined(OS_WIN) 1.272 + arg = QuoteForCommandLineToArgvW(arg); 1.273 +#endif 1.274 + params.append(arg); 1.275 + } 1.276 + } 1.277 + return params; 1.278 +} 1.279 + 1.280 +FilePath CommandLine::GetProgram() const { 1.281 + return FilePath(argv_[0]); 1.282 +} 1.283 + 1.284 +void CommandLine::SetProgram(const FilePath& program) { 1.285 + TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); 1.286 +} 1.287 + 1.288 +bool CommandLine::HasSwitch(const std::string& switch_string) const { 1.289 + return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end(); 1.290 +} 1.291 + 1.292 +std::string CommandLine::GetSwitchValueASCII( 1.293 + const std::string& switch_string) const { 1.294 + StringType value = GetSwitchValueNative(switch_string); 1.295 + if (!IsStringASCII(value)) { 1.296 + DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII."; 1.297 + return std::string(); 1.298 + } 1.299 +#if defined(OS_WIN) 1.300 + return WideToASCII(value); 1.301 +#else 1.302 + return value; 1.303 +#endif 1.304 +} 1.305 + 1.306 +FilePath CommandLine::GetSwitchValuePath( 1.307 + const std::string& switch_string) const { 1.308 + return FilePath(GetSwitchValueNative(switch_string)); 1.309 +} 1.310 + 1.311 +CommandLine::StringType CommandLine::GetSwitchValueNative( 1.312 + const std::string& switch_string) const { 1.313 + SwitchMap::const_iterator result = switches_.end(); 1.314 + result = switches_.find(LowerASCIIOnWindows(switch_string)); 1.315 + return result == switches_.end() ? StringType() : result->second; 1.316 +} 1.317 + 1.318 +void CommandLine::AppendSwitch(const std::string& switch_string) { 1.319 + AppendSwitchNative(switch_string, StringType()); 1.320 +} 1.321 + 1.322 +void CommandLine::AppendSwitchPath(const std::string& switch_string, 1.323 + const FilePath& path) { 1.324 + AppendSwitchNative(switch_string, path.value()); 1.325 +} 1.326 + 1.327 +void CommandLine::AppendSwitchNative(const std::string& switch_string, 1.328 + const CommandLine::StringType& value) { 1.329 + std::string switch_key(LowerASCIIOnWindows(switch_string)); 1.330 +#if defined(OS_WIN) 1.331 + StringType combined_switch_string(ASCIIToWide(switch_key)); 1.332 +#elif defined(OS_POSIX) 1.333 + StringType combined_switch_string(switch_string); 1.334 +#endif 1.335 + size_t prefix_length = GetSwitchPrefixLength(combined_switch_string); 1.336 + switches_[switch_key.substr(prefix_length)] = value; 1.337 + // Preserve existing switch prefixes in |argv_|; only append one if necessary. 1.338 + if (prefix_length == 0) 1.339 + combined_switch_string = kSwitchPrefixes[0] + combined_switch_string; 1.340 + if (!value.empty()) 1.341 + combined_switch_string += kSwitchValueSeparator + value; 1.342 + // Append the switch and update the switches/arguments divider |begin_args_|. 1.343 + argv_.insert(argv_.begin() + begin_args_++, combined_switch_string); 1.344 +} 1.345 + 1.346 +void CommandLine::AppendSwitchASCII(const std::string& switch_string, 1.347 + const std::string& value_string) { 1.348 +#if defined(OS_WIN) 1.349 + AppendSwitchNative(switch_string, ASCIIToWide(value_string)); 1.350 +#elif defined(OS_POSIX) 1.351 + AppendSwitchNative(switch_string, value_string); 1.352 +#endif 1.353 +} 1.354 + 1.355 +void CommandLine::CopySwitchesFrom(const CommandLine& source, 1.356 + const char* const switches[], 1.357 + size_t count) { 1.358 + for (size_t i = 0; i < count; ++i) { 1.359 + if (source.HasSwitch(switches[i])) 1.360 + AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i])); 1.361 + } 1.362 +} 1.363 + 1.364 +CommandLine::StringVector CommandLine::GetArgs() const { 1.365 + // Gather all arguments after the last switch (may include kSwitchTerminator). 1.366 + StringVector args(argv_.begin() + begin_args_, argv_.end()); 1.367 + // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?) 1.368 + StringVector::iterator switch_terminator = 1.369 + std::find(args.begin(), args.end(), kSwitchTerminator); 1.370 + if (switch_terminator != args.end()) 1.371 + args.erase(switch_terminator); 1.372 + return args; 1.373 +} 1.374 + 1.375 +void CommandLine::AppendArg(const std::string& value) { 1.376 +#if defined(OS_WIN) 1.377 + DCHECK(IsStringUTF8(value)); 1.378 + AppendArgNative(UTF8ToWide(value)); 1.379 +#elif defined(OS_POSIX) 1.380 + AppendArgNative(value); 1.381 +#endif 1.382 +} 1.383 + 1.384 +void CommandLine::AppendArgPath(const FilePath& path) { 1.385 + AppendArgNative(path.value()); 1.386 +} 1.387 + 1.388 +void CommandLine::AppendArgNative(const CommandLine::StringType& value) { 1.389 + argv_.push_back(value); 1.390 +} 1.391 + 1.392 +void CommandLine::AppendArguments(const CommandLine& other, 1.393 + bool include_program) { 1.394 + if (include_program) 1.395 + SetProgram(other.GetProgram()); 1.396 + AppendSwitchesAndArguments(*this, other.argv()); 1.397 +} 1.398 + 1.399 +void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { 1.400 + if (wrapper.empty()) 1.401 + return; 1.402 + // The wrapper may have embedded arguments (like "gdb --args"). In this case, 1.403 + // we don't pretend to do anything fancy, we just split on spaces. 1.404 + StringVector wrapper_argv; 1.405 + base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv); 1.406 + // Prepend the wrapper and update the switches/arguments |begin_args_|. 1.407 + argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end()); 1.408 + begin_args_ += wrapper_argv.size(); 1.409 +} 1.410 + 1.411 +#if defined(OS_WIN) 1.412 +void CommandLine::ParseFromString(const std::wstring& command_line) { 1.413 + std::wstring command_line_string; 1.414 + TrimWhitespace(command_line, TRIM_ALL, &command_line_string); 1.415 + if (command_line_string.empty()) 1.416 + return; 1.417 + 1.418 + int num_args = 0; 1.419 + wchar_t** args = NULL; 1.420 + args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args); 1.421 + 1.422 + DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " 1.423 + << command_line; 1.424 + InitFromArgv(num_args, args); 1.425 + LocalFree(args); 1.426 +} 1.427 +#endif