blob: 70b9c7532c142cd08b0587e35ae3b174218d43d8 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/utils.h"
Darin Petkovf74eb652010-08-04 12:08:38 -07006
David Zeuthen910ec5b2013-09-26 12:10:58 -07007#include <attr/xattr.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +00008#include <sys/mount.h>
Darin Petkovc6c135c2010-08-11 13:36:18 -07009#include <sys/resource.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000010#include <sys/stat.h>
11#include <sys/types.h>
Andrew de los Reyes712b3ac2011-01-07 13:47:52 -080012#include <sys/wait.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include <dirent.h>
14#include <errno.h>
Andrew de los Reyes970bb282009-12-09 16:34:04 -080015#include <fcntl.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000016#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
Darin Petkovf74eb652010-08-04 12:08:38 -070020
adlr@google.com3defe6a2009-12-04 20:57:17 +000021#include <algorithm>
Chris Sosac1972482013-04-30 22:31:10 -070022#include <vector>
Darin Petkovf74eb652010-08-04 12:08:38 -070023
Will Drewry8f71da82010-08-30 14:07:11 -050024#include <base/file_path.h>
25#include <base/file_util.h>
Mike Frysinger8155d082012-04-06 15:23:18 -040026#include <base/logging.h>
Chris Sosafc661a12013-02-26 14:43:21 -080027#include <base/posix/eintr_wrapper.h>
Will Drewry8f71da82010-08-30 14:07:11 -050028#include <base/rand_util.h>
Jay Srinivasan480ddfa2012-06-01 19:15:26 -070029#include <base/string_number_conversions.h>
Chris Sosac1972482013-04-30 22:31:10 -070030#include <base/string_split.h>
Will Drewry8f71da82010-08-30 14:07:11 -050031#include <base/string_util.h>
Mike Frysinger8155d082012-04-06 15:23:18 -040032#include <base/stringprintf.h>
Gilad Arnold8e3f1262013-01-08 14:59:54 -080033#include <glib.h>
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -080034#include <google/protobuf/stubs/common.h>
Will Drewry8f71da82010-08-30 14:07:11 -050035
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070036#include "update_engine/constants.h"
Andrew de los Reyes970bb282009-12-09 16:34:04 -080037#include "update_engine/file_writer.h"
Darin Petkov33d30642010-08-04 10:18:57 -070038#include "update_engine/omaha_request_params.h"
Darin Petkov296889c2010-07-23 16:20:54 -070039#include "update_engine/subprocess.h"
Jay Srinivasan55f50c22013-01-10 19:24:35 -080040#include "update_engine/system_state.h"
41#include "update_engine/update_attempter.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000042
Jay Srinivasan480ddfa2012-06-01 19:15:26 -070043using base::Time;
Gilad Arnold8e3f1262013-01-08 14:59:54 -080044using base::TimeDelta;
adlr@google.com3defe6a2009-12-04 20:57:17 +000045using std::min;
Chris Sosac1972482013-04-30 22:31:10 -070046using std::pair;
adlr@google.com3defe6a2009-12-04 20:57:17 +000047using std::string;
48using std::vector;
49
50namespace chromeos_update_engine {
51
Ben Chan77a1eba2012-10-07 22:54:55 -070052namespace {
53
54// The following constants control how UnmountFilesystem should retry if
55// umount() fails with an errno EBUSY, i.e. retry 5 times over the course of
56// one second.
57const int kUnmountMaxNumOfRetries = 5;
58const int kUnmountRetryIntervalInMicroseconds = 200 * 1000; // 200 ms
Alex Deymo032e7722014-03-25 17:53:56 -070059
60// Number of bytes to read from a file to attempt to detect its contents. Used
61// in GetFileFormat.
62const int kGetFileFormatMaxHeaderSize = 32;
63
Ben Chan77a1eba2012-10-07 22:54:55 -070064} // namespace
65
adlr@google.com3defe6a2009-12-04 20:57:17 +000066namespace utils {
67
Chris Sosa4f8ee272012-11-30 13:01:54 -080068// Cgroup container is created in update-engine's upstart script located at
69// /etc/init/update-engine.conf.
70static const char kCGroupDir[] = "/sys/fs/cgroup/cpu/update-engine";
71
J. Richard Barnette63137e52013-10-28 10:57:29 -070072string ParseECVersion(string input_line) {
73 TrimWhitespaceASCII(input_line, TRIM_ALL, &input_line);
Chris Sosac1972482013-04-30 22:31:10 -070074
75 // At this point we want to conver the format key=value pair from mosys to
76 // a vector of key value pairs.
77 vector<pair<string, string> > kv_pairs;
J. Richard Barnette63137e52013-10-28 10:57:29 -070078 if (base::SplitStringIntoKeyValuePairs(input_line, '=', ' ', &kv_pairs)) {
Chris Sosac1972482013-04-30 22:31:10 -070079 for (vector<pair<string, string> >::iterator it = kv_pairs.begin();
80 it != kv_pairs.end(); ++it) {
81 // Finally match against the fw_verion which may have quotes.
82 if (it->first == "fw_version") {
83 string output;
84 // Trim any quotes.
85 TrimString(it->second, "\"", &output);
86 return output;
87 }
88 }
89 }
90 LOG(ERROR) << "Unable to parse fwid from ec info.";
91 return "";
92}
93
94
J. Richard Barnette30842932013-10-28 15:04:23 -070095const string KernelDeviceOfBootDevice(const std::string& boot_device) {
96 if (boot_device.empty())
97 return boot_device;
98
99 string ubiblock_prefix("/dev/ubiblock");
100 string ret;
101 char partition_num;
102 if (StringHasPrefix(boot_device, ubiblock_prefix)) {
103 // eg: /dev/ubiblock3_0 becomes /dev/mtdblock2
104 ret = "/dev/mtdblock";
105 partition_num = boot_device[ubiblock_prefix.size()];
106 } else {
107 // eg: /dev/sda3 becomes /dev/sda2
108 // eg: /dev/mmcblk0p3 becomes /dev/mmcblk0p2
109 ret = boot_device.substr(0, boot_device.size() - 1);
110 partition_num = boot_device[boot_device.size() - 1];
111 }
112
113 // Currently this assumes the partition number of the boot device is
114 // 3, 5, or 7, and changes it to 2, 4, or 6, respectively, to
115 // get the kernel device.
116 if (partition_num == '3' || partition_num == '5' || partition_num == '7') {
117 ret.append(1, partition_num - 1);
118 return ret;
119 }
120
121 return "";
122}
123
124
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800125bool WriteFile(const char* path, const char* data, int data_len) {
126 DirectFileWriter writer;
127 TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
128 O_WRONLY | O_CREAT | O_TRUNC,
Chris Masone4dc2ada2010-09-23 12:43:03 -0700129 0600));
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800130 ScopedFileWriterCloser closer(&writer);
Don Garrette410e0f2011-11-10 15:39:01 -0800131 TEST_AND_RETURN_FALSE_ERRNO(writer.Write(data, data_len));
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800132 return true;
133}
134
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700135bool WriteAll(int fd, const void* buf, size_t count) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700136 const char* c_buf = static_cast<const char*>(buf);
137 ssize_t bytes_written = 0;
138 while (bytes_written < static_cast<ssize_t>(count)) {
139 ssize_t rc = write(fd, c_buf + bytes_written, count - bytes_written);
140 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
141 bytes_written += rc;
142 }
143 return true;
144}
145
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700146bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
147 const char* c_buf = static_cast<const char*>(buf);
Gilad Arnold780db212012-07-11 13:12:49 -0700148 size_t bytes_written = 0;
149 int num_attempts = 0;
150 while (bytes_written < count) {
151 num_attempts++;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700152 ssize_t rc = pwrite(fd, c_buf + bytes_written, count - bytes_written,
153 offset + bytes_written);
Gilad Arnold780db212012-07-11 13:12:49 -0700154 // TODO(garnold) for debugging failure in chromium-os:31077; to be removed.
155 if (rc < 0) {
156 PLOG(ERROR) << "pwrite error; num_attempts=" << num_attempts
157 << " bytes_written=" << bytes_written
158 << " count=" << count << " offset=" << offset;
159 }
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700160 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
161 bytes_written += rc;
162 }
163 return true;
164}
165
166bool PReadAll(int fd, void* buf, size_t count, off_t offset,
167 ssize_t* out_bytes_read) {
168 char* c_buf = static_cast<char*>(buf);
169 ssize_t bytes_read = 0;
170 while (bytes_read < static_cast<ssize_t>(count)) {
171 ssize_t rc = pread(fd, c_buf + bytes_read, count - bytes_read,
172 offset + bytes_read);
173 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
174 if (rc == 0) {
175 break;
176 }
177 bytes_read += rc;
178 }
179 *out_bytes_read = bytes_read;
180 return true;
Darin Petkov296889c2010-07-23 16:20:54 -0700181
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700182}
183
Gilad Arnold19a45f02012-07-19 12:36:10 -0700184// Append |nbytes| of content from |buf| to the vector pointed to by either
185// |vec_p| or |str_p|.
186static void AppendBytes(const char* buf, size_t nbytes,
187 std::vector<char>* vec_p) {
188 CHECK(buf);
189 CHECK(vec_p);
190 vec_p->insert(vec_p->end(), buf, buf + nbytes);
191}
192static void AppendBytes(const char* buf, size_t nbytes,
193 std::string* str_p) {
194 CHECK(buf);
195 CHECK(str_p);
196 str_p->append(buf, nbytes);
197}
198
199// Reads from an open file |fp|, appending the read content to the container
200// pointer to by |out_p|. Returns true upon successful reading all of the
Darin Petkov8e447e02013-04-16 16:23:50 +0200201// file's content, false otherwise. If |size| is not -1, reads up to |size|
202// bytes.
Gilad Arnold19a45f02012-07-19 12:36:10 -0700203template <class T>
Darin Petkov8e447e02013-04-16 16:23:50 +0200204static bool Read(FILE* fp, off_t size, T* out_p) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700205 CHECK(fp);
Darin Petkov8e447e02013-04-16 16:23:50 +0200206 CHECK(size == -1 || size >= 0);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700207 char buf[1024];
Darin Petkov8e447e02013-04-16 16:23:50 +0200208 while (size == -1 || size > 0) {
209 off_t bytes_to_read = sizeof(buf);
210 if (size > 0 && bytes_to_read > size) {
211 bytes_to_read = size;
212 }
213 size_t nbytes = fread(buf, 1, bytes_to_read, fp);
214 if (!nbytes) {
215 break;
216 }
Gilad Arnold19a45f02012-07-19 12:36:10 -0700217 AppendBytes(buf, nbytes, out_p);
Darin Petkov8e447e02013-04-16 16:23:50 +0200218 if (size != -1) {
219 CHECK(size >= static_cast<off_t>(nbytes));
220 size -= nbytes;
221 }
222 }
223 if (ferror(fp)) {
224 return false;
225 }
226 return size == 0 || feof(fp);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700227}
228
Darin Petkov8e447e02013-04-16 16:23:50 +0200229// Opens a file |path| for reading and appends its the contents to a container
230// |out_p|. Starts reading the file from |offset|. If |offset| is beyond the end
231// of the file, returns success. If |size| is not -1, reads up to |size| bytes.
Gilad Arnold19a45f02012-07-19 12:36:10 -0700232template <class T>
Darin Petkov8e447e02013-04-16 16:23:50 +0200233static bool ReadFileChunkAndAppend(const std::string& path,
234 off_t offset,
235 off_t size,
236 T* out_p) {
237 CHECK_GE(offset, 0);
238 CHECK(size == -1 || size >= 0);
239 file_util::ScopedFILE fp(fopen(path.c_str(), "r"));
240 if (!fp.get())
adlr@google.com3defe6a2009-12-04 20:57:17 +0000241 return false;
Darin Petkov8e447e02013-04-16 16:23:50 +0200242 if (offset) {
243 // Return success without appending any data if a chunk beyond the end of
244 // the file is requested.
245 if (offset >= FileSize(path)) {
246 return true;
247 }
248 TEST_AND_RETURN_FALSE_ERRNO(fseek(fp.get(), offset, SEEK_SET) == 0);
249 }
250 return Read(fp.get(), size, out_p);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000251}
252
Gilad Arnold19a45f02012-07-19 12:36:10 -0700253// Invokes a pipe |cmd|, then uses |append_func| to append its stdout to a
254// container |out_p|.
255template <class T>
256static bool ReadPipeAndAppend(const std::string& cmd, T* out_p) {
257 FILE* fp = popen(cmd.c_str(), "r");
258 if (!fp)
adlr@google.com3defe6a2009-12-04 20:57:17 +0000259 return false;
Darin Petkov8e447e02013-04-16 16:23:50 +0200260 bool success = Read(fp, -1, out_p);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700261 return (success && pclose(fp) >= 0);
262}
263
264
Darin Petkov8e447e02013-04-16 16:23:50 +0200265bool ReadFile(const string& path, vector<char>* out_p) {
266 return ReadFileChunkAndAppend(path, 0, -1, out_p);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700267}
268
Darin Petkov8e447e02013-04-16 16:23:50 +0200269bool ReadFile(const string& path, string* out_p) {
270 return ReadFileChunkAndAppend(path, 0, -1, out_p);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700271}
272
Darin Petkov8e447e02013-04-16 16:23:50 +0200273bool ReadFileChunk(const string& path, off_t offset, off_t size,
274 vector<char>* out_p) {
275 return ReadFileChunkAndAppend(path, offset, size, out_p);
276}
277
278bool ReadPipe(const string& cmd, vector<char>* out_p) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700279 return ReadPipeAndAppend(cmd, out_p);
280}
281
Darin Petkov8e447e02013-04-16 16:23:50 +0200282bool ReadPipe(const string& cmd, string* out_p) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700283 return ReadPipeAndAppend(cmd, out_p);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000284}
285
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700286off_t FileSize(const string& path) {
287 struct stat stbuf;
288 int rc = stat(path.c_str(), &stbuf);
289 CHECK_EQ(rc, 0);
290 if (rc < 0)
291 return rc;
292 return stbuf.st_size;
293}
294
adlr@google.com3defe6a2009-12-04 20:57:17 +0000295void HexDumpArray(const unsigned char* const arr, const size_t length) {
296 const unsigned char* const char_arr =
297 reinterpret_cast<const unsigned char* const>(arr);
298 LOG(INFO) << "Logging array of length: " << length;
299 const unsigned int bytes_per_line = 16;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700300 for (uint32_t i = 0; i < length; i += bytes_per_line) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000301 const unsigned int bytes_remaining = length - i;
302 const unsigned int bytes_per_this_line = min(bytes_per_line,
303 bytes_remaining);
304 char header[100];
305 int r = snprintf(header, sizeof(header), "0x%08x : ", i);
306 TEST_AND_RETURN(r == 13);
307 string line = header;
308 for (unsigned int j = 0; j < bytes_per_this_line; j++) {
309 char buf[20];
310 unsigned char c = char_arr[i + j];
311 r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c));
312 TEST_AND_RETURN(r == 3);
313 line += buf;
314 }
315 LOG(INFO) << line;
316 }
317}
318
319namespace {
320class ScopedDirCloser {
321 public:
322 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
323 ~ScopedDirCloser() {
324 if (dir_ && *dir_) {
325 int r = closedir(*dir_);
326 TEST_AND_RETURN_ERRNO(r == 0);
327 *dir_ = NULL;
328 dir_ = NULL;
329 }
330 }
331 private:
332 DIR** dir_;
333};
334} // namespace {}
335
336bool RecursiveUnlinkDir(const std::string& path) {
337 struct stat stbuf;
338 int r = lstat(path.c_str(), &stbuf);
339 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
340 if ((r < 0) && (errno == ENOENT))
341 // path request is missing. that's fine.
342 return true;
343 if (!S_ISDIR(stbuf.st_mode)) {
344 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700345 (errno == ENOENT));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000346 // success or path disappeared before we could unlink.
347 return true;
348 }
349 {
350 // We have a dir, unlink all children, then delete dir
351 DIR *dir = opendir(path.c_str());
352 TEST_AND_RETURN_FALSE_ERRNO(dir);
353 ScopedDirCloser dir_closer(&dir);
354 struct dirent dir_entry;
355 struct dirent *dir_entry_p;
356 int err = 0;
357 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
358 if (dir_entry_p == NULL) {
359 // end of stream reached
360 break;
361 }
362 // Skip . and ..
363 if (!strcmp(dir_entry_p->d_name, ".") ||
364 !strcmp(dir_entry_p->d_name, ".."))
365 continue;
366 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700367 dir_entry_p->d_name));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000368 }
369 TEST_AND_RETURN_FALSE(err == 0);
370 }
371 // unlink dir
372 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
373 return true;
374}
375
Alex Vakulenko4f5b1442014-02-21 12:19:44 -0800376std::string GetDiskName(const string& partition_name) {
377 std::string disk_name;
378 return SplitPartitionName(partition_name, &disk_name, nullptr) ?
379 disk_name : std::string();
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700380}
381
Alex Vakulenko4f5b1442014-02-21 12:19:44 -0800382int GetPartitionNumber(const std::string& partition_name) {
383 int partition_num = 0;
384 return SplitPartitionName(partition_name, nullptr, &partition_num) ?
385 partition_num : 0;
386}
387
388bool SplitPartitionName(const std::string& partition_name,
389 std::string* out_disk_name,
390 int* out_partition_num) {
391 if (!StringHasPrefix(partition_name, "/dev/")) {
392 LOG(ERROR) << "Invalid partition device name: " << partition_name;
393 return false;
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700394 }
Alex Vakulenko4f5b1442014-02-21 12:19:44 -0800395
396 if (StringHasPrefix(partition_name, "/dev/ubiblock")) {
397 // NAND block devices have weird naming which could be something
398 // like "/dev/ubiblock2_0". Since update engine doesn't have proper
399 // support for NAND devices yet, don't bother parsing their names for now.
400 LOG(ERROR) << "UBI block devices are not supported: " << partition_name;
401 return false;
402 }
403
404 size_t pos = partition_name.find_last_not_of("0123456789");
405 if (pos == string::npos || (pos + 1) == partition_name.size()) {
406 LOG(ERROR) << "Unable to parse partition device name: "
407 << partition_name;
408 return false;
409 }
410
411 if (out_disk_name) {
412 // Special case for MMC devices which have the following naming scheme:
413 // mmcblk0p2
414 bool valid_mmc_device = StringHasPrefix(partition_name, "/dev/mmcblk") &&
415 partition_name[pos] == 'p';
416 *out_disk_name =
417 partition_name.substr(0, valid_mmc_device ? pos : (pos + 1));
418 }
419
420 if (out_partition_num) {
421 std::string partition_str = partition_name.substr(pos + 1);
422 *out_partition_num = atoi(partition_str.c_str());
423 }
424 return true;
425}
426
427std::string MakePartitionName(const std::string& disk_name,
428 int partition_num) {
429 if (!StringHasPrefix(disk_name, "/dev/")) {
430 LOG(ERROR) << "Invalid disk name: " << disk_name;
431 return std::string();
432 }
433
434 if (partition_num < 1) {
435 LOG(ERROR) << "Invalid partition number: " << partition_num;
436 return std::string();
437 }
438
439 std::string partition_name = disk_name;
440 if (!StringHasPrefix(disk_name, "/dev/mmcblk")) {
441 // Special case for MMC devices. Add "p" to separate the disk name
442 // from partition number
443 partition_name += 'p';
444 }
445
446 base::StringAppendF(&partition_name, "%d", partition_num);
447 return partition_name;
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700448}
449
Darin Petkovf74eb652010-08-04 12:08:38 -0700450string SysfsBlockDevice(const string& device) {
451 FilePath device_path(device);
452 if (device_path.DirName().value() != "/dev") {
453 return "";
454 }
455 return FilePath("/sys/block").Append(device_path.BaseName()).value();
456}
457
458bool IsRemovableDevice(const std::string& device) {
459 string sysfs_block = SysfsBlockDevice(device);
460 string removable;
461 if (sysfs_block.empty() ||
462 !file_util::ReadFileToString(FilePath(sysfs_block).Append("removable"),
463 &removable)) {
464 return false;
465 }
466 TrimWhitespaceASCII(removable, TRIM_ALL, &removable);
467 return removable == "1";
468}
469
adlr@google.com3defe6a2009-12-04 20:57:17 +0000470std::string ErrnoNumberAsString(int err) {
471 char buf[100];
472 buf[0] = '\0';
473 return strerror_r(err, buf, sizeof(buf));
474}
475
476std::string NormalizePath(const std::string& path, bool strip_trailing_slash) {
477 string ret;
478 bool last_insert_was_slash = false;
479 for (string::const_iterator it = path.begin(); it != path.end(); ++it) {
480 if (*it == '/') {
481 if (last_insert_was_slash)
482 continue;
483 last_insert_was_slash = true;
484 } else {
485 last_insert_was_slash = false;
486 }
487 ret.push_back(*it);
488 }
489 if (strip_trailing_slash && last_insert_was_slash) {
490 string::size_type last_non_slash = ret.find_last_not_of('/');
491 if (last_non_slash != string::npos) {
492 ret.resize(last_non_slash + 1);
493 } else {
494 ret = "";
495 }
496 }
497 return ret;
498}
499
500bool FileExists(const char* path) {
501 struct stat stbuf;
502 return 0 == lstat(path, &stbuf);
503}
504
Darin Petkov30291ed2010-11-12 10:23:06 -0800505bool IsSymlink(const char* path) {
506 struct stat stbuf;
507 return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
508}
509
adlr@google.com3defe6a2009-12-04 20:57:17 +0000510std::string TempFilename(string path) {
511 static const string suffix("XXXXXX");
512 CHECK(StringHasSuffix(path, suffix));
513 do {
514 string new_suffix;
515 for (unsigned int i = 0; i < suffix.size(); i++) {
516 int r = rand() % (26 * 2 + 10); // [a-zA-Z0-9]
517 if (r < 26)
518 new_suffix.append(1, 'a' + r);
519 else if (r < (26 * 2))
520 new_suffix.append(1, 'A' + r - 26);
521 else
522 new_suffix.append(1, '0' + r - (26 * 2));
523 }
524 CHECK_EQ(new_suffix.size(), suffix.size());
525 path.resize(path.size() - new_suffix.size());
526 path.append(new_suffix);
527 } while (FileExists(path.c_str()));
528 return path;
529}
530
Gilad Arnoldd04f8e22014-01-09 13:13:40 -0800531// If |path| is absolute, or explicit relative to the current working directory,
532// leaves it as is. Otherwise, if TMPDIR is defined in the environment and is
533// non-empty, prepends it to |path|. Otherwise, prepends /tmp. Returns the
534// resulting path.
535static const string PrependTmpdir(const string& path) {
536 if (path[0] == '/' || StartsWithASCII(path, "./", true) ||
537 StartsWithASCII(path, "../", true))
538 return path;
539
540 const char *tmpdir = getenv("TMPDIR");
541 const string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp");
542 return prefix + "/" + path;
543}
544
545bool MakeTempFile(const std::string& base_filename_template,
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700546 std::string* filename,
547 int* fd) {
Gilad Arnoldd04f8e22014-01-09 13:13:40 -0800548 const string filename_template = PrependTmpdir(base_filename_template);
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700549 DCHECK(filename || fd);
550 vector<char> buf(filename_template.size() + 1);
551 memcpy(&buf[0], filename_template.data(), filename_template.size());
552 buf[filename_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700553
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700554 int mkstemp_fd = mkstemp(&buf[0]);
555 TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
556 if (filename) {
557 *filename = &buf[0];
558 }
559 if (fd) {
560 *fd = mkstemp_fd;
561 } else {
562 close(mkstemp_fd);
563 }
564 return true;
565}
566
Gilad Arnoldd04f8e22014-01-09 13:13:40 -0800567bool MakeTempDirectory(const std::string& base_dirname_template,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700568 std::string* dirname) {
Gilad Arnoldd04f8e22014-01-09 13:13:40 -0800569 const string dirname_template = PrependTmpdir(base_dirname_template);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700570 DCHECK(dirname);
571 vector<char> buf(dirname_template.size() + 1);
572 memcpy(&buf[0], dirname_template.data(), dirname_template.size());
573 buf[dirname_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700574
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700575 char* return_code = mkdtemp(&buf[0]);
576 TEST_AND_RETURN_FALSE_ERRNO(return_code != NULL);
577 *dirname = &buf[0];
578 return true;
579}
580
adlr@google.com3defe6a2009-12-04 20:57:17 +0000581bool StringHasSuffix(const std::string& str, const std::string& suffix) {
582 if (suffix.size() > str.size())
583 return false;
584 return 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
585}
586
587bool StringHasPrefix(const std::string& str, const std::string& prefix) {
588 if (prefix.size() > str.size())
589 return false;
590 return 0 == str.compare(0, prefix.size(), prefix);
591}
592
adlr@google.com3defe6a2009-12-04 20:57:17 +0000593bool MountFilesystem(const string& device,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700594 const string& mountpoint,
595 unsigned long mountflags) {
596 int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", mountflags, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000597 if (rc < 0) {
598 string msg = ErrnoNumberAsString(errno);
599 LOG(ERROR) << "Unable to mount destination device: " << msg << ". "
600 << device << " on " << mountpoint;
601 return false;
602 }
603 return true;
604}
605
606bool UnmountFilesystem(const string& mountpoint) {
Ben Chan77a1eba2012-10-07 22:54:55 -0700607 for (int num_retries = 0; ; ++num_retries) {
608 if (umount(mountpoint.c_str()) == 0)
609 break;
610
611 TEST_AND_RETURN_FALSE_ERRNO(errno == EBUSY &&
612 num_retries < kUnmountMaxNumOfRetries);
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800613 g_usleep(kUnmountRetryIntervalInMicroseconds);
Ben Chan77a1eba2012-10-07 22:54:55 -0700614 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000615 return true;
616}
617
Darin Petkovd3f8c892010-10-12 21:38:45 -0700618bool GetFilesystemSize(const std::string& device,
619 int* out_block_count,
620 int* out_block_size) {
621 int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY));
622 TEST_AND_RETURN_FALSE(fd >= 0);
623 ScopedFdCloser fd_closer(&fd);
624 return GetFilesystemSizeFromFD(fd, out_block_count, out_block_size);
625}
626
627bool GetFilesystemSizeFromFD(int fd,
628 int* out_block_count,
629 int* out_block_size) {
630 TEST_AND_RETURN_FALSE(fd >= 0);
631
632 // Determine the ext3 filesystem size by directly reading the block count and
633 // block size information from the superblock. See include/linux/ext3_fs.h for
634 // more details on the structure.
635 ssize_t kBufferSize = 16 * sizeof(uint32_t);
636 char buffer[kBufferSize];
637 const int kSuperblockOffset = 1024;
638 if (HANDLE_EINTR(pread(fd, buffer, kBufferSize, kSuperblockOffset)) !=
639 kBufferSize) {
640 PLOG(ERROR) << "Unable to determine file system size:";
641 return false;
642 }
643 uint32_t block_count; // ext3_fs.h: ext3_super_block.s_blocks_count
644 uint32_t log_block_size; // ext3_fs.h: ext3_super_block.s_log_block_size
645 uint16_t magic; // ext3_fs.h: ext3_super_block.s_magic
646 memcpy(&block_count, &buffer[1 * sizeof(int32_t)], sizeof(block_count));
647 memcpy(&log_block_size, &buffer[6 * sizeof(int32_t)], sizeof(log_block_size));
648 memcpy(&magic, &buffer[14 * sizeof(int32_t)], sizeof(magic));
649 block_count = le32toh(block_count);
650 const int kExt3MinBlockLogSize = 10; // ext3_fs.h: EXT3_MIN_BLOCK_LOG_SIZE
651 log_block_size = le32toh(log_block_size) + kExt3MinBlockLogSize;
652 magic = le16toh(magic);
653
654 // Sanity check the parameters.
655 const uint16_t kExt3SuperMagic = 0xef53; // ext3_fs.h: EXT3_SUPER_MAGIC
656 TEST_AND_RETURN_FALSE(magic == kExt3SuperMagic);
657 const int kExt3MinBlockSize = 1024; // ext3_fs.h: EXT3_MIN_BLOCK_SIZE
658 const int kExt3MaxBlockSize = 4096; // ext3_fs.h: EXT3_MAX_BLOCK_SIZE
659 int block_size = 1 << log_block_size;
660 TEST_AND_RETURN_FALSE(block_size >= kExt3MinBlockSize &&
661 block_size <= kExt3MaxBlockSize);
662 TEST_AND_RETURN_FALSE(block_count > 0);
663
664 if (out_block_count) {
665 *out_block_count = block_count;
666 }
667 if (out_block_size) {
668 *out_block_size = block_size;
669 }
670 return true;
671}
672
Alex Deymo032e7722014-03-25 17:53:56 -0700673// Tries to parse the header of an ELF file to obtain a human-readable
674// description of it on the |output| string.
675static bool GetFileFormatELF(const char* buffer, size_t size, string* output) {
676 // 0x00: EI_MAG - ELF magic header, 4 bytes.
677 if (size < 4 || memcmp(buffer, "\x7F""ELF", 4) != 0)
678 return false;
679 *output = "ELF";
680
681 // 0x04: EI_CLASS, 1 byte.
682 if (size < 0x04 + 1)
683 return true;
684 switch (buffer[4]) {
685 case 1:
686 *output += " 32-bit";
687 break;
688 case 2:
689 *output += " 64-bit";
690 break;
691 default:
692 *output += " ?-bit";
693 }
694
695 // 0x05: EI_DATA, endianness, 1 byte.
696 if (size < 0x05 + 1)
697 return true;
698 char ei_data = buffer[5];
699 switch (ei_data) {
700 case 1:
701 *output += " little-endian";
702 break;
703 case 2:
704 *output += " big-endian";
705 break;
706 default:
707 *output += " ?-endian";
708 // Don't parse anything after the 0x10 offset if endianness is unknown.
709 return true;
710 }
711
712 // 0x12: e_machine, 2 byte endianness based on ei_data
713 if (size < 0x12 + 2)
714 return true;
715 uint16 e_machine = *reinterpret_cast<const uint16*>(buffer+0x12);
716 // Fix endianess regardless of the host endianess.
717 if (ei_data == 1)
718 e_machine = le16toh(e_machine);
719 else
720 e_machine = be16toh(e_machine);
721
722 switch (e_machine) {
723 case 0x03:
724 *output += " x86";
725 break;
726 case 0x28:
727 *output += " arm";
728 break;
729 case 0x3E:
730 *output += " x86-64";
731 break;
732 default:
733 *output += " unknown-arch";
734 }
735 return true;
736}
737
738string GetFileFormat(const string& path) {
739 vector<char> buffer;
740 if (!ReadFileChunkAndAppend(path, 0, kGetFileFormatMaxHeaderSize, &buffer))
741 return "File not found.";
742
743 string result;
744 if (GetFileFormatELF(buffer.data(), buffer.size(), &result))
745 return result;
746
747 return "data";
748}
749
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700750bool GetBootloader(BootLoader* out_bootloader) {
751 // For now, hardcode to syslinux.
752 *out_bootloader = BootLoader_SYSLINUX;
753 return true;
754}
755
Darin Petkova0b9e772011-10-06 05:05:56 -0700756string GetAndFreeGError(GError** error) {
757 if (!*error) {
758 return "Unknown GLib error.";
759 }
760 string message =
761 base::StringPrintf("GError(%d): %s",
762 (*error)->code,
763 (*error)->message ? (*error)->message : "(unknown)");
764 g_error_free(*error);
765 *error = NULL;
766 return message;
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700767}
768
Darin Petkov296889c2010-07-23 16:20:54 -0700769bool Reboot() {
770 vector<string> command;
771 command.push_back("/sbin/shutdown");
772 command.push_back("-r");
773 command.push_back("now");
774 int rc = 0;
Darin Petkov85d02b72011-05-17 13:25:51 -0700775 Subprocess::SynchronousExec(command, &rc, NULL);
Darin Petkov296889c2010-07-23 16:20:54 -0700776 TEST_AND_RETURN_FALSE(rc == 0);
777 return true;
778}
779
Andrew de los Reyes712b3ac2011-01-07 13:47:52 -0800780namespace {
781// Do the actual trigger. We do it as a main-loop callback to (try to) get a
782// consistent stack trace.
783gboolean TriggerCrashReporterUpload(void* unused) {
784 pid_t pid = fork();
785 CHECK(pid >= 0) << "fork failed"; // fork() failed. Something is very wrong.
786 if (pid == 0) {
787 // We are the child. Crash.
788 abort(); // never returns
789 }
790 // We are the parent. Wait for child to terminate.
791 pid_t result = waitpid(pid, NULL, 0);
792 LOG_IF(ERROR, result < 0) << "waitpid() failed";
793 return FALSE; // Don't call this callback again
794}
795} // namespace {}
796
797void ScheduleCrashReporterUpload() {
798 g_idle_add(&TriggerCrashReporterUpload, NULL);
799}
800
Chris Sosa4f8ee272012-11-30 13:01:54 -0800801bool SetCpuShares(CpuShares shares) {
802 string string_shares = base::IntToString(static_cast<int>(shares));
803 string cpu_shares_file = string(utils::kCGroupDir) + "/cpu.shares";
804 LOG(INFO) << "Setting cgroup cpu shares to " << string_shares;
805 if(utils::WriteFile(cpu_shares_file.c_str(), string_shares.c_str(),
806 string_shares.size())){
807 return true;
808 } else {
809 LOG(ERROR) << "Failed to change cgroup cpu shares to "<< string_shares
810 << " using " << cpu_shares_file;
811 return false;
812 }
Darin Petkovc6c135c2010-08-11 13:36:18 -0700813}
814
Chris Sosa4f8ee272012-11-30 13:01:54 -0800815int CompareCpuShares(CpuShares shares_lhs,
816 CpuShares shares_rhs) {
817 return static_cast<int>(shares_lhs) - static_cast<int>(shares_rhs);
Darin Petkovc6c135c2010-08-11 13:36:18 -0700818}
819
Darin Petkov5c0a8af2010-08-24 13:39:13 -0700820int FuzzInt(int value, unsigned int range) {
821 int min = value - range / 2;
822 int max = value + range - range / 2;
823 return base::RandInt(min, max);
824}
825
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800826gboolean GlibRunClosure(gpointer data) {
827 google::protobuf::Closure* callback =
828 reinterpret_cast<google::protobuf::Closure*>(data);
829 callback->Run();
830 return FALSE;
831}
832
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700833string FormatSecs(unsigned secs) {
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800834 return FormatTimeDelta(TimeDelta::FromSeconds(secs));
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700835}
836
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800837string FormatTimeDelta(TimeDelta delta) {
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700838 // Canonicalize into days, hours, minutes, seconds and microseconds.
839 unsigned days = delta.InDays();
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800840 delta -= TimeDelta::FromDays(days);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700841 unsigned hours = delta.InHours();
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800842 delta -= TimeDelta::FromHours(hours);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700843 unsigned mins = delta.InMinutes();
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800844 delta -= TimeDelta::FromMinutes(mins);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700845 unsigned secs = delta.InSeconds();
Gilad Arnold8e3f1262013-01-08 14:59:54 -0800846 delta -= TimeDelta::FromSeconds(secs);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700847 unsigned usecs = delta.InMicroseconds();
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800848
849 // Construct and return string.
850 string str;
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700851 if (days)
852 base::StringAppendF(&str, "%ud", days);
853 if (days || hours)
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800854 base::StringAppendF(&str, "%uh", hours);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700855 if (days || hours || mins)
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800856 base::StringAppendF(&str, "%um", mins);
Gilad Arnoldd7b513d2012-05-10 14:25:27 -0700857 base::StringAppendF(&str, "%u", secs);
858 if (usecs) {
859 int width = 6;
860 while ((usecs / 10) * 10 == usecs) {
861 usecs /= 10;
862 width--;
863 }
864 base::StringAppendF(&str, ".%0*u", width, usecs);
865 }
866 base::StringAppendF(&str, "s");
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800867 return str;
868}
869
Jay Srinivasan480ddfa2012-06-01 19:15:26 -0700870string ToString(const Time utc_time) {
871 Time::Exploded exp_time;
872 utc_time.UTCExplode(&exp_time);
873 return StringPrintf("%d/%d/%d %d:%02d:%02d GMT",
874 exp_time.month,
875 exp_time.day_of_month,
876 exp_time.year,
877 exp_time.hour,
878 exp_time.minute,
879 exp_time.second);
880}
adlr@google.com3defe6a2009-12-04 20:57:17 +0000881
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700882string ToString(bool b) {
883 return (b ? "true" : "false");
884}
885
Alex Deymo1c656c42013-06-28 11:02:14 -0700886string ToString(DownloadSource source) {
Jay Srinivasan19409b72013-04-12 19:23:36 -0700887 switch (source) {
888 case kDownloadSourceHttpsServer: return "HttpsServer";
889 case kDownloadSourceHttpServer: return "HttpServer";
David Zeuthenbb8bdc72013-09-03 13:43:48 -0700890 case kDownloadSourceHttpPeer: return "HttpPeer";
Jay Srinivasan19409b72013-04-12 19:23:36 -0700891 case kNumDownloadSources: return "Unknown";
892 // Don't add a default case to let the compiler warn about newly added
893 // download sources which should be added here.
894 }
895
896 return "Unknown";
897}
898
Alex Deymo1c656c42013-06-28 11:02:14 -0700899string ToString(PayloadType payload_type) {
900 switch (payload_type) {
901 case kPayloadTypeDelta: return "Delta";
902 case kPayloadTypeFull: return "Full";
903 case kPayloadTypeForcedFull: return "ForcedFull";
904 case kNumPayloadTypes: return "Unknown";
905 // Don't add a default case to let the compiler warn about newly added
906 // payload types which should be added here.
907 }
908
909 return "Unknown";
910}
911
David Zeuthena99981f2013-04-29 13:42:47 -0700912ErrorCode GetBaseErrorCode(ErrorCode code) {
Jay Srinivasanf0572052012-10-23 18:12:56 -0700913 // Ignore the higher order bits in the code by applying the mask as
914 // we want the enumerations to be in the small contiguous range
David Zeuthena99981f2013-04-29 13:42:47 -0700915 // with values less than kErrorCodeUmaReportedMax.
916 ErrorCode base_code = static_cast<ErrorCode>(code & ~kErrorCodeSpecialFlags);
Jay Srinivasanf0572052012-10-23 18:12:56 -0700917
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800918 // Make additional adjustments required for UMA and error classification.
919 // TODO(jaysri): Move this logic to UeErrorCode.cc when we fix
920 // chromium-os:34369.
David Zeuthena99981f2013-04-29 13:42:47 -0700921 if (base_code >= kErrorCodeOmahaRequestHTTPResponseBase) {
Jay Srinivasanf0572052012-10-23 18:12:56 -0700922 // Since we want to keep the enums to a small value, aggregate all HTTP
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800923 // errors into this one bucket for UMA and error classification purposes.
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800924 LOG(INFO) << "Converting error code " << base_code
David Zeuthena99981f2013-04-29 13:42:47 -0700925 << " to kErrorCodeOmahaErrorInHTTPResponse";
926 base_code = kErrorCodeOmahaErrorInHTTPResponse;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700927 }
928
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800929 return base_code;
930}
931
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800932// Returns a printable version of the various flags denoted in the higher order
933// bits of the given code. Returns an empty string if none of those bits are
934// set.
935string GetFlagNames(uint32_t code) {
David Zeuthena99981f2013-04-29 13:42:47 -0700936 uint32_t flags = code & kErrorCodeSpecialFlags;
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800937 string flag_names;
938 string separator = "";
939 for(size_t i = 0; i < sizeof(flags) * 8; i++) {
940 uint32_t flag = flags & (1 << i);
941 if (flag) {
David Zeuthena99981f2013-04-29 13:42:47 -0700942 flag_names += separator + CodeToString(static_cast<ErrorCode>(flag));
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800943 separator = ", ";
944 }
945 }
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800946
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800947 return flag_names;
Jay Srinivasanf0572052012-10-23 18:12:56 -0700948}
949
David Zeuthena99981f2013-04-29 13:42:47 -0700950void SendErrorCodeToUma(SystemState* system_state, ErrorCode code) {
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800951 if (!system_state)
952 return;
953
David Zeuthena99981f2013-04-29 13:42:47 -0700954 ErrorCode uma_error_code = GetBaseErrorCode(code);
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800955
956 // If the code doesn't have flags computed already, compute them now based on
957 // the state of the current update attempt.
David Zeuthena99981f2013-04-29 13:42:47 -0700958 uint32_t flags = code & kErrorCodeSpecialFlags;
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800959 if (!flags)
960 flags = system_state->update_attempter()->GetErrorCodeFlags();
961
962 // Determine the UMA bucket depending on the flags. But, ignore the resumed
963 // flag, as it's perfectly normal for production devices to resume their
964 // downloads and so we want to record those cases also in NormalErrorCodes
965 // bucket.
David Zeuthena99981f2013-04-29 13:42:47 -0700966 string metric = (flags & ~kErrorCodeResumedFlag) ?
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800967 "Installer.DevModeErrorCodes" : "Installer.NormalErrorCodes";
968
969 LOG(INFO) << "Sending error code " << uma_error_code
970 << " (" << CodeToString(uma_error_code) << ")"
971 << " to UMA metric: " << metric
972 << ". Flags = " << (flags ? GetFlagNames(flags) : "None");
973
974 system_state->metrics_lib()->SendEnumToUMA(metric,
975 uma_error_code,
David Zeuthena99981f2013-04-29 13:42:47 -0700976 kErrorCodeUmaReportedMax);
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800977}
978
David Zeuthena99981f2013-04-29 13:42:47 -0700979string CodeToString(ErrorCode code) {
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800980 // If the given code has both parts (i.e. the error code part and the flags
981 // part) then strip off the flags part since the switch statement below
982 // has case statements only for the base error code or a single flag but
983 // doesn't support any combinations of those.
David Zeuthena99981f2013-04-29 13:42:47 -0700984 if ((code & kErrorCodeSpecialFlags) && (code & ~kErrorCodeSpecialFlags))
985 code = static_cast<ErrorCode>(code & ~kErrorCodeSpecialFlags);
Jay Srinivasan55f50c22013-01-10 19:24:35 -0800986 switch (code) {
David Zeuthena99981f2013-04-29 13:42:47 -0700987 case kErrorCodeSuccess: return "kErrorCodeSuccess";
988 case kErrorCodeError: return "kErrorCodeError";
989 case kErrorCodeOmahaRequestError: return "kErrorCodeOmahaRequestError";
990 case kErrorCodeOmahaResponseHandlerError:
991 return "kErrorCodeOmahaResponseHandlerError";
992 case kErrorCodeFilesystemCopierError:
993 return "kErrorCodeFilesystemCopierError";
994 case kErrorCodePostinstallRunnerError:
995 return "kErrorCodePostinstallRunnerError";
Gilad Arnold21504f02013-05-24 08:51:22 -0700996 case kErrorCodePayloadMismatchedType:
997 return "kErrorCodePayloadMismatchedType";
David Zeuthena99981f2013-04-29 13:42:47 -0700998 case kErrorCodeInstallDeviceOpenError:
999 return "kErrorCodeInstallDeviceOpenError";
1000 case kErrorCodeKernelDeviceOpenError:
1001 return "kErrorCodeKernelDeviceOpenError";
1002 case kErrorCodeDownloadTransferError:
1003 return "kErrorCodeDownloadTransferError";
1004 case kErrorCodePayloadHashMismatchError:
1005 return "kErrorCodePayloadHashMismatchError";
1006 case kErrorCodePayloadSizeMismatchError:
1007 return "kErrorCodePayloadSizeMismatchError";
1008 case kErrorCodeDownloadPayloadVerificationError:
1009 return "kErrorCodeDownloadPayloadVerificationError";
1010 case kErrorCodeDownloadNewPartitionInfoError:
1011 return "kErrorCodeDownloadNewPartitionInfoError";
1012 case kErrorCodeDownloadWriteError:
1013 return "kErrorCodeDownloadWriteError";
1014 case kErrorCodeNewRootfsVerificationError:
1015 return "kErrorCodeNewRootfsVerificationError";
1016 case kErrorCodeNewKernelVerificationError:
1017 return "kErrorCodeNewKernelVerificationError";
1018 case kErrorCodeSignedDeltaPayloadExpectedError:
1019 return "kErrorCodeSignedDeltaPayloadExpectedError";
1020 case kErrorCodeDownloadPayloadPubKeyVerificationError:
1021 return "kErrorCodeDownloadPayloadPubKeyVerificationError";
1022 case kErrorCodePostinstallBootedFromFirmwareB:
1023 return "kErrorCodePostinstallBootedFromFirmwareB";
1024 case kErrorCodeDownloadStateInitializationError:
1025 return "kErrorCodeDownloadStateInitializationError";
1026 case kErrorCodeDownloadInvalidMetadataMagicString:
1027 return "kErrorCodeDownloadInvalidMetadataMagicString";
1028 case kErrorCodeDownloadSignatureMissingInManifest:
1029 return "kErrorCodeDownloadSignatureMissingInManifest";
1030 case kErrorCodeDownloadManifestParseError:
1031 return "kErrorCodeDownloadManifestParseError";
1032 case kErrorCodeDownloadMetadataSignatureError:
1033 return "kErrorCodeDownloadMetadataSignatureError";
1034 case kErrorCodeDownloadMetadataSignatureVerificationError:
1035 return "kErrorCodeDownloadMetadataSignatureVerificationError";
1036 case kErrorCodeDownloadMetadataSignatureMismatch:
1037 return "kErrorCodeDownloadMetadataSignatureMismatch";
1038 case kErrorCodeDownloadOperationHashVerificationError:
1039 return "kErrorCodeDownloadOperationHashVerificationError";
1040 case kErrorCodeDownloadOperationExecutionError:
1041 return "kErrorCodeDownloadOperationExecutionError";
1042 case kErrorCodeDownloadOperationHashMismatch:
1043 return "kErrorCodeDownloadOperationHashMismatch";
1044 case kErrorCodeOmahaRequestEmptyResponseError:
1045 return "kErrorCodeOmahaRequestEmptyResponseError";
1046 case kErrorCodeOmahaRequestXMLParseError:
1047 return "kErrorCodeOmahaRequestXMLParseError";
1048 case kErrorCodeDownloadInvalidMetadataSize:
1049 return "kErrorCodeDownloadInvalidMetadataSize";
1050 case kErrorCodeDownloadInvalidMetadataSignature:
1051 return "kErrorCodeDownloadInvalidMetadataSignature";
1052 case kErrorCodeOmahaResponseInvalid:
1053 return "kErrorCodeOmahaResponseInvalid";
1054 case kErrorCodeOmahaUpdateIgnoredPerPolicy:
1055 return "kErrorCodeOmahaUpdateIgnoredPerPolicy";
1056 case kErrorCodeOmahaUpdateDeferredPerPolicy:
1057 return "kErrorCodeOmahaUpdateDeferredPerPolicy";
1058 case kErrorCodeOmahaErrorInHTTPResponse:
1059 return "kErrorCodeOmahaErrorInHTTPResponse";
1060 case kErrorCodeDownloadOperationHashMissingError:
1061 return "kErrorCodeDownloadOperationHashMissingError";
1062 case kErrorCodeDownloadMetadataSignatureMissingError:
1063 return "kErrorCodeDownloadMetadataSignatureMissingError";
1064 case kErrorCodeOmahaUpdateDeferredForBackoff:
1065 return "kErrorCodeOmahaUpdateDeferredForBackoff";
1066 case kErrorCodePostinstallPowerwashError:
1067 return "kErrorCodePostinstallPowerwashError";
1068 case kErrorCodeUpdateCanceledByChannelChange:
1069 return "kErrorCodeUpdateCanceledByChannelChange";
1070 case kErrorCodeUmaReportedMax:
1071 return "kErrorCodeUmaReportedMax";
1072 case kErrorCodeOmahaRequestHTTPResponseBase:
1073 return "kErrorCodeOmahaRequestHTTPResponseBase";
1074 case kErrorCodeResumedFlag:
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001075 return "Resumed";
David Zeuthena99981f2013-04-29 13:42:47 -07001076 case kErrorCodeDevModeFlag:
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001077 return "DevMode";
David Zeuthena99981f2013-04-29 13:42:47 -07001078 case kErrorCodeTestImageFlag:
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001079 return "TestImage";
David Zeuthena99981f2013-04-29 13:42:47 -07001080 case kErrorCodeTestOmahaUrlFlag:
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001081 return "TestOmahaUrl";
David Zeuthena99981f2013-04-29 13:42:47 -07001082 case kErrorCodeSpecialFlags:
1083 return "kErrorCodeSpecialFlags";
Don Garrett81018e02013-07-30 18:46:31 -07001084 case kErrorCodePostinstallFirmwareRONotUpdatable:
1085 return "kErrorCodePostinstallFirmwareRONotUpdatable";
Don Garrett4d039442013-10-28 18:40:06 -07001086 case kErrorCodeUnsupportedMajorPayloadVersion:
1087 return "kErrorCodeUnsupportedMajorPayloadVersion";
1088 case kErrorCodeUnsupportedMinorPayloadVersion:
1089 return "kErrorCodeUnsupportedMinorPayloadVersion";
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001090 // Don't add a default case to let the compiler warn about newly added
1091 // error codes which should be added here.
1092 }
1093
1094 return "Unknown error: " + base::UintToString(static_cast<unsigned>(code));
1095}
Jay Srinivasanf0572052012-10-23 18:12:56 -07001096
Gilad Arnold30dedd82013-07-03 06:19:09 -07001097bool CreatePowerwashMarkerFile(const char* file_path) {
1098 const char* marker_file = file_path ? file_path : kPowerwashMarkerFile;
1099 bool result = utils::WriteFile(marker_file,
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07001100 kPowerwashCommand,
1101 strlen(kPowerwashCommand));
Gilad Arnold30dedd82013-07-03 06:19:09 -07001102 if (result) {
1103 LOG(INFO) << "Created " << marker_file << " to powerwash on next reboot";
1104 } else {
1105 PLOG(ERROR) << "Error in creating powerwash marker file: " << marker_file;
1106 }
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07001107
1108 return result;
1109}
1110
Gilad Arnold30dedd82013-07-03 06:19:09 -07001111bool DeletePowerwashMarkerFile(const char* file_path) {
1112 const char* marker_file = file_path ? file_path : kPowerwashMarkerFile;
1113 const FilePath kPowerwashMarkerPath(marker_file);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07001114 bool result = file_util::Delete(kPowerwashMarkerPath, false);
1115
1116 if (result)
1117 LOG(INFO) << "Successfully deleted the powerwash marker file : "
Gilad Arnold30dedd82013-07-03 06:19:09 -07001118 << marker_file;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07001119 else
1120 PLOG(ERROR) << "Could not delete the powerwash marker file : "
Gilad Arnold30dedd82013-07-03 06:19:09 -07001121 << marker_file;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07001122
1123 return result;
1124}
1125
Chris Sosad317e402013-06-12 13:47:09 -07001126bool GetInstallDev(const std::string& boot_dev, std::string* install_dev) {
1127 TEST_AND_RETURN_FALSE(StringHasPrefix(boot_dev, "/dev/"));
Liam McLoughlin049d1652013-07-31 18:47:46 -07001128 string::iterator it;
1129 string ubiblock_prefix("/dev/ubiblock");
1130
1131 install_dev->assign(boot_dev);
1132
1133 if(StringHasPrefix(boot_dev, ubiblock_prefix)) {
1134 // UBI-based device
1135 it = install_dev->begin() + ubiblock_prefix.length();
1136 } else {
1137 // non-UBI device
1138 it = install_dev->end() - 1; // last character in string
1139 }
1140
Chris Sosad317e402013-06-12 13:47:09 -07001141 // Right now, we just switch '3' and '5' partition numbers.
Liam McLoughlin049d1652013-07-31 18:47:46 -07001142 TEST_AND_RETURN_FALSE(*it == '3' || *it == '5');
1143 *it = (*it == '3' ? '5' : '3');
1144
Chris Sosad317e402013-06-12 13:47:09 -07001145 return true;
1146}
1147
David Zeuthen27a48bc2013-08-06 12:06:29 -07001148Time TimeFromStructTimespec(struct timespec *ts) {
1149 int64 us = static_cast<int64>(ts->tv_sec) * Time::kMicrosecondsPerSecond +
1150 static_cast<int64>(ts->tv_nsec) / Time::kNanosecondsPerMicrosecond;
1151 return Time::UnixEpoch() + TimeDelta::FromMicroseconds(us);
1152}
1153
1154gchar** StringVectorToGStrv(const vector<string> &vector) {
1155 GPtrArray *p = g_ptr_array_new();
1156 for (std::vector<string>::const_iterator i = vector.begin();
1157 i != vector.end(); ++i) {
1158 g_ptr_array_add(p, g_strdup(i->c_str()));
1159 }
1160 g_ptr_array_add(p, NULL);
1161 return reinterpret_cast<gchar**>(g_ptr_array_free(p, FALSE));
1162}
1163
1164string StringVectorToString(const vector<string> &vector) {
1165 string str = "[";
1166 for (std::vector<string>::const_iterator i = vector.begin();
1167 i != vector.end(); ++i) {
1168 if (i != vector.begin())
1169 str += ", ";
1170 str += '"';
1171 str += *i;
1172 str += '"';
1173 }
1174 str += "]";
1175 return str;
1176}
1177
David Zeuthen8f191b22013-08-06 12:27:50 -07001178string CalculateP2PFileId(const string& payload_hash, size_t payload_size) {
1179 string encoded_hash;
1180 OmahaHashCalculator::Base64Encode(payload_hash.c_str(),
1181 payload_hash.size(),
1182 &encoded_hash);
1183 return StringPrintf("cros_update_size_%zu_hash_%s",
1184 payload_size,
1185 encoded_hash.c_str());
1186}
1187
David Zeuthen910ec5b2013-09-26 12:10:58 -07001188bool IsXAttrSupported(const base::FilePath& dir_path) {
1189 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
1190
1191 int fd = mkstemp(path);
1192 if (fd == -1) {
1193 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
1194 free(path);
1195 return false;
1196 }
1197
1198 if (unlink(path) != 0) {
1199 PLOG(ERROR) << "Error unlinking temporary file " << path;
1200 close(fd);
1201 free(path);
1202 return false;
1203 }
1204
1205 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
1206 if (xattr_res != 0) {
1207 if (errno == ENOTSUP) {
1208 // Leave it to call-sites to warn about non-support.
1209 } else {
1210 PLOG(ERROR) << "Error setting xattr on " << path;
1211 }
1212 }
1213 close(fd);
1214 free(path);
1215 return xattr_res == 0;
1216}
1217
David Zeuthene7f89172013-10-31 10:21:04 -07001218bool DecodeAndStoreBase64String(const std::string& base64_encoded,
1219 base::FilePath *out_path) {
1220 vector<char> contents;
1221
1222 out_path->clear();
1223
1224 if (base64_encoded.size() == 0) {
1225 LOG(ERROR) << "Can't decode empty string.";
1226 return false;
1227 }
1228
1229 if (!OmahaHashCalculator::Base64Decode(base64_encoded, &contents) ||
1230 contents.size() == 0) {
1231 LOG(ERROR) << "Error decoding base64.";
1232 return false;
1233 }
1234
1235 FILE *file = file_util::CreateAndOpenTemporaryFile(out_path);
1236 if (file == NULL) {
1237 LOG(ERROR) << "Error creating temporary file.";
1238 return false;
1239 }
1240
1241 if (fwrite(&contents[0], 1, contents.size(), file) != contents.size()) {
1242 PLOG(ERROR) << "Error writing to temporary file.";
1243 if (fclose(file) != 0)
1244 PLOG(ERROR) << "Error closing temporary file.";
1245 if (unlink(out_path->value().c_str()) != 0)
1246 PLOG(ERROR) << "Error unlinking temporary file.";
1247 out_path->clear();
1248 return false;
1249 }
1250
1251 if (fclose(file) != 0) {
1252 PLOG(ERROR) << "Error closing temporary file.";
1253 out_path->clear();
1254 return false;
1255 }
1256
1257 return true;
1258}
1259
David Zeuthen639aa362014-02-03 16:23:44 -08001260bool ConvertToOmahaInstallDate(base::Time time, int *out_num_days) {
1261 time_t unix_time = time.ToTimeT();
1262 // Output of: date +"%s" --date="Jan 1, 2007 0:00 PST".
1263 const time_t kOmahaEpoch = 1167638400;
1264 const int64_t kNumSecondsPerWeek = 7*24*3600;
1265 const int64_t kNumDaysPerWeek = 7;
1266
1267 time_t omaha_time = unix_time - kOmahaEpoch;
1268
1269 if (omaha_time < 0)
1270 return false;
1271
1272 // Note, as per the comment in utils.h we are deliberately not
1273 // handling DST correctly.
1274
1275 int64_t num_weeks_since_omaha_epoch = omaha_time / kNumSecondsPerWeek;
1276 *out_num_days = num_weeks_since_omaha_epoch * kNumDaysPerWeek;
1277
1278 return true;
1279}
1280
adlr@google.com3defe6a2009-12-04 20:57:17 +00001281} // namespace utils
1282
1283} // namespace chromeos_update_engine