blob: a874ec059435120b574e1eeae2b48711ed42e7f5 [file] [log] [blame]
Chris Sosa45d9f102014-03-24 11:18:54 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenko7a1dc0b2014-08-15 11:45:46 -07005#include <memory>
Chris Sosa45d9f102014-03-24 11:18:54 -07006#include <string>
Christopher Wiley48e37282014-05-08 14:43:58 -07007#include <sysexits.h>
Chris Sosa45d9f102014-03-24 11:18:54 -07008
Christopher Wiley2d0369e2015-03-03 12:57:54 -08009#include <base/cancelable_callback.h>
Chris Sosaababc5c2014-04-09 15:42:01 -070010#include <base/command_line.h>
Alex Vakulenko61ad4db2015-01-20 10:50:04 -080011#include <base/json/json_reader.h>
Chris Sosa45d9f102014-03-24 11:18:54 -070012#include <base/logging.h>
Christopher Wiley48e37282014-05-08 14:43:58 -070013#include <base/memory/ref_counted.h>
Christopher Wiley2d0369e2015-03-03 12:57:54 -080014#include <base/memory/weak_ptr.h>
Alex Vakulenko420e49f2014-12-01 17:53:27 -080015#include <base/strings/stringprintf.h>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070016#include <base/values.h>
Alex Vakulenkoa9044342014-08-23 19:31:27 -070017#include <chromeos/any.h>
Alex Vakulenko420e49f2014-12-01 17:53:27 -080018#include <chromeos/daemons/dbus_daemon.h>
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070019#include <chromeos/data_encoding.h>
Alex Vakulenko63cd5fa2014-08-27 08:04:22 -070020#include <chromeos/dbus/data_serialization.h>
Alex Vakulenko07216fe2014-09-19 15:31:09 -070021#include <chromeos/dbus/dbus_method_invoker.h>
22#include <chromeos/errors/error.h>
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -070023#include <chromeos/strings/string_utils.h>
Alex Vakulenko576c9792014-09-22 16:49:45 -070024#include <chromeos/variant_dictionary.h>
Chris Sosa45d9f102014-03-24 11:18:54 -070025#include <dbus/bus.h>
Christopher Wileya4915c42014-03-27 14:45:37 -070026#include <dbus/message.h>
Christopher Wiley48e37282014-05-08 14:43:58 -070027#include <dbus/object_proxy.h>
Christopher Wileyadb901d2014-05-07 09:58:45 -070028#include <dbus/object_manager.h>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070029#include <dbus/values_util.h>
Chris Sosa45d9f102014-03-24 11:18:54 -070030
Alex Vakulenko2348e422014-11-21 08:57:57 -080031#include "buffet/dbus-proxies.h"
Chris Sosa45d9f102014-03-24 11:18:54 -070032
Alex Vakulenko420e49f2014-12-01 17:53:27 -080033using chromeos::Error;
Alex Vakulenko07216fe2014-09-19 15:31:09 -070034using chromeos::ErrorPtr;
Christopher Wiley2d0369e2015-03-03 12:57:54 -080035using org::chromium::Buffet::ManagerProxy;
Alex Vakulenko07216fe2014-09-19 15:31:09 -070036
Chris Sosa45d9f102014-03-24 11:18:54 -070037namespace {
38
Christopher Wileya4915c42014-03-27 14:45:37 -070039void usage() {
Alex Vakulenko420e49f2014-12-01 17:53:27 -080040 printf(R"(Possible commands:
41 - TestMethod <message>
Alex Vakulenko420e49f2014-12-01 17:53:27 -080042 - CheckDeviceRegistered
43 - GetDeviceInfo
44 - RegisterDevice param1=val1&param2=val2...
45 - AddCommand '{"name":"command_name","parameters":{}}'
Nathan Bullocked53c662015-01-07 09:57:42 -050046 - UpdateState prop_name prop_value
Alex Vakulenko61ad4db2015-01-20 10:50:04 -080047 - GetState
Alex Vakulenko420e49f2014-12-01 17:53:27 -080048 - PendingCommands
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -070049 - SetCommandVisibility pkg1.cmd1[,pkg2.cm2,...] [all|cloud|local|none]
Alex Vakulenko420e49f2014-12-01 17:53:27 -080050)");
Christopher Wileya4915c42014-03-27 14:45:37 -070051}
52
Alex Vakulenko61ad4db2015-01-20 10:50:04 -080053// Helpers for JsonToAny().
54template<typename T>
55chromeos::Any GetJsonValue(const base::Value& json,
56 bool(base::Value::*fnc)(T*) const) {
57 T val;
58 CHECK((json.*fnc)(&val));
59 return val;
60}
61
62template<typename T>
63chromeos::Any GetJsonList(const base::ListValue& list); // Prototype.
64
65// Converts a JSON value into an Any so it can be sent over D-Bus using
66// UpdateState D-Bus method from Buffet.
67chromeos::Any JsonToAny(const base::Value& json) {
68 chromeos::Any prop_value;
69 switch (json.GetType()) {
70 case base::Value::TYPE_NULL:
71 prop_value = nullptr;
72 break;
73 case base::Value::TYPE_BOOLEAN:
74 prop_value = GetJsonValue<bool>(json, &base::Value::GetAsBoolean);
75 break;
76 case base::Value::TYPE_INTEGER:
77 prop_value = GetJsonValue<int>(json, &base::Value::GetAsInteger);
78 break;
79 case base::Value::TYPE_DOUBLE:
80 prop_value = GetJsonValue<double>(json, &base::Value::GetAsDouble);
81 break;
82 case base::Value::TYPE_STRING:
83 prop_value = GetJsonValue<std::string>(json, &base::Value::GetAsString);
84 break;
85 case base::Value::TYPE_BINARY:
86 LOG(FATAL) << "Binary values should not happen";
87 break;
88 case base::Value::TYPE_DICTIONARY: {
89 const base::DictionaryValue* dict = nullptr; // Still owned by |json|.
90 CHECK(json.GetAsDictionary(&dict));
91 chromeos::VariantDictionary var_dict;
92 base::DictionaryValue::Iterator it(*dict);
93 while (!it.IsAtEnd()) {
94 var_dict.emplace(it.key(), JsonToAny(it.value()));
95 it.Advance();
96 }
97 prop_value = var_dict;
98 break;
99 }
100 case base::Value::TYPE_LIST: {
101 const base::ListValue* list = nullptr; // Still owned by |json|.
102 CHECK(json.GetAsList(&list));
103 CHECK(!list->empty()) << "Unable to deduce the type of list elements.";
104 switch ((*list->begin())->GetType()) {
105 case base::Value::TYPE_BOOLEAN:
106 prop_value = GetJsonList<bool>(*list);
107 break;
108 case base::Value::TYPE_INTEGER:
109 prop_value = GetJsonList<int>(*list);
110 break;
111 case base::Value::TYPE_DOUBLE:
112 prop_value = GetJsonList<double>(*list);
113 break;
114 case base::Value::TYPE_STRING:
115 prop_value = GetJsonList<std::string>(*list);
116 break;
117 case base::Value::TYPE_DICTIONARY:
118 prop_value = GetJsonList<chromeos::VariantDictionary>(*list);
119 break;
120 default:
121 LOG(FATAL) << "Unsupported JSON value type for list element: "
122 << (*list->begin())->GetType();
123 }
124 break;
125 }
126 default:
127 LOG(FATAL) << "Unexpected JSON value type: " << json.GetType();
128 break;
129 }
130 return prop_value;
131}
132
133template<typename T>
134chromeos::Any GetJsonList(const base::ListValue& list) {
135 std::vector<T> val;
136 val.reserve(list.GetSize());
137 for (const base::Value* v : list)
138 val.push_back(JsonToAny(*v).Get<T>());
139 return val;
140}
141
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800142class Daemon : public chromeos::DBusDaemon {
Christopher Wiley48e37282014-05-08 14:43:58 -0700143 public:
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800144 Daemon() = default;
145
146 protected:
147 int OnInit() override {
148 int return_code = chromeos::DBusDaemon::OnInit();
149 if (return_code != EX_OK)
150 return return_code;
151
152 object_manager_.reset(new org::chromium::Buffet::ObjectManagerProxy{bus_});
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800153 return_code = ScheduleActions();
154 if (return_code == EX_USAGE) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800155 usage();
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800156 }
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800157 return return_code;
Christopher Wileya4915c42014-03-27 14:45:37 -0700158 }
159
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800160 void OnShutdown(int* return_code) override {
161 if (*return_code == EX_OK)
162 *return_code = exit_code_;
163 }
Alex Vakulenko7a1dc0b2014-08-15 11:45:46 -0700164
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800165 private:
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800166 int ScheduleActions() {
Alex Vakulenkofc575a42015-04-02 14:31:10 -0700167 auto args = base::CommandLine::ForCurrentProcess()->GetArgs();
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800168
169 // Pop the command off of the args list.
170 std::string command = args.front();
171 args.erase(args.begin());
172 base::Callback<void(ManagerProxy*)> job;
173 if (command.compare("TestMethod") == 0) {
174 if (!args.empty() && !CheckArgs(command, args, 1))
175 return EX_USAGE;
176 std::string message;
177 if (!args.empty())
178 message = args.back();
179 job = base::Bind(&Daemon::CallTestMethod, weak_factory_.GetWeakPtr(),
180 message);
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800181 } else if (command.compare("CheckDeviceRegistered") == 0 ||
182 command.compare("cr") == 0) {
183 if (!CheckArgs(command, args, 0))
184 return EX_USAGE;
185 job = base::Bind(&Daemon::CallCheckDeviceRegistered,
186 weak_factory_.GetWeakPtr());
187 } else if (command.compare("GetDeviceInfo") == 0 ||
188 command.compare("di") == 0) {
189 if (!CheckArgs(command, args, 0))
190 return EX_USAGE;
191 job = base::Bind(&Daemon::CallGetDeviceInfo,
192 weak_factory_.GetWeakPtr());
193 } else if (command.compare("RegisterDevice") == 0 ||
194 command.compare("rd") == 0) {
195 if (!args.empty() && !CheckArgs(command, args, 1))
196 return EX_USAGE;
197 std::string dict;
198 if (!args.empty())
199 dict = args.back();
200 job = base::Bind(&Daemon::CallRegisterDevice,
201 weak_factory_.GetWeakPtr(), dict);
202 } else if (command.compare("UpdateState") == 0 ||
203 command.compare("us") == 0) {
204 if (!CheckArgs(command, args, 2))
205 return EX_USAGE;
206 job = base::Bind(&Daemon::CallUpdateState, weak_factory_.GetWeakPtr(),
207 args.front(), args.back());
208 } else if (command.compare("GetState") == 0 ||
209 command.compare("gs") == 0) {
210 if (!CheckArgs(command, args, 0))
211 return EX_USAGE;
212 job = base::Bind(&Daemon::CallGetState, weak_factory_.GetWeakPtr());
213 } else if (command.compare("AddCommand") == 0 ||
214 command.compare("ac") == 0) {
215 if (!CheckArgs(command, args, 1))
216 return EX_USAGE;
217 job = base::Bind(&Daemon::CallAddCommand, weak_factory_.GetWeakPtr(),
218 args.back());
219 } else if (command.compare("PendingCommands") == 0 ||
220 command.compare("pc") == 0) {
221 if (!CheckArgs(command, args, 0))
222 return EX_USAGE;
223 // CallGetPendingCommands relies on ObjectManager but it is being
224 // initialized asynchronously without a way to get a callback when
225 // it is ready to be used. So, just wait a bit before calling its
226 // methods.
227 base::MessageLoop::current()->PostDelayedTask(
228 FROM_HERE,
229 base::Bind(&Daemon::CallGetPendingCommands,
230 weak_factory_.GetWeakPtr()),
231 base::TimeDelta::FromMilliseconds(100));
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -0700232 } else if (command.compare("SetCommandVisibility") == 0 ||
233 command.compare("cv") == 0) {
234 if (!CheckArgs(command, args, 2))
235 return EX_USAGE;
236 job = base::Bind(&Daemon::CallSetCommandVisibility,
237 weak_factory_.GetWeakPtr(), args.front(), args.back());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800238 } else {
239 fprintf(stderr, "Unknown command: '%s'\n", command.c_str());
240 return EX_USAGE;
241 }
242 if (!job.is_null())
243 object_manager_->SetManagerAddedCallback(job);
244 timeout_task_.Reset(
245 base::Bind(&Daemon::OnJobTimeout, weak_factory_.GetWeakPtr()));
246 base::MessageLoop::current()->PostDelayedTask(
247 FROM_HERE,
248 timeout_task_.callback(),
249 base::TimeDelta::FromSeconds(10));
250
251 return EX_OK;
252 }
253
254 void OnJobComplete() {
255 timeout_task_.Cancel();
256 Quit();
257 }
258
259 void OnJobTimeout() {
260 fprintf(stderr, "Timed out before completing request.");
261 Quit();
262 }
263
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800264 void ReportError(Error* error) {
265 fprintf(stderr, "Failed to receive a response: %s\n",
266 error->GetMessage().c_str());
267 exit_code_ = EX_UNAVAILABLE;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800268 OnJobComplete();
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800269 }
270
271 bool CheckArgs(const std::string& command,
272 const std::vector<std::string>& args,
273 size_t expected_arg_count) {
274 if (args.size() == expected_arg_count)
275 return true;
276 fprintf(stderr, "Invalid number of arguments for command '%s'\n",
277 command.c_str());
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800278 return false;
279 }
280
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800281 void CallTestMethod(const std::string& message, ManagerProxy* manager_proxy) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700282 ErrorPtr error;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700283 std::string response_message;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800284 if (!manager_proxy->TestMethod(message, &response_message, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800285 return ReportError(error.get());
Christopher Wiley48e37282014-05-08 14:43:58 -0700286 }
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800287 printf("Received a response: %s\n", response_message.c_str());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800288 OnJobComplete();
Christopher Wiley48e37282014-05-08 14:43:58 -0700289 }
290
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800291 void CallCheckDeviceRegistered(ManagerProxy* manager_proxy) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700292 ErrorPtr error;
Christopher Wiley48e37282014-05-08 14:43:58 -0700293 std::string device_id;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800294 if (!manager_proxy->CheckDeviceRegistered(&device_id, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800295 return ReportError(error.get());
Christopher Wiley48e37282014-05-08 14:43:58 -0700296 }
297
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800298 printf("Device ID: %s\n",
299 device_id.empty() ? "<unregistered>" : device_id.c_str());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800300 OnJobComplete();
Christopher Wiley48e37282014-05-08 14:43:58 -0700301 }
302
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800303 void CallGetDeviceInfo(ManagerProxy* manager_proxy) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700304 ErrorPtr error;
Christopher Wiley48e37282014-05-08 14:43:58 -0700305 std::string device_info;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800306 if (!manager_proxy->GetDeviceInfo(&device_info, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800307 return ReportError(error.get());
Christopher Wiley48e37282014-05-08 14:43:58 -0700308 }
309
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400310 printf("%s\n", device_info.c_str());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800311 OnJobComplete();
Christopher Wiley48e37282014-05-08 14:43:58 -0700312 }
313
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800314 void CallRegisterDevice(const std::string& args,
315 ManagerProxy* manager_proxy) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800316 chromeos::VariantDictionary params;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700317 if (!args.empty()) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800318 auto key_values = chromeos::data_encoding::WebParamsDecode(args);
Alex Vakulenkoa0424dd2014-06-13 16:10:17 -0700319 for (const auto& pair : key_values) {
Alex Vakulenkoa9044342014-08-23 19:31:27 -0700320 params.insert(std::make_pair(pair.first, chromeos::Any(pair.second)));
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700321 }
322 }
323
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700324 ErrorPtr error;
Christopher Wiley48e37282014-05-08 14:43:58 -0700325 std::string device_id;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800326 if (!manager_proxy->RegisterDevice(params, &device_id, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800327 return ReportError(error.get());
Christopher Wiley48e37282014-05-08 14:43:58 -0700328 }
329
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800330 printf("Device registered: %s\n", device_id.c_str());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800331 OnJobComplete();
Christopher Wiley48e37282014-05-08 14:43:58 -0700332 }
333
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800334 void CallUpdateState(const std::string& prop,
335 const std::string& value,
336 ManagerProxy* manager_proxy) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700337 ErrorPtr error;
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800338 std::string error_message;
339 std::unique_ptr<base::Value> json(base::JSONReader::ReadAndReturnError(
340 value, base::JSON_PARSE_RFC, nullptr, &error_message));
341 if (!json) {
342 Error::AddTo(&error, FROM_HERE, chromeos::errors::json::kDomain,
343 chromeos::errors::json::kParseError, error_message);
344 return ReportError(error.get());
345 }
346
347 chromeos::VariantDictionary property_set{{prop, JsonToAny(*json)}};
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800348 if (!manager_proxy->UpdateState(property_set, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800349 return ReportError(error.get());
Christopher Wiley48e37282014-05-08 14:43:58 -0700350 }
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800351 OnJobComplete();
Christopher Wiley48e37282014-05-08 14:43:58 -0700352 }
353
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800354 void CallGetState(ManagerProxy* manager_proxy) {
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800355 std::string json;
356 ErrorPtr error;
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800357 if (!manager_proxy->GetState(&json, &error)) {
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800358 return ReportError(error.get());
359 }
Nathan Bullock4b6c0fb2015-04-01 15:32:58 -0400360 printf("%s\n", json.c_str());
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800361 OnJobComplete();
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800362 }
363
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800364 void CallAddCommand(const std::string& command, ManagerProxy* manager_proxy) {
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700365 ErrorPtr error;
Vitaly Buka64fc5fc2015-03-24 12:42:24 -0700366 std::string id;
367 if (!manager_proxy->AddCommand(command, &id, &error)) {
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800368 return ReportError(error.get());
Alex Vakulenko665c8852014-09-11 16:57:24 -0700369 }
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800370 OnJobComplete();
Alex Vakulenko665c8852014-09-11 16:57:24 -0700371 }
372
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800373 void CallGetPendingCommands() {
374 printf("Pending commands:\n");
375 for (auto* cmd : object_manager_->GetCommandInstances()) {
Vitaly Buka4129dfa2015-04-29 12:16:58 -0700376 printf("%10s - '%s' (id:%s)\n", cmd->status().c_str(),
377 cmd->name().c_str(), cmd->id().c_str());
Christopher Wileyadb901d2014-05-07 09:58:45 -0700378 }
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800379 OnJobComplete();
Christopher Wileyadb901d2014-05-07 09:58:45 -0700380 }
381
Alex Vakulenkoe03af6d2015-04-20 11:00:54 -0700382 void CallSetCommandVisibility(const std::string& command_list,
383 const std::string& visibility,
384 ManagerProxy* manager_proxy) {
385 ErrorPtr error;
386 std::vector<std::string> commands =
387 chromeos::string_utils::Split(command_list, ",", true, true);
388 if (!manager_proxy->SetCommandVisibility(commands, visibility, &error)) {
389 return ReportError(error.get());
390 }
391 OnJobComplete();
392 }
393
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800394 std::unique_ptr<org::chromium::Buffet::ObjectManagerProxy> object_manager_;
Christopher Wileyc900e482015-02-15 15:42:04 -0800395 int exit_code_{EX_OK};
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800396 base::CancelableCallback<void()> timeout_task_;
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800397
Christopher Wiley2d0369e2015-03-03 12:57:54 -0800398 base::WeakPtrFactory<Daemon> weak_factory_{this};
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800399 DISALLOW_COPY_AND_ASSIGN(Daemon);
Christopher Wiley48e37282014-05-08 14:43:58 -0700400};
401
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800402} // anonymous namespace
Christopher Wiley48e37282014-05-08 14:43:58 -0700403
404int main(int argc, char** argv) {
Alex Vakulenkofc575a42015-04-02 14:31:10 -0700405 base::CommandLine::Init(argc, argv);
406 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
407 base::CommandLine::StringVector args = cl->GetArgs();
Christopher Wiley48e37282014-05-08 14:43:58 -0700408 if (args.empty()) {
Christopher Wileya4915c42014-03-27 14:45:37 -0700409 usage();
Chris Sosaababc5c2014-04-09 15:42:01 -0700410 return EX_USAGE;
Christopher Wileya4915c42014-03-27 14:45:37 -0700411 }
412
Alex Vakulenko420e49f2014-12-01 17:53:27 -0800413 Daemon daemon;
414 return daemon.Run();
Christopher Wiley48e37282014-05-08 14:43:58 -0700415}