OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // 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" |
| 6 #include <sys/mount.h> |
| 7 #include <sys/stat.h> |
| 8 #include <sys/types.h> |
| 9 #include <dirent.h> |
| 10 #include <errno.h> |
| 11 #include <stdio.h> |
| 12 #include <stdlib.h> |
| 13 #include <string.h> |
| 14 #include <unistd.h> |
| 15 #include <algorithm> |
| 16 #include "chromeos/obsolete_logging.h" |
| 17 |
| 18 using std::min; |
| 19 using std::string; |
| 20 using std::vector; |
| 21 |
| 22 namespace chromeos_update_engine { |
| 23 |
| 24 namespace utils { |
| 25 |
| 26 bool ReadFile(const std::string& path, std::vector<char>* out) { |
| 27 CHECK(out); |
| 28 FILE* fp = fopen(path.c_str(), "r"); |
| 29 if (!fp) |
| 30 return false; |
| 31 const size_t kChunkSize = 1024; |
| 32 size_t read_size; |
| 33 do { |
| 34 char buf[kChunkSize]; |
| 35 read_size = fread(buf, 1, kChunkSize, fp); |
| 36 if (read_size == 0) |
| 37 break; |
| 38 out->insert(out->end(), buf, buf + read_size); |
| 39 } while (read_size == kChunkSize); |
| 40 bool success = !ferror(fp); |
| 41 TEST_AND_RETURN_FALSE_ERRNO(fclose(fp) == 0); |
| 42 return success; |
| 43 } |
| 44 |
| 45 bool ReadFileToString(const std::string& path, std::string* out) { |
| 46 vector<char> data; |
| 47 bool success = ReadFile(path, &data); |
| 48 if (!success) { |
| 49 return false; |
| 50 } |
| 51 (*out) = string(&data[0], data.size()); |
| 52 return true; |
| 53 } |
| 54 |
| 55 void HexDumpArray(const unsigned char* const arr, const size_t length) { |
| 56 const unsigned char* const char_arr = |
| 57 reinterpret_cast<const unsigned char* const>(arr); |
| 58 LOG(INFO) << "Logging array of length: " << length; |
| 59 const unsigned int bytes_per_line = 16; |
| 60 for (size_t i = 0; i < length; i += bytes_per_line) { |
| 61 const unsigned int bytes_remaining = length - i; |
| 62 const unsigned int bytes_per_this_line = min(bytes_per_line, |
| 63 bytes_remaining); |
| 64 char header[100]; |
| 65 int r = snprintf(header, sizeof(header), "0x%08x : ", i); |
| 66 TEST_AND_RETURN(r == 13); |
| 67 string line = header; |
| 68 for (unsigned int j = 0; j < bytes_per_this_line; j++) { |
| 69 char buf[20]; |
| 70 unsigned char c = char_arr[i + j]; |
| 71 r = snprintf(buf, sizeof(buf), "%02x ", static_cast<unsigned int>(c)); |
| 72 TEST_AND_RETURN(r == 3); |
| 73 line += buf; |
| 74 } |
| 75 LOG(INFO) << line; |
| 76 } |
| 77 } |
| 78 |
| 79 namespace { |
| 80 class ScopedDirCloser { |
| 81 public: |
| 82 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {} |
| 83 ~ScopedDirCloser() { |
| 84 if (dir_ && *dir_) { |
| 85 int r = closedir(*dir_); |
| 86 TEST_AND_RETURN_ERRNO(r == 0); |
| 87 *dir_ = NULL; |
| 88 dir_ = NULL; |
| 89 } |
| 90 } |
| 91 private: |
| 92 DIR** dir_; |
| 93 }; |
| 94 } // namespace {} |
| 95 |
| 96 bool RecursiveUnlinkDir(const std::string& path) { |
| 97 struct stat stbuf; |
| 98 int r = lstat(path.c_str(), &stbuf); |
| 99 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT)); |
| 100 if ((r < 0) && (errno == ENOENT)) |
| 101 // path request is missing. that's fine. |
| 102 return true; |
| 103 if (!S_ISDIR(stbuf.st_mode)) { |
| 104 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) || |
| 105 (errno == ENOENT)); |
| 106 // success or path disappeared before we could unlink. |
| 107 return true; |
| 108 } |
| 109 { |
| 110 // We have a dir, unlink all children, then delete dir |
| 111 DIR *dir = opendir(path.c_str()); |
| 112 TEST_AND_RETURN_FALSE_ERRNO(dir); |
| 113 ScopedDirCloser dir_closer(&dir); |
| 114 struct dirent dir_entry; |
| 115 struct dirent *dir_entry_p; |
| 116 int err = 0; |
| 117 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) { |
| 118 if (dir_entry_p == NULL) { |
| 119 // end of stream reached |
| 120 break; |
| 121 } |
| 122 // Skip . and .. |
| 123 if (!strcmp(dir_entry_p->d_name, ".") || |
| 124 !strcmp(dir_entry_p->d_name, "..")) |
| 125 continue; |
| 126 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" + |
| 127 dir_entry_p->d_name)); |
| 128 } |
| 129 TEST_AND_RETURN_FALSE(err == 0); |
| 130 } |
| 131 // unlink dir |
| 132 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT)); |
| 133 return true; |
| 134 } |
| 135 |
| 136 std::string ErrnoNumberAsString(int err) { |
| 137 char buf[100]; |
| 138 buf[0] = '\0'; |
| 139 return strerror_r(err, buf, sizeof(buf)); |
| 140 } |
| 141 |
| 142 std::string NormalizePath(const std::string& path, bool strip_trailing_slash) { |
| 143 string ret; |
| 144 bool last_insert_was_slash = false; |
| 145 for (string::const_iterator it = path.begin(); it != path.end(); ++it) { |
| 146 if (*it == '/') { |
| 147 if (last_insert_was_slash) |
| 148 continue; |
| 149 last_insert_was_slash = true; |
| 150 } else { |
| 151 last_insert_was_slash = false; |
| 152 } |
| 153 ret.push_back(*it); |
| 154 } |
| 155 if (strip_trailing_slash && last_insert_was_slash) { |
| 156 string::size_type last_non_slash = ret.find_last_not_of('/'); |
| 157 if (last_non_slash != string::npos) { |
| 158 ret.resize(last_non_slash + 1); |
| 159 } else { |
| 160 ret = ""; |
| 161 } |
| 162 } |
| 163 return ret; |
| 164 } |
| 165 |
| 166 bool FileExists(const char* path) { |
| 167 struct stat stbuf; |
| 168 return 0 == lstat(path, &stbuf); |
| 169 } |
| 170 |
| 171 std::string TempFilename(string path) { |
| 172 static const string suffix("XXXXXX"); |
| 173 CHECK(StringHasSuffix(path, suffix)); |
| 174 do { |
| 175 string new_suffix; |
| 176 for (unsigned int i = 0; i < suffix.size(); i++) { |
| 177 int r = rand() % (26 * 2 + 10); // [a-zA-Z0-9] |
| 178 if (r < 26) |
| 179 new_suffix.append(1, 'a' + r); |
| 180 else if (r < (26 * 2)) |
| 181 new_suffix.append(1, 'A' + r - 26); |
| 182 else |
| 183 new_suffix.append(1, '0' + r - (26 * 2)); |
| 184 } |
| 185 CHECK_EQ(new_suffix.size(), suffix.size()); |
| 186 path.resize(path.size() - new_suffix.size()); |
| 187 path.append(new_suffix); |
| 188 } while (FileExists(path.c_str())); |
| 189 return path; |
| 190 } |
| 191 |
| 192 bool StringHasSuffix(const std::string& str, const std::string& suffix) { |
| 193 if (suffix.size() > str.size()) |
| 194 return false; |
| 195 return 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix); |
| 196 } |
| 197 |
| 198 bool StringHasPrefix(const std::string& str, const std::string& prefix) { |
| 199 if (prefix.size() > str.size()) |
| 200 return false; |
| 201 return 0 == str.compare(0, prefix.size(), prefix); |
| 202 } |
| 203 |
| 204 const std::string BootDevice() { |
| 205 string proc_cmdline; |
| 206 if (!ReadFileToString("/proc/cmdline", &proc_cmdline)) |
| 207 return ""; |
| 208 // look for "root=" in the command line |
| 209 string::size_type pos = 0; |
| 210 if (!StringHasPrefix(proc_cmdline, "root=")) { |
| 211 pos = proc_cmdline.find(" root=") + 1; |
| 212 } |
| 213 if (pos == string::npos) { |
| 214 // can't find root= |
| 215 return ""; |
| 216 } |
| 217 // at this point, pos is the point in the string where "root=" starts |
| 218 string ret; |
| 219 pos += strlen("root="); // advance to the device name itself |
| 220 while (pos < proc_cmdline.size()) { |
| 221 char c = proc_cmdline[pos]; |
| 222 if (c == ' ') |
| 223 break; |
| 224 ret += c; |
| 225 pos++; |
| 226 } |
| 227 return ret; |
| 228 // TODO(adlr): use findfs to figure out UUID= or LABEL= filesystems |
| 229 } |
| 230 |
| 231 bool MountFilesystem(const string& device, |
| 232 const string& mountpoint) { |
| 233 int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", 0, NULL); |
| 234 if (rc < 0) { |
| 235 string msg = ErrnoNumberAsString(errno); |
| 236 LOG(ERROR) << "Unable to mount destination device: " << msg << ". " |
| 237 << device << " on " << mountpoint; |
| 238 return false; |
| 239 } |
| 240 return true; |
| 241 } |
| 242 |
| 243 bool UnmountFilesystem(const string& mountpoint) { |
| 244 TEST_AND_RETURN_FALSE_ERRNO(umount(mountpoint.c_str()) == 0); |
| 245 return true; |
| 246 } |
| 247 |
| 248 const string kStatefulPartition = "/mnt/stateful_partition"; |
| 249 |
| 250 } // namespace utils |
| 251 |
| 252 } // namespace chromeos_update_engine |
| 253 |
OLD | NEW |