blob: 4678a83cdbab4935149e19b562edf586e94ec3e5 [file] [log] [blame]
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Darin Petkov5a7f5652010-07-22 21:40:09 -07005#include <string>
6
Alex Deymo8ce80d62015-01-27 15:10:43 -08007#include <base/command_line.h>
Alex Deymo44666f92014-07-22 20:29:24 -07008#include <base/logging.h>
David Zeuthen9d73a722014-04-04 14:52:46 -07009#include <chromeos/dbus/service_constants.h>
Steve Fung97b6f5a2014-10-07 12:39:51 -070010#include <chromeos/flag_helper.h>
Ben Chan46bf5c82013-06-24 11:17:41 -070011#include <dbus/dbus.h>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070012#include <glib.h>
Steve Fung97b6f5a2014-10-07 12:39:51 -070013#include <inttypes.h>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070014
15#include "update_engine/dbus_constants.h"
Alex Deymo44666f92014-07-22 20:29:24 -070016#include "update_engine/glib_utils.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070017
18extern "C" {
Timothy Jennison08d49312015-03-04 13:46:40 -050019#include "update_engine/org.chromium.UpdateEngineInterface.dbusclient.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070020}
21
David Zeuthen75a4c3e2013-09-06 11:36:59 -070022using chromeos_update_engine::AttemptUpdateFlags;
23using chromeos_update_engine::kAttemptUpdateFlagNonInteractive;
Alex Deymo44666f92014-07-22 20:29:24 -070024using chromeos_update_engine::kUpdateEngineServiceInterface;
25using chromeos_update_engine::kUpdateEngineServiceName;
26using chromeos_update_engine::kUpdateEngineServicePath;
Darin Petkova0b9e772011-10-06 05:05:56 -070027using chromeos_update_engine::utils::GetAndFreeGError;
Darin Petkov5a7f5652010-07-22 21:40:09 -070028using std::string;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070029
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070030namespace {
31
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070032bool GetProxy(DBusGProxy** out_proxy) {
33 DBusGConnection* bus;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070034 DBusGProxy* proxy = nullptr;
35 GError* error = nullptr;
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070036 const int kTries = 4;
Darin Petkova0b9e772011-10-06 05:05:56 -070037 const int kRetrySeconds = 10;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070038
39 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
Alex Vakulenko88b591f2014-08-28 16:48:57 -070040 if (bus == nullptr) {
Richard Barnetted7936062013-01-18 13:38:51 -080041 LOG(ERROR) << "Failed to get bus: " << GetAndFreeGError(&error);
42 exit(1);
43 }
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070044 for (int i = 0; !proxy && i < kTries; ++i) {
Darin Petkova0b9e772011-10-06 05:05:56 -070045 if (i > 0) {
46 LOG(INFO) << "Retrying to get dbus proxy. Try "
47 << (i + 1) << "/" << kTries;
Gilad Arnold8e3f1262013-01-08 14:59:54 -080048 g_usleep(kRetrySeconds * G_USEC_PER_SEC);
Darin Petkova0b9e772011-10-06 05:05:56 -070049 }
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070050 proxy = dbus_g_proxy_new_for_name_owner(bus,
51 kUpdateEngineServiceName,
52 kUpdateEngineServicePath,
53 kUpdateEngineServiceInterface,
54 &error);
Darin Petkova0b9e772011-10-06 05:05:56 -070055 LOG_IF(WARNING, !proxy) << "Error getting dbus proxy for "
56 << kUpdateEngineServiceName << ": "
57 << GetAndFreeGError(&error);
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070058 }
Alex Vakulenko88b591f2014-08-28 16:48:57 -070059 if (proxy == nullptr) {
Richard Barnetted7936062013-01-18 13:38:51 -080060 LOG(ERROR) << "Giving up -- unable to get dbus proxy for "
61 << kUpdateEngineServiceName;
62 exit(1);
63 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070064 *out_proxy = proxy;
65 return true;
66}
67
68static void StatusUpdateSignalHandler(DBusGProxy* proxy,
69 int64_t last_checked_time,
70 double progress,
71 gchar* current_operation,
72 gchar* new_version,
73 int64_t new_size,
74 void* user_data) {
75 LOG(INFO) << "Got status update:";
76 LOG(INFO) << " last_checked_time: " << last_checked_time;
77 LOG(INFO) << " progress: " << progress;
78 LOG(INFO) << " current_operation: " << current_operation;
79 LOG(INFO) << " new_version: " << new_version;
80 LOG(INFO) << " new_size: " << new_size;
81}
82
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070083bool ResetStatus() {
84 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070085 GError* error = nullptr;
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070086
87 CHECK(GetProxy(&proxy));
88
Alex Deymo36dc2f32013-08-29 15:45:06 -070089 gboolean rc = update_engine_client_reset_status(proxy, &error);
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070090 return rc;
91}
92
93
Alex Vakulenko88b591f2014-08-28 16:48:57 -070094// If |op| is non-null, sets it to the current operation string or an
Darin Petkov58529db2010-08-13 09:19:47 -070095// empty string if unable to obtain the current status.
96bool GetStatus(string* op) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070097 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070098 GError* error = nullptr;
Andrew de los Reyesada42202010-07-15 22:23:20 -070099
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700100 CHECK(GetProxy(&proxy));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700101
102 gint64 last_checked_time = 0;
103 gdouble progress = 0.0;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700104 char* current_op = nullptr;
105 char* new_version = nullptr;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700106 gint64 new_size = 0;
107
Alex Deymo36dc2f32013-08-29 15:45:06 -0700108 gboolean rc = update_engine_client_get_status(proxy,
109 &last_checked_time,
110 &progress,
111 &current_op,
112 &new_version,
113 &new_size,
114 &error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700115 if (rc == FALSE) {
Darin Petkova0b9e772011-10-06 05:05:56 -0700116 LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700117 }
118 printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
119 "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
120 last_checked_time,
121 progress,
122 current_op,
123 new_version,
124 new_size);
Darin Petkov58529db2010-08-13 09:19:47 -0700125 if (op) {
126 *op = current_op ? current_op : "";
127 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700128 return true;
129}
130
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700131// Should never return.
132void WatchForUpdates() {
133 DBusGProxy* proxy;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700134
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700135 CHECK(GetProxy(&proxy));
Andrew de los Reyesada42202010-07-15 22:23:20 -0700136
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700137 // Register marshaller
138 dbus_g_object_register_marshaller(
David Zeuthen7cb12f92014-04-08 10:35:39 -0700139 g_cclosure_marshal_generic,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700140 G_TYPE_NONE,
141 G_TYPE_INT64,
142 G_TYPE_DOUBLE,
143 G_TYPE_STRING,
144 G_TYPE_STRING,
145 G_TYPE_INT64,
146 G_TYPE_INVALID);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700147
148 static const char kStatusUpdate[] = "StatusUpdate";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700149 dbus_g_proxy_add_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700150 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700151 G_TYPE_INT64,
152 G_TYPE_DOUBLE,
153 G_TYPE_STRING,
154 G_TYPE_STRING,
155 G_TYPE_INT64,
156 G_TYPE_INVALID);
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700157 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700158 dbus_g_proxy_connect_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700159 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700160 G_CALLBACK(StatusUpdateSignalHandler),
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700161 nullptr,
162 nullptr);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700163 g_main_loop_run(loop);
164 g_main_loop_unref(loop);
165}
166
Chris Sosad317e402013-06-12 13:47:09 -0700167bool Rollback(bool rollback) {
168 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700169 GError* error = nullptr;
Chris Sosad317e402013-06-12 13:47:09 -0700170
171 CHECK(GetProxy(&proxy));
172
Alex Deymo36dc2f32013-08-29 15:45:06 -0700173 gboolean rc = update_engine_client_attempt_rollback(proxy,
174 rollback,
175 &error);
Chris Sosad317e402013-06-12 13:47:09 -0700176 CHECK_EQ(rc, TRUE) << "Error with rollback request: "
177 << GetAndFreeGError(&error);
178 return true;
179}
180
Alex Deymof329b932014-10-30 01:37:48 -0700181string GetRollbackPartition() {
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800182 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700183 GError* error = nullptr;
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800184
185 CHECK(GetProxy(&proxy));
186
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700187 char* rollback_partition = nullptr;
188 gboolean rc = update_engine_client_get_rollback_partition(proxy,
189 &rollback_partition,
190 &error);
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800191 CHECK_EQ(rc, TRUE) << "Error while querying rollback partition availabilty: "
192 << GetAndFreeGError(&error);
Alex Deymof329b932014-10-30 01:37:48 -0700193 string partition = rollback_partition;
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700194 g_free(rollback_partition);
195 return partition;
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800196}
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700197
Alex Deymof329b932014-10-30 01:37:48 -0700198string GetKernelDevices() {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700199 DBusGProxy* proxy;
200 GError* error = nullptr;
201
202 CHECK(GetProxy(&proxy));
203
204 char* kernel_devices = nullptr;
205 gboolean rc = update_engine_client_get_kernel_devices(proxy,
206 &kernel_devices,
207 &error);
208 CHECK_EQ(rc, TRUE) << "Error while getting a list of kernel devices: "
209 << GetAndFreeGError(&error);
Alex Deymof329b932014-10-30 01:37:48 -0700210 string devices = kernel_devices;
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700211 g_free(kernel_devices);
212 return devices;
213}
214
Steve Fung97b6f5a2014-10-07 12:39:51 -0700215bool CheckForUpdates(const string& app_version,
216 const string& omaha_url,
217 bool interactive) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700218 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700219 GError* error = nullptr;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700220
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700221 CHECK(GetProxy(&proxy));
222
David Zeuthen75a4c3e2013-09-06 11:36:59 -0700223 AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(
Steve Fung97b6f5a2014-10-07 12:39:51 -0700224 interactive ? 0 : kAttemptUpdateFlagNonInteractive);
David Zeuthen75a4c3e2013-09-06 11:36:59 -0700225 gboolean rc =
226 update_engine_client_attempt_update_with_flags(proxy,
227 app_version.c_str(),
228 omaha_url.c_str(),
229 static_cast<gint>(flags),
230 &error);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700231 CHECK_EQ(rc, TRUE) << "Error checking for update: "
Darin Petkova0b9e772011-10-06 05:05:56 -0700232 << GetAndFreeGError(&error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700233 return true;
234}
235
Darin Petkov296889c2010-07-23 16:20:54 -0700236bool RebootIfNeeded() {
237 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700238 GError* error = nullptr;
Darin Petkov296889c2010-07-23 16:20:54 -0700239
240 CHECK(GetProxy(&proxy));
241
242 gboolean rc =
Alex Deymo36dc2f32013-08-29 15:45:06 -0700243 update_engine_client_reboot_if_needed(proxy, &error);
Darin Petkov296889c2010-07-23 16:20:54 -0700244 // Reboot error code doesn't necessarily mean that a reboot
245 // failed. For example, D-Bus may be shutdown before we receive the
246 // result.
Darin Petkova0b9e772011-10-06 05:05:56 -0700247 LOG_IF(INFO, !rc) << "Reboot error message: " << GetAndFreeGError(&error);
Darin Petkov296889c2010-07-23 16:20:54 -0700248 return true;
249}
250
Chris Sosacb7fa882013-07-25 17:02:59 -0700251void SetTargetChannel(const string& target_channel, bool allow_powerwash) {
Darin Petkov8daa3242010-10-25 13:28:47 -0700252 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700253 GError* error = nullptr;
Darin Petkov8daa3242010-10-25 13:28:47 -0700254
255 CHECK(GetProxy(&proxy));
256
Alex Deymo36dc2f32013-08-29 15:45:06 -0700257 gboolean rc = update_engine_client_set_channel(proxy,
258 target_channel.c_str(),
259 allow_powerwash,
260 &error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700261 CHECK_EQ(rc, true) << "Error setting the channel: "
Darin Petkova0b9e772011-10-06 05:05:56 -0700262 << GetAndFreeGError(&error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700263 LOG(INFO) << "Channel permanently set to: " << target_channel;
Darin Petkov8daa3242010-10-25 13:28:47 -0700264}
265
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700266string GetChannel(bool get_current_channel) {
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900267 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700268 GError* error = nullptr;
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900269
270 CHECK(GetProxy(&proxy));
271
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700272 char* channel = nullptr;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700273 gboolean rc = update_engine_client_get_channel(proxy,
274 get_current_channel,
275 &channel,
276 &error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700277 CHECK_EQ(rc, true) << "Error getting the channel: "
278 << GetAndFreeGError(&error);
279 string output = channel;
280 g_free(channel);
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900281 return output;
282}
283
Alex Deymo5fdf7762013-07-17 20:01:40 -0700284void SetUpdateOverCellularPermission(gboolean allowed) {
Alex Deymof4867c42013-06-28 14:41:39 -0700285 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700286 GError* error = nullptr;
Alex Deymof4867c42013-06-28 14:41:39 -0700287
288 CHECK(GetProxy(&proxy));
289
Alex Deymo36dc2f32013-08-29 15:45:06 -0700290 gboolean rc = update_engine_client_set_update_over_cellular_permission(
291 proxy,
292 allowed,
293 &error);
Alex Deymof4867c42013-06-28 14:41:39 -0700294 CHECK_EQ(rc, true) << "Error setting the update over cellular setting: "
295 << GetAndFreeGError(&error);
Alex Deymof4867c42013-06-28 14:41:39 -0700296}
297
298bool GetUpdateOverCellularPermission() {
299 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700300 GError* error = nullptr;
Alex Deymof4867c42013-06-28 14:41:39 -0700301
302 CHECK(GetProxy(&proxy));
303
304 gboolean allowed;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700305 gboolean rc = update_engine_client_get_update_over_cellular_permission(
306 proxy,
307 &allowed,
308 &error);
Alex Deymof4867c42013-06-28 14:41:39 -0700309 CHECK_EQ(rc, true) << "Error getting the update over cellular setting: "
310 << GetAndFreeGError(&error);
311 return allowed;
312}
313
Alex Deymo5fdf7762013-07-17 20:01:40 -0700314void SetP2PUpdatePermission(gboolean enabled) {
315 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700316 GError* error = nullptr;
Alex Deymo5fdf7762013-07-17 20:01:40 -0700317
318 CHECK(GetProxy(&proxy));
319
Alex Deymo36dc2f32013-08-29 15:45:06 -0700320 gboolean rc = update_engine_client_set_p2p_update_permission(
321 proxy,
322 enabled,
323 &error);
Alex Deymo5fdf7762013-07-17 20:01:40 -0700324 CHECK_EQ(rc, true) << "Error setting the peer-to-peer update setting: "
325 << GetAndFreeGError(&error);
326}
327
328bool GetP2PUpdatePermission() {
329 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700330 GError* error = nullptr;
Alex Deymo5fdf7762013-07-17 20:01:40 -0700331
332 CHECK(GetProxy(&proxy));
333
334 gboolean enabled;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700335 gboolean rc = update_engine_client_get_p2p_update_permission(
336 proxy,
337 &enabled,
338 &error);
Alex Deymo5fdf7762013-07-17 20:01:40 -0700339 CHECK_EQ(rc, true) << "Error getting the peer-to-peer update setting: "
340 << GetAndFreeGError(&error);
341 return enabled;
342}
343
Darin Petkov58529db2010-08-13 09:19:47 -0700344static gboolean CompleteUpdateSource(gpointer data) {
345 string current_op;
346 if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
347 LOG(ERROR) << "Update failed.";
348 exit(1);
349 }
350 if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
351 LOG(INFO) << "Update succeeded -- reboot needed.";
352 exit(0);
353 }
354 return TRUE;
355}
356
357// This is similar to watching for updates but rather than registering
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700358// a signal watch, actively poll the daemon just in case it stops
Darin Petkov58529db2010-08-13 09:19:47 -0700359// sending notifications.
360void CompleteUpdate() {
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700361 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
362 g_timeout_add_seconds(5, CompleteUpdateSource, nullptr);
Darin Petkov58529db2010-08-13 09:19:47 -0700363 g_main_loop_run(loop);
364 g_main_loop_unref(loop);
365}
366
Alex Vakulenkodea2eac2014-03-14 15:56:59 -0700367void ShowPrevVersion() {
368 DBusGProxy* proxy;
369 GError* error = nullptr;
370
371 CHECK(GetProxy(&proxy));
372
373 char* prev_version = nullptr;
374
375 gboolean rc = update_engine_client_get_prev_version(proxy,
376 &prev_version,
377 &error);
378 if (!rc) {
379 LOG(ERROR) << "Error getting previous version: "
380 << GetAndFreeGError(&error);
381 } else {
382 LOG(INFO) << "Previous version = " << prev_version;
383 g_free(prev_version);
384 }
385}
386
David Zeuthen9d73a722014-04-04 14:52:46 -0700387bool CheckIfRebootIsNeeded(DBusGProxy *proxy, bool *out_reboot_needed) {
388 gint64 last_checked_time = 0;
389 gdouble progress = 0.0;
390 char* current_op = nullptr;
391 char* new_version = nullptr;
392 gint64 new_size = 0;
393 GError* error = nullptr;
394
395 if (!update_engine_client_get_status(proxy,
396 &last_checked_time,
397 &progress,
398 &current_op,
399 &new_version,
400 &new_size,
401 &error)) {
402 LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
403 return false;
404 }
405 *out_reboot_needed =
406 (g_strcmp0(current_op,
407 update_engine::kUpdateStatusUpdatedNeedReboot) == 0);
408 g_free(current_op);
409 g_free(new_version);
410 return true;
411}
412
413// Determines if reboot is needed. The result is returned in
414// |out_reboot_needed|. Returns true if the check succeeded, false
415// otherwise.
416bool IsRebootNeeded(bool *out_reboot_needed) {
417 DBusGProxy* proxy = nullptr;
418 CHECK(GetProxy(&proxy));
419 bool ret = CheckIfRebootIsNeeded(proxy, out_reboot_needed);
420 g_object_unref(proxy);
421 return ret;
422}
423
424static void OnBlockUntilRebootStatusCallback(
425 DBusGProxy* proxy,
426 int64_t last_checked_time,
427 double progress,
428 const gchar* current_operation,
429 const gchar* new_version,
430 int64_t new_size,
431 void* user_data) {
432 GMainLoop *loop = reinterpret_cast<GMainLoop*>(user_data);
433 if (g_strcmp0(current_operation,
434 update_engine::kUpdateStatusUpdatedNeedReboot) == 0) {
435 g_main_loop_quit(loop);
436 }
437}
438
439bool CheckRebootNeeded(DBusGProxy *proxy, GMainLoop *loop) {
440 bool reboot_needed;
441 if (!CheckIfRebootIsNeeded(proxy, &reboot_needed))
442 return false;
443 if (reboot_needed)
444 return true;
445 // This will block until OnBlockUntilRebootStatusCallback() calls
446 // g_main_loop_quit().
447 g_main_loop_run(loop);
448 return true;
449}
450
451// Blocks until a reboot is needed. Returns true if waiting succeeded,
452// false if an error occurred.
453bool BlockUntilRebootIsNeeded() {
454 // The basic idea is to get a proxy, listen to signals and only then
455 // check the status. If no reboot is needed, just sit and wait for
456 // the StatusUpdate signal to convey that a reboot is pending.
457 DBusGProxy* proxy = nullptr;
458 CHECK(GetProxy(&proxy));
459 dbus_g_object_register_marshaller(
460 g_cclosure_marshal_generic,
461 G_TYPE_NONE,
462 G_TYPE_INT64,
463 G_TYPE_DOUBLE,
464 G_TYPE_STRING,
465 G_TYPE_STRING,
466 G_TYPE_INT64,
467 G_TYPE_INVALID);
468 dbus_g_proxy_add_signal(proxy,
469 update_engine::kStatusUpdate, // Signal name.
470 G_TYPE_INT64,
471 G_TYPE_DOUBLE,
472 G_TYPE_STRING,
473 G_TYPE_STRING,
474 G_TYPE_INT64,
475 G_TYPE_INVALID);
476 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
477 dbus_g_proxy_connect_signal(proxy,
478 update_engine::kStatusUpdate,
479 G_CALLBACK(OnBlockUntilRebootStatusCallback),
480 loop,
481 nullptr); // free_data_func.
482
483 bool ret = CheckRebootNeeded(proxy, loop);
484
485 dbus_g_proxy_disconnect_signal(proxy,
486 update_engine::kStatusUpdate,
487 G_CALLBACK(OnBlockUntilRebootStatusCallback),
488 loop);
489 g_main_loop_unref(loop);
490 g_object_unref(proxy);
491 return ret;
492}
493
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700494} // namespace
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700495
496int main(int argc, char** argv) {
Steve Fung97b6f5a2014-10-07 12:39:51 -0700497 DEFINE_string(app_version, "", "Force the current app version.");
498 DEFINE_string(channel, "",
499 "Set the target channel. The device will be powerwashed if the "
500 "target channel is more stable than the current channel unless "
501 "--nopowerwash is specified.");
502 DEFINE_bool(check_for_update, false, "Initiate check for updates.");
503 DEFINE_bool(follow, false, "Wait for any update operations to complete."
504 "Exit status is 0 if the update succeeded, and 1 otherwise.");
505 DEFINE_bool(interactive, true, "Mark the update request as interactive.");
506 DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
507 DEFINE_string(p2p_update, "",
508 "Enables (\"yes\") or disables (\"no\") the peer-to-peer update"
509 " sharing.");
510 DEFINE_bool(powerwash, true, "When performing rollback or channel change, "
511 "do a powerwash or allow it respectively.");
512 DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
513 DEFINE_bool(is_reboot_needed, false, "Exit status 0 if reboot is needed, "
514 "2 if reboot is not needed or 1 if an error occurred.");
515 DEFINE_bool(block_until_reboot_is_needed, false, "Blocks until reboot is "
516 "needed. Returns non-zero exit status if an error occurred.");
517 DEFINE_bool(reset_status, false, "Sets the status in update_engine to idle.");
Alex Deymo1ac8b592015-01-26 13:22:58 -0800518 DEFINE_bool(rollback, false,
519 "Perform a rollback to the previous partition. The device will "
520 "be powerwashed unless --nopowerwash is specified.");
Steve Fung97b6f5a2014-10-07 12:39:51 -0700521 DEFINE_bool(can_rollback, false, "Shows whether rollback partition "
522 "is available.");
523 DEFINE_bool(show_channel, false, "Show the current and target channels.");
524 DEFINE_bool(show_p2p_update, false,
525 "Show the current setting for peer-to-peer update sharing.");
526 DEFINE_bool(show_update_over_cellular, false,
527 "Show the current setting for updates over cellular networks.");
528 DEFINE_bool(status, false, "Print the status to stdout.");
529 DEFINE_bool(update, false, "Forces an update and waits for it to complete. "
530 "Implies --follow.");
531 DEFINE_string(update_over_cellular, "",
532 "Enables (\"yes\") or disables (\"no\") the updates over "
533 "cellular networks.");
534 DEFINE_bool(watch_for_updates, false,
535 "Listen for status updates and print them to the screen.");
536 DEFINE_bool(prev_version, false,
537 "Show the previous OS version used before the update reboot.");
538 DEFINE_bool(show_kernels, false, "Show the list of kernel patritions and "
539 "whether each of them is bootable or not");
540
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700541 // Boilerplate init commands.
542 g_type_init();
Ben Chan46bf5c82013-06-24 11:17:41 -0700543 dbus_threads_init_default();
Steve Fung97b6f5a2014-10-07 12:39:51 -0700544 chromeos::FlagHelper::Init(argc, argv, "Chromium OS Update Engine Client");
Andrew de los Reyesada42202010-07-15 22:23:20 -0700545
Alex Deymo8ce80d62015-01-27 15:10:43 -0800546 // Ensure there are no positional arguments.
547 const std::vector<string> positional_args =
548 base::CommandLine::ForCurrentProcess()->GetArgs();
549 if (!positional_args.empty()) {
550 LOG(ERROR) << "Found a positional argument '" << positional_args.front()
551 << "'. If you want to pass a value to a flag, pass it as "
552 "--flag=value.";
553 return 1;
554 }
555
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -0700556 // Update the status if requested.
557 if (FLAGS_reset_status) {
558 LOG(INFO) << "Setting Update Engine status to idle ...";
559 if (!ResetStatus()) {
560 LOG(ERROR) << "ResetStatus failed.";
561 return 1;
562 }
Gilad Arnold50c60632013-01-25 10:27:19 -0800563 LOG(INFO) << "ResetStatus succeeded; to undo partition table changes run:\n"
564 "(D=$(rootdev -d) P=$(rootdev -s); cgpt p -i$(($(echo ${P#$D} "
565 "| sed 's/^[^0-9]*//')-1)) $D;)";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700566 }
Darin Petkov58529db2010-08-13 09:19:47 -0700567
Alex Deymof4867c42013-06-28 14:41:39 -0700568 // Changes the current update over cellular network setting.
569 if (!FLAGS_update_over_cellular.empty()) {
570 gboolean allowed = FLAGS_update_over_cellular == "yes";
571 if (!allowed && FLAGS_update_over_cellular != "no") {
572 LOG(ERROR) << "Unknown option: \"" << FLAGS_update_over_cellular
573 << "\". Please specify \"yes\" or \"no\".";
574 } else {
575 SetUpdateOverCellularPermission(allowed);
576 }
577 }
578
579 // Show the current update over cellular network setting.
580 if (FLAGS_show_update_over_cellular) {
581 bool allowed = GetUpdateOverCellularPermission();
582 LOG(INFO) << "Current update over cellular network setting: "
583 << (allowed ? "ENABLED" : "DISABLED");
584 }
585
Chris Sosacb7fa882013-07-25 17:02:59 -0700586 if (!FLAGS_powerwash && !FLAGS_rollback && FLAGS_channel.empty()) {
Chris Sosa192449e2013-10-28 14:16:19 -0700587 LOG(ERROR) << "powerwash flag only makes sense rollback or channel change";
Chris Sosacb7fa882013-07-25 17:02:59 -0700588 return 1;
589 }
590
Alex Deymo5fdf7762013-07-17 20:01:40 -0700591 // Change the P2P enabled setting.
592 if (!FLAGS_p2p_update.empty()) {
593 gboolean enabled = FLAGS_p2p_update == "yes";
594 if (!enabled && FLAGS_p2p_update != "no") {
595 LOG(ERROR) << "Unknown option: \"" << FLAGS_p2p_update
596 << "\". Please specify \"yes\" or \"no\".";
597 } else {
598 SetP2PUpdatePermission(enabled);
599 }
600 }
601
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800602 // Show the rollback availability.
603 if (FLAGS_can_rollback) {
Alex Deymof329b932014-10-30 01:37:48 -0700604 string rollback_partition = GetRollbackPartition();
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700605 bool can_rollback = true;
606 if (rollback_partition.empty()) {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700607 rollback_partition = "UNAVAILABLE";
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700608 can_rollback = false;
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700609 } else {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700610 rollback_partition = "AVAILABLE: " + rollback_partition;
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700611 }
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700612
613 LOG(INFO) << "Rollback partition: " << rollback_partition;
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700614 if (!can_rollback) {
615 return 1;
616 }
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800617 }
618
Alex Deymo5fdf7762013-07-17 20:01:40 -0700619 // Show the current P2P enabled setting.
620 if (FLAGS_show_p2p_update) {
621 bool enabled = GetP2PUpdatePermission();
622 LOG(INFO) << "Current update using P2P setting: "
623 << (enabled ? "ENABLED" : "DISABLED");
624 }
625
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700626 // First, update the target channel if requested.
627 if (!FLAGS_channel.empty())
Chris Sosacb7fa882013-07-25 17:02:59 -0700628 SetTargetChannel(FLAGS_channel, FLAGS_powerwash);
Darin Petkov8daa3242010-10-25 13:28:47 -0700629
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700630 // Show the current and target channels if requested.
631 if (FLAGS_show_channel) {
632 string current_channel = GetChannel(true);
633 LOG(INFO) << "Current Channel: " << current_channel;
634
635 string target_channel = GetChannel(false);
636 if (!target_channel.empty())
637 LOG(INFO) << "Target Channel (pending update): " << target_channel;
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900638 }
639
Chris Sosad317e402013-06-12 13:47:09 -0700640 bool do_update_request = FLAGS_check_for_update | FLAGS_update |
641 !FLAGS_app_version.empty() | !FLAGS_omaha_url.empty();
Chris Sosa192449e2013-10-28 14:16:19 -0700642 if (FLAGS_update)
643 FLAGS_follow = true;
Chris Sosad317e402013-06-12 13:47:09 -0700644
Chris Sosad317e402013-06-12 13:47:09 -0700645 if (do_update_request && FLAGS_rollback) {
Chris Sosa192449e2013-10-28 14:16:19 -0700646 LOG(ERROR) << "Incompatible flags specified with rollback."
647 << "Rollback should not include update-related flags.";
Chris Sosad317e402013-06-12 13:47:09 -0700648 return 1;
649 }
650
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700651 if (FLAGS_rollback) {
Chris Sosad317e402013-06-12 13:47:09 -0700652 LOG(INFO) << "Requesting rollback.";
653 CHECK(Rollback(FLAGS_powerwash)) << "Request for rollback failed.";
Chris Sosad317e402013-06-12 13:47:09 -0700654 }
655
Darin Petkov58529db2010-08-13 09:19:47 -0700656 // Initiate an update check, if necessary.
Chris Sosad317e402013-06-12 13:47:09 -0700657 if (do_update_request) {
Darin Petkov296889c2010-07-23 16:20:54 -0700658 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Darin Petkov58529db2010-08-13 09:19:47 -0700659 string app_version = FLAGS_app_version;
660 if (FLAGS_update && app_version.empty()) {
661 app_version = "ForcedUpdate";
662 LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700663 }
Darin Petkov58529db2010-08-13 09:19:47 -0700664 LOG(INFO) << "Initiating update check and install.";
Steve Fung97b6f5a2014-10-07 12:39:51 -0700665 CHECK(CheckForUpdates(app_version, FLAGS_omaha_url, FLAGS_interactive))
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700666 << "Update check/initiate update failed.";
Chris Sosa192449e2013-10-28 14:16:19 -0700667 }
Darin Petkov58529db2010-08-13 09:19:47 -0700668
Chris Sosa192449e2013-10-28 14:16:19 -0700669 // These final options are all mutually exclusive with one another.
David Zeuthen9d73a722014-04-04 14:52:46 -0700670 if (FLAGS_follow + FLAGS_watch_for_updates + FLAGS_reboot +
671 FLAGS_status + FLAGS_is_reboot_needed +
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700672 FLAGS_block_until_reboot_is_needed > 1) {
Chris Sosa192449e2013-10-28 14:16:19 -0700673 LOG(ERROR) << "Multiple exclusive options selected. "
674 << "Select only one of --follow, --watch_for_updates, --reboot, "
David Zeuthen9d73a722014-04-04 14:52:46 -0700675 << "--is_reboot_needed, --block_until_reboot_is_needed, "
Chris Sosa192449e2013-10-28 14:16:19 -0700676 << "or --status.";
677 return 1;
678 }
679
680 if (FLAGS_status) {
681 LOG(INFO) << "Querying Update Engine status...";
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700682 if (!GetStatus(nullptr)) {
Chris Sosa192449e2013-10-28 14:16:19 -0700683 LOG(ERROR) << "GetStatus failed.";
Darin Petkov58529db2010-08-13 09:19:47 -0700684 return 1;
685 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700686 return 0;
687 }
Darin Petkov58529db2010-08-13 09:19:47 -0700688
Chris Sosa192449e2013-10-28 14:16:19 -0700689 if (FLAGS_follow) {
690 LOG(INFO) << "Waiting for update to complete.";
691 CompleteUpdate(); // Should never return.
692 return 1;
693 }
694
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700695 if (FLAGS_watch_for_updates) {
696 LOG(INFO) << "Watching for status updates.";
697 WatchForUpdates(); // Should never return.
698 return 1;
699 }
Darin Petkov58529db2010-08-13 09:19:47 -0700700
Darin Petkov296889c2010-07-23 16:20:54 -0700701 if (FLAGS_reboot) {
702 LOG(INFO) << "Requesting a reboot...";
703 CHECK(RebootIfNeeded());
704 return 0;
705 }
Andrew de los Reyesada42202010-07-15 22:23:20 -0700706
Alex Vakulenkodea2eac2014-03-14 15:56:59 -0700707 if (FLAGS_prev_version) {
708 ShowPrevVersion();
709 }
710
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700711 if (FLAGS_show_kernels) {
712 LOG(INFO) << "Kernel partitions:\n"
713 << GetKernelDevices();
714 }
715
David Zeuthen9d73a722014-04-04 14:52:46 -0700716 if (FLAGS_is_reboot_needed) {
717 bool reboot_needed = false;
718 if (!IsRebootNeeded(&reboot_needed))
719 return 1;
720 else if (!reboot_needed)
721 return 2;
722 }
723
724 if (FLAGS_block_until_reboot_is_needed) {
725 if (!BlockUntilRebootIsNeeded())
726 return 1;
727 }
728
Darin Petkov8daa3242010-10-25 13:28:47 -0700729 LOG(INFO) << "Done.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700730 return 0;
731}