blob: 9d1b5d00dce2f04308f5d3e95298fe03e3ad6503 [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
139std::string GetUnusedLoopDevice() {
140 // get a loop device we can use for the install device
141 FILE* find_dev_cmd = popen("losetup -f", "r");
142 CHECK(find_dev_cmd);
143
144 string ret;
145 char dev[100] = {0};
146 size_t r;
147 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
148 EXPECT_LT(r, sizeof(dev));
149 ret.insert(ret.end(), dev, dev + r);
150 }
151 EXPECT_EQ(r, 0);
152 EXPECT_TRUE(feof(find_dev_cmd));
153 fclose(find_dev_cmd);
154
155 // strip trailing \n on dev
156 if (*ret.rbegin() == '\n')
157 ret.resize(ret.size() - 1);
158
159 return ret;
160}
161
Andrew de los Reyes80061062010-02-04 14:25:00 -0800162bool ExpectVectorsEq(const vector<char>& expected, const vector<char>& actual) {
163 EXPECT_EQ(expected.size(), actual.size());
164 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000165 return false;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800166 for (unsigned int i = 0; i < expected.size(); i++) {
167 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000168 }
169 return true;
170}
171
Andrew de los Reyes80061062010-02-04 14:25:00 -0800172void FillWithData(vector<char>* buffer) {
173 size_t input_counter = 0;
174 for (vector<char>::iterator it = buffer->begin(); it != buffer->end(); ++it) {
175 *it = kRandomString[input_counter];
176 input_counter++;
177 input_counter %= sizeof(kRandomString);
178 }
179}
180
Thieu Le5c7d9752010-12-15 16:09:28 -0800181void CreateEmptyExtImageAtPath(const string& path,
182 size_t size,
183 int block_size) {
184 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
185 " seek=%zu bs=1 count=1",
186 path.c_str(), size)));
187 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b %d -F %s",
188 block_size, path.c_str())));
189}
190
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000191void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
192 // create 10MiB sparse file
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000193 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
194 " seek=10485759 bs=1 count=1",
195 path.c_str())));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700196 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -b 4096 -F %s", path.c_str())));
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800197 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000198 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800199 kMountPath)));
200 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", kMountPath)));
201 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", kMountPath)));
202 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", kMountPath)));
203 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", kMountPath)));
204 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", kMountPath)));
205 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", kMountPath)));
206 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", kMountPath)));
207 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", kMountPath)));
208 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", kMountPath)));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000209 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800210 kMountPath, kMountPath)));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700211 EXPECT_EQ(0, System(StringPrintf("umount -d %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800212
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000213 if (out_paths) {
214 out_paths->clear();
215 out_paths->push_back("");
216 out_paths->push_back("/hi");
217 out_paths->push_back("/hello");
218 out_paths->push_back("/some_dir");
219 out_paths->push_back("/some_dir/empty_dir");
220 out_paths->push_back("/some_dir/mnt");
221 out_paths->push_back("/some_dir/test");
222 out_paths->push_back("/some_dir/fifo");
223 out_paths->push_back("/cdev");
224 out_paths->push_back("/testlink");
225 out_paths->push_back("/sym");
226 out_paths->push_back("/lost+found");
227 }
228}
229
230void VerifyAllPaths(const string& parent, set<string> expected_paths) {
231 FilesystemIterator iter(parent, set<string>());
232 ino_t test_ino = 0;
233 ino_t testlink_ino = 0;
234 while (!iter.IsEnd()) {
235 string path = iter.GetFullPath();
236 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
237 EXPECT_EQ(1, expected_paths.erase(path));
238 if (utils::StringHasSuffix(path, "/hi") ||
239 utils::StringHasSuffix(path, "/hello") ||
240 utils::StringHasSuffix(path, "/test") ||
241 utils::StringHasSuffix(path, "/testlink")) {
242 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
243 if (utils::StringHasSuffix(path, "/test"))
244 test_ino = iter.GetStat().st_ino;
245 else if (utils::StringHasSuffix(path, "/testlink"))
246 testlink_ino = iter.GetStat().st_ino;
247 } else if (utils::StringHasSuffix(path, "/some_dir") ||
248 utils::StringHasSuffix(path, "/empty_dir") ||
249 utils::StringHasSuffix(path, "/mnt") ||
250 utils::StringHasSuffix(path, "/lost+found") ||
251 parent == path) {
252 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
253 } else if (utils::StringHasSuffix(path, "/fifo")) {
254 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
255 } else if (utils::StringHasSuffix(path, "/cdev")) {
256 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
257 } else if (utils::StringHasSuffix(path, "/sym")) {
258 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
259 } else {
260 LOG(INFO) << "got non hardcoded path: " << path;
261 }
262 iter.Increment();
263 }
264 EXPECT_EQ(testlink_ino, test_ino);
265 EXPECT_NE(0, test_ino);
266 EXPECT_FALSE(iter.IsErr());
267 EXPECT_TRUE(expected_paths.empty());
268 if (!expected_paths.empty()) {
269 for (set<string>::const_iterator it = expected_paths.begin();
270 it != expected_paths.end(); ++it) {
271 LOG(INFO) << "extra path: " << *it;
272 }
273 }
274}
275
Thieu Le5c7d9752010-12-15 16:09:28 -0800276ScopedLoopMounter::ScopedLoopMounter(const std::string& file_path,
277 std::string* mnt_path,
278 unsigned long flags) {
279 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
280 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
281
282 std::string loop_dev = GetUnusedLoopDevice();
283 EXPECT_EQ(0, system(StringPrintf("losetup %s %s", loop_dev.c_str(),
284 file_path.c_str()).c_str()));
285 loop_releaser_.reset(new ScopedLoopbackDeviceReleaser(loop_dev));
286
287 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
288 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
289}
290
rspangler@google.com49fdf182009-10-10 00:57:34 +0000291} // namespace chromeos_update_engine