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