blob: fb2d418f38f357643e4217169c7a8d42df7adb36 [file] [log] [blame]
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07001// Copyright (c) 2010 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
Darin Petkov5a7f5652010-07-22 21:40:09 -07005#include <string>
6
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07007#include <gflags/gflags.h>
8#include <glib.h>
9
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070010#include "update_engine/marshal.glibmarshal.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070011#include "update_engine/dbus_constants.h"
12#include "update_engine/subprocess.h"
13#include "update_engine/utils.h"
14
15extern "C" {
16#include "update_engine/update_engine.dbusclient.h"
17}
18
19using chromeos_update_engine::kUpdateEngineServiceName;
20using chromeos_update_engine::kUpdateEngineServicePath;
21using chromeos_update_engine::kUpdateEngineServiceInterface;
Andrew de los Reyesc7020782010-04-28 10:46:04 -070022using chromeos_update_engine::utils::GetGErrorMessage;
Darin Petkov5a7f5652010-07-22 21:40:09 -070023using std::string;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070024
Darin Petkov296889c2010-07-23 16:20:54 -070025DEFINE_string(app_version, "", "Force the current app version.");
26DEFINE_bool(check_for_update, false, "Initiate check for updates.");
Darin Petkov296889c2010-07-23 16:20:54 -070027DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
28DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
Satoru Takabayashi583667b2010-10-27 13:09:57 +090029DEFINE_bool(show_track, false, "Show the update track.");
Darin Petkov5a7f5652010-07-22 21:40:09 -070030DEFINE_bool(status, false, "Print the status to stdout.");
Darin Petkov8daa3242010-10-25 13:28:47 -070031DEFINE_string(track, "", "Permanently change the update track.");
Darin Petkov58529db2010-08-13 09:19:47 -070032DEFINE_bool(update, false, "Forces an update and waits for its completion. "
33 "Exit status is 0 if the update succeeded, and 1 otherwise.");
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070034DEFINE_bool(watch_for_updates, false,
35 "Listen for status updates and print them to the screen.");
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070036
37namespace {
38
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070039bool GetProxy(DBusGProxy** out_proxy) {
40 DBusGConnection* bus;
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070041 DBusGProxy* proxy = NULL;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070042 GError* error = NULL;
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070043 const int kTries = 4;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070044
45 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
46 if (!bus) {
47 LOG(FATAL) << "Failed to get bus";
48 }
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070049 for (int i = 0; !proxy && i < kTries; ++i) {
Andrew de los Reyes8ed2d162011-08-12 11:09:43 -070050 LOG_IF(INFO, i) << "Trying to get dbus proxy. Try "
51 << (i + 1) << "/" << kTries;
Andrew de los Reyes68ab6ed2011-08-09 14:46:39 -070052 proxy = dbus_g_proxy_new_for_name_owner(bus,
53 kUpdateEngineServiceName,
54 kUpdateEngineServicePath,
55 kUpdateEngineServiceInterface,
56 &error);
57 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070058 if (!proxy) {
Kenneth Waters71e8e5c2010-09-10 09:50:40 -070059 LOG(FATAL) << "Error getting dbus proxy for "
60 << kUpdateEngineServiceName << ": " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070061 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070062 *out_proxy = proxy;
63 return true;
64}
65
66static void StatusUpdateSignalHandler(DBusGProxy* proxy,
67 int64_t last_checked_time,
68 double progress,
69 gchar* current_operation,
70 gchar* new_version,
71 int64_t new_size,
72 void* user_data) {
73 LOG(INFO) << "Got status update:";
74 LOG(INFO) << " last_checked_time: " << last_checked_time;
75 LOG(INFO) << " progress: " << progress;
76 LOG(INFO) << " current_operation: " << current_operation;
77 LOG(INFO) << " new_version: " << new_version;
78 LOG(INFO) << " new_size: " << new_size;
79}
80
Darin Petkov58529db2010-08-13 09:19:47 -070081// If |op| is non-NULL, sets it to the current operation string or an
82// empty string if unable to obtain the current status.
83bool GetStatus(string* op) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070084 DBusGProxy* proxy;
85 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -070086
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070087 CHECK(GetProxy(&proxy));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070088
89 gint64 last_checked_time = 0;
90 gdouble progress = 0.0;
91 char* current_op = NULL;
92 char* new_version = NULL;
93 gint64 new_size = 0;
94
95 gboolean rc = org_chromium_UpdateEngineInterface_get_status(
96 proxy,
97 &last_checked_time,
98 &progress,
99 &current_op,
100 &new_version,
101 &new_size,
102 &error);
103 if (rc == FALSE) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700104 LOG(INFO) << "Error getting status: " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700105 }
106 printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
107 "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
108 last_checked_time,
109 progress,
110 current_op,
111 new_version,
112 new_size);
Darin Petkov58529db2010-08-13 09:19:47 -0700113 if (op) {
114 *op = current_op ? current_op : "";
115 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700116 return true;
117}
118
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700119// Should never return.
120void WatchForUpdates() {
121 DBusGProxy* proxy;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700122
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700123 CHECK(GetProxy(&proxy));
Andrew de los Reyesada42202010-07-15 22:23:20 -0700124
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700125 // Register marshaller
126 dbus_g_object_register_marshaller(
127 update_engine_VOID__INT64_DOUBLE_STRING_STRING_INT64,
128 G_TYPE_NONE,
129 G_TYPE_INT64,
130 G_TYPE_DOUBLE,
131 G_TYPE_STRING,
132 G_TYPE_STRING,
133 G_TYPE_INT64,
134 G_TYPE_INVALID);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700135
136 static const char kStatusUpdate[] = "StatusUpdate";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700137 dbus_g_proxy_add_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700138 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700139 G_TYPE_INT64,
140 G_TYPE_DOUBLE,
141 G_TYPE_STRING,
142 G_TYPE_STRING,
143 G_TYPE_INT64,
144 G_TYPE_INVALID);
145 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
146 dbus_g_proxy_connect_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700147 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700148 G_CALLBACK(StatusUpdateSignalHandler),
149 NULL,
150 NULL);
151 g_main_loop_run(loop);
152 g_main_loop_unref(loop);
153}
154
Darin Petkov58529db2010-08-13 09:19:47 -0700155bool CheckForUpdates(const string& app_version, const string& omaha_url) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700156 DBusGProxy* proxy;
157 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700158
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700159 CHECK(GetProxy(&proxy));
160
161 gboolean rc =
Darin Petkov5a7f5652010-07-22 21:40:09 -0700162 org_chromium_UpdateEngineInterface_attempt_update(proxy,
163 app_version.c_str(),
164 omaha_url.c_str(),
165 &error);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700166 CHECK_EQ(rc, TRUE) << "Error checking for update: "
167 << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700168 return true;
169}
170
Darin Petkov296889c2010-07-23 16:20:54 -0700171bool RebootIfNeeded() {
172 DBusGProxy* proxy;
173 GError* error = NULL;
174
175 CHECK(GetProxy(&proxy));
176
177 gboolean rc =
178 org_chromium_UpdateEngineInterface_reboot_if_needed(proxy, &error);
179 // Reboot error code doesn't necessarily mean that a reboot
180 // failed. For example, D-Bus may be shutdown before we receive the
181 // result.
182 LOG_IF(INFO, !rc) << "Reboot error message: " << GetGErrorMessage(error);
183 return true;
184}
185
Darin Petkov8daa3242010-10-25 13:28:47 -0700186void SetTrack(const string& track) {
187 DBusGProxy* proxy;
188 GError* error = NULL;
189
190 CHECK(GetProxy(&proxy));
191
192 gboolean rc =
193 org_chromium_UpdateEngineInterface_set_track(proxy,
194 track.c_str(),
195 &error);
196 CHECK_EQ(rc, true) << "Error setting the track: "
197 << GetGErrorMessage(error);
Darin Petkov49d91322010-10-25 16:34:58 -0700198 LOG(INFO) << "Track permanently set to: " << track;
Darin Petkov8daa3242010-10-25 13:28:47 -0700199}
200
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900201string GetTrack() {
202 DBusGProxy* proxy;
203 GError* error = NULL;
204
205 CHECK(GetProxy(&proxy));
206
207 char* track = NULL;
208 gboolean rc =
209 org_chromium_UpdateEngineInterface_get_track(proxy,
210 &track,
211 &error);
212 CHECK_EQ(rc, true) << "Error getting the track: "
213 << GetGErrorMessage(error);
214 string output = track;
215 g_free(track);
216 return output;
217}
218
Darin Petkov58529db2010-08-13 09:19:47 -0700219static gboolean CompleteUpdateSource(gpointer data) {
220 string current_op;
221 if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
222 LOG(ERROR) << "Update failed.";
223 exit(1);
224 }
225 if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
226 LOG(INFO) << "Update succeeded -- reboot needed.";
227 exit(0);
228 }
229 return TRUE;
230}
231
232// This is similar to watching for updates but rather than registering
233// a signal watch, activelly poll the daemon just in case it stops
234// sending notifications.
235void CompleteUpdate() {
236 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
237 g_timeout_add_seconds(5, CompleteUpdateSource, NULL);
238 g_main_loop_run(loop);
239 g_main_loop_unref(loop);
240}
241
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700242} // namespace {}
243
244int main(int argc, char** argv) {
245 // Boilerplate init commands.
246 g_type_init();
247 g_thread_init(NULL);
248 dbus_g_thread_init();
249 chromeos_update_engine::Subprocess::Init();
250 google::ParseCommandLineFlags(&argc, &argv, true);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700251
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700252 if (FLAGS_status) {
253 LOG(INFO) << "Querying Update Engine status...";
Darin Petkov58529db2010-08-13 09:19:47 -0700254 if (!GetStatus(NULL)) {
255 LOG(FATAL) << "GetStatus failed.";
256 return 1;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700257 }
258 return 0;
259 }
Darin Petkov58529db2010-08-13 09:19:47 -0700260
Darin Petkov8daa3242010-10-25 13:28:47 -0700261 // First, update the track if requested.
262 if (!FLAGS_track.empty()) {
263 SetTrack(FLAGS_track);
264 }
265
Satoru Takabayashi583667b2010-10-27 13:09:57 +0900266 // Show the track if requested.
267 if (FLAGS_show_track) {
268 LOG(INFO) << "Track: " << GetTrack();
269 }
270
Darin Petkov58529db2010-08-13 09:19:47 -0700271 // Initiate an update check, if necessary.
272 if (FLAGS_check_for_update ||
273 FLAGS_update ||
274 !FLAGS_app_version.empty() ||
275 !FLAGS_omaha_url.empty()) {
Darin Petkov296889c2010-07-23 16:20:54 -0700276 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Darin Petkov58529db2010-08-13 09:19:47 -0700277 string app_version = FLAGS_app_version;
278 if (FLAGS_update && app_version.empty()) {
279 app_version = "ForcedUpdate";
280 LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700281 }
Darin Petkov58529db2010-08-13 09:19:47 -0700282 LOG(INFO) << "Initiating update check and install.";
283 CHECK(CheckForUpdates(app_version, FLAGS_omaha_url))
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700284 << "Update check/initiate update failed.";
Darin Petkov58529db2010-08-13 09:19:47 -0700285
286 // Wait for an update to complete.
287 if (FLAGS_update) {
Darin Petkov9d911fa2010-08-19 09:36:08 -0700288 LOG(INFO) << "Waiting for update to complete.";
Darin Petkov58529db2010-08-13 09:19:47 -0700289 CompleteUpdate(); // Should never return.
290 return 1;
291 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700292 return 0;
293 }
Darin Petkov58529db2010-08-13 09:19:47 -0700294
295 // Start watching for updates.
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700296 if (FLAGS_watch_for_updates) {
Darin Petkov296889c2010-07-23 16:20:54 -0700297 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700298 LOG(INFO) << "Watching for status updates.";
299 WatchForUpdates(); // Should never return.
300 return 1;
301 }
Darin Petkov58529db2010-08-13 09:19:47 -0700302
Darin Petkov296889c2010-07-23 16:20:54 -0700303 if (FLAGS_reboot) {
304 LOG(INFO) << "Requesting a reboot...";
305 CHECK(RebootIfNeeded());
306 return 0;
307 }
Andrew de los Reyesada42202010-07-15 22:23:20 -0700308
Darin Petkov8daa3242010-10-25 13:28:47 -0700309 LOG(INFO) << "Done.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700310 return 0;
311}