blob: fcaae46cc22de9c469a07305bb57f8645a265205 [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
Don Garrett58e8b1f2012-01-31 16:38:16 -0800139string BindToUnusedLoopDevice(const string &filename) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000140 // get a loop device we can use for the install device
Don Garrett58e8b1f2012-01-31 16:38:16 -0800141 string cmd = "losetup --show -f " + filename;
142
143 FILE* find_dev_cmd = popen(cmd.c_str(), "r");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000144 CHECK(find_dev_cmd);
145
146 string ret;
147 char dev[100] = {0};
148 size_t r;
149 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
150 EXPECT_LT(r, sizeof(dev));
151 ret.insert(ret.end(), dev, dev + r);
152 }
153 EXPECT_EQ(r, 0);
154 EXPECT_TRUE(feof(find_dev_cmd));
155 fclose(find_dev_cmd);
156
157 // strip trailing \n on dev
158 if (*ret.rbegin() == '\n')
159 ret.resize(ret.size() - 1);
160
Don Garrett58e8b1f2012-01-31 16:38:16 -0800161 // Ensure that the device starts with "/dev/loop"
162 EXPECT_TRUE(StartsWithASCII(ret, "/dev/loop", true));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000163 return ret;
164}
165
Andrew de los Reyes80061062010-02-04 14:25:00 -0800166bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
167 EXPECT_EQ(expected.size(), actual.size());
168 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000169 return false;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800170 for (unsigned int i = 0; i < expected.size(); i++) {
171 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000172 }
173 return true;
174}
175
Andrew de los Reyes80061062010-02-04 14:25:00 -0800176void FillWithData(vector<char>* buffer) {
177 size_t input_counter = 0;
178 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
179 *it = kRandomString[input_counter];
180 input_counter++;
181 input_counter %= sizeof(kRandomString);
182 }
183}
184
Thieu Le5c7d9752010-12-15 16:09:28 -0800185void CreateEmptyExtImageAtPath(const string& path,
186 size_t size,
187 int block_size) {
188 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
189 " seek=%zu bs=1 count=1",
190 path.c_str(), size)));
191 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
192 block_size, path.c_str())));
193}
194
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000195void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
196 // create 10MiB sparse file
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000197 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
198 " seek=10485759 bs=1 count=1",
199 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700200 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800201 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000202 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800203 kMountPath)));
204 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
205 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
206 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
207 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
208 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
209 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
210 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
211 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
212 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000213 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800214 kMountPath, kMountPath)));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800215 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0", kMountPath)));
216 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
217 kMountPath, kMountPath)));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800218 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
219 kMountPath)));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700220 EXPECT_EQ(0, System(StringPrintf("umount -d %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800221
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000222 if (out_paths) {
223 out_paths->clear();
224 out_paths->push_back("");
225 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800226 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000227 out_paths->push_back("/hello");
228 out_paths->push_back("/some_dir");
229 out_paths->push_back("/some_dir/empty_dir");
230 out_paths->push_back("/some_dir/mnt");
231 out_paths->push_back("/some_dir/test");
232 out_paths->push_back("/some_dir/fifo");
233 out_paths->push_back("/cdev");
234 out_paths->push_back("/testlink");
235 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800236 out_paths->push_back("/srchardlink0");
237 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000238 out_paths->push_back("/lost+found");
239 }
240}
241
242void VerifyAllPaths(const string& parent, set<string> expected_paths) {
243 FilesystemIterator iter(parent, set<string>());
244 ino_t test_ino = 0;
245 ino_t testlink_ino = 0;
246 while (!iter.IsEnd()) {
247 string path = iter.GetFullPath();
248 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
249 EXPECT_EQ(1, expected_paths.erase(path));
250 if (utils::StringHasSuffix(path, "/hi") ||
251 utils::StringHasSuffix(path, "/hello") ||
252 utils::StringHasSuffix(path, "/test") ||
253 utils::StringHasSuffix(path, "/testlink")) {
254 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
255 if (utils::StringHasSuffix(path, "/test"))
256 test_ino = iter.GetStat().st_ino;
257 else if (utils::StringHasSuffix(path, "/testlink"))
258 testlink_ino = iter.GetStat().st_ino;
259 } else if (utils::StringHasSuffix(path, "/some_dir") ||
260 utils::StringHasSuffix(path, "/empty_dir") ||
261 utils::StringHasSuffix(path, "/mnt") ||
262 utils::StringHasSuffix(path, "/lost+found") ||
263 parent == path) {
264 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
265 } else if (utils::StringHasSuffix(path, "/fifo")) {
266 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
267 } else if (utils::StringHasSuffix(path, "/cdev")) {
268 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
269 } else if (utils::StringHasSuffix(path, "/sym")) {
270 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
271 } else {
272 LOG(INFO) << "got non hardcoded path: " << path;
273 }
274 iter.Increment();
275 }
276 EXPECT_EQ(testlink_ino, test_ino);
277 EXPECT_NE(0, test_ino);
278 EXPECT_FALSE(iter.IsErr());
279 EXPECT_TRUE(expected_paths.empty());
280 if (!expected_paths.empty()) {
281 for (set<string>::const_iterator it = expected_paths.begin();
282 it != expected_paths.end(); ++it) {
283 LOG(INFO) << "extra path: " << *it;
284 }
285 }
286}
287
Don Garrett58e8b1f2012-01-31 16:38:16 -0800288ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
289 string* mnt_path,
Thieu Le5c7d9752010-12-15 16:09:28 -0800290 unsigned long flags) {
291 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
292 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
293
Don Garrett58e8b1f2012-01-31 16:38:16 -0800294 string loop_dev;
295 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800296
297 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
298 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
299}
300
rspangler@google.com49fdf182009-10-10 00:57:34 +0000301} // namespace chromeos_update_engine