blob: d00f432ca684cb09630de3775883df5f3f5739ea [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
Gilad Arnold61d9d2c2013-07-22 17:54:52 -070031const char* const kMountPathTemplate = "/tmp/UpdateEngineTests_mnt-XXXXXX";
32
adlr@google.comc98a7ed2009-12-04 18:54:03 +000033bool WriteFileVector(const std::string& path, const std::vector<char>& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080034 return utils::WriteFile(path.c_str(), &data[0], data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +000035}
36
37bool WriteFileString(const std::string& path, const std::string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080038 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +000039}
40
adlr@google.comc98a7ed2009-12-04 18:54:03 +000041std::string Readlink(const std::string& path) {
42 vector<char> buf(PATH_MAX + 1);
43 ssize_t r = readlink(path.c_str(), &buf[0], buf.size());
44 if (r < 0)
45 return "";
46 CHECK_LT(r, static_cast<ssize_t>(buf.size()));
47 buf.resize(r);
48 string ret;
49 ret.insert(ret.begin(), buf.begin(), buf.end());
50 return ret;
51}
52
rspangler@google.com49fdf182009-10-10 00:57:34 +000053std::vector<char> GzipCompressData(const std::vector<char>& data) {
54 const char fname[] = "/tmp/GzipCompressDataTemp";
adlr@google.comc98a7ed2009-12-04 18:54:03 +000055 if (!WriteFileVector(fname, data)) {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070056 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000057 return vector<char>();
58 }
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070059 EXPECT_EQ(0, system((string("cat ") + fname + "|gzip>" +
60 fname + ".gz").c_str()));
61 EXPECT_EQ(0, system((string("rm ") + fname).c_str()));
adlr@google.comc98a7ed2009-12-04 18:54:03 +000062 vector<char> ret;
63 EXPECT_TRUE(utils::ReadFile(string(fname) + ".gz", &ret));
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070064 EXPECT_EQ(0, system((string("rm ") + fname + ".gz").c_str()));
rspangler@google.com49fdf182009-10-10 00:57:34 +000065 return ret;
66}
67
adlr@google.comc98a7ed2009-12-04 18:54:03 +000068vector<char> GenerateSampleMbr() {
69 // This is the actual MBR from my dev machine. Partition 1 (the first)
70 // is currently marked bootable
Han Shen2643cb72012-06-26 14:45:33 -070071 unsigned char mbr[512] = {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000072 0xeb, 0x48, 0x90, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
73 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
74 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
75 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
76 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
77 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
78 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
79 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x03, 0x02,
80 0xff, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
81 0x00, 0x02, 0xfa, 0x90, 0x90, 0xf6, 0xc2, 0x80,
82 0x75, 0x02, 0xb2, 0x80, 0xea, 0x59, 0x7c, 0x00,
83 0x00, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc,
84 0x00, 0x20, 0xfb, 0xa0, 0x40, 0x7c, 0x3c, 0xff,
85 0x74, 0x02, 0x88, 0xc2, 0x52, 0xbe, 0x7f, 0x7d,
86 0xe8, 0x34, 0x01, 0xf6, 0xc2, 0x80, 0x74, 0x54,
87 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x5a,
88 0x52, 0x72, 0x49, 0x81, 0xfb, 0x55, 0xaa, 0x75,
89 0x43, 0xa0, 0x41, 0x7c, 0x84, 0xc0, 0x75, 0x05,
90 0x83, 0xe1, 0x01, 0x74, 0x37, 0x66, 0x8b, 0x4c,
91 0x10, 0xbe, 0x05, 0x7c, 0xc6, 0x44, 0xff, 0x01,
92 0x66, 0x8b, 0x1e, 0x44, 0x7c, 0xc7, 0x04, 0x10,
93 0x00, 0xc7, 0x44, 0x02, 0x01, 0x00, 0x66, 0x89,
94 0x5c, 0x08, 0xc7, 0x44, 0x06, 0x00, 0x70, 0x66,
95 0x31, 0xc0, 0x89, 0x44, 0x04, 0x66, 0x89, 0x44,
96 0x0c, 0xb4, 0x42, 0xcd, 0x13, 0x72, 0x05, 0xbb,
97 0x00, 0x70, 0xeb, 0x7d, 0xb4, 0x08, 0xcd, 0x13,
98 0x73, 0x0a, 0xf6, 0xc2, 0x80, 0x0f, 0x84, 0xea,
99 0x00, 0xe9, 0x8d, 0x00, 0xbe, 0x05, 0x7c, 0xc6,
100 0x44, 0xff, 0x00, 0x66, 0x31, 0xc0, 0x88, 0xf0,
101 0x40, 0x66, 0x89, 0x44, 0x04, 0x31, 0xd2, 0x88,
102 0xca, 0xc1, 0xe2, 0x02, 0x88, 0xe8, 0x88, 0xf4,
103 0x40, 0x89, 0x44, 0x08, 0x31, 0xc0, 0x88, 0xd0,
104 0xc0, 0xe8, 0x02, 0x66, 0x89, 0x04, 0x66, 0xa1,
105 0x44, 0x7c, 0x66, 0x31, 0xd2, 0x66, 0xf7, 0x34,
106 0x88, 0x54, 0x0a, 0x66, 0x31, 0xd2, 0x66, 0xf7,
107 0x74, 0x04, 0x88, 0x54, 0x0b, 0x89, 0x44, 0x0c,
108 0x3b, 0x44, 0x08, 0x7d, 0x3c, 0x8a, 0x54, 0x0d,
109 0xc0, 0xe2, 0x06, 0x8a, 0x4c, 0x0a, 0xfe, 0xc1,
110 0x08, 0xd1, 0x8a, 0x6c, 0x0c, 0x5a, 0x8a, 0x74,
111 0x0b, 0xbb, 0x00, 0x70, 0x8e, 0xc3, 0x31, 0xdb,
112 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x72, 0x2a, 0x8c,
113 0xc3, 0x8e, 0x06, 0x48, 0x7c, 0x60, 0x1e, 0xb9,
114 0x00, 0x01, 0x8e, 0xdb, 0x31, 0xf6, 0x31, 0xff,
115 0xfc, 0xf3, 0xa5, 0x1f, 0x61, 0xff, 0x26, 0x42,
116 0x7c, 0xbe, 0x85, 0x7d, 0xe8, 0x40, 0x00, 0xeb,
117 0x0e, 0xbe, 0x8a, 0x7d, 0xe8, 0x38, 0x00, 0xeb,
118 0x06, 0xbe, 0x94, 0x7d, 0xe8, 0x30, 0x00, 0xbe,
119 0x99, 0x7d, 0xe8, 0x2a, 0x00, 0xeb, 0xfe, 0x47,
120 0x52, 0x55, 0x42, 0x20, 0x00, 0x47, 0x65, 0x6f,
121 0x6d, 0x00, 0x48, 0x61, 0x72, 0x64, 0x20, 0x44,
122 0x69, 0x73, 0x6b, 0x00, 0x52, 0x65, 0x61, 0x64,
123 0x00, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x00,
124 0xbb, 0x01, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xac,
125 0x3c, 0x00, 0x75, 0xf4, 0xc3, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x50, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x80, 0x01,
128 0x01, 0x00, 0x83, 0xfe, 0xff, 0xff, 0x3f, 0x00,
129 0x00, 0x00, 0x09, 0x7f, 0x32, 0x06, 0x00, 0xfe,
130 0xff, 0xff, 0x05, 0xfe, 0xff, 0xff, 0x48, 0x7f,
131 0x32, 0x06, 0x79, 0x59, 0x2d, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
136 };
137 vector<char> ret;
Han Shen2643cb72012-06-26 14:45:33 -0700138 ret.insert(ret.begin(), reinterpret_cast<char *>(mbr),
139 reinterpret_cast<char *>(mbr + sizeof(mbr)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000140 return ret;
141}
142
Gilad Arnold19a45f02012-07-19 12:36:10 -0700143// Binds provided |filename| to an unused loopback device, whose name is written
144// to the string pointed to by |lo_dev_name_p|. Returns true on success, false
145// otherwise (along with corresponding test failures), in which case the content
146// of |lo_dev_name_p| is unknown.
147bool BindToUnusedLoopDevice(const string& filename, string* lo_dev_name_p) {
148 CHECK(lo_dev_name_p);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800149
Gilad Arnold19a45f02012-07-19 12:36:10 -0700150 // Bind to an unused loopback device, sanity check the device name.
151 lo_dev_name_p->clear();
152 if (!(utils::ReadPipe("losetup --show -f " + filename, lo_dev_name_p) &&
153 StartsWithASCII(*lo_dev_name_p, "/dev/loop", true))) {
154 ADD_FAILURE();
155 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000156 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000157
Gilad Arnold19a45f02012-07-19 12:36:10 -0700158 // Strip anything from the first newline char.
159 size_t newline_pos = lo_dev_name_p->find('\n');
160 if (newline_pos != string::npos)
161 lo_dev_name_p->erase(newline_pos);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000162
Gilad Arnold19a45f02012-07-19 12:36:10 -0700163 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000164}
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;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700170 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800171 for (unsigned int i = 0; i < expected.size(); i++) {
172 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700173 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000174 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700175 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000176}
177
Andrew de los Reyes80061062010-02-04 14:25:00 -0800178void FillWithData(vector<char>* buffer) {
179 size_t input_counter = 0;
180 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
181 *it = kRandomString[input_counter];
182 input_counter++;
183 input_counter %= sizeof(kRandomString);
184 }
185}
186
Thieu Le5c7d9752010-12-15 16:09:28 -0800187void CreateEmptyExtImageAtPath(const string& path,
188 size_t size,
189 int block_size) {
190 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
191 " seek=%zu bs=1 count=1",
192 path.c_str(), size)));
193 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
194 block_size, path.c_str())));
195}
196
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000197void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700198 // create 10MiB sparse file, mounted at a unique location.
199 string mount_path;
200 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
Alex Deymoa58b62a2013-08-08 21:21:48 -0700201 ScopedDirRemover mount_path_unlinker(mount_path);
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700202
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000203 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
204 " seek=10485759 bs=1 count=1",
205 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700206 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000207 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700208 mount_path.c_str())));
209 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
210 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
211 mount_path.c_str())));
212 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
213 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
214 mount_path.c_str())));
215 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
216 mount_path.c_str())));
217 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
218 mount_path.c_str())));
219 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
220 mount_path.c_str())));
221 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
222 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
223 mount_path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000224 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700225 mount_path.c_str(), mount_path.c_str())));
226 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
227 mount_path.c_str())));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800228 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700229 mount_path.c_str(), mount_path.c_str())));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800230 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700231 mount_path.c_str())));
232 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
Thieu Le5c7d9752010-12-15 16:09:28 -0800233
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000234 if (out_paths) {
235 out_paths->clear();
236 out_paths->push_back("");
237 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800238 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000239 out_paths->push_back("/hello");
240 out_paths->push_back("/some_dir");
241 out_paths->push_back("/some_dir/empty_dir");
242 out_paths->push_back("/some_dir/mnt");
243 out_paths->push_back("/some_dir/test");
244 out_paths->push_back("/some_dir/fifo");
245 out_paths->push_back("/cdev");
246 out_paths->push_back("/testlink");
247 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800248 out_paths->push_back("/srchardlink0");
249 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000250 out_paths->push_back("/lost+found");
251 }
252}
253
254void VerifyAllPaths(const string& parent, set<string> expected_paths) {
255 FilesystemIterator iter(parent, set<string>());
256 ino_t test_ino = 0;
257 ino_t testlink_ino = 0;
258 while (!iter.IsEnd()) {
259 string path = iter.GetFullPath();
260 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
261 EXPECT_EQ(1, expected_paths.erase(path));
262 if (utils::StringHasSuffix(path, "/hi") ||
263 utils::StringHasSuffix(path, "/hello") ||
264 utils::StringHasSuffix(path, "/test") ||
265 utils::StringHasSuffix(path, "/testlink")) {
266 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
267 if (utils::StringHasSuffix(path, "/test"))
268 test_ino = iter.GetStat().st_ino;
269 else if (utils::StringHasSuffix(path, "/testlink"))
270 testlink_ino = iter.GetStat().st_ino;
271 } else if (utils::StringHasSuffix(path, "/some_dir") ||
272 utils::StringHasSuffix(path, "/empty_dir") ||
273 utils::StringHasSuffix(path, "/mnt") ||
274 utils::StringHasSuffix(path, "/lost+found") ||
275 parent == path) {
276 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
277 } else if (utils::StringHasSuffix(path, "/fifo")) {
278 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
279 } else if (utils::StringHasSuffix(path, "/cdev")) {
280 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
281 } else if (utils::StringHasSuffix(path, "/sym")) {
282 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
283 } else {
284 LOG(INFO) << "got non hardcoded path: " << path;
285 }
286 iter.Increment();
287 }
288 EXPECT_EQ(testlink_ino, test_ino);
289 EXPECT_NE(0, test_ino);
290 EXPECT_FALSE(iter.IsErr());
291 EXPECT_TRUE(expected_paths.empty());
292 if (!expected_paths.empty()) {
293 for (set<string>::const_iterator it = expected_paths.begin();
294 it != expected_paths.end(); ++it) {
295 LOG(INFO) << "extra path: " << *it;
296 }
297 }
298}
299
Don Garrett58e8b1f2012-01-31 16:38:16 -0800300ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
301 string* mnt_path,
Thieu Le5c7d9752010-12-15 16:09:28 -0800302 unsigned long flags) {
303 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
304 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
305
Don Garrett58e8b1f2012-01-31 16:38:16 -0800306 string loop_dev;
307 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800308
309 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
310 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
311}
312
rspangler@google.com49fdf182009-10-10 00:57:34 +0000313} // namespace chromeos_update_engine