blob: e1256a7f0fd3cb8127d2bd32c18509ad3ecad05a [file] [log] [blame]
Darin Petkov296889c2010-07-23 16:20:54 -07001// Copyright (c) 2009 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
adlr@google.com3defe6a2009-12-04 20:57:17 +00007#include <sys/mount.h>
Darin Petkovc6c135c2010-08-11 13:36:18 -07008#include <sys/resource.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +00009#include <sys/stat.h>
10#include <sys/types.h>
Andrew de los Reyes712b3ac2011-01-07 13:47:52 -080011#include <sys/wait.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000012#include <dirent.h>
13#include <errno.h>
Andrew de los Reyes970bb282009-12-09 16:34:04 -080014#include <fcntl.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
Darin Petkovf74eb652010-08-04 12:08:38 -070019
adlr@google.com3defe6a2009-12-04 20:57:17 +000020#include <algorithm>
Darin Petkovf74eb652010-08-04 12:08:38 -070021
Darin Petkovd3f8c892010-10-12 21:38:45 -070022#include <base/eintr_wrapper.h>
Will Drewry8f71da82010-08-30 14:07:11 -050023#include <base/file_path.h>
24#include <base/file_util.h>
25#include <base/rand_util.h>
26#include <base/string_util.h>
27#include <base/logging.h>
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -080028#include <google/protobuf/stubs/common.h>
Will Drewry8f71da82010-08-30 14:07:11 -050029#include <rootdev/rootdev.h>
30
Andrew de los Reyes970bb282009-12-09 16:34:04 -080031#include "update_engine/file_writer.h"
Darin Petkov33d30642010-08-04 10:18:57 -070032#include "update_engine/omaha_request_params.h"
Darin Petkov296889c2010-07-23 16:20:54 -070033#include "update_engine/subprocess.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000034
35using std::min;
36using std::string;
37using std::vector;
38
39namespace chromeos_update_engine {
40
41namespace utils {
42
Darin Petkov2a0e6332010-09-24 14:43:41 -070043static const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
Darin Petkova07586b2010-10-20 13:41:15 -070044static const char kDevImageMarker[] = "/root/.dev_mode";
Darin Petkov2a0e6332010-09-24 14:43:41 -070045
Darin Petkov33d30642010-08-04 10:18:57 -070046bool IsOfficialBuild() {
Darin Petkova07586b2010-10-20 13:41:15 -070047 return !file_util::PathExists(FilePath(kDevImageMarker));
Darin Petkov33d30642010-08-04 10:18:57 -070048}
49
Darin Petkov2a0e6332010-09-24 14:43:41 -070050bool IsOOBEComplete() {
51 return file_util::PathExists(FilePath(kOOBECompletedMarker));
52}
53
Darin Petkovc91dd6b2011-01-10 12:31:34 -080054bool IsNormalBootMode() {
Darin Petkov44d98d92011-03-21 16:08:11 -070055 // TODO(petkov): Convert to a library call once a crossystem library is
56 // available (crosbug.com/13291).
57 int exit_code = 0;
58 vector<string> cmd(1, "/usr/bin/crossystem");
59 cmd.push_back("devsw_boot?1");
60
61 // Assume dev mode if the dev switch is set to 1 and there was no error
62 // executing crossystem. Assume normal mode otherwise.
63 bool success = Subprocess::SynchronousExec(cmd, &exit_code);
64 bool dev_mode = success && exit_code == 0;
65 LOG_IF(INFO, dev_mode) << "Booted in dev mode.";
66 return !dev_mode;
Darin Petkovc91dd6b2011-01-10 12:31:34 -080067}
68
Andrew de los Reyes970bb282009-12-09 16:34:04 -080069bool WriteFile(const char* path, const char* data, int data_len) {
70 DirectFileWriter writer;
71 TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
72 O_WRONLY | O_CREAT | O_TRUNC,
Chris Masone4dc2ada2010-09-23 12:43:03 -070073 0600));
Andrew de los Reyes970bb282009-12-09 16:34:04 -080074 ScopedFileWriterCloser closer(&writer);
75 TEST_AND_RETURN_FALSE_ERRNO(data_len == writer.Write(data, data_len));
76 return true;
77}
78
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070079bool WriteAll(int fd, const void* buf, size_t count) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070080 const char* c_buf = static_cast<const char*>(buf);
81 ssize_t bytes_written = 0;
82 while (bytes_written < static_cast<ssize_t>(count)) {
83 ssize_t rc = write(fd, c_buf + bytes_written, count - bytes_written);
84 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
85 bytes_written += rc;
86 }
87 return true;
88}
89
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070090bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
91 const char* c_buf = static_cast<const char*>(buf);
92 ssize_t bytes_written = 0;
93 while (bytes_written < static_cast<ssize_t>(count)) {
94 ssize_t rc = pwrite(fd, c_buf + bytes_written, count - bytes_written,
95 offset + bytes_written);
96 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
97 bytes_written += rc;
98 }
99 return true;
100}
101
102bool PReadAll(int fd, void* buf, size_t count, off_t offset,
103 ssize_t* out_bytes_read) {
104 char* c_buf = static_cast<char*>(buf);
105 ssize_t bytes_read = 0;
106 while (bytes_read < static_cast<ssize_t>(count)) {
107 ssize_t rc = pread(fd, c_buf + bytes_read, count - bytes_read,
108 offset + bytes_read);
109 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
110 if (rc == 0) {
111 break;
112 }
113 bytes_read += rc;
114 }
115 *out_bytes_read = bytes_read;
116 return true;
Darin Petkov296889c2010-07-23 16:20:54 -0700117
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700118}
119
adlr@google.com3defe6a2009-12-04 20:57:17 +0000120bool ReadFile(const std::string& path, std::vector<char>* out) {
121 CHECK(out);
122 FILE* fp = fopen(path.c_str(), "r");
123 if (!fp)
124 return false;
125 const size_t kChunkSize = 1024;
126 size_t read_size;
127 do {
128 char buf[kChunkSize];
129 read_size = fread(buf, 1, kChunkSize, fp);
130 if (read_size == 0)
131 break;
132 out->insert(out->end(), buf, buf + read_size);
133 } while (read_size == kChunkSize);
134 bool success = !ferror(fp);
135 TEST_AND_RETURN_FALSE_ERRNO(fclose(fp) == 0);
136 return success;
137}
138
139bool ReadFileToString(const std::string& path, std::string* out) {
140 vector<char> data;
141 bool success = ReadFile(path, &data);
142 if (!success) {
143 return false;
144 }
145 (*out) = string(&data[0], data.size());
146 return true;
147}
148
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700149off_t FileSize(const string& path) {
150 struct stat stbuf;
151 int rc = stat(path.c_str(), &stbuf);
152 CHECK_EQ(rc, 0);
153 if (rc < 0)
154 return rc;
155 return stbuf.st_size;
156}
157
adlr@google.com3defe6a2009-12-04 20:57:17 +0000158void HexDumpArray(const unsigned char* const arr, const size_t length) {
159 const unsigned char* const char_arr =
160 reinterpret_cast<const unsigned char* const>(arr);
161 LOG(INFO) << "Logging array of length: " << length;
162 const unsigned int bytes_per_line = 16;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700163 for (uint32_t i = 0; i < length; i += bytes_per_line) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000164 const unsigned int bytes_remaining = length - i;
165 const unsigned int bytes_per_this_line = min(bytes_per_line,
166 bytes_remaining);
167 char header[100];
168 int r = snprintf(header, sizeof(header), "0x%08x : ", i);
169 TEST_AND_RETURN(r == 13);
170 string line = header;
171 for (unsigned int j = 0; j < bytes_per_this_line; j++) {
172 char buf[20];
173 unsigned char c = char_arr[i + j];
174 r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c));
175 TEST_AND_RETURN(r == 3);
176 line += buf;
177 }
178 LOG(INFO) << line;
179 }
180}
181
182namespace {
183class ScopedDirCloser {
184 public:
185 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
186 ~ScopedDirCloser() {
187 if (dir_ && *dir_) {
188 int r = closedir(*dir_);
189 TEST_AND_RETURN_ERRNO(r == 0);
190 *dir_ = NULL;
191 dir_ = NULL;
192 }
193 }
194 private:
195 DIR** dir_;
196};
197} // namespace {}
198
199bool RecursiveUnlinkDir(const std::string& path) {
200 struct stat stbuf;
201 int r = lstat(path.c_str(), &stbuf);
202 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
203 if ((r < 0) && (errno == ENOENT))
204 // path request is missing. that's fine.
205 return true;
206 if (!S_ISDIR(stbuf.st_mode)) {
207 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700208 (errno == ENOENT));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000209 // success or path disappeared before we could unlink.
210 return true;
211 }
212 {
213 // We have a dir, unlink all children, then delete dir
214 DIR *dir = opendir(path.c_str());
215 TEST_AND_RETURN_FALSE_ERRNO(dir);
216 ScopedDirCloser dir_closer(&dir);
217 struct dirent dir_entry;
218 struct dirent *dir_entry_p;
219 int err = 0;
220 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
221 if (dir_entry_p == NULL) {
222 // end of stream reached
223 break;
224 }
225 // Skip . and ..
226 if (!strcmp(dir_entry_p->d_name, ".") ||
227 !strcmp(dir_entry_p->d_name, ".."))
228 continue;
229 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700230 dir_entry_p->d_name));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000231 }
232 TEST_AND_RETURN_FALSE(err == 0);
233 }
234 // unlink dir
235 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
236 return true;
237}
238
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700239string RootDevice(const string& partition_device) {
Darin Petkovf74eb652010-08-04 12:08:38 -0700240 FilePath device_path(partition_device);
241 if (device_path.DirName().value() != "/dev") {
242 return "";
243 }
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700244 string::const_iterator it = --partition_device.end();
245 for (; it >= partition_device.begin(); --it) {
246 if (!isdigit(*it))
247 break;
248 }
249 // Some devices contain a p before the partitions. For example:
250 // /dev/mmc0p4 should be shortened to /dev/mmc0.
251 if (*it == 'p')
252 --it;
253 return string(partition_device.begin(), it + 1);
254}
255
256string PartitionNumber(const string& partition_device) {
257 CHECK(!partition_device.empty());
258 string::const_iterator it = --partition_device.end();
259 for (; it >= partition_device.begin(); --it) {
260 if (!isdigit(*it))
261 break;
262 }
263 return string(it + 1, partition_device.end());
264}
265
Darin Petkovf74eb652010-08-04 12:08:38 -0700266string SysfsBlockDevice(const string& device) {
267 FilePath device_path(device);
268 if (device_path.DirName().value() != "/dev") {
269 return "";
270 }
271 return FilePath("/sys/block").Append(device_path.BaseName()).value();
272}
273
274bool IsRemovableDevice(const std::string& device) {
275 string sysfs_block = SysfsBlockDevice(device);
276 string removable;
277 if (sysfs_block.empty() ||
278 !file_util::ReadFileToString(FilePath(sysfs_block).Append("removable"),
279 &removable)) {
280 return false;
281 }
282 TrimWhitespaceASCII(removable, TRIM_ALL, &removable);
283 return removable == "1";
284}
285
adlr@google.com3defe6a2009-12-04 20:57:17 +0000286std::string ErrnoNumberAsString(int err) {
287 char buf[100];
288 buf[0] = '\0';
289 return strerror_r(err, buf, sizeof(buf));
290}
291
292std::string NormalizePath(const std::string& path, bool strip_trailing_slash) {
293 string ret;
294 bool last_insert_was_slash = false;
295 for (string::const_iterator it = path.begin(); it != path.end(); ++it) {
296 if (*it == '/') {
297 if (last_insert_was_slash)
298 continue;
299 last_insert_was_slash = true;
300 } else {
301 last_insert_was_slash = false;
302 }
303 ret.push_back(*it);
304 }
305 if (strip_trailing_slash && last_insert_was_slash) {
306 string::size_type last_non_slash = ret.find_last_not_of('/');
307 if (last_non_slash != string::npos) {
308 ret.resize(last_non_slash + 1);
309 } else {
310 ret = "";
311 }
312 }
313 return ret;
314}
315
316bool FileExists(const char* path) {
317 struct stat stbuf;
318 return 0 == lstat(path, &stbuf);
319}
320
Darin Petkov30291ed2010-11-12 10:23:06 -0800321bool IsSymlink(const char* path) {
322 struct stat stbuf;
323 return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
324}
325
adlr@google.com3defe6a2009-12-04 20:57:17 +0000326std::string TempFilename(string path) {
327 static const string suffix("XXXXXX");
328 CHECK(StringHasSuffix(path, suffix));
329 do {
330 string new_suffix;
331 for (unsigned int i = 0; i < suffix.size(); i++) {
332 int r = rand() % (26 * 2 + 10); // [a-zA-Z0-9]
333 if (r < 26)
334 new_suffix.append(1, 'a' + r);
335 else if (r < (26 * 2))
336 new_suffix.append(1, 'A' + r - 26);
337 else
338 new_suffix.append(1, '0' + r - (26 * 2));
339 }
340 CHECK_EQ(new_suffix.size(), suffix.size());
341 path.resize(path.size() - new_suffix.size());
342 path.append(new_suffix);
343 } while (FileExists(path.c_str()));
344 return path;
345}
346
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700347bool MakeTempFile(const std::string& filename_template,
348 std::string* filename,
349 int* fd) {
350 DCHECK(filename || fd);
351 vector<char> buf(filename_template.size() + 1);
352 memcpy(&buf[0], filename_template.data(), filename_template.size());
353 buf[filename_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700354
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700355 int mkstemp_fd = mkstemp(&buf[0]);
356 TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
357 if (filename) {
358 *filename = &buf[0];
359 }
360 if (fd) {
361 *fd = mkstemp_fd;
362 } else {
363 close(mkstemp_fd);
364 }
365 return true;
366}
367
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700368bool MakeTempDirectory(const std::string& dirname_template,
369 std::string* dirname) {
370 DCHECK(dirname);
371 vector<char> buf(dirname_template.size() + 1);
372 memcpy(&buf[0], dirname_template.data(), dirname_template.size());
373 buf[dirname_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700374
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700375 char* return_code = mkdtemp(&buf[0]);
376 TEST_AND_RETURN_FALSE_ERRNO(return_code != NULL);
377 *dirname = &buf[0];
378 return true;
379}
380
adlr@google.com3defe6a2009-12-04 20:57:17 +0000381bool StringHasSuffix(const std::string& str, const std::string& suffix) {
382 if (suffix.size() > str.size())
383 return false;
384 return 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
385}
386
387bool StringHasPrefix(const std::string& str, const std::string& prefix) {
388 if (prefix.size() > str.size())
389 return false;
390 return 0 == str.compare(0, prefix.size(), prefix);
391}
392
Will Drewry8f71da82010-08-30 14:07:11 -0500393const std::string BootDevice() {
394 char boot_path[PATH_MAX];
395 // Resolve the boot device path fully, including dereferencing
396 // through dm-verity.
397 int ret = rootdev(boot_path, sizeof(boot_path), true, false);
398
399 if (ret < 0) {
400 LOG(ERROR) << "rootdev failed to find the root device";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000401 return "";
402 }
Will Drewry8f71da82010-08-30 14:07:11 -0500403 LOG_IF(WARNING, ret > 0) << "rootdev found a device name with no device node";
404
405 // This local variable is used to construct the return string and is not
406 // passed around after use.
407 return boot_path;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000408}
409
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700410const string BootKernelDevice(const std::string& boot_device) {
411 // Currntly this assumes the last digit of the boot device is
412 // 3, 5, or 7, and changes it to 2, 4, or 6, respectively, to
413 // get the kernel device.
414 string ret = boot_device;
415 if (ret.empty())
416 return ret;
417 char last_char = ret[ret.size() - 1];
418 if (last_char == '3' || last_char == '5' || last_char == '7') {
419 ret[ret.size() - 1] = last_char - 1;
420 return ret;
421 }
422 return "";
423}
424
adlr@google.com3defe6a2009-12-04 20:57:17 +0000425bool MountFilesystem(const string& device,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700426 const string& mountpoint,
427 unsigned long mountflags) {
428 int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", mountflags, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000429 if (rc < 0) {
430 string msg = ErrnoNumberAsString(errno);
431 LOG(ERROR) << "Unable to mount destination device: " << msg << ". "
432 << device << " on " << mountpoint;
433 return false;
434 }
435 return true;
436}
437
438bool UnmountFilesystem(const string& mountpoint) {
439 TEST_AND_RETURN_FALSE_ERRNO(umount(mountpoint.c_str()) == 0);
440 return true;
441}
442
Darin Petkovd3f8c892010-10-12 21:38:45 -0700443bool GetFilesystemSize(const std::string& device,
444 int* out_block_count,
445 int* out_block_size) {
446 int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY));
447 TEST_AND_RETURN_FALSE(fd >= 0);
448 ScopedFdCloser fd_closer(&fd);
449 return GetFilesystemSizeFromFD(fd, out_block_count, out_block_size);
450}
451
452bool GetFilesystemSizeFromFD(int fd,
453 int* out_block_count,
454 int* out_block_size) {
455 TEST_AND_RETURN_FALSE(fd >= 0);
456
457 // Determine the ext3 filesystem size by directly reading the block count and
458 // block size information from the superblock. See include/linux/ext3_fs.h for
459 // more details on the structure.
460 ssize_t kBufferSize = 16 * sizeof(uint32_t);
461 char buffer[kBufferSize];
462 const int kSuperblockOffset = 1024;
463 if (HANDLE_EINTR(pread(fd, buffer, kBufferSize, kSuperblockOffset)) !=
464 kBufferSize) {
465 PLOG(ERROR) << "Unable to determine file system size:";
466 return false;
467 }
468 uint32_t block_count; // ext3_fs.h: ext3_super_block.s_blocks_count
469 uint32_t log_block_size; // ext3_fs.h: ext3_super_block.s_log_block_size
470 uint16_t magic; // ext3_fs.h: ext3_super_block.s_magic
471 memcpy(&block_count, &buffer[1 * sizeof(int32_t)], sizeof(block_count));
472 memcpy(&log_block_size, &buffer[6 * sizeof(int32_t)], sizeof(log_block_size));
473 memcpy(&magic, &buffer[14 * sizeof(int32_t)], sizeof(magic));
474 block_count = le32toh(block_count);
475 const int kExt3MinBlockLogSize = 10; // ext3_fs.h: EXT3_MIN_BLOCK_LOG_SIZE
476 log_block_size = le32toh(log_block_size) + kExt3MinBlockLogSize;
477 magic = le16toh(magic);
478
479 // Sanity check the parameters.
480 const uint16_t kExt3SuperMagic = 0xef53; // ext3_fs.h: EXT3_SUPER_MAGIC
481 TEST_AND_RETURN_FALSE(magic == kExt3SuperMagic);
482 const int kExt3MinBlockSize = 1024; // ext3_fs.h: EXT3_MIN_BLOCK_SIZE
483 const int kExt3MaxBlockSize = 4096; // ext3_fs.h: EXT3_MAX_BLOCK_SIZE
484 int block_size = 1 << log_block_size;
485 TEST_AND_RETURN_FALSE(block_size >= kExt3MinBlockSize &&
486 block_size <= kExt3MaxBlockSize);
487 TEST_AND_RETURN_FALSE(block_count > 0);
488
489 if (out_block_count) {
490 *out_block_count = block_count;
491 }
492 if (out_block_size) {
493 *out_block_size = block_size;
494 }
495 return true;
496}
497
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700498bool GetBootloader(BootLoader* out_bootloader) {
499 // For now, hardcode to syslinux.
500 *out_bootloader = BootLoader_SYSLINUX;
501 return true;
502}
503
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700504const char* GetGErrorMessage(const GError* error) {
505 if (!error)
506 return "Unknown error.";
507 return error->message;
508}
509
Darin Petkov296889c2010-07-23 16:20:54 -0700510bool Reboot() {
511 vector<string> command;
512 command.push_back("/sbin/shutdown");
513 command.push_back("-r");
514 command.push_back("now");
515 int rc = 0;
516 Subprocess::SynchronousExec(command, &rc);
517 TEST_AND_RETURN_FALSE(rc == 0);
518 return true;
519}
520
Andrew de los Reyes712b3ac2011-01-07 13:47:52 -0800521namespace {
522// Do the actual trigger. We do it as a main-loop callback to (try to) get a
523// consistent stack trace.
524gboolean TriggerCrashReporterUpload(void* unused) {
525 pid_t pid = fork();
526 CHECK(pid >= 0) << "fork failed"; // fork() failed. Something is very wrong.
527 if (pid == 0) {
528 // We are the child. Crash.
529 abort(); // never returns
530 }
531 // We are the parent. Wait for child to terminate.
532 pid_t result = waitpid(pid, NULL, 0);
533 LOG_IF(ERROR, result < 0) << "waitpid() failed";
534 return FALSE; // Don't call this callback again
535}
536} // namespace {}
537
538void ScheduleCrashReporterUpload() {
539 g_idle_add(&TriggerCrashReporterUpload, NULL);
540}
541
Darin Petkovc6c135c2010-08-11 13:36:18 -0700542bool SetProcessPriority(ProcessPriority priority) {
543 int prio = static_cast<int>(priority);
544 LOG(INFO) << "Setting process priority to " << prio;
545 TEST_AND_RETURN_FALSE(setpriority(PRIO_PROCESS, 0, prio) == 0);
546 return true;
547}
548
549int ComparePriorities(ProcessPriority priority_lhs,
550 ProcessPriority priority_rhs) {
551 return static_cast<int>(priority_rhs) - static_cast<int>(priority_lhs);
552}
553
Darin Petkov5c0a8af2010-08-24 13:39:13 -0700554int FuzzInt(int value, unsigned int range) {
555 int min = value - range / 2;
556 int max = value + range - range / 2;
557 return base::RandInt(min, max);
558}
559
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800560gboolean GlibRunClosure(gpointer data) {
561 google::protobuf::Closure* callback =
562 reinterpret_cast<google::protobuf::Closure*>(data);
563 callback->Run();
564 return FALSE;
565}
566
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800567const char* const kStatefulPartition = "/mnt/stateful_partition";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000568
569} // namespace utils
570
571} // namespace chromeos_update_engine