From 3defe6acb3609e70e851a6eff062577d25a2af9d Mon Sep 17 00:00:00 2001 From: "adlr@google.com" Date: Fri, 4 Dec 2009 20:57:17 +0000 Subject: Missed new files in last commit Review URL: http://codereview.chromium.org/465067 git-svn-id: svn://chrome-svn/chromeos/trunk@336 06c00378-0e64-4dae-be16-12b19f9950a1 --- utils.cc | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 utils.cc (limited to 'utils.cc') diff --git a/utils.cc b/utils.cc new file mode 100644 index 00000000..693062df --- /dev/null +++ b/utils.cc @@ -0,0 +1,253 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "update_engine/utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chromeos/obsolete_logging.h" + +using std::min; +using std::string; +using std::vector; + +namespace chromeos_update_engine { + +namespace utils { + +bool ReadFile(const std::string& path, std::vector* out) { + CHECK(out); + FILE* fp = fopen(path.c_str(), "r"); + if (!fp) + return false; + const size_t kChunkSize = 1024; + size_t read_size; + do { + char buf[kChunkSize]; + read_size = fread(buf, 1, kChunkSize, fp); + if (read_size == 0) + break; + out->insert(out->end(), buf, buf + read_size); + } while (read_size == kChunkSize); + bool success = !ferror(fp); + TEST_AND_RETURN_FALSE_ERRNO(fclose(fp) == 0); + return success; +} + +bool ReadFileToString(const std::string& path, std::string* out) { + vector data; + bool success = ReadFile(path, &data); + if (!success) { + return false; + } + (*out) = string(&data[0], data.size()); + return true; +} + +void HexDumpArray(const unsigned char* const arr, const size_t length) { + const unsigned char* const char_arr = + reinterpret_cast(arr); + LOG(INFO) << "Logging array of length: " << length; + const unsigned int bytes_per_line = 16; + for (size_t i = 0; i < length; i += bytes_per_line) { + const unsigned int bytes_remaining = length - i; + const unsigned int bytes_per_this_line = min(bytes_per_line, + bytes_remaining); + char header[100]; + int r = snprintf(header, sizeof(header), "0x%08x : ", i); + TEST_AND_RETURN(r == 13); + string line = header; + for (unsigned int j = 0; j < bytes_per_this_line; j++) { + char buf[20]; + unsigned char c = char_arr[i + j]; + r = snprintf(buf, sizeof(buf), "%02x ", static_cast(c)); + TEST_AND_RETURN(r == 3); + line += buf; + } + LOG(INFO) << line; + } +} + +namespace { +class ScopedDirCloser { + public: + explicit ScopedDirCloser(DIR** dir) : dir_(dir) {} + ~ScopedDirCloser() { + if (dir_ && *dir_) { + int r = closedir(*dir_); + TEST_AND_RETURN_ERRNO(r == 0); + *dir_ = NULL; + dir_ = NULL; + } + } + private: + DIR** dir_; +}; +} // namespace {} + +bool RecursiveUnlinkDir(const std::string& path) { + struct stat stbuf; + int r = lstat(path.c_str(), &stbuf); + TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT)); + if ((r < 0) && (errno == ENOENT)) + // path request is missing. that's fine. + return true; + if (!S_ISDIR(stbuf.st_mode)) { + TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) || + (errno == ENOENT)); + // success or path disappeared before we could unlink. + return true; + } + { + // We have a dir, unlink all children, then delete dir + DIR *dir = opendir(path.c_str()); + TEST_AND_RETURN_FALSE_ERRNO(dir); + ScopedDirCloser dir_closer(&dir); + struct dirent dir_entry; + struct dirent *dir_entry_p; + int err = 0; + while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) { + if (dir_entry_p == NULL) { + // end of stream reached + break; + } + // Skip . and .. + if (!strcmp(dir_entry_p->d_name, ".") || + !strcmp(dir_entry_p->d_name, "..")) + continue; + TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" + + dir_entry_p->d_name)); + } + TEST_AND_RETURN_FALSE(err == 0); + } + // unlink dir + TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT)); + return true; +} + +std::string ErrnoNumberAsString(int err) { + char buf[100]; + buf[0] = '\0'; + return strerror_r(err, buf, sizeof(buf)); +} + +std::string NormalizePath(const std::string& path, bool strip_trailing_slash) { + string ret; + bool last_insert_was_slash = false; + for (string::const_iterator it = path.begin(); it != path.end(); ++it) { + if (*it == '/') { + if (last_insert_was_slash) + continue; + last_insert_was_slash = true; + } else { + last_insert_was_slash = false; + } + ret.push_back(*it); + } + if (strip_trailing_slash && last_insert_was_slash) { + string::size_type last_non_slash = ret.find_last_not_of('/'); + if (last_non_slash != string::npos) { + ret.resize(last_non_slash + 1); + } else { + ret = ""; + } + } + return ret; +} + +bool FileExists(const char* path) { + struct stat stbuf; + return 0 == lstat(path, &stbuf); +} + +std::string TempFilename(string path) { + static const string suffix("XXXXXX"); + CHECK(StringHasSuffix(path, suffix)); + do { + string new_suffix; + for (unsigned int i = 0; i < suffix.size(); i++) { + int r = rand() % (26 * 2 + 10); // [a-zA-Z0-9] + if (r < 26) + new_suffix.append(1, 'a' + r); + else if (r < (26 * 2)) + new_suffix.append(1, 'A' + r - 26); + else + new_suffix.append(1, '0' + r - (26 * 2)); + } + CHECK_EQ(new_suffix.size(), suffix.size()); + path.resize(path.size() - new_suffix.size()); + path.append(new_suffix); + } while (FileExists(path.c_str())); + return path; +} + +bool StringHasSuffix(const std::string& str, const std::string& suffix) { + if (suffix.size() > str.size()) + return false; + return 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix); +} + +bool StringHasPrefix(const std::string& str, const std::string& prefix) { + if (prefix.size() > str.size()) + return false; + return 0 == str.compare(0, prefix.size(), prefix); +} + +const std::string BootDevice() { + string proc_cmdline; + if (!ReadFileToString("/proc/cmdline", &proc_cmdline)) + return ""; + // look for "root=" in the command line + string::size_type pos = 0; + if (!StringHasPrefix(proc_cmdline, "root=")) { + pos = proc_cmdline.find(" root=") + 1; + } + if (pos == string::npos) { + // can't find root= + return ""; + } + // at this point, pos is the point in the string where "root=" starts + string ret; + pos += strlen("root="); // advance to the device name itself + while (pos < proc_cmdline.size()) { + char c = proc_cmdline[pos]; + if (c == ' ') + break; + ret += c; + pos++; + } + return ret; + // TODO(adlr): use findfs to figure out UUID= or LABEL= filesystems +} + +bool MountFilesystem(const string& device, + const string& mountpoint) { + int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", 0, NULL); + if (rc < 0) { + string msg = ErrnoNumberAsString(errno); + LOG(ERROR) << "Unable to mount destination device: " << msg << ". " + << device << " on " << mountpoint; + return false; + } + return true; +} + +bool UnmountFilesystem(const string& mountpoint) { + TEST_AND_RETURN_FALSE_ERRNO(umount(mountpoint.c_str()) == 0); + return true; +} + +const string kStatefulPartition = "/mnt/stateful_partition"; + +} // namespace utils + +} // namespace chromeos_update_engine + -- cgit v1.2.3