blob: 6e5ec441663116f0b7cb003f3ee7db46d7504047 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
rspangler@google.com49fdf182009-10-10 00:57:34 +00002// 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"
Mike Frysinger8155d082012-04-06 15:23:18 -040019#include <base/stringprintf.h>
Chris Masone790e62e2010-08-12 10:41:18 -070020#include "base/logging.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000021#include "update_engine/file_writer.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000022#include "update_engine/filesystem_iterator.h"
23#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000024
adlr@google.comc98a7ed2009-12-04 18:54:03 +000025using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000026using std::string;
27using std::vector;
28
29namespace chromeos_update_engine {
30
adlr@google.comc98a7ed2009-12-04 18:54:03 +000031bool WriteFileVector(const std::string& path, const std::vector<char>& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080032 return utils::WriteFile(path.c_str(), &data[0], data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +000033}
34
35bool WriteFileString(const std::string& path, const std::string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080036 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +000037}
38
adlr@google.comc98a7ed2009-12-04 18:54:03 +000039std::string Readlink(const std::string& path) {
40 vector<char> buf(PATH_MAX + 1);
41 ssize_t r = readlink(path.c_str(), &buf[0], buf.size());
42 if (r < 0)
43 return "";
44 CHECK_LT(r, static_cast<ssize_t>(buf.size()));
45 buf.resize(r);
46 string ret;
47 ret.insert(ret.begin(), buf.begin(), buf.end());
48 return ret;
49}
50
rspangler@google.com49fdf182009-10-10 00:57:34 +000051std::vector<char> GzipCompressData(const std::vector<char>& data) {
52 const char fname[] = "/tmp/GzipCompressDataTemp";
adlr@google.comc98a7ed2009-12-04 18:54:03 +000053 if (!WriteFileVector(fname, data)) {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070054 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000055 return vector<char>();
56 }
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070057 EXPECT_EQ(0, system((string("cat ") + fname + "|gzip>" +
58 fname + ".gz").c_str()));
59 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
adlr@google.comc98a7ed2009-12-04 18:54:03 +000060 vector<char> ret;
61 EXPECT_TRUE(utils::ReadFile(string(fname) + ".gz", &ret));
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070062 EXPECT_EQ(0, system((string("rm ") + fname + ".gz").c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000063 return ret;
64}
65
adlr@google.comc98a7ed2009-12-04 18:54:03 +000066vector<char> GenerateSampleMbr() {
67 // This is the actual MBR from my dev machine. Partition 1 (the first)
68 // is currently marked bootable
69 char mbr[512] = {
70 0xeb, 0x48, 0x90, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
71 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
72 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
73 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
74 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
75 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
76 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
77 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x03, 0x02,
78 0xff, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
79 0x00, 0x02, 0xfa, 0x90, 0x90, 0xf6, 0xc2, 0x80,
80 0x75, 0x02, 0xb2, 0x80, 0xea, 0x59, 0x7c, 0x00,
81 0x00, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc,
82 0x00, 0x20, 0xfb, 0xa0, 0x40, 0x7c, 0x3c, 0xff,
83 0x74, 0x02, 0x88, 0xc2, 0x52, 0xbe, 0x7f, 0x7d,
84 0xe8, 0x34, 0x01, 0xf6, 0xc2, 0x80, 0x74, 0x54,
85 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x5a,
86 0x52, 0x72, 0x49, 0x81, 0xfb, 0x55, 0xaa, 0x75,
87 0x43, 0xa0, 0x41, 0x7c, 0x84, 0xc0, 0x75, 0x05,
88 0x83, 0xe1, 0x01, 0x74, 0x37, 0x66, 0x8b, 0x4c,
89 0x10, 0xbe, 0x05, 0x7c, 0xc6, 0x44, 0xff, 0x01,
90 0x66, 0x8b, 0x1e, 0x44, 0x7c, 0xc7, 0x04, 0x10,
91 0x00, 0xc7, 0x44, 0x02, 0x01, 0x00, 0x66, 0x89,
92 0x5c, 0x08, 0xc7, 0x44, 0x06, 0x00, 0x70, 0x66,
93 0x31, 0xc0, 0x89, 0x44, 0x04, 0x66, 0x89, 0x44,
94 0x0c, 0xb4, 0x42, 0xcd, 0x13, 0x72, 0x05, 0xbb,
95 0x00, 0x70, 0xeb, 0x7d, 0xb4, 0x08, 0xcd, 0x13,
96 0x73, 0x0a, 0xf6, 0xc2, 0x80, 0x0f, 0x84, 0xea,
97 0x00, 0xe9, 0x8d, 0x00, 0xbe, 0x05, 0x7c, 0xc6,
98 0x44, 0xff, 0x00, 0x66, 0x31, 0xc0, 0x88, 0xf0,
99 0x40, 0x66, 0x89, 0x44, 0x04, 0x31, 0xd2, 0x88,
100 0xca, 0xc1, 0xe2, 0x02, 0x88, 0xe8, 0x88, 0xf4,
101 0x40, 0x89, 0x44, 0x08, 0x31, 0xc0, 0x88, 0xd0,
102 0xc0, 0xe8, 0x02, 0x66, 0x89, 0x04, 0x66, 0xa1,
103 0x44, 0x7c, 0x66, 0x31, 0xd2, 0x66, 0xf7, 0x34,
104 0x88, 0x54, 0x0a, 0x66, 0x31, 0xd2, 0x66, 0xf7,
105 0x74, 0x04, 0x88, 0x54, 0x0b, 0x89, 0x44, 0x0c,
106 0x3b, 0x44, 0x08, 0x7d, 0x3c, 0x8a, 0x54, 0x0d,
107 0xc0, 0xe2, 0x06, 0x8a, 0x4c, 0x0a, 0xfe, 0xc1,
108 0x08, 0xd1, 0x8a, 0x6c, 0x0c, 0x5a, 0x8a, 0x74,
109 0x0b, 0xbb, 0x00, 0x70, 0x8e, 0xc3, 0x31, 0xdb,
110 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x72, 0x2a, 0x8c,
111 0xc3, 0x8e, 0x06, 0x48, 0x7c, 0x60, 0x1e, 0xb9,
112 0x00, 0x01, 0x8e, 0xdb, 0x31, 0xf6, 0x31, 0xff,
113 0xfc, 0xf3, 0xa5, 0x1f, 0x61, 0xff, 0x26, 0x42,
114 0x7c, 0xbe, 0x85, 0x7d, 0xe8, 0x40, 0x00, 0xeb,
115 0x0e, 0xbe, 0x8a, 0x7d, 0xe8, 0x38, 0x00, 0xeb,
116 0x06, 0xbe, 0x94, 0x7d, 0xe8, 0x30, 0x00, 0xbe,
117 0x99, 0x7d, 0xe8, 0x2a, 0x00, 0xeb, 0xfe, 0x47,
118 0x52, 0x55, 0x42, 0x20, 0x00, 0x47, 0x65, 0x6f,
119 0x6d, 0x00, 0x48, 0x61, 0x72, 0x64, 0x20, 0x44,
120 0x69, 0x73, 0x6b, 0x00, 0x52, 0x65, 0x61, 0x64,
121 0x00, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x00,
122 0xbb, 0x01, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xac,
123 0x3c, 0x00, 0x75, 0xf4, 0xc3, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x50, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x80, 0x01,
126 0x01, 0x00, 0x83, 0xfe, 0xff, 0xff, 0x3f, 0x00,
127 0x00, 0x00, 0x09, 0x7f, 0x32, 0x06, 0x00, 0xfe,
128 0xff, 0xff, 0x05, 0xfe, 0xff, 0xff, 0x48, 0x7f,
129 0x32, 0x06, 0x79, 0x59, 0x2d, 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, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
134 };
135 vector<char> ret;
136 ret.insert(ret.begin(), mbr, mbr + sizeof(mbr));
137 return ret;
138}
139
Don Garrett58e8b1f2012-01-31 16:38:16 -0800140string BindToUnusedLoopDevice(const string &filename) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000141 // get a loop device we can use for the install device
Don Garrett58e8b1f2012-01-31 16:38:16 -0800142 string cmd = "losetup --show -f " + filename;
143
144 FILE* find_dev_cmd = popen(cmd.c_str(), "r");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000145 CHECK(find_dev_cmd);
146
147 string ret;
148 char dev[100] = {0};
149 size_t r;
150 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
151 EXPECT_LT(r, sizeof(dev));
152 ret.insert(ret.end(), dev, dev + r);
153 }
154 EXPECT_EQ(r, 0);
155 EXPECT_TRUE(feof(find_dev_cmd));
156 fclose(find_dev_cmd);
157
158 // strip trailing \n on dev
159 if (*ret.rbegin() == '\n')
160 ret.resize(ret.size() - 1);
161
Don Garrett58e8b1f2012-01-31 16:38:16 -0800162 // Ensure that the device starts with "/dev/loop"
163 EXPECT_TRUE(StartsWithASCII(ret, "/dev/loop", true));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000164 return ret;
165}
166
Andrew de los Reyes80061062010-02-04 14:25:00 -0800167bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
168 EXPECT_EQ(expected.size(), actual.size());
169 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000170 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700171 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800172 for (unsigned int i = 0; i < expected.size(); i++) {
173 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700174 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000175 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700176 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000177}
178
Andrew de los Reyes80061062010-02-04 14:25:00 -0800179void FillWithData(vector<char>* buffer) {
180 size_t input_counter = 0;
181 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
182 *it = kRandomString[input_counter];
183 input_counter++;
184 input_counter %= sizeof(kRandomString);
185 }
186}
187
Thieu Le5c7d9752010-12-15 16:09:28 -0800188void CreateEmptyExtImageAtPath(const string& path,
189 size_t size,
190 int block_size) {
191 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
192 " seek=%zu bs=1 count=1",
193 path.c_str(), size)));
194 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
195 block_size, path.c_str())));
196}
197
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000198void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
199 // create 10MiB sparse file
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000200 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
201 " seek=10485759 bs=1 count=1",
202 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700203 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800204 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800206 kMountPath)));
207 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
208 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
209 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
210 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
211 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
212 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
213 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
214 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
215 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000216 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800217 kMountPath, kMountPath)));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800218 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0", kMountPath)));
219 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
220 kMountPath, kMountPath)));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800221 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
222 kMountPath)));
David James7f42b822012-02-16 15:44:16 -0800223 EXPECT_EQ(0, System(StringPrintf("umount %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800224
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000225 if (out_paths) {
226 out_paths->clear();
227 out_paths->push_back("");
228 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800229 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000230 out_paths->push_back("/hello");
231 out_paths->push_back("/some_dir");
232 out_paths->push_back("/some_dir/empty_dir");
233 out_paths->push_back("/some_dir/mnt");
234 out_paths->push_back("/some_dir/test");
235 out_paths->push_back("/some_dir/fifo");
236 out_paths->push_back("/cdev");
237 out_paths->push_back("/testlink");
238 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800239 out_paths->push_back("/srchardlink0");
240 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000241 out_paths->push_back("/lost+found");
242 }
243}
244
245void VerifyAllPaths(const string& parent, set<string> expected_paths) {
246 FilesystemIterator iter(parent, set<string>());
247 ino_t test_ino = 0;
248 ino_t testlink_ino = 0;
249 while (!iter.IsEnd()) {
250 string path = iter.GetFullPath();
251 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
252 EXPECT_EQ(1, expected_paths.erase(path));
253 if (utils::StringHasSuffix(path, "/hi") ||
254 utils::StringHasSuffix(path, "/hello") ||
255 utils::StringHasSuffix(path, "/test") ||
256 utils::StringHasSuffix(path, "/testlink")) {
257 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
258 if (utils::StringHasSuffix(path, "/test"))
259 test_ino = iter.GetStat().st_ino;
260 else if (utils::StringHasSuffix(path, "/testlink"))
261 testlink_ino = iter.GetStat().st_ino;
262 } else if (utils::StringHasSuffix(path, "/some_dir") ||
263 utils::StringHasSuffix(path, "/empty_dir") ||
264 utils::StringHasSuffix(path, "/mnt") ||
265 utils::StringHasSuffix(path, "/lost+found") ||
266 parent == path) {
267 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
268 } else if (utils::StringHasSuffix(path, "/fifo")) {
269 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
270 } else if (utils::StringHasSuffix(path, "/cdev")) {
271 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
272 } else if (utils::StringHasSuffix(path, "/sym")) {
273 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
274 } else {
275 LOG(INFO) << "got non hardcoded path: " << path;
276 }
277 iter.Increment();
278 }
279 EXPECT_EQ(testlink_ino, test_ino);
280 EXPECT_NE(0, test_ino);
281 EXPECT_FALSE(iter.IsErr());
282 EXPECT_TRUE(expected_paths.empty());
283 if (!expected_paths.empty()) {
284 for (set<string>::const_iterator it = expected_paths.begin();
285 it != expected_paths.end(); ++it) {
286 LOG(INFO) << "extra path: " << *it;
287 }
288 }
289}
290
Don Garrett58e8b1f2012-01-31 16:38:16 -0800291ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
292 string* mnt_path,
Thieu Le5c7d9752010-12-15 16:09:28 -0800293 unsigned long flags) {
294 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
295 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
296
Don Garrett58e8b1f2012-01-31 16:38:16 -0800297 string loop_dev;
298 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800299
300 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
301 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
302}
303
rspangler@google.com49fdf182009-10-10 00:57:34 +0000304} // namespace chromeos_update_engine