blob: 3815d7bfabc76ca9dc35e4fb68f082e21b8ff388 [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 Reyes29da8aa2011-02-15 13:34:57 -0800211 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0", kMountPath)));
212 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
213 kMountPath, kMountPath)));
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700214 EXPECT_EQ(0, System(StringPrintf("umount -d %s", kMountPath)));
Thieu Le5c7d9752010-12-15 16:09:28 -0800215
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000216 if (out_paths) {
217 out_paths->clear();
218 out_paths->push_back("");
219 out_paths->push_back("/hi");
220 out_paths->push_back("/hello");
221 out_paths->push_back("/some_dir");
222 out_paths->push_back("/some_dir/empty_dir");
223 out_paths->push_back("/some_dir/mnt");
224 out_paths->push_back("/some_dir/test");
225 out_paths->push_back("/some_dir/fifo");
226 out_paths->push_back("/cdev");
227 out_paths->push_back("/testlink");
228 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800229 out_paths->push_back("/srchardlink0");
230 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000231 out_paths->push_back("/lost+found");
232 }
233}
234
235void VerifyAllPaths(const string& parent, set<string> expected_paths) {
236 FilesystemIterator iter(parent, set<string>());
237 ino_t test_ino = 0;
238 ino_t testlink_ino = 0;
239 while (!iter.IsEnd()) {
240 string path = iter.GetFullPath();
241 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
242 EXPECT_EQ(1, expected_paths.erase(path));
243 if (utils::StringHasSuffix(path, "/hi") ||
244 utils::StringHasSuffix(path, "/hello") ||
245 utils::StringHasSuffix(path, "/test") ||
246 utils::StringHasSuffix(path, "/testlink")) {
247 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
248 if (utils::StringHasSuffix(path, "/test"))
249 test_ino = iter.GetStat().st_ino;
250 else if (utils::StringHasSuffix(path, "/testlink"))
251 testlink_ino = iter.GetStat().st_ino;
252 } else if (utils::StringHasSuffix(path, "/some_dir") ||
253 utils::StringHasSuffix(path, "/empty_dir") ||
254 utils::StringHasSuffix(path, "/mnt") ||
255 utils::StringHasSuffix(path, "/lost+found") ||
256 parent == path) {
257 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
258 } else if (utils::StringHasSuffix(path, "/fifo")) {
259 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
260 } else if (utils::StringHasSuffix(path, "/cdev")) {
261 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
262 } else if (utils::StringHasSuffix(path, "/sym")) {
263 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
264 } else {
265 LOG(INFO) << "got non hardcoded path: " << path;
266 }
267 iter.Increment();
268 }
269 EXPECT_EQ(testlink_ino, test_ino);
270 EXPECT_NE(0, test_ino);
271 EXPECT_FALSE(iter.IsErr());
272 EXPECT_TRUE(expected_paths.empty());
273 if (!expected_paths.empty()) {
274 for (set<string>::const_iterator it = expected_paths.begin();
275 it != expected_paths.end(); ++it) {
276 LOG(INFO) << "extra path: " << *it;
277 }
278 }
279}
280
Thieu Le5c7d9752010-12-15 16:09:28 -0800281ScopedLoopMounter::ScopedLoopMounter(const std::string& file_path,
282 std::string* mnt_path,
283 unsigned long flags) {
284 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/mnt.XXXXXX", mnt_path));
285 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
286
287 std::string loop_dev = GetUnusedLoopDevice();
288 EXPECT_EQ(0, system(StringPrintf("losetup %s %s", loop_dev.c_str(),
289 file_path.c_str()).c_str()));
290 loop_releaser_.reset(new ScopedLoopbackDeviceReleaser(loop_dev));
291
292 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
293 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
294}
295
rspangler@google.com49fdf182009-10-10 00:57:34 +0000296} // namespace chromeos_update_engine