1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/trace/common/service_util.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "syzygy/common/com_utils.h"
19 :
20 : namespace trace {
21 : namespace common {
22 :
23 : bool AcquireMutex(const base::StringPiece16& mutex_name,
24 E : base::win::ScopedHandle* mutex) {
25 E : DCHECK(mutex != NULL);
26 E : DCHECK(!mutex->IsValid());
27 :
28 E : std::wstring name(mutex_name.begin(), mutex_name.end());
29 E : const wchar_t* name_ptr = name.empty() ? NULL : name.c_str();
30 :
31 E : base::win::ScopedHandle tmp_mutex(::CreateMutex(NULL, FALSE, name_ptr));
32 E : if (!tmp_mutex.IsValid()) {
33 i : DWORD error = ::GetLastError();
34 i : LOG(ERROR) << "Failed to create named mutex: " << ::common::LogWe(error)
35 : << ".";
36 i : return false;
37 : }
38 E : const DWORD kOneSecondInMs = 1000;
39 :
40 E : switch (::WaitForSingleObject(tmp_mutex.Get(), kOneSecondInMs)) {
41 : case WAIT_ABANDONED:
42 i : LOG(WARNING) << "Orphaned named mutex found!";
43 : // Fall through...
44 :
45 : case WAIT_OBJECT_0:
46 E : VLOG(1) << "Named mutex acquired.";
47 E : mutex->Set(tmp_mutex.Take());
48 E : return true;
49 :
50 : case WAIT_TIMEOUT:
51 E : LOG(ERROR) << "A synonymous named mutex already exists.";
52 E : break;
53 :
54 : default: {
55 i : DWORD error = ::GetLastError();
56 i : LOG(ERROR) << "Failed to acquire mutex: " << ::common::LogWe(error)
57 : << ".";
58 : break;
59 : }
60 : }
61 E : return false;
62 E : }
63 :
64 : bool InitEvent(const base::StringPiece16& event_name,
65 E : base::win::ScopedHandle* handle) {
66 E : DCHECK(handle != NULL);
67 E : DCHECK(!handle->IsValid());
68 :
69 : // StringPieces aren't guaranteed to be NULL terminated, so we make a copy.
70 E : std::wstring name(event_name.begin(), event_name.end());
71 E : const wchar_t* name_ptr = name.empty() ? NULL : name.c_str();
72 :
73 E : handle->Set(::CreateEvent(NULL, TRUE, FALSE, name_ptr));
74 E : if (!handle->IsValid())
75 i : return false;
76 E : return true;
77 E : }
78 :
79 E : ScopedConsoleCtrlHandler::ScopedConsoleCtrlHandler() : handler_(NULL) {
80 E : }
81 :
82 E : ScopedConsoleCtrlHandler::~ScopedConsoleCtrlHandler() {
83 E : if (handler_ != NULL) {
84 E : ignore_result(::SetConsoleCtrlHandler(handler_, FALSE));
85 E : handler_ = NULL;
86 : }
87 E : }
88 :
89 E : bool ScopedConsoleCtrlHandler::Init(PHANDLER_ROUTINE handler) {
90 E : DCHECK(handler != NULL);
91 E : DCHECK(handler_ == NULL);
92 :
93 E : if (!::SetConsoleCtrlHandler(handler, TRUE)) {
94 i : DWORD err = ::GetLastError();
95 i : LOG(ERROR) << "Failed to register console control handler: "
96 : << ::common::LogWe(err) << ".";
97 i : return false;
98 : }
99 :
100 E : handler_ = handler;
101 E : return true;
102 E : }
103 :
104 : bool SplitCommandLine(const base::CommandLine* orig_command_line,
105 : base::CommandLine* logger_command_line,
106 E : std::unique_ptr<base::CommandLine>* app_command_line) {
107 E : DCHECK(orig_command_line != NULL);
108 E : DCHECK(!orig_command_line->argv().empty());
109 E : DCHECK(logger_command_line != NULL);
110 E : DCHECK(app_command_line != NULL);
111 :
112 : // Copy the initial parts of the command-line, up to and including the
113 : // first non-switch argument (which should be the "action"), into a
114 : // string vector for the logger command line.
115 E : base::CommandLine::StringVector logger_argv;
116 : base::CommandLine::StringVector::const_iterator it =
117 E : orig_command_line->argv().begin();
118 E : logger_argv.push_back(*(it++)); // Always copy the program.
119 E : for (; it != orig_command_line->argv().end(); ++it) {
120 E : logger_argv.push_back(*it);
121 E : if ((*it)[0] != L'-') {
122 E : ++it;
123 E : break;
124 : }
125 E : }
126 :
127 : // Strip out the (optional) sentinel which marks the split between the
128 : // two command-lines.
129 E : if (it != orig_command_line->argv().end() && *it == L"--")
130 E : ++it;
131 :
132 : // Copy the rest of the command-line arguments into a string vector for the
133 : // app command line.
134 E : base::CommandLine::StringVector app_argv;
135 E : for (; it != orig_command_line->argv().end(); ++it) {
136 E : app_argv.push_back(*it);
137 E : }
138 :
139 : // Initialize logger command lines with the new arguments.
140 E : logger_command_line->InitFromArgv(logger_argv);
141 :
142 : // Initialize application command lines with the new arguments.
143 E : if (!app_argv.empty()) {
144 : // Avoid switches processing in application commandLine parsing.
145 : // Otherwise, we break command like:
146 : // agent_logger.exe START -- <app> -d 1 -c 2.
147 : // We should not re-order <app> parameters.
148 E : app_command_line->reset(new base::CommandLine(base::FilePath(app_argv[0])));
149 E : for (size_t arg = 1; arg < app_argv.size(); ++arg)
150 E : app_command_line->get()->AppendArgNative(app_argv[arg]);
151 : }
152 :
153 E : return true;
154 E : }
155 :
156 : } // namespace common
157 : } // namespace trace
|