blob: 53799792620f48736a3d6579f8852b138d34fd91 [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
Han Shen2643cb72012-06-26 14:45:33 -070069 unsigned char mbr[512] = {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000070 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;
Han Shen2643cb72012-06-26 14:45:33 -0700136 ret.insert(ret.begin(), reinterpret_cast<char *>(mbr),
137 reinterpret_cast<char *>(mbr + sizeof(mbr)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000138 return ret;
139}
140
Gilad Arnold19a45f02012-07-19 12:36:10 -0700141// Binds provided |filename| to an unused loopback device, whose name is written
142// to the string pointed to by |lo_dev_name_p|. Returns true on success, false
143// otherwise (along with corresponding test failures), in which case the content
144// of |lo_dev_name_p| is unknown.
145bool BindToUnusedLoopDevice(const string& filename, string* lo_dev_name_p) {
146 CHECK(lo_dev_name_p);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800147
Gilad Arnold19a45f02012-07-19 12:36:10 -0700148 // Bind to an unused loopback device, sanity check the device name.
149 lo_dev_name_p->clear();
150 if (!(utils::ReadPipe("losetup --show -f " + filename, lo_dev_name_p) &&
151 StartsWithASCII(*lo_dev_name_p, "/dev/loop", true))) {
152 ADD_FAILURE();
153 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000154 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000155
Gilad Arnold19a45f02012-07-19 12:36:10 -0700156 // Strip anything from the first newline char.
157 size_t newline_pos = lo_dev_name_p->find('\n');
158 if (newline_pos != string::npos)
159 lo_dev_name_p->erase(newline_pos);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000160
Gilad Arnold19a45f02012-07-19 12:36:10 -0700161 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000162}
163
Andrew de los Reyes80061062010-02-04 14:25:00 -0800164bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
165 EXPECT_EQ(expected.size(), actual.size());
166 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000167 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700168 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800169 for (unsigned int i = 0; i < expected.size(); i++) {
170 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700171 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000172 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700173 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000174}
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)));
Ben Chan77a1eba2012-10-07 22:54:55 -0700220 EXPECT_TRUE(utils::UnmountFilesystem(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