blob: 40d300c4d04ad06bfa655d46ae9591b1af8ae9db [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
Don Garrett58e8b1f2012-01-31 16:38:16 -0800141string BindToUnusedLoopDevice(const string &filename) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000142 // get a loop device we can use for the install device
Don Garrett58e8b1f2012-01-31 16:38:16 -0800143 string cmd = "losetup --show -f " + filename;
144
145 FILE* find_dev_cmd = popen(cmd.c_str(), "r");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000146 CHECK(find_dev_cmd);
147
148 string ret;
149 char dev[100] = {0};
150 size_t r;
151 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
152 EXPECT_LT(r, sizeof(dev));
153 ret.insert(ret.end(), dev, dev + r);
154 }
155 EXPECT_EQ(r, 0);
156 EXPECT_TRUE(feof(find_dev_cmd));
157 fclose(find_dev_cmd);
158
159 // strip trailing \n on dev
160 if (*ret.rbegin() == '\n')
161 ret.resize(ret.size() - 1);
162
Don Garrett58e8b1f2012-01-31 16:38:16 -0800163 // Ensure that the device starts with "/dev/loop"
164 EXPECT_TRUE(StartsWithASCII(ret, "/dev/loop", true));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000165 return ret;
166}
167
Andrew de los Reyes80061062010-02-04 14:25:00 -0800168bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
169 EXPECT_EQ(expected.size(), actual.size());
170 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000171 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700172 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800173 for (unsigned int i = 0; i < expected.size(); i++) {
174 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700175 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000176 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700177 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000178}
179
Andrew de los Reyes80061062010-02-04 14:25:00 -0800180void FillWithData(vector<char>* buffer) {
181 size_t input_counter = 0;
182 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
183 *it = kRandomString[input_counter];
184 input_counter++;
185 input_counter %= sizeof(kRandomString);
186 }
187}
188
Thieu Le5c7d9752010-12-15 16:09:28 -0800189void CreateEmptyExtImageAtPath(const string& path,
190 size_t size,
191 int block_size) {
192 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
193 " seek=%zu bs=1 count=1",
194 path.c_str(), size)));
195 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
196 block_size, path.c_str())));
197}
198
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000199void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
200 // create 10MiB sparse file
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000201 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
202 " seek=10485759 bs=1 count=1",
203 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700204 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800205 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000206 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800207 kMountPath)));
208 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
209 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
210 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
211 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
212 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
213 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
214 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
215 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
216 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000217 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800218 kMountPath, kMountPath)));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800219 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0", kMountPath)));
220 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
221 kMountPath, kMountPath)));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800222 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
223 kMountPath)));
David James7f42b822012-02-16 15:44:16 -0800224 EXPECT_EQ(0, System(StringPrintf("umount %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800225
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000226 if (out_paths) {
227 out_paths->clear();
228 out_paths->push_back("");
229 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800230 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000231 out_paths->push_back("/hello");
232 out_paths->push_back("/some_dir");
233 out_paths->push_back("/some_dir/empty_dir");
234 out_paths->push_back("/some_dir/mnt");
235 out_paths->push_back("/some_dir/test");
236 out_paths->push_back("/some_dir/fifo");
237 out_paths->push_back("/cdev");
238 out_paths->push_back("/testlink");
239 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800240 out_paths->push_back("/srchardlink0");
241 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000242 out_paths->push_back("/lost+found");
243 }
244}
245
246void VerifyAllPaths(const string& parent, set<string> expected_paths) {
247 FilesystemIterator iter(parent, set<string>());
248 ino_t test_ino = 0;
249 ino_t testlink_ino = 0;
250 while (!iter.IsEnd()) {
251 string path = iter.GetFullPath();
252 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
253 EXPECT_EQ(1, expected_paths.erase(path));
254 if (utils::StringHasSuffix(path, "/hi") ||
255 utils::StringHasSuffix(path, "/hello") ||
256 utils::StringHasSuffix(path, "/test") ||
257 utils::StringHasSuffix(path, "/testlink")) {
258 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
259 if (utils::StringHasSuffix(path, "/test"))
260 test_ino = iter.GetStat().st_ino;
261 else if (utils::StringHasSuffix(path, "/testlink"))
262 testlink_ino = iter.GetStat().st_ino;
263 } else if (utils::StringHasSuffix(path, "/some_dir") ||
264 utils::StringHasSuffix(path, "/empty_dir") ||
265 utils::StringHasSuffix(path, "/mnt") ||
266 utils::StringHasSuffix(path, "/lost+found") ||
267 parent == path) {
268 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
269 } else if (utils::StringHasSuffix(path, "/fifo")) {
270 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
271 } else if (utils::StringHasSuffix(path, "/cdev")) {
272 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
273 } else if (utils::StringHasSuffix(path, "/sym")) {
274 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
275 } else {
276 LOG(INFO) << "got non hardcoded path: " << path;
277 }
278 iter.Increment();
279 }
280 EXPECT_EQ(testlink_ino, test_ino);
281 EXPECT_NE(0, test_ino);
282 EXPECT_FALSE(iter.IsErr());
283 EXPECT_TRUE(expected_paths.empty());
284 if (!expected_paths.empty()) {
285 for (set<string>::const_iterator it = expected_paths.begin();
286 it != expected_paths.end(); ++it) {
287 LOG(INFO) << "extra path: " << *it;
288 }
289 }
290}
291
Don Garrett58e8b1f2012-01-31 16:38:16 -0800292ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
293 string* mnt_path,
Thieu Le5c7d9752010-12-15 16:09:28 -0800294 unsigned long flags) {
295 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
296 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
297
Don Garrett58e8b1f2012-01-31 16:38:16 -0800298 string loop_dev;
299 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800300
301 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
302 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
303}
304
rspangler@google.com49fdf182009-10-10 00:57:34 +0000305} // namespace chromeos_update_engine