blob: a662242b4e66f89a973085a827768f5f8279881b [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.");
Darin Petkov5a7f5652010-07-22 21:40:09 -070029DEFINE_bool(status, false, "Print the status to stdout.");
Darin Petkov8daa3242010-10-25 13:28:47 -070030DEFINE_string(track, "", "Permanently change the update track.");
Darin Petkov58529db2010-08-13 09:19:47 -070031DEFINE_bool(update, false, "Forces an update and waits for its completion. "
32 "Exit status is 0 if the update succeeded, and 1 otherwise.");
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070033DEFINE_bool(watch_for_updates, false,
34 "Listen for status updates and print them to the screen.");
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070035
36namespace {
37
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070038bool GetProxy(DBusGProxy** out_proxy) {
39 DBusGConnection* bus;
40 DBusGProxy* proxy;
41 GError* error = NULL;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070042
43 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
44 if (!bus) {
45 LOG(FATAL) << "Failed to get bus";
46 }
47 proxy = dbus_g_proxy_new_for_name_owner(bus,
48 kUpdateEngineServiceName,
49 kUpdateEngineServicePath,
50 kUpdateEngineServiceInterface,
51 &error);
52 if (!proxy) {
Kenneth Waters71e8e5c2010-09-10 09:50:40 -070053 LOG(FATAL) << "Error getting dbus proxy for "
54 << kUpdateEngineServiceName << ": " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070055 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070056 *out_proxy = proxy;
57 return true;
58}
59
60static void StatusUpdateSignalHandler(DBusGProxy* proxy,
61 int64_t last_checked_time,
62 double progress,
63 gchar* current_operation,
64 gchar* new_version,
65 int64_t new_size,
66 void* user_data) {
67 LOG(INFO) << "Got status update:";
68 LOG(INFO) << " last_checked_time: " << last_checked_time;
69 LOG(INFO) << " progress: " << progress;
70 LOG(INFO) << " current_operation: " << current_operation;
71 LOG(INFO) << " new_version: " << new_version;
72 LOG(INFO) << " new_size: " << new_size;
73}
74
Darin Petkov58529db2010-08-13 09:19:47 -070075// If |op| is non-NULL, sets it to the current operation string or an
76// empty string if unable to obtain the current status.
77bool GetStatus(string* op) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070078 DBusGProxy* proxy;
79 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -070080
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070081 CHECK(GetProxy(&proxy));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070082
83 gint64 last_checked_time = 0;
84 gdouble progress = 0.0;
85 char* current_op = NULL;
86 char* new_version = NULL;
87 gint64 new_size = 0;
88
89 gboolean rc = org_chromium_UpdateEngineInterface_get_status(
90 proxy,
91 &last_checked_time,
92 &progress,
93 &current_op,
94 &new_version,
95 &new_size,
96 &error);
97 if (rc == FALSE) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070098 LOG(INFO) << "Error getting status: " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070099 }
100 printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
101 "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
102 last_checked_time,
103 progress,
104 current_op,
105 new_version,
106 new_size);
Darin Petkov58529db2010-08-13 09:19:47 -0700107 if (op) {
108 *op = current_op ? current_op : "";
109 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700110 return true;
111}
112
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700113// Should never return.
114void WatchForUpdates() {
115 DBusGProxy* proxy;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700116
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700117 CHECK(GetProxy(&proxy));
Andrew de los Reyesada42202010-07-15 22:23:20 -0700118
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700119 // Register marshaller
120 dbus_g_object_register_marshaller(
121 update_engine_VOID__INT64_DOUBLE_STRING_STRING_INT64,
122 G_TYPE_NONE,
123 G_TYPE_INT64,
124 G_TYPE_DOUBLE,
125 G_TYPE_STRING,
126 G_TYPE_STRING,
127 G_TYPE_INT64,
128 G_TYPE_INVALID);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700129
130 static const char kStatusUpdate[] = "StatusUpdate";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700131 dbus_g_proxy_add_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700132 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700133 G_TYPE_INT64,
134 G_TYPE_DOUBLE,
135 G_TYPE_STRING,
136 G_TYPE_STRING,
137 G_TYPE_INT64,
138 G_TYPE_INVALID);
139 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
140 dbus_g_proxy_connect_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700141 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700142 G_CALLBACK(StatusUpdateSignalHandler),
143 NULL,
144 NULL);
145 g_main_loop_run(loop);
146 g_main_loop_unref(loop);
147}
148
Darin Petkov58529db2010-08-13 09:19:47 -0700149bool CheckForUpdates(const string& app_version, const string& omaha_url) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700150 DBusGProxy* proxy;
151 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700152
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700153 CHECK(GetProxy(&proxy));
154
155 gboolean rc =
Darin Petkov5a7f5652010-07-22 21:40:09 -0700156 org_chromium_UpdateEngineInterface_attempt_update(proxy,
157 app_version.c_str(),
158 omaha_url.c_str(),
159 &error);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700160 CHECK_EQ(rc, TRUE) << "Error checking for update: "
161 << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700162 return true;
163}
164
Darin Petkov296889c2010-07-23 16:20:54 -0700165bool RebootIfNeeded() {
166 DBusGProxy* proxy;
167 GError* error = NULL;
168
169 CHECK(GetProxy(&proxy));
170
171 gboolean rc =
172 org_chromium_UpdateEngineInterface_reboot_if_needed(proxy, &error);
173 // Reboot error code doesn't necessarily mean that a reboot
174 // failed. For example, D-Bus may be shutdown before we receive the
175 // result.
176 LOG_IF(INFO, !rc) << "Reboot error message: " << GetGErrorMessage(error);
177 return true;
178}
179
Darin Petkov8daa3242010-10-25 13:28:47 -0700180void SetTrack(const string& track) {
181 DBusGProxy* proxy;
182 GError* error = NULL;
183
184 CHECK(GetProxy(&proxy));
185
186 gboolean rc =
187 org_chromium_UpdateEngineInterface_set_track(proxy,
188 track.c_str(),
189 &error);
190 CHECK_EQ(rc, true) << "Error setting the track: "
191 << GetGErrorMessage(error);
192 LOG(INFO) << "TODO: Track permanently set to: " << track;
193}
194
Darin Petkov58529db2010-08-13 09:19:47 -0700195static gboolean CompleteUpdateSource(gpointer data) {
196 string current_op;
197 if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
198 LOG(ERROR) << "Update failed.";
199 exit(1);
200 }
201 if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
202 LOG(INFO) << "Update succeeded -- reboot needed.";
203 exit(0);
204 }
205 return TRUE;
206}
207
208// This is similar to watching for updates but rather than registering
209// a signal watch, activelly poll the daemon just in case it stops
210// sending notifications.
211void CompleteUpdate() {
212 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
213 g_timeout_add_seconds(5, CompleteUpdateSource, NULL);
214 g_main_loop_run(loop);
215 g_main_loop_unref(loop);
216}
217
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700218} // namespace {}
219
220int main(int argc, char** argv) {
221 // Boilerplate init commands.
222 g_type_init();
223 g_thread_init(NULL);
224 dbus_g_thread_init();
225 chromeos_update_engine::Subprocess::Init();
226 google::ParseCommandLineFlags(&argc, &argv, true);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700227
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700228 if (FLAGS_status) {
229 LOG(INFO) << "Querying Update Engine status...";
Darin Petkov58529db2010-08-13 09:19:47 -0700230 if (!GetStatus(NULL)) {
231 LOG(FATAL) << "GetStatus failed.";
232 return 1;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700233 }
234 return 0;
235 }
Darin Petkov58529db2010-08-13 09:19:47 -0700236
Darin Petkov8daa3242010-10-25 13:28:47 -0700237 // First, update the track if requested.
238 if (!FLAGS_track.empty()) {
239 SetTrack(FLAGS_track);
240 }
241
Darin Petkov58529db2010-08-13 09:19:47 -0700242 // Initiate an update check, if necessary.
243 if (FLAGS_check_for_update ||
244 FLAGS_update ||
245 !FLAGS_app_version.empty() ||
246 !FLAGS_omaha_url.empty()) {
Darin Petkov296889c2010-07-23 16:20:54 -0700247 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Darin Petkov58529db2010-08-13 09:19:47 -0700248 string app_version = FLAGS_app_version;
249 if (FLAGS_update && app_version.empty()) {
250 app_version = "ForcedUpdate";
251 LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700252 }
Darin Petkov58529db2010-08-13 09:19:47 -0700253 LOG(INFO) << "Initiating update check and install.";
254 CHECK(CheckForUpdates(app_version, FLAGS_omaha_url))
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700255 << "Update check/initiate update failed.";
Darin Petkov58529db2010-08-13 09:19:47 -0700256
257 // Wait for an update to complete.
258 if (FLAGS_update) {
Darin Petkov9d911fa2010-08-19 09:36:08 -0700259 LOG(INFO) << "Waiting for update to complete.";
Darin Petkov58529db2010-08-13 09:19:47 -0700260 CompleteUpdate(); // Should never return.
261 return 1;
262 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700263 return 0;
264 }
Darin Petkov58529db2010-08-13 09:19:47 -0700265
266 // Start watching for updates.
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700267 if (FLAGS_watch_for_updates) {
Darin Petkov296889c2010-07-23 16:20:54 -0700268 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700269 LOG(INFO) << "Watching for status updates.";
270 WatchForUpdates(); // Should never return.
271 return 1;
272 }
Darin Petkov58529db2010-08-13 09:19:47 -0700273
Darin Petkov296889c2010-07-23 16:20:54 -0700274 if (FLAGS_reboot) {
275 LOG(INFO) << "Requesting a reboot...";
276 CHECK(RebootIfNeeded());
277 return 0;
278 }
Andrew de los Reyesada42202010-07-15 22:23:20 -0700279
Darin Petkov8daa3242010-10-25 13:28:47 -0700280 LOG(INFO) << "Done.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700281 return 0;
282}