blob: 7206171e89e4dd24534fb975fa9554931c217410 [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>
Darin Petkovc91dd6b2011-01-10 12:31:34 -080028#include <cros_boot_mode/boot_mode.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() {
55 cros_boot_mode::BootMode mode;
56 mode.Initialize(false, // unsupported_is_developer
57 true); // use_bootloader
58 bool normal = mode.mode() == cros_boot_mode::BootMode::kNormal;
59 LOG_IF(INFO, !normal) << "Boot mode not normal: " << mode.mode_text();
60 return normal;
61}
62
Andrew de los Reyes970bb282009-12-09 16:34:04 -080063bool WriteFile(const char* path, const char* data, int data_len) {
64 DirectFileWriter writer;
65 TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
66 O_WRONLY | O_CREAT | O_TRUNC,
Chris Masone4dc2ada2010-09-23 12:43:03 -070067 0600));
Andrew de los Reyes970bb282009-12-09 16:34:04 -080068 ScopedFileWriterCloser closer(&writer);
69 TEST_AND_RETURN_FALSE_ERRNO(data_len == writer.Write(data, data_len));
70 return true;
71}
72
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070073bool WriteAll(int fd, const void* buf, size_t count) {
Andrew de los Reyesb10320d2010-03-31 16:44:44 -070074 const char* c_buf = static_cast<const char*>(buf);
75 ssize_t bytes_written = 0;
76 while (bytes_written < static_cast<ssize_t>(count)) {
77 ssize_t rc = write(fd, c_buf + bytes_written, count - bytes_written);
78 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
79 bytes_written += rc;
80 }
81 return true;
82}
83
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070084bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
85 const char* c_buf = static_cast<const char*>(buf);
86 ssize_t bytes_written = 0;
87 while (bytes_written < static_cast<ssize_t>(count)) {
88 ssize_t rc = pwrite(fd, c_buf + bytes_written, count - bytes_written,
89 offset + bytes_written);
90 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
91 bytes_written += rc;
92 }
93 return true;
94}
95
96bool PReadAll(int fd, void* buf, size_t count, off_t offset,
97 ssize_t* out_bytes_read) {
98 char* c_buf = static_cast<char*>(buf);
99 ssize_t bytes_read = 0;
100 while (bytes_read < static_cast<ssize_t>(count)) {
101 ssize_t rc = pread(fd, c_buf + bytes_read, count - bytes_read,
102 offset + bytes_read);
103 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
104 if (rc == 0) {
105 break;
106 }
107 bytes_read += rc;
108 }
109 *out_bytes_read = bytes_read;
110 return true;
Darin Petkov296889c2010-07-23 16:20:54 -0700111
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700112}
113
adlr@google.com3defe6a2009-12-04 20:57:17 +0000114bool ReadFile(const std::string& path, std::vector<char>* out) {
115 CHECK(out);
116 FILE* fp = fopen(path.c_str(), "r");
117 if (!fp)
118 return false;
119 const size_t kChunkSize = 1024;
120 size_t read_size;
121 do {
122 char buf[kChunkSize];
123 read_size = fread(buf, 1, kChunkSize, fp);
124 if (read_size == 0)
125 break;
126 out->insert(out->end(), buf, buf + read_size);
127 } while (read_size == kChunkSize);
128 bool success = !ferror(fp);
129 TEST_AND_RETURN_FALSE_ERRNO(fclose(fp) == 0);
130 return success;
131}
132
133bool ReadFileToString(const std::string& path, std::string* out) {
134 vector<char> data;
135 bool success = ReadFile(path, &data);
136 if (!success) {
137 return false;
138 }
139 (*out) = string(&data[0], data.size());
140 return true;
141}
142
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700143off_t FileSize(const string& path) {
144 struct stat stbuf;
145 int rc = stat(path.c_str(), &stbuf);
146 CHECK_EQ(rc, 0);
147 if (rc < 0)
148 return rc;
149 return stbuf.st_size;
150}
151
adlr@google.com3defe6a2009-12-04 20:57:17 +0000152void HexDumpArray(const unsigned char* const arr, const size_t length) {
153 const unsigned char* const char_arr =
154 reinterpret_cast<const unsigned char* const>(arr);
155 LOG(INFO) << "Logging array of length: " << length;
156 const unsigned int bytes_per_line = 16;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700157 for (uint32_t i = 0; i < length; i += bytes_per_line) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000158 const unsigned int bytes_remaining = length - i;
159 const unsigned int bytes_per_this_line = min(bytes_per_line,
160 bytes_remaining);
161 char header[100];
162 int r = snprintf(header, sizeof(header), "0x%08x : ", i);
163 TEST_AND_RETURN(r == 13);
164 string line = header;
165 for (unsigned int j = 0; j < bytes_per_this_line; j++) {
166 char buf[20];
167 unsigned char c = char_arr[i + j];
168 r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c));
169 TEST_AND_RETURN(r == 3);
170 line += buf;
171 }
172 LOG(INFO) << line;
173 }
174}
175
176namespace {
177class ScopedDirCloser {
178 public:
179 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
180 ~ScopedDirCloser() {
181 if (dir_ && *dir_) {
182 int r = closedir(*dir_);
183 TEST_AND_RETURN_ERRNO(r == 0);
184 *dir_ = NULL;
185 dir_ = NULL;
186 }
187 }
188 private:
189 DIR** dir_;
190};
191} // namespace {}
192
193bool RecursiveUnlinkDir(const std::string& path) {
194 struct stat stbuf;
195 int r = lstat(path.c_str(), &stbuf);
196 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
197 if ((r < 0) && (errno == ENOENT))
198 // path request is missing. that's fine.
199 return true;
200 if (!S_ISDIR(stbuf.st_mode)) {
201 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700202 (errno == ENOENT));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000203 // success or path disappeared before we could unlink.
204 return true;
205 }
206 {
207 // We have a dir, unlink all children, then delete dir
208 DIR *dir = opendir(path.c_str());
209 TEST_AND_RETURN_FALSE_ERRNO(dir);
210 ScopedDirCloser dir_closer(&dir);
211 struct dirent dir_entry;
212 struct dirent *dir_entry_p;
213 int err = 0;
214 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
215 if (dir_entry_p == NULL) {
216 // end of stream reached
217 break;
218 }
219 // Skip . and ..
220 if (!strcmp(dir_entry_p->d_name, ".") ||
221 !strcmp(dir_entry_p->d_name, ".."))
222 continue;
223 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700224 dir_entry_p->d_name));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000225 }
226 TEST_AND_RETURN_FALSE(err == 0);
227 }
228 // unlink dir
229 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
230 return true;
231}
232
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700233string RootDevice(const string& partition_device) {
Darin Petkovf74eb652010-08-04 12:08:38 -0700234 FilePath device_path(partition_device);
235 if (device_path.DirName().value() != "/dev") {
236 return "";
237 }
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700238 string::const_iterator it = --partition_device.end();
239 for (; it >= partition_device.begin(); --it) {
240 if (!isdigit(*it))
241 break;
242 }
243 // Some devices contain a p before the partitions. For example:
244 // /dev/mmc0p4 should be shortened to /dev/mmc0.
245 if (*it == 'p')
246 --it;
247 return string(partition_device.begin(), it + 1);
248}
249
250string PartitionNumber(const string& partition_device) {
251 CHECK(!partition_device.empty());
252 string::const_iterator it = --partition_device.end();
253 for (; it >= partition_device.begin(); --it) {
254 if (!isdigit(*it))
255 break;
256 }
257 return string(it + 1, partition_device.end());
258}
259
Darin Petkovf74eb652010-08-04 12:08:38 -0700260string SysfsBlockDevice(const string& device) {
261 FilePath device_path(device);
262 if (device_path.DirName().value() != "/dev") {
263 return "";
264 }
265 return FilePath("/sys/block").Append(device_path.BaseName()).value();
266}
267
268bool IsRemovableDevice(const std::string& device) {
269 string sysfs_block = SysfsBlockDevice(device);
270 string removable;
271 if (sysfs_block.empty() ||
272 !file_util::ReadFileToString(FilePath(sysfs_block).Append("removable"),
273 &removable)) {
274 return false;
275 }
276 TrimWhitespaceASCII(removable, TRIM_ALL, &removable);
277 return removable == "1";
278}
279
adlr@google.com3defe6a2009-12-04 20:57:17 +0000280std::string ErrnoNumberAsString(int err) {
281 char buf[100];
282 buf[0] = '\0';
283 return strerror_r(err, buf, sizeof(buf));
284}
285
286std::string NormalizePath(const std::string& path, bool strip_trailing_slash) {
287 string ret;
288 bool last_insert_was_slash = false;
289 for (string::const_iterator it = path.begin(); it != path.end(); ++it) {
290 if (*it == '/') {
291 if (last_insert_was_slash)
292 continue;
293 last_insert_was_slash = true;
294 } else {
295 last_insert_was_slash = false;
296 }
297 ret.push_back(*it);
298 }
299 if (strip_trailing_slash && last_insert_was_slash) {
300 string::size_type last_non_slash = ret.find_last_not_of('/');
301 if (last_non_slash != string::npos) {
302 ret.resize(last_non_slash + 1);
303 } else {
304 ret = "";
305 }
306 }
307 return ret;
308}
309
310bool FileExists(const char* path) {
311 struct stat stbuf;
312 return 0 == lstat(path, &stbuf);
313}
314
Darin Petkov30291ed2010-11-12 10:23:06 -0800315bool IsSymlink(const char* path) {
316 struct stat stbuf;
317 return lstat(path, &stbuf) == 0 && S_ISLNK(stbuf.st_mode) != 0;
318}
319
adlr@google.com3defe6a2009-12-04 20:57:17 +0000320std::string TempFilename(string path) {
321 static const string suffix("XXXXXX");
322 CHECK(StringHasSuffix(path, suffix));
323 do {
324 string new_suffix;
325 for (unsigned int i = 0; i < suffix.size(); i++) {
326 int r = rand() % (26 * 2 + 10); // [a-zA-Z0-9]
327 if (r < 26)
328 new_suffix.append(1, 'a' + r);
329 else if (r < (26 * 2))
330 new_suffix.append(1, 'A' + r - 26);
331 else
332 new_suffix.append(1, '0' + r - (26 * 2));
333 }
334 CHECK_EQ(new_suffix.size(), suffix.size());
335 path.resize(path.size() - new_suffix.size());
336 path.append(new_suffix);
337 } while (FileExists(path.c_str()));
338 return path;
339}
340
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700341bool MakeTempFile(const std::string& filename_template,
342 std::string* filename,
343 int* fd) {
344 DCHECK(filename || fd);
345 vector<char> buf(filename_template.size() + 1);
346 memcpy(&buf[0], filename_template.data(), filename_template.size());
347 buf[filename_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700348
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700349 int mkstemp_fd = mkstemp(&buf[0]);
350 TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
351 if (filename) {
352 *filename = &buf[0];
353 }
354 if (fd) {
355 *fd = mkstemp_fd;
356 } else {
357 close(mkstemp_fd);
358 }
359 return true;
360}
361
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700362bool MakeTempDirectory(const std::string& dirname_template,
363 std::string* dirname) {
364 DCHECK(dirname);
365 vector<char> buf(dirname_template.size() + 1);
366 memcpy(&buf[0], dirname_template.data(), dirname_template.size());
367 buf[dirname_template.size()] = '\0';
Darin Petkov296889c2010-07-23 16:20:54 -0700368
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700369 char* return_code = mkdtemp(&buf[0]);
370 TEST_AND_RETURN_FALSE_ERRNO(return_code != NULL);
371 *dirname = &buf[0];
372 return true;
373}
374
adlr@google.com3defe6a2009-12-04 20:57:17 +0000375bool StringHasSuffix(const std::string& str, const std::string& suffix) {
376 if (suffix.size() > str.size())
377 return false;
378 return 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
379}
380
381bool StringHasPrefix(const std::string& str, const std::string& prefix) {
382 if (prefix.size() > str.size())
383 return false;
384 return 0 == str.compare(0, prefix.size(), prefix);
385}
386
Will Drewry8f71da82010-08-30 14:07:11 -0500387const std::string BootDevice() {
388 char boot_path[PATH_MAX];
389 // Resolve the boot device path fully, including dereferencing
390 // through dm-verity.
391 int ret = rootdev(boot_path, sizeof(boot_path), true, false);
392
393 if (ret < 0) {
394 LOG(ERROR) << "rootdev failed to find the root device";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000395 return "";
396 }
Will Drewry8f71da82010-08-30 14:07:11 -0500397 LOG_IF(WARNING, ret > 0) << "rootdev found a device name with no device node";
398
399 // This local variable is used to construct the return string and is not
400 // passed around after use.
401 return boot_path;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000402}
403
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700404const string BootKernelDevice(const std::string& boot_device) {
405 // Currntly this assumes the last digit of the boot device is
406 // 3, 5, or 7, and changes it to 2, 4, or 6, respectively, to
407 // get the kernel device.
408 string ret = boot_device;
409 if (ret.empty())
410 return ret;
411 char last_char = ret[ret.size() - 1];
412 if (last_char == '3' || last_char == '5' || last_char == '7') {
413 ret[ret.size() - 1] = last_char - 1;
414 return ret;
415 }
416 return "";
417}
418
adlr@google.com3defe6a2009-12-04 20:57:17 +0000419bool MountFilesystem(const string& device,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700420 const string& mountpoint,
421 unsigned long mountflags) {
422 int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", mountflags, NULL);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000423 if (rc < 0) {
424 string msg = ErrnoNumberAsString(errno);
425 LOG(ERROR) << "Unable to mount destination device: " << msg << ". "
426 << device << " on " << mountpoint;
427 return false;
428 }
429 return true;
430}
431
432bool UnmountFilesystem(const string& mountpoint) {
433 TEST_AND_RETURN_FALSE_ERRNO(umount(mountpoint.c_str()) == 0);
434 return true;
435}
436
Darin Petkovd3f8c892010-10-12 21:38:45 -0700437bool GetFilesystemSize(const std::string& device,
438 int* out_block_count,
439 int* out_block_size) {
440 int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY));
441 TEST_AND_RETURN_FALSE(fd >= 0);
442 ScopedFdCloser fd_closer(&fd);
443 return GetFilesystemSizeFromFD(fd, out_block_count, out_block_size);
444}
445
446bool GetFilesystemSizeFromFD(int fd,
447 int* out_block_count,
448 int* out_block_size) {
449 TEST_AND_RETURN_FALSE(fd >= 0);
450
451 // Determine the ext3 filesystem size by directly reading the block count and
452 // block size information from the superblock. See include/linux/ext3_fs.h for
453 // more details on the structure.
454 ssize_t kBufferSize = 16 * sizeof(uint32_t);
455 char buffer[kBufferSize];
456 const int kSuperblockOffset = 1024;
457 if (HANDLE_EINTR(pread(fd, buffer, kBufferSize, kSuperblockOffset)) !=
458 kBufferSize) {
459 PLOG(ERROR) << "Unable to determine file system size:";
460 return false;
461 }
462 uint32_t block_count; // ext3_fs.h: ext3_super_block.s_blocks_count
463 uint32_t log_block_size; // ext3_fs.h: ext3_super_block.s_log_block_size
464 uint16_t magic; // ext3_fs.h: ext3_super_block.s_magic
465 memcpy(&block_count, &buffer[1 * sizeof(int32_t)], sizeof(block_count));
466 memcpy(&log_block_size, &buffer[6 * sizeof(int32_t)], sizeof(log_block_size));
467 memcpy(&magic, &buffer[14 * sizeof(int32_t)], sizeof(magic));
468 block_count = le32toh(block_count);
469 const int kExt3MinBlockLogSize = 10; // ext3_fs.h: EXT3_MIN_BLOCK_LOG_SIZE
470 log_block_size = le32toh(log_block_size) + kExt3MinBlockLogSize;
471 magic = le16toh(magic);
472
473 // Sanity check the parameters.
474 const uint16_t kExt3SuperMagic = 0xef53; // ext3_fs.h: EXT3_SUPER_MAGIC
475 TEST_AND_RETURN_FALSE(magic == kExt3SuperMagic);
476 const int kExt3MinBlockSize = 1024; // ext3_fs.h: EXT3_MIN_BLOCK_SIZE
477 const int kExt3MaxBlockSize = 4096; // ext3_fs.h: EXT3_MAX_BLOCK_SIZE
478 int block_size = 1 << log_block_size;
479 TEST_AND_RETURN_FALSE(block_size >= kExt3MinBlockSize &&
480 block_size <= kExt3MaxBlockSize);
481 TEST_AND_RETURN_FALSE(block_count > 0);
482
483 if (out_block_count) {
484 *out_block_count = block_count;
485 }
486 if (out_block_size) {
487 *out_block_size = block_size;
488 }
489 return true;
490}
491
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700492bool GetBootloader(BootLoader* out_bootloader) {
493 // For now, hardcode to syslinux.
494 *out_bootloader = BootLoader_SYSLINUX;
495 return true;
496}
497
Andrew de los Reyesc7020782010-04-28 10:46:04 -0700498const char* GetGErrorMessage(const GError* error) {
499 if (!error)
500 return "Unknown error.";
501 return error->message;
502}
503
Darin Petkov296889c2010-07-23 16:20:54 -0700504bool Reboot() {
505 vector<string> command;
506 command.push_back("/sbin/shutdown");
507 command.push_back("-r");
508 command.push_back("now");
509 int rc = 0;
510 Subprocess::SynchronousExec(command, &rc);
511 TEST_AND_RETURN_FALSE(rc == 0);
512 return true;
513}
514
Andrew de los Reyes712b3ac2011-01-07 13:47:52 -0800515namespace {
516// Do the actual trigger. We do it as a main-loop callback to (try to) get a
517// consistent stack trace.
518gboolean TriggerCrashReporterUpload(void* unused) {
519 pid_t pid = fork();
520 CHECK(pid >= 0) << "fork failed"; // fork() failed. Something is very wrong.
521 if (pid == 0) {
522 // We are the child. Crash.
523 abort(); // never returns
524 }
525 // We are the parent. Wait for child to terminate.
526 pid_t result = waitpid(pid, NULL, 0);
527 LOG_IF(ERROR, result < 0) << "waitpid() failed";
528 return FALSE; // Don't call this callback again
529}
530} // namespace {}
531
532void ScheduleCrashReporterUpload() {
533 g_idle_add(&TriggerCrashReporterUpload, NULL);
534}
535
Darin Petkovc6c135c2010-08-11 13:36:18 -0700536bool SetProcessPriority(ProcessPriority priority) {
537 int prio = static_cast<int>(priority);
538 LOG(INFO) << "Setting process priority to " << prio;
539 TEST_AND_RETURN_FALSE(setpriority(PRIO_PROCESS, 0, prio) == 0);
540 return true;
541}
542
543int ComparePriorities(ProcessPriority priority_lhs,
544 ProcessPriority priority_rhs) {
545 return static_cast<int>(priority_rhs) - static_cast<int>(priority_lhs);
546}
547
Darin Petkov5c0a8af2010-08-24 13:39:13 -0700548int FuzzInt(int value, unsigned int range) {
549 int min = value - range / 2;
550 int max = value + range - range / 2;
551 return base::RandInt(min, max);
552}
553
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800554const char* const kStatefulPartition = "/mnt/stateful_partition";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000555
556} // namespace utils
557
558} // namespace chromeos_update_engine