blob: 85c73d73950eccf676d13713fab3cde718ad5096 [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS 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
adlr@google.comc98a7ed2009-12-04 18:54:03 +00005#include "update_engine/test_utils.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07006
rspangler@google.com49fdf182009-10-10 00:57:34 +00007#include <sys/stat.h>
8#include <sys/types.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00009#include <errno.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000010#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070013
adlr@google.comc98a7ed2009-12-04 18:54:03 +000014#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000015#include <string>
16#include <vector>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070017
adlr@google.comc98a7ed2009-12-04 18:54:03 +000018#include "base/string_util.h"
Chris Masone790e62e2010-08-12 10:41:18 -070019#include "base/logging.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000020#include "update_engine/file_writer.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000021#include "update_engine/filesystem_iterator.h"
22#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000023
adlr@google.comc98a7ed2009-12-04 18:54:03 +000024using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000025using std::string;
26using std::vector;
27
28namespace chromeos_update_engine {
29
adlr@google.comc98a7ed2009-12-04 18:54:03 +000030bool WriteFileVector(const std::string& path, const std::vector<char>& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080031 return utils::WriteFile(path.c_str(), &data[0], data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +000032}
33
34bool WriteFileString(const std::string& path, const std::string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080035 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +000036}
37
adlr@google.comc98a7ed2009-12-04 18:54:03 +000038std::string Readlink(const std::string& path) {
39 vector<char> buf(PATH_MAX + 1);
40 ssize_t r = readlink(path.c_str(), &buf[0], buf.size());
41 if (r < 0)
42 return "";
43 CHECK_LT(r, static_cast<ssize_t>(buf.size()));
44 buf.resize(r);
45 string ret;
46 ret.insert(ret.begin(), buf.begin(), buf.end());
47 return ret;
48}
49
rspangler@google.com49fdf182009-10-10 00:57:34 +000050std::vector<char> GzipCompressData(const std::vector<char>& data) {
51 const char fname[] = "/tmp/GzipCompressDataTemp";
adlr@google.comc98a7ed2009-12-04 18:54:03 +000052 if (!WriteFileVector(fname, data)) {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070053 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000054 return vector<char>();
55 }
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070056 EXPECT_EQ(0, system((string("cat ") + fname + "|gzip>" +
57 fname + ".gz").c_str()));
58 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
adlr@google.comc98a7ed2009-12-04 18:54:03 +000059 vector<char> ret;
60 EXPECT_TRUE(utils::ReadFile(string(fname) + ".gz", &ret));
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070061 EXPECT_EQ(0, system((string("rm ") + fname + ".gz").c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000062 return ret;
63}
64
adlr@google.comc98a7ed2009-12-04 18:54:03 +000065vector<char> GenerateSampleMbr() {
66 // This is the actual MBR from my dev machine. Partition 1 (the first)
67 // is currently marked bootable
68 char mbr[512] = {
69 0xeb, 0x48, 0x90, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
70 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
71 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
72 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
73 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
74 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
75 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
76 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x03, 0x02,
77 0xff, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
78 0x00, 0x02, 0xfa, 0x90, 0x90, 0xf6, 0xc2, 0x80,
79 0x75, 0x02, 0xb2, 0x80, 0xea, 0x59, 0x7c, 0x00,
80 0x00, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc,
81 0x00, 0x20, 0xfb, 0xa0, 0x40, 0x7c, 0x3c, 0xff,
82 0x74, 0x02, 0x88, 0xc2, 0x52, 0xbe, 0x7f, 0x7d,
83 0xe8, 0x34, 0x01, 0xf6, 0xc2, 0x80, 0x74, 0x54,
84 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x5a,
85 0x52, 0x72, 0x49, 0x81, 0xfb, 0x55, 0xaa, 0x75,
86 0x43, 0xa0, 0x41, 0x7c, 0x84, 0xc0, 0x75, 0x05,
87 0x83, 0xe1, 0x01, 0x74, 0x37, 0x66, 0x8b, 0x4c,
88 0x10, 0xbe, 0x05, 0x7c, 0xc6, 0x44, 0xff, 0x01,
89 0x66, 0x8b, 0x1e, 0x44, 0x7c, 0xc7, 0x04, 0x10,
90 0x00, 0xc7, 0x44, 0x02, 0x01, 0x00, 0x66, 0x89,
91 0x5c, 0x08, 0xc7, 0x44, 0x06, 0x00, 0x70, 0x66,
92 0x31, 0xc0, 0x89, 0x44, 0x04, 0x66, 0x89, 0x44,
93 0x0c, 0xb4, 0x42, 0xcd, 0x13, 0x72, 0x05, 0xbb,
94 0x00, 0x70, 0xeb, 0x7d, 0xb4, 0x08, 0xcd, 0x13,
95 0x73, 0x0a, 0xf6, 0xc2, 0x80, 0x0f, 0x84, 0xea,
96 0x00, 0xe9, 0x8d, 0x00, 0xbe, 0x05, 0x7c, 0xc6,
97 0x44, 0xff, 0x00, 0x66, 0x31, 0xc0, 0x88, 0xf0,
98 0x40, 0x66, 0x89, 0x44, 0x04, 0x31, 0xd2, 0x88,
99 0xca, 0xc1, 0xe2, 0x02, 0x88, 0xe8, 0x88, 0xf4,
100 0x40, 0x89, 0x44, 0x08, 0x31, 0xc0, 0x88, 0xd0,
101 0xc0, 0xe8, 0x02, 0x66, 0x89, 0x04, 0x66, 0xa1,
102 0x44, 0x7c, 0x66, 0x31, 0xd2, 0x66, 0xf7, 0x34,
103 0x88, 0x54, 0x0a, 0x66, 0x31, 0xd2, 0x66, 0xf7,
104 0x74, 0x04, 0x88, 0x54, 0x0b, 0x89, 0x44, 0x0c,
105 0x3b, 0x44, 0x08, 0x7d, 0x3c, 0x8a, 0x54, 0x0d,
106 0xc0, 0xe2, 0x06, 0x8a, 0x4c, 0x0a, 0xfe, 0xc1,
107 0x08, 0xd1, 0x8a, 0x6c, 0x0c, 0x5a, 0x8a, 0x74,
108 0x0b, 0xbb, 0x00, 0x70, 0x8e, 0xc3, 0x31, 0xdb,
109 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x72, 0x2a, 0x8c,
110 0xc3, 0x8e, 0x06, 0x48, 0x7c, 0x60, 0x1e, 0xb9,
111 0x00, 0x01, 0x8e, 0xdb, 0x31, 0xf6, 0x31, 0xff,
112 0xfc, 0xf3, 0xa5, 0x1f, 0x61, 0xff, 0x26, 0x42,
113 0x7c, 0xbe, 0x85, 0x7d, 0xe8, 0x40, 0x00, 0xeb,
114 0x0e, 0xbe, 0x8a, 0x7d, 0xe8, 0x38, 0x00, 0xeb,
115 0x06, 0xbe, 0x94, 0x7d, 0xe8, 0x30, 0x00, 0xbe,
116 0x99, 0x7d, 0xe8, 0x2a, 0x00, 0xeb, 0xfe, 0x47,
117 0x52, 0x55, 0x42, 0x20, 0x00, 0x47, 0x65, 0x6f,
118 0x6d, 0x00, 0x48, 0x61, 0x72, 0x64, 0x20, 0x44,
119 0x69, 0x73, 0x6b, 0x00, 0x52, 0x65, 0x61, 0x64,
120 0x00, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x00,
121 0xbb, 0x01, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xac,
122 0x3c, 0x00, 0x75, 0xf4, 0xc3, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x50, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x80, 0x01,
125 0x01, 0x00, 0x83, 0xfe, 0xff, 0xff, 0x3f, 0x00,
126 0x00, 0x00, 0x09, 0x7f, 0x32, 0x06, 0x00, 0xfe,
127 0xff, 0xff, 0x05, 0xfe, 0xff, 0xff, 0x48, 0x7f,
128 0x32, 0x06, 0x79, 0x59, 0x2d, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
133 };
134 vector<char> ret;
135 ret.insert(ret.begin(), mbr, mbr + sizeof(mbr));
136 return ret;
137}
138
139std::string GetUnusedLoopDevice() {
140 // get a loop device we can use for the install device
141 FILE* find_dev_cmd = popen("losetup -f", "r");
142 CHECK(find_dev_cmd);
143
144 string ret;
145 char dev[100] = {0};
146 size_t r;
147 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
148 EXPECT_LT(r, sizeof(dev));
149 ret.insert(ret.end(), dev, dev + r);
150 }
151 EXPECT_EQ(r, 0);
152 EXPECT_TRUE(feof(find_dev_cmd));
153 fclose(find_dev_cmd);
154
155 // strip trailing \n on dev
156 if (*ret.rbegin() == '\n')
157 ret.resize(ret.size() - 1);
158
159 return ret;
160}
161
Andrew de los Reyes80061062010-02-04 14:25:00 -0800162bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
163 EXPECT_EQ(expected.size(), actual.size());
164 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000165 return false;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800166 for (unsigned int i = 0; i < expected.size(); i++) {
167 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000168 }
169 return true;
170}
171
Andrew de los Reyes80061062010-02-04 14:25:00 -0800172void FillWithData(vector<char>* buffer) {
173 size_t input_counter = 0;
174 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
175 *it = kRandomString[input_counter];
176 input_counter++;
177 input_counter %= sizeof(kRandomString);
178 }
179}
180
Thieu Le5c7d9752010-12-15 16:09:28 -0800181void CreateEmptyExtImageAtPath(const string& path,
182 size_t size,
183 int block_size) {
184 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
185 " seek=%zu bs=1 count=1",
186 path.c_str(), size)));
187 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
188 block_size, path.c_str())));
189}
190
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000191void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
192 // create 10MiB sparse file
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000193 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
194 " seek=10485759 bs=1 count=1",
195 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700196 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800197 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000198 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800199 kMountPath)));
200 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
201 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
202 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
203 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
204 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
205 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
206 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
207 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
208 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000209 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800210 kMountPath, kMountPath)));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800211 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0", kMountPath)));
212 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
213 kMountPath, kMountPath)));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800214 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
215 kMountPath)));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700216 EXPECT_EQ(0, System(StringPrintf("umount -d %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800217
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000218 if (out_paths) {
219 out_paths->clear();
220 out_paths->push_back("");
221 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800222 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000223 out_paths->push_back("/hello");
224 out_paths->push_back("/some_dir");
225 out_paths->push_back("/some_dir/empty_dir");
226 out_paths->push_back("/some_dir/mnt");
227 out_paths->push_back("/some_dir/test");
228 out_paths->push_back("/some_dir/fifo");
229 out_paths->push_back("/cdev");
230 out_paths->push_back("/testlink");
231 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800232 out_paths->push_back("/srchardlink0");
233 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000234 out_paths->push_back("/lost+found");
235 }
236}
237
238void VerifyAllPaths(const string& parent, set<string> expected_paths) {
239 FilesystemIterator iter(parent, set<string>());
240 ino_t test_ino = 0;
241 ino_t testlink_ino = 0;
242 while (!iter.IsEnd()) {
243 string path = iter.GetFullPath();
244 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
245 EXPECT_EQ(1, expected_paths.erase(path));
246 if (utils::StringHasSuffix(path, "/hi") ||
247 utils::StringHasSuffix(path, "/hello") ||
248 utils::StringHasSuffix(path, "/test") ||
249 utils::StringHasSuffix(path, "/testlink")) {
250 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
251 if (utils::StringHasSuffix(path, "/test"))
252 test_ino = iter.GetStat().st_ino;
253 else if (utils::StringHasSuffix(path, "/testlink"))
254 testlink_ino = iter.GetStat().st_ino;
255 } else if (utils::StringHasSuffix(path, "/some_dir") ||
256 utils::StringHasSuffix(path, "/empty_dir") ||
257 utils::StringHasSuffix(path, "/mnt") ||
258 utils::StringHasSuffix(path, "/lost+found") ||
259 parent == path) {
260 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
261 } else if (utils::StringHasSuffix(path, "/fifo")) {
262 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
263 } else if (utils::StringHasSuffix(path, "/cdev")) {
264 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
265 } else if (utils::StringHasSuffix(path, "/sym")) {
266 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
267 } else {
268 LOG(INFO) << "got non hardcoded path: " << path;
269 }
270 iter.Increment();
271 }
272 EXPECT_EQ(testlink_ino, test_ino);
273 EXPECT_NE(0, test_ino);
274 EXPECT_FALSE(iter.IsErr());
275 EXPECT_TRUE(expected_paths.empty());
276 if (!expected_paths.empty()) {
277 for (set<string>::const_iterator it = expected_paths.begin();
278 it != expected_paths.end(); ++it) {
279 LOG(INFO) << "extra path: " << *it;
280 }
281 }
282}
283
Thieu Le5c7d9752010-12-15 16:09:28 -0800284ScopedLoopMounter::ScopedLoopMounter(const std::string& file_path,
285 std::string* mnt_path,
286 unsigned long flags) {
287 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
288 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
289
290 std::string loop_dev = GetUnusedLoopDevice();
291 EXPECT_EQ(0, system(StringPrintf("losetup %s %s", loop_dev.c_str(),
292 file_path.c_str()).c_str()));
293 loop_releaser_.reset(new ScopedLoopbackDeviceReleaser(loop_dev));
294
295 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
296 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
297}
298
rspangler@google.com49fdf182009-10-10 00:57:34 +0000299} // namespace chromeos_update_engine