blob: 0fe511cad19d067e1c3a1decc4524fb94b5ee915 [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 Deymo44666f92014-07-22 20:29:24 -07007#include <base/logging.h>
David Zeuthen9d73a722014-04-04 14:52:46 -07008#include <chromeos/dbus/service_constants.h>
Steve Fung97b6f5a2014-10-07 12:39:51 -07009#include <chromeos/flag_helper.h>
Ben Chan46bf5c82013-06-24 11:17:41 -070010#include <dbus/dbus.h>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070011#include <glib.h>
Steve Fung97b6f5a2014-10-07 12:39:51 -070012#include <inttypes.h>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070013
14#include "update_engine/dbus_constants.h"
Alex Deymo44666f92014-07-22 20:29:24 -070015#include "update_engine/glib_utils.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070016
17extern "C" {
18#include "update_engine/update_engine.dbusclient.h"
19}
20
David Zeuthen75a4c3e2013-09-06 11:36:59 -070021using chromeos_update_engine::AttemptUpdateFlags;
22using chromeos_update_engine::kAttemptUpdateFlagNonInteractive;
Alex Deymo44666f92014-07-22 20:29:24 -070023using chromeos_update_engine::kUpdateEngineServiceInterface;
24using chromeos_update_engine::kUpdateEngineServiceName;
25using chromeos_update_engine::kUpdateEngineServicePath;
Darin Petkova0b9e772011-10-06 05:05:56 -070026using chromeos_update_engine::utils::GetAndFreeGError;
Darin Petkov5a7f5652010-07-22 21:40:09 -070027using std::string;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070028
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070029namespace {
30
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070031bool GetProxy(DBusGProxy** out_proxy) {
32 DBusGConnection* bus;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070033 DBusGProxy* proxy = nullptr;
34 GError* error = nullptr;
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070035 const int kTries = 4;
Darin Petkova0b9e772011-10-06 05:05:56 -070036 const int kRetrySeconds = 10;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070037
38 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
Alex Vakulenko88b591f2014-08-28 16:48:57 -070039 if (bus == nullptr) {
Richard Barnetted7936062013-01-18 13:38:51 -080040 LOG(ERROR) << "Failed to get bus: " << GetAndFreeGError(&error);
41 exit(1);
42 }
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070043 for (int i = 0; !proxy && i < kTries; ++i) {
Darin Petkova0b9e772011-10-06 05:05:56 -070044 if (i > 0) {
45 LOG(INFO) << "Retrying to get dbus proxy. Try "
46 << (i + 1) << "/" << kTries;
Gilad Arnold8e3f1262013-01-08 14:59:54 -080047 g_usleep(kRetrySeconds * G_USEC_PER_SEC);
Darin Petkova0b9e772011-10-06 05:05:56 -070048 }
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070049 proxy = dbus_g_proxy_new_for_name_owner(bus,
50 kUpdateEngineServiceName,
51 kUpdateEngineServicePath,
52 kUpdateEngineServiceInterface,
53 &error);
Darin Petkova0b9e772011-10-06 05:05:56 -070054 LOG_IF(WARNING, !proxy) << "Error getting dbus proxy for "
55 << kUpdateEngineServiceName << ": "
56 << GetAndFreeGError(&error);
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070057 }
Alex Vakulenko88b591f2014-08-28 16:48:57 -070058 if (proxy == nullptr) {
Richard Barnetted7936062013-01-18 13:38:51 -080059 LOG(ERROR) << "Giving up -- unable to get dbus proxy for "
60 << kUpdateEngineServiceName;
61 exit(1);
62 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070063 *out_proxy = proxy;
64 return true;
65}
66
67static void StatusUpdateSignalHandler(DBusGProxy* proxy,
68 int64_t last_checked_time,
69 double progress,
70 gchar* current_operation,
71 gchar* new_version,
72 int64_t new_size,
73 void* user_data) {
74 LOG(INFO) << "Got status update:";
75 LOG(INFO) << " last_checked_time: " << last_checked_time;
76 LOG(INFO) << " progress: " << progress;
77 LOG(INFO) << " current_operation: " << current_operation;
78 LOG(INFO) << " new_version: " << new_version;
79 LOG(INFO) << " new_size: " << new_size;
80}
81
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070082bool ResetStatus() {
83 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070084 GError* error = nullptr;
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070085
86 CHECK(GetProxy(&proxy));
87
Alex Deymo36dc2f32013-08-29 15:45:06 -070088 gboolean rc = update_engine_client_reset_status(proxy, &error);
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -070089 return rc;
90}
91
92
Alex Vakulenko88b591f2014-08-28 16:48:57 -070093// If |op| is non-null, sets it to the current operation string or an
Darin Petkov58529db2010-08-13 09:19:47 -070094// empty string if unable to obtain the current status.
95bool GetStatus(string* op) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070096 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -070097 GError* error = nullptr;
Andrew de los Reyesada42202010-07-15 22:23:20 -070098
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070099 CHECK(GetProxy(&proxy));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700100
101 gint64 last_checked_time = 0;
102 gdouble progress = 0.0;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700103 char* current_op = nullptr;
104 char* new_version = nullptr;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700105 gint64 new_size = 0;
106
Alex Deymo36dc2f32013-08-29 15:45:06 -0700107 gboolean rc = update_engine_client_get_status(proxy,
108 &last_checked_time,
109 &progress,
110 &current_op,
111 &new_version,
112 &new_size,
113 &error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700114 if (rc == FALSE) {
Darin Petkova0b9e772011-10-06 05:05:56 -0700115 LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700116 }
117 printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
118 "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
119 last_checked_time,
120 progress,
121 current_op,
122 new_version,
123 new_size);
Darin Petkov58529db2010-08-13 09:19:47 -0700124 if (op) {
125 *op = current_op ? current_op : "";
126 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700127 return true;
128}
129
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700130// Should never return.
131void WatchForUpdates() {
132 DBusGProxy* proxy;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700133
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700134 CHECK(GetProxy(&proxy));
Andrew de los Reyesada42202010-07-15 22:23:20 -0700135
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700136 // Register marshaller
137 dbus_g_object_register_marshaller(
David Zeuthen7cb12f92014-04-08 10:35:39 -0700138 g_cclosure_marshal_generic,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700139 G_TYPE_NONE,
140 G_TYPE_INT64,
141 G_TYPE_DOUBLE,
142 G_TYPE_STRING,
143 G_TYPE_STRING,
144 G_TYPE_INT64,
145 G_TYPE_INVALID);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700146
147 static const char kStatusUpdate[] = "StatusUpdate";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700148 dbus_g_proxy_add_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700149 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700150 G_TYPE_INT64,
151 G_TYPE_DOUBLE,
152 G_TYPE_STRING,
153 G_TYPE_STRING,
154 G_TYPE_INT64,
155 G_TYPE_INVALID);
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700156 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700157 dbus_g_proxy_connect_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700158 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700159 G_CALLBACK(StatusUpdateSignalHandler),
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700160 nullptr,
161 nullptr);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700162 g_main_loop_run(loop);
163 g_main_loop_unref(loop);
164}
165
Chris Sosad317e402013-06-12 13:47:09 -0700166bool Rollback(bool rollback) {
167 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700168 GError* error = nullptr;
Chris Sosad317e402013-06-12 13:47:09 -0700169
170 CHECK(GetProxy(&proxy));
171
Alex Deymo36dc2f32013-08-29 15:45:06 -0700172 gboolean rc = update_engine_client_attempt_rollback(proxy,
173 rollback,
174 &error);
Chris Sosad317e402013-06-12 13:47:09 -0700175 CHECK_EQ(rc, TRUE) << "Error with rollback request: "
176 << GetAndFreeGError(&error);
177 return true;
178}
179
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700180std::string GetRollbackPartition() {
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800181 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700182 GError* error = nullptr;
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800183
184 CHECK(GetProxy(&proxy));
185
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700186 char* rollback_partition = nullptr;
187 gboolean rc = update_engine_client_get_rollback_partition(proxy,
188 &rollback_partition,
189 &error);
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800190 CHECK_EQ(rc, TRUE) << "Error while querying rollback partition availabilty: "
191 << GetAndFreeGError(&error);
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700192 std::string partition = rollback_partition;
193 g_free(rollback_partition);
194 return partition;
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800195}
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700196
197std::string GetKernelDevices() {
198 DBusGProxy* proxy;
199 GError* error = nullptr;
200
201 CHECK(GetProxy(&proxy));
202
203 char* kernel_devices = nullptr;
204 gboolean rc = update_engine_client_get_kernel_devices(proxy,
205 &kernel_devices,
206 &error);
207 CHECK_EQ(rc, TRUE) << "Error while getting a list of kernel devices: "
208 << GetAndFreeGError(&error);
209 std::string devices = kernel_devices;
210 g_free(kernel_devices);
211 return devices;
212}
213
Steve Fung97b6f5a2014-10-07 12:39:51 -0700214bool CheckForUpdates(const string& app_version,
215 const string& omaha_url,
216 bool interactive) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700217 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700218 GError* error = nullptr;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700219
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700220 CHECK(GetProxy(&proxy));
221
David Zeuthen75a4c3e2013-09-06 11:36:59 -0700222 AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(
Steve Fung97b6f5a2014-10-07 12:39:51 -0700223 interactive ? 0 : kAttemptUpdateFlagNonInteractive);
David Zeuthen75a4c3e2013-09-06 11:36:59 -0700224 gboolean rc =
225 update_engine_client_attempt_update_with_flags(proxy,
226 app_version.c_str(),
227 omaha_url.c_str(),
228 static_cast<gint>(flags),
229 &error);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700230 CHECK_EQ(rc, TRUE) << "Error checking for update: "
Darin Petkova0b9e772011-10-06 05:05:56 -0700231 << GetAndFreeGError(&error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700232 return true;
233}
234
Darin Petkov296889c2010-07-23 16:20:54 -0700235bool RebootIfNeeded() {
236 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700237 GError* error = nullptr;
Darin Petkov296889c2010-07-23 16:20:54 -0700238
239 CHECK(GetProxy(&proxy));
240
241 gboolean rc =
Alex Deymo36dc2f32013-08-29 15:45:06 -0700242 update_engine_client_reboot_if_needed(proxy, &error);
Darin Petkov296889c2010-07-23 16:20:54 -0700243 // Reboot error code doesn't necessarily mean that a reboot
244 // failed. For example, D-Bus may be shutdown before we receive the
245 // result.
Darin Petkova0b9e772011-10-06 05:05:56 -0700246 LOG_IF(INFO, !rc) << "Reboot error message: " << GetAndFreeGError(&error);
Darin Petkov296889c2010-07-23 16:20:54 -0700247 return true;
248}
249
Chris Sosacb7fa882013-07-25 17:02:59 -0700250void SetTargetChannel(const string& target_channel, bool allow_powerwash) {
Darin Petkov8daa3242010-10-25 13:28:47 -0700251 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700252 GError* error = nullptr;
Darin Petkov8daa3242010-10-25 13:28:47 -0700253
254 CHECK(GetProxy(&proxy));
255
Alex Deymo36dc2f32013-08-29 15:45:06 -0700256 gboolean rc = update_engine_client_set_channel(proxy,
257 target_channel.c_str(),
258 allow_powerwash,
259 &error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700260 CHECK_EQ(rc, true) << "Error setting the channel: "
Darin Petkova0b9e772011-10-06 05:05:56 -0700261 << GetAndFreeGError(&error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700262 LOG(INFO) << "Channel permanently set to: " << target_channel;
Darin Petkov8daa3242010-10-25 13:28:47 -0700263}
264
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700265string GetChannel(bool get_current_channel) {
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900266 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700267 GError* error = nullptr;
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900268
269 CHECK(GetProxy(&proxy));
270
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700271 char* channel = nullptr;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700272 gboolean rc = update_engine_client_get_channel(proxy,
273 get_current_channel,
274 &channel,
275 &error);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700276 CHECK_EQ(rc, true) << "Error getting the channel: "
277 << GetAndFreeGError(&error);
278 string output = channel;
279 g_free(channel);
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900280 return output;
281}
282
Alex Deymo5fdf7762013-07-17 20:01:40 -0700283void SetUpdateOverCellularPermission(gboolean allowed) {
Alex Deymof4867c42013-06-28 14:41:39 -0700284 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700285 GError* error = nullptr;
Alex Deymof4867c42013-06-28 14:41:39 -0700286
287 CHECK(GetProxy(&proxy));
288
Alex Deymo36dc2f32013-08-29 15:45:06 -0700289 gboolean rc = update_engine_client_set_update_over_cellular_permission(
290 proxy,
291 allowed,
292 &error);
Alex Deymof4867c42013-06-28 14:41:39 -0700293 CHECK_EQ(rc, true) << "Error setting the update over cellular setting: "
294 << GetAndFreeGError(&error);
Alex Deymof4867c42013-06-28 14:41:39 -0700295}
296
297bool GetUpdateOverCellularPermission() {
298 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700299 GError* error = nullptr;
Alex Deymof4867c42013-06-28 14:41:39 -0700300
301 CHECK(GetProxy(&proxy));
302
303 gboolean allowed;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700304 gboolean rc = update_engine_client_get_update_over_cellular_permission(
305 proxy,
306 &allowed,
307 &error);
Alex Deymof4867c42013-06-28 14:41:39 -0700308 CHECK_EQ(rc, true) << "Error getting the update over cellular setting: "
309 << GetAndFreeGError(&error);
310 return allowed;
311}
312
Alex Deymo5fdf7762013-07-17 20:01:40 -0700313void SetP2PUpdatePermission(gboolean enabled) {
314 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700315 GError* error = nullptr;
Alex Deymo5fdf7762013-07-17 20:01:40 -0700316
317 CHECK(GetProxy(&proxy));
318
Alex Deymo36dc2f32013-08-29 15:45:06 -0700319 gboolean rc = update_engine_client_set_p2p_update_permission(
320 proxy,
321 enabled,
322 &error);
Alex Deymo5fdf7762013-07-17 20:01:40 -0700323 CHECK_EQ(rc, true) << "Error setting the peer-to-peer update setting: "
324 << GetAndFreeGError(&error);
325}
326
327bool GetP2PUpdatePermission() {
328 DBusGProxy* proxy;
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700329 GError* error = nullptr;
Alex Deymo5fdf7762013-07-17 20:01:40 -0700330
331 CHECK(GetProxy(&proxy));
332
333 gboolean enabled;
Alex Deymo36dc2f32013-08-29 15:45:06 -0700334 gboolean rc = update_engine_client_get_p2p_update_permission(
335 proxy,
336 &enabled,
337 &error);
Alex Deymo5fdf7762013-07-17 20:01:40 -0700338 CHECK_EQ(rc, true) << "Error getting the peer-to-peer update setting: "
339 << GetAndFreeGError(&error);
340 return enabled;
341}
342
Darin Petkov58529db2010-08-13 09:19:47 -0700343static gboolean CompleteUpdateSource(gpointer data) {
344 string current_op;
345 if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
346 LOG(ERROR) << "Update failed.";
347 exit(1);
348 }
349 if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
350 LOG(INFO) << "Update succeeded -- reboot needed.";
351 exit(0);
352 }
353 return TRUE;
354}
355
356// This is similar to watching for updates but rather than registering
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700357// a signal watch, actively poll the daemon just in case it stops
Darin Petkov58529db2010-08-13 09:19:47 -0700358// sending notifications.
359void CompleteUpdate() {
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700360 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
361 g_timeout_add_seconds(5, CompleteUpdateSource, nullptr);
Darin Petkov58529db2010-08-13 09:19:47 -0700362 g_main_loop_run(loop);
363 g_main_loop_unref(loop);
364}
365
Alex Vakulenkodea2eac2014-03-14 15:56:59 -0700366void ShowPrevVersion() {
367 DBusGProxy* proxy;
368 GError* error = nullptr;
369
370 CHECK(GetProxy(&proxy));
371
372 char* prev_version = nullptr;
373
374 gboolean rc = update_engine_client_get_prev_version(proxy,
375 &prev_version,
376 &error);
377 if (!rc) {
378 LOG(ERROR) << "Error getting previous version: "
379 << GetAndFreeGError(&error);
380 } else {
381 LOG(INFO) << "Previous version = " << prev_version;
382 g_free(prev_version);
383 }
384}
385
David Zeuthen9d73a722014-04-04 14:52:46 -0700386bool CheckIfRebootIsNeeded(DBusGProxy *proxy, bool *out_reboot_needed) {
387 gint64 last_checked_time = 0;
388 gdouble progress = 0.0;
389 char* current_op = nullptr;
390 char* new_version = nullptr;
391 gint64 new_size = 0;
392 GError* error = nullptr;
393
394 if (!update_engine_client_get_status(proxy,
395 &last_checked_time,
396 &progress,
397 &current_op,
398 &new_version,
399 &new_size,
400 &error)) {
401 LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
402 return false;
403 }
404 *out_reboot_needed =
405 (g_strcmp0(current_op,
406 update_engine::kUpdateStatusUpdatedNeedReboot) == 0);
407 g_free(current_op);
408 g_free(new_version);
409 return true;
410}
411
412// Determines if reboot is needed. The result is returned in
413// |out_reboot_needed|. Returns true if the check succeeded, false
414// otherwise.
415bool IsRebootNeeded(bool *out_reboot_needed) {
416 DBusGProxy* proxy = nullptr;
417 CHECK(GetProxy(&proxy));
418 bool ret = CheckIfRebootIsNeeded(proxy, out_reboot_needed);
419 g_object_unref(proxy);
420 return ret;
421}
422
423static void OnBlockUntilRebootStatusCallback(
424 DBusGProxy* proxy,
425 int64_t last_checked_time,
426 double progress,
427 const gchar* current_operation,
428 const gchar* new_version,
429 int64_t new_size,
430 void* user_data) {
431 GMainLoop *loop = reinterpret_cast<GMainLoop*>(user_data);
432 if (g_strcmp0(current_operation,
433 update_engine::kUpdateStatusUpdatedNeedReboot) == 0) {
434 g_main_loop_quit(loop);
435 }
436}
437
438bool CheckRebootNeeded(DBusGProxy *proxy, GMainLoop *loop) {
439 bool reboot_needed;
440 if (!CheckIfRebootIsNeeded(proxy, &reboot_needed))
441 return false;
442 if (reboot_needed)
443 return true;
444 // This will block until OnBlockUntilRebootStatusCallback() calls
445 // g_main_loop_quit().
446 g_main_loop_run(loop);
447 return true;
448}
449
450// Blocks until a reboot is needed. Returns true if waiting succeeded,
451// false if an error occurred.
452bool BlockUntilRebootIsNeeded() {
453 // The basic idea is to get a proxy, listen to signals and only then
454 // check the status. If no reboot is needed, just sit and wait for
455 // the StatusUpdate signal to convey that a reboot is pending.
456 DBusGProxy* proxy = nullptr;
457 CHECK(GetProxy(&proxy));
458 dbus_g_object_register_marshaller(
459 g_cclosure_marshal_generic,
460 G_TYPE_NONE,
461 G_TYPE_INT64,
462 G_TYPE_DOUBLE,
463 G_TYPE_STRING,
464 G_TYPE_STRING,
465 G_TYPE_INT64,
466 G_TYPE_INVALID);
467 dbus_g_proxy_add_signal(proxy,
468 update_engine::kStatusUpdate, // Signal name.
469 G_TYPE_INT64,
470 G_TYPE_DOUBLE,
471 G_TYPE_STRING,
472 G_TYPE_STRING,
473 G_TYPE_INT64,
474 G_TYPE_INVALID);
475 GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
476 dbus_g_proxy_connect_signal(proxy,
477 update_engine::kStatusUpdate,
478 G_CALLBACK(OnBlockUntilRebootStatusCallback),
479 loop,
480 nullptr); // free_data_func.
481
482 bool ret = CheckRebootNeeded(proxy, loop);
483
484 dbus_g_proxy_disconnect_signal(proxy,
485 update_engine::kStatusUpdate,
486 G_CALLBACK(OnBlockUntilRebootStatusCallback),
487 loop);
488 g_main_loop_unref(loop);
489 g_object_unref(proxy);
490 return ret;
491}
492
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700493} // namespace
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700494
495int main(int argc, char** argv) {
Steve Fung97b6f5a2014-10-07 12:39:51 -0700496 DEFINE_string(app_version, "", "Force the current app version.");
497 DEFINE_string(channel, "",
498 "Set the target channel. The device will be powerwashed if the "
499 "target channel is more stable than the current channel unless "
500 "--nopowerwash is specified.");
501 DEFINE_bool(check_for_update, false, "Initiate check for updates.");
502 DEFINE_bool(follow, false, "Wait for any update operations to complete."
503 "Exit status is 0 if the update succeeded, and 1 otherwise.");
504 DEFINE_bool(interactive, true, "Mark the update request as interactive.");
505 DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
506 DEFINE_string(p2p_update, "",
507 "Enables (\"yes\") or disables (\"no\") the peer-to-peer update"
508 " sharing.");
509 DEFINE_bool(powerwash, true, "When performing rollback or channel change, "
510 "do a powerwash or allow it respectively.");
511 DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
512 DEFINE_bool(is_reboot_needed, false, "Exit status 0 if reboot is needed, "
513 "2 if reboot is not needed or 1 if an error occurred.");
514 DEFINE_bool(block_until_reboot_is_needed, false, "Blocks until reboot is "
515 "needed. Returns non-zero exit status if an error occurred.");
516 DEFINE_bool(reset_status, false, "Sets the status in update_engine to idle.");
517 DEFINE_bool(rollback, false, "Perform a rollback to the previous partition.");
518 DEFINE_bool(can_rollback, false, "Shows whether rollback partition "
519 "is available.");
520 DEFINE_bool(show_channel, false, "Show the current and target channels.");
521 DEFINE_bool(show_p2p_update, false,
522 "Show the current setting for peer-to-peer update sharing.");
523 DEFINE_bool(show_update_over_cellular, false,
524 "Show the current setting for updates over cellular networks.");
525 DEFINE_bool(status, false, "Print the status to stdout.");
526 DEFINE_bool(update, false, "Forces an update and waits for it to complete. "
527 "Implies --follow.");
528 DEFINE_string(update_over_cellular, "",
529 "Enables (\"yes\") or disables (\"no\") the updates over "
530 "cellular networks.");
531 DEFINE_bool(watch_for_updates, false,
532 "Listen for status updates and print them to the screen.");
533 DEFINE_bool(prev_version, false,
534 "Show the previous OS version used before the update reboot.");
535 DEFINE_bool(show_kernels, false, "Show the list of kernel patritions and "
536 "whether each of them is bootable or not");
537
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700538 // Boilerplate init commands.
539 g_type_init();
Ben Chan46bf5c82013-06-24 11:17:41 -0700540 dbus_threads_init_default();
Steve Fung97b6f5a2014-10-07 12:39:51 -0700541 chromeos::FlagHelper::Init(argc, argv, "Chromium OS Update Engine Client");
Andrew de los Reyesada42202010-07-15 22:23:20 -0700542
Jay Srinivasanc1ba09a2012-08-14 14:15:57 -0700543 // Update the status if requested.
544 if (FLAGS_reset_status) {
545 LOG(INFO) << "Setting Update Engine status to idle ...";
546 if (!ResetStatus()) {
547 LOG(ERROR) << "ResetStatus failed.";
548 return 1;
549 }
Gilad Arnold50c60632013-01-25 10:27:19 -0800550 LOG(INFO) << "ResetStatus succeeded; to undo partition table changes run:\n"
551 "(D=$(rootdev -d) P=$(rootdev -s); cgpt p -i$(($(echo ${P#$D} "
552 "| sed 's/^[^0-9]*//')-1)) $D;)";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700553 }
Darin Petkov58529db2010-08-13 09:19:47 -0700554
Alex Deymof4867c42013-06-28 14:41:39 -0700555 // Changes the current update over cellular network setting.
556 if (!FLAGS_update_over_cellular.empty()) {
557 gboolean allowed = FLAGS_update_over_cellular == "yes";
558 if (!allowed && FLAGS_update_over_cellular != "no") {
559 LOG(ERROR) << "Unknown option: \"" << FLAGS_update_over_cellular
560 << "\". Please specify \"yes\" or \"no\".";
561 } else {
562 SetUpdateOverCellularPermission(allowed);
563 }
564 }
565
566 // Show the current update over cellular network setting.
567 if (FLAGS_show_update_over_cellular) {
568 bool allowed = GetUpdateOverCellularPermission();
569 LOG(INFO) << "Current update over cellular network setting: "
570 << (allowed ? "ENABLED" : "DISABLED");
571 }
572
Chris Sosacb7fa882013-07-25 17:02:59 -0700573 if (!FLAGS_powerwash && !FLAGS_rollback && FLAGS_channel.empty()) {
Chris Sosa192449e2013-10-28 14:16:19 -0700574 LOG(ERROR) << "powerwash flag only makes sense rollback or channel change";
Chris Sosacb7fa882013-07-25 17:02:59 -0700575 return 1;
576 }
577
Alex Deymo5fdf7762013-07-17 20:01:40 -0700578 // Change the P2P enabled setting.
579 if (!FLAGS_p2p_update.empty()) {
580 gboolean enabled = FLAGS_p2p_update == "yes";
581 if (!enabled && FLAGS_p2p_update != "no") {
582 LOG(ERROR) << "Unknown option: \"" << FLAGS_p2p_update
583 << "\". Please specify \"yes\" or \"no\".";
584 } else {
585 SetP2PUpdatePermission(enabled);
586 }
587 }
588
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800589 // Show the rollback availability.
590 if (FLAGS_can_rollback) {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700591 std::string rollback_partition = GetRollbackPartition();
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700592 bool can_rollback = true;
593 if (rollback_partition.empty()) {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700594 rollback_partition = "UNAVAILABLE";
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700595 can_rollback = false;
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700596 } else {
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700597 rollback_partition = "AVAILABLE: " + rollback_partition;
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700598 }
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700599
600 LOG(INFO) << "Rollback partition: " << rollback_partition;
Chris Sosaf5c0b9c2014-04-17 16:12:03 -0700601 if (!can_rollback) {
602 return 1;
603 }
Alex Vakulenko59e253e2014-02-24 10:40:21 -0800604 }
605
Alex Deymo5fdf7762013-07-17 20:01:40 -0700606 // Show the current P2P enabled setting.
607 if (FLAGS_show_p2p_update) {
608 bool enabled = GetP2PUpdatePermission();
609 LOG(INFO) << "Current update using P2P setting: "
610 << (enabled ? "ENABLED" : "DISABLED");
611 }
612
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700613 // First, update the target channel if requested.
614 if (!FLAGS_channel.empty())
Chris Sosacb7fa882013-07-25 17:02:59 -0700615 SetTargetChannel(FLAGS_channel, FLAGS_powerwash);
Darin Petkov8daa3242010-10-25 13:28:47 -0700616
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700617 // Show the current and target channels if requested.
618 if (FLAGS_show_channel) {
619 string current_channel = GetChannel(true);
620 LOG(INFO) << "Current Channel: " << current_channel;
621
622 string target_channel = GetChannel(false);
623 if (!target_channel.empty())
624 LOG(INFO) << "Target Channel (pending update): " << target_channel;
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900625 }
626
Chris Sosad317e402013-06-12 13:47:09 -0700627 bool do_update_request = FLAGS_check_for_update | FLAGS_update |
628 !FLAGS_app_version.empty() | !FLAGS_omaha_url.empty();
Chris Sosa192449e2013-10-28 14:16:19 -0700629 if (FLAGS_update)
630 FLAGS_follow = true;
Chris Sosad317e402013-06-12 13:47:09 -0700631
Chris Sosad317e402013-06-12 13:47:09 -0700632 if (do_update_request && FLAGS_rollback) {
Chris Sosa192449e2013-10-28 14:16:19 -0700633 LOG(ERROR) << "Incompatible flags specified with rollback."
634 << "Rollback should not include update-related flags.";
Chris Sosad317e402013-06-12 13:47:09 -0700635 return 1;
636 }
637
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700638 if (FLAGS_rollback) {
Chris Sosad317e402013-06-12 13:47:09 -0700639 LOG(INFO) << "Requesting rollback.";
640 CHECK(Rollback(FLAGS_powerwash)) << "Request for rollback failed.";
Chris Sosad317e402013-06-12 13:47:09 -0700641 }
642
Darin Petkov58529db2010-08-13 09:19:47 -0700643 // Initiate an update check, if necessary.
Chris Sosad317e402013-06-12 13:47:09 -0700644 if (do_update_request) {
Darin Petkov296889c2010-07-23 16:20:54 -0700645 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Darin Petkov58529db2010-08-13 09:19:47 -0700646 string app_version = FLAGS_app_version;
647 if (FLAGS_update && app_version.empty()) {
648 app_version = "ForcedUpdate";
649 LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700650 }
Darin Petkov58529db2010-08-13 09:19:47 -0700651 LOG(INFO) << "Initiating update check and install.";
Steve Fung97b6f5a2014-10-07 12:39:51 -0700652 CHECK(CheckForUpdates(app_version, FLAGS_omaha_url, FLAGS_interactive))
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700653 << "Update check/initiate update failed.";
Chris Sosa192449e2013-10-28 14:16:19 -0700654 }
Darin Petkov58529db2010-08-13 09:19:47 -0700655
Chris Sosa192449e2013-10-28 14:16:19 -0700656 // These final options are all mutually exclusive with one another.
David Zeuthen9d73a722014-04-04 14:52:46 -0700657 if (FLAGS_follow + FLAGS_watch_for_updates + FLAGS_reboot +
658 FLAGS_status + FLAGS_is_reboot_needed +
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700659 FLAGS_block_until_reboot_is_needed > 1) {
Chris Sosa192449e2013-10-28 14:16:19 -0700660 LOG(ERROR) << "Multiple exclusive options selected. "
661 << "Select only one of --follow, --watch_for_updates, --reboot, "
David Zeuthen9d73a722014-04-04 14:52:46 -0700662 << "--is_reboot_needed, --block_until_reboot_is_needed, "
Chris Sosa192449e2013-10-28 14:16:19 -0700663 << "or --status.";
664 return 1;
665 }
666
667 if (FLAGS_status) {
668 LOG(INFO) << "Querying Update Engine status...";
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700669 if (!GetStatus(nullptr)) {
Chris Sosa192449e2013-10-28 14:16:19 -0700670 LOG(ERROR) << "GetStatus failed.";
Darin Petkov58529db2010-08-13 09:19:47 -0700671 return 1;
672 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700673 return 0;
674 }
Darin Petkov58529db2010-08-13 09:19:47 -0700675
Chris Sosa192449e2013-10-28 14:16:19 -0700676 if (FLAGS_follow) {
677 LOG(INFO) << "Waiting for update to complete.";
678 CompleteUpdate(); // Should never return.
679 return 1;
680 }
681
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700682 if (FLAGS_watch_for_updates) {
683 LOG(INFO) << "Watching for status updates.";
684 WatchForUpdates(); // Should never return.
685 return 1;
686 }
Darin Petkov58529db2010-08-13 09:19:47 -0700687
Darin Petkov296889c2010-07-23 16:20:54 -0700688 if (FLAGS_reboot) {
689 LOG(INFO) << "Requesting a reboot...";
690 CHECK(RebootIfNeeded());
691 return 0;
692 }
Andrew de los Reyesada42202010-07-15 22:23:20 -0700693
Alex Vakulenkodea2eac2014-03-14 15:56:59 -0700694 if (FLAGS_prev_version) {
695 ShowPrevVersion();
696 }
697
Alex Vakulenko2bddadd2014-03-27 13:23:46 -0700698 if (FLAGS_show_kernels) {
699 LOG(INFO) << "Kernel partitions:\n"
700 << GetKernelDevices();
701 }
702
David Zeuthen9d73a722014-04-04 14:52:46 -0700703 if (FLAGS_is_reboot_needed) {
704 bool reboot_needed = false;
705 if (!IsRebootNeeded(&reboot_needed))
706 return 1;
707 else if (!reboot_needed)
708 return 2;
709 }
710
711 if (FLAGS_block_until_reboot_is_needed) {
712 if (!BlockUntilRebootIsNeeded())
713 return 1;
714 }
715
Darin Petkov8daa3242010-10-25 13:28:47 -0700716 LOG(INFO) << "Done.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700717 return 0;
718}