blob: e25d313ddabcdd30a58c8e15bf169370c8a9fbe2 [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 Petkov58529db2010-08-13 09:19:47 -070030DEFINE_bool(update, false, "Forces an update and waits for its completion. "
31 "Exit status is 0 if the update succeeded, and 1 otherwise.");
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070032DEFINE_bool(watch_for_updates, false,
33 "Listen for status updates and print them to the screen.");
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070034
35namespace {
36
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070037bool GetProxy(DBusGProxy** out_proxy) {
38 DBusGConnection* bus;
39 DBusGProxy* proxy;
40 GError* error = NULL;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070041
42 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
43 if (!bus) {
44 LOG(FATAL) << "Failed to get bus";
45 }
46 proxy = dbus_g_proxy_new_for_name_owner(bus,
47 kUpdateEngineServiceName,
48 kUpdateEngineServicePath,
49 kUpdateEngineServiceInterface,
50 &error);
51 if (!proxy) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070052 LOG(FATAL) << "Error getting proxy: " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070053 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070054 *out_proxy = proxy;
55 return true;
56}
57
58static void StatusUpdateSignalHandler(DBusGProxy* proxy,
59 int64_t last_checked_time,
60 double progress,
61 gchar* current_operation,
62 gchar* new_version,
63 int64_t new_size,
64 void* user_data) {
65 LOG(INFO) << "Got status update:";
66 LOG(INFO) << " last_checked_time: " << last_checked_time;
67 LOG(INFO) << " progress: " << progress;
68 LOG(INFO) << " current_operation: " << current_operation;
69 LOG(INFO) << " new_version: " << new_version;
70 LOG(INFO) << " new_size: " << new_size;
71}
72
Darin Petkov58529db2010-08-13 09:19:47 -070073// If |op| is non-NULL, sets it to the current operation string or an
74// empty string if unable to obtain the current status.
75bool GetStatus(string* op) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070076 DBusGProxy* proxy;
77 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -070078
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070079 CHECK(GetProxy(&proxy));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070080
81 gint64 last_checked_time = 0;
82 gdouble progress = 0.0;
83 char* current_op = NULL;
84 char* new_version = NULL;
85 gint64 new_size = 0;
86
87 gboolean rc = org_chromium_UpdateEngineInterface_get_status(
88 proxy,
89 &last_checked_time,
90 &progress,
91 &current_op,
92 &new_version,
93 &new_size,
94 &error);
95 if (rc == FALSE) {
Andrew de los Reyesc7020782010-04-28 10:46:04 -070096 LOG(INFO) << "Error getting status: " << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070097 }
98 printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
99 "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
100 last_checked_time,
101 progress,
102 current_op,
103 new_version,
104 new_size);
Darin Petkov58529db2010-08-13 09:19:47 -0700105 if (op) {
106 *op = current_op ? current_op : "";
107 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700108 return true;
109}
110
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700111// Should never return.
112void WatchForUpdates() {
113 DBusGProxy* proxy;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700114
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700115 CHECK(GetProxy(&proxy));
Andrew de los Reyesada42202010-07-15 22:23:20 -0700116
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700117 // Register marshaller
118 dbus_g_object_register_marshaller(
119 update_engine_VOID__INT64_DOUBLE_STRING_STRING_INT64,
120 G_TYPE_NONE,
121 G_TYPE_INT64,
122 G_TYPE_DOUBLE,
123 G_TYPE_STRING,
124 G_TYPE_STRING,
125 G_TYPE_INT64,
126 G_TYPE_INVALID);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700127
128 static const char kStatusUpdate[] = "StatusUpdate";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700129 dbus_g_proxy_add_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700130 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700131 G_TYPE_INT64,
132 G_TYPE_DOUBLE,
133 G_TYPE_STRING,
134 G_TYPE_STRING,
135 G_TYPE_INT64,
136 G_TYPE_INVALID);
137 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
138 dbus_g_proxy_connect_signal(proxy,
Andrew de los Reyesada42202010-07-15 22:23:20 -0700139 kStatusUpdate,
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700140 G_CALLBACK(StatusUpdateSignalHandler),
141 NULL,
142 NULL);
143 g_main_loop_run(loop);
144 g_main_loop_unref(loop);
145}
146
Darin Petkov58529db2010-08-13 09:19:47 -0700147bool CheckForUpdates(const string& app_version, const string& omaha_url) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700148 DBusGProxy* proxy;
149 GError* error = NULL;
Andrew de los Reyesada42202010-07-15 22:23:20 -0700150
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700151 CHECK(GetProxy(&proxy));
152
153 gboolean rc =
Darin Petkov5a7f5652010-07-22 21:40:09 -0700154 org_chromium_UpdateEngineInterface_attempt_update(proxy,
155 app_version.c_str(),
156 omaha_url.c_str(),
157 &error);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700158 CHECK_EQ(rc, TRUE) << "Error checking for update: "
159 << GetGErrorMessage(error);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700160 return true;
161}
162
Darin Petkov296889c2010-07-23 16:20:54 -0700163bool RebootIfNeeded() {
164 DBusGProxy* proxy;
165 GError* error = NULL;
166
167 CHECK(GetProxy(&proxy));
168
169 gboolean rc =
170 org_chromium_UpdateEngineInterface_reboot_if_needed(proxy, &error);
171 // Reboot error code doesn't necessarily mean that a reboot
172 // failed. For example, D-Bus may be shutdown before we receive the
173 // result.
174 LOG_IF(INFO, !rc) << "Reboot error message: " << GetGErrorMessage(error);
175 return true;
176}
177
Darin Petkov58529db2010-08-13 09:19:47 -0700178static gboolean CompleteUpdateSource(gpointer data) {
179 string current_op;
180 if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
181 LOG(ERROR) << "Update failed.";
182 exit(1);
183 }
184 if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
185 LOG(INFO) << "Update succeeded -- reboot needed.";
186 exit(0);
187 }
188 return TRUE;
189}
190
191// This is similar to watching for updates but rather than registering
192// a signal watch, activelly poll the daemon just in case it stops
193// sending notifications.
194void CompleteUpdate() {
195 GMainLoop* loop = g_main_loop_new (NULL, TRUE);
196 g_timeout_add_seconds(5, CompleteUpdateSource, NULL);
197 g_main_loop_run(loop);
198 g_main_loop_unref(loop);
199}
200
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700201} // namespace {}
202
203int main(int argc, char** argv) {
204 // Boilerplate init commands.
205 g_type_init();
206 g_thread_init(NULL);
207 dbus_g_thread_init();
208 chromeos_update_engine::Subprocess::Init();
209 google::ParseCommandLineFlags(&argc, &argv, true);
Andrew de los Reyesada42202010-07-15 22:23:20 -0700210
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700211 if (FLAGS_status) {
212 LOG(INFO) << "Querying Update Engine status...";
Darin Petkov58529db2010-08-13 09:19:47 -0700213 if (!GetStatus(NULL)) {
214 LOG(FATAL) << "GetStatus failed.";
215 return 1;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700216 }
217 return 0;
218 }
Darin Petkov58529db2010-08-13 09:19:47 -0700219
220 // Initiate an update check, if necessary.
221 if (FLAGS_check_for_update ||
222 FLAGS_update ||
223 !FLAGS_app_version.empty() ||
224 !FLAGS_omaha_url.empty()) {
Darin Petkov296889c2010-07-23 16:20:54 -0700225 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Darin Petkov58529db2010-08-13 09:19:47 -0700226 string app_version = FLAGS_app_version;
227 if (FLAGS_update && app_version.empty()) {
228 app_version = "ForcedUpdate";
229 LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700230 }
Darin Petkov58529db2010-08-13 09:19:47 -0700231 LOG(INFO) << "Initiating update check and install.";
232 CHECK(CheckForUpdates(app_version, FLAGS_omaha_url))
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700233 << "Update check/initiate update failed.";
Darin Petkov58529db2010-08-13 09:19:47 -0700234
235 // Wait for an update to complete.
236 if (FLAGS_update) {
237 LOG(INFO) << "Waiting for update the complete.";
238 CompleteUpdate(); // Should never return.
239 return 1;
240 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700241 return 0;
242 }
Darin Petkov58529db2010-08-13 09:19:47 -0700243
244 // Start watching for updates.
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700245 if (FLAGS_watch_for_updates) {
Darin Petkov296889c2010-07-23 16:20:54 -0700246 LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700247 LOG(INFO) << "Watching for status updates.";
248 WatchForUpdates(); // Should never return.
249 return 1;
250 }
Darin Petkov58529db2010-08-13 09:19:47 -0700251
Darin Petkov296889c2010-07-23 16:20:54 -0700252 if (FLAGS_reboot) {
253 LOG(INFO) << "Requesting a reboot...";
254 CHECK(RebootIfNeeded());
255 return 0;
256 }
Andrew de los Reyesada42202010-07-15 22:23:20 -0700257
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700258 LOG(INFO) << "No flags specified. Exiting.";
259 return 0;
260}