blob: d916458e30387b07bc55a094b4cdff39f2647ba3 [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"
rspangler@google.com49fdf182009-10-10 00:57:34 +00006#include <sys/stat.h>
7#include <sys/types.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00008#include <errno.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +00009#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000012#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000013#include <string>
14#include <vector>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000015#include "base/string_util.h"
16#include "chromeos/obsolete_logging.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000017
18#include "update_engine/file_writer.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000019#include "update_engine/filesystem_iterator.h"
20#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000021
adlr@google.comc98a7ed2009-12-04 18:54:03 +000022using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000023using std::string;
24using std::vector;
25
26namespace chromeos_update_engine {
27
adlr@google.comc98a7ed2009-12-04 18:54:03 +000028bool WriteFileVector(const std::string& path, const std::vector<char>& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080029 return utils::WriteFile(path.c_str(), &data[0], data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +000030}
31
32bool WriteFileString(const std::string& path, const std::string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -080033 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +000034}
35
36off_t FileSize(const string& path) {
37 struct stat stbuf;
38 int rc = stat(path.c_str(), &stbuf);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000039 CHECK_EQ(rc, 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +000040 if (rc < 0)
41 return rc;
42 return stbuf.st_size;
43}
44
adlr@google.comc98a7ed2009-12-04 18:54:03 +000045std::string Readlink(const std::string& path) {
46 vector<char> buf(PATH_MAX + 1);
47 ssize_t r = readlink(path.c_str(), &buf[0], buf.size());
48 if (r < 0)
49 return "";
50 CHECK_LT(r, static_cast<ssize_t>(buf.size()));
51 buf.resize(r);
52 string ret;
53 ret.insert(ret.begin(), buf.begin(), buf.end());
54 return ret;
55}
56
rspangler@google.com49fdf182009-10-10 00:57:34 +000057std::vector<char> GzipCompressData(const std::vector<char>& data) {
58 const char fname[] = "/tmp/GzipCompressDataTemp";
adlr@google.comc98a7ed2009-12-04 18:54:03 +000059 if (!WriteFileVector(fname, data)) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000060 system((string("rm ") + fname).c_str());
61 return vector<char>();
62 }
63 system((string("cat ") + fname + "|gzip>" + fname + ".gz").c_str());
64 system((string("rm ") + fname).c_str());
adlr@google.comc98a7ed2009-12-04 18:54:03 +000065 vector<char> ret;
66 EXPECT_TRUE(utils::ReadFile(string(fname) + ".gz", &ret));
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 system((string("rm ") + fname + ".gz").c_str());
68 return ret;
69}
70
adlr@google.comc98a7ed2009-12-04 18:54:03 +000071vector<char> GenerateSampleMbr() {
72 // This is the actual MBR from my dev machine. Partition 1 (the first)
73 // is currently marked bootable
74 char mbr[512] = {
75 0xeb, 0x48, 0x90, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
76 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
77 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
78 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
79 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
80 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
81 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
82 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x03, 0x02,
83 0xff, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
84 0x00, 0x02, 0xfa, 0x90, 0x90, 0xf6, 0xc2, 0x80,
85 0x75, 0x02, 0xb2, 0x80, 0xea, 0x59, 0x7c, 0x00,
86 0x00, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc,
87 0x00, 0x20, 0xfb, 0xa0, 0x40, 0x7c, 0x3c, 0xff,
88 0x74, 0x02, 0x88, 0xc2, 0x52, 0xbe, 0x7f, 0x7d,
89 0xe8, 0x34, 0x01, 0xf6, 0xc2, 0x80, 0x74, 0x54,
90 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x5a,
91 0x52, 0x72, 0x49, 0x81, 0xfb, 0x55, 0xaa, 0x75,
92 0x43, 0xa0, 0x41, 0x7c, 0x84, 0xc0, 0x75, 0x05,
93 0x83, 0xe1, 0x01, 0x74, 0x37, 0x66, 0x8b, 0x4c,
94 0x10, 0xbe, 0x05, 0x7c, 0xc6, 0x44, 0xff, 0x01,
95 0x66, 0x8b, 0x1e, 0x44, 0x7c, 0xc7, 0x04, 0x10,
96 0x00, 0xc7, 0x44, 0x02, 0x01, 0x00, 0x66, 0x89,
97 0x5c, 0x08, 0xc7, 0x44, 0x06, 0x00, 0x70, 0x66,
98 0x31, 0xc0, 0x89, 0x44, 0x04, 0x66, 0x89, 0x44,
99 0x0c, 0xb4, 0x42, 0xcd, 0x13, 0x72, 0x05, 0xbb,
100 0x00, 0x70, 0xeb, 0x7d, 0xb4, 0x08, 0xcd, 0x13,
101 0x73, 0x0a, 0xf6, 0xc2, 0x80, 0x0f, 0x84, 0xea,
102 0x00, 0xe9, 0x8d, 0x00, 0xbe, 0x05, 0x7c, 0xc6,
103 0x44, 0xff, 0x00, 0x66, 0x31, 0xc0, 0x88, 0xf0,
104 0x40, 0x66, 0x89, 0x44, 0x04, 0x31, 0xd2, 0x88,
105 0xca, 0xc1, 0xe2, 0x02, 0x88, 0xe8, 0x88, 0xf4,
106 0x40, 0x89, 0x44, 0x08, 0x31, 0xc0, 0x88, 0xd0,
107 0xc0, 0xe8, 0x02, 0x66, 0x89, 0x04, 0x66, 0xa1,
108 0x44, 0x7c, 0x66, 0x31, 0xd2, 0x66, 0xf7, 0x34,
109 0x88, 0x54, 0x0a, 0x66, 0x31, 0xd2, 0x66, 0xf7,
110 0x74, 0x04, 0x88, 0x54, 0x0b, 0x89, 0x44, 0x0c,
111 0x3b, 0x44, 0x08, 0x7d, 0x3c, 0x8a, 0x54, 0x0d,
112 0xc0, 0xe2, 0x06, 0x8a, 0x4c, 0x0a, 0xfe, 0xc1,
113 0x08, 0xd1, 0x8a, 0x6c, 0x0c, 0x5a, 0x8a, 0x74,
114 0x0b, 0xbb, 0x00, 0x70, 0x8e, 0xc3, 0x31, 0xdb,
115 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x72, 0x2a, 0x8c,
116 0xc3, 0x8e, 0x06, 0x48, 0x7c, 0x60, 0x1e, 0xb9,
117 0x00, 0x01, 0x8e, 0xdb, 0x31, 0xf6, 0x31, 0xff,
118 0xfc, 0xf3, 0xa5, 0x1f, 0x61, 0xff, 0x26, 0x42,
119 0x7c, 0xbe, 0x85, 0x7d, 0xe8, 0x40, 0x00, 0xeb,
120 0x0e, 0xbe, 0x8a, 0x7d, 0xe8, 0x38, 0x00, 0xeb,
121 0x06, 0xbe, 0x94, 0x7d, 0xe8, 0x30, 0x00, 0xbe,
122 0x99, 0x7d, 0xe8, 0x2a, 0x00, 0xeb, 0xfe, 0x47,
123 0x52, 0x55, 0x42, 0x20, 0x00, 0x47, 0x65, 0x6f,
124 0x6d, 0x00, 0x48, 0x61, 0x72, 0x64, 0x20, 0x44,
125 0x69, 0x73, 0x6b, 0x00, 0x52, 0x65, 0x61, 0x64,
126 0x00, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x00,
127 0xbb, 0x01, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xac,
128 0x3c, 0x00, 0x75, 0xf4, 0xc3, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x50, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x80, 0x01,
131 0x01, 0x00, 0x83, 0xfe, 0xff, 0xff, 0x3f, 0x00,
132 0x00, 0x00, 0x09, 0x7f, 0x32, 0x06, 0x00, 0xfe,
133 0xff, 0xff, 0x05, 0xfe, 0xff, 0xff, 0x48, 0x7f,
134 0x32, 0x06, 0x79, 0x59, 0x2d, 0x00, 0x00, 0x00,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
139 };
140 vector<char> ret;
141 ret.insert(ret.begin(), mbr, mbr + sizeof(mbr));
142 return ret;
143}
144
145std::string GetUnusedLoopDevice() {
146 // get a loop device we can use for the install device
147 FILE* find_dev_cmd = popen("losetup -f", "r");
148 CHECK(find_dev_cmd);
149
150 string ret;
151 char dev[100] = {0};
152 size_t r;
153 while ((r = fread(dev, 1, sizeof(dev - 1), find_dev_cmd)) > 0) {
154 EXPECT_LT(r, sizeof(dev));
155 ret.insert(ret.end(), dev, dev + r);
156 }
157 EXPECT_EQ(r, 0);
158 EXPECT_TRUE(feof(find_dev_cmd));
159 fclose(find_dev_cmd);
160
161 // strip trailing \n on dev
162 if (*ret.rbegin() == '\n')
163 ret.resize(ret.size() - 1);
164
165 return ret;
166}
167
168bool ExpectVectorsEq(const vector<char>& a, const vector<char>& b) {
169 EXPECT_EQ(a.size(), b.size());
170 if (a.size() != b.size())
171 return false;
172 for (unsigned int i = 0; i < a.size(); i++) {
173 EXPECT_EQ(a[i], b[i]) << "offset: " << i;
174 }
175 return true;
176}
177
178void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
179 // create 10MiB sparse file
180 const char* const mount_path = kMountPath.c_str();
181 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
182 " seek=10485759 bs=1 count=1",
183 path.c_str())));
184 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -F %s", path.c_str())));
185 EXPECT_EQ(0, System(StringPrintf("mkdir -p %s", mount_path)));
186 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
187 mount_path)));
188 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path)));
189 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello", mount_path)));
190 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path)));
191 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir", mount_path)));
192 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt", mount_path)));
193 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test", mount_path)));
194 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo", mount_path)));
195 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path)));
196 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym", mount_path)));
197 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
198 mount_path, mount_path)));
199 EXPECT_EQ(0, System(StringPrintf("umount %s", mount_path)));
200
201 if (out_paths) {
202 out_paths->clear();
203 out_paths->push_back("");
204 out_paths->push_back("/hi");
205 out_paths->push_back("/hello");
206 out_paths->push_back("/some_dir");
207 out_paths->push_back("/some_dir/empty_dir");
208 out_paths->push_back("/some_dir/mnt");
209 out_paths->push_back("/some_dir/test");
210 out_paths->push_back("/some_dir/fifo");
211 out_paths->push_back("/cdev");
212 out_paths->push_back("/testlink");
213 out_paths->push_back("/sym");
214 out_paths->push_back("/lost+found");
215 }
216}
217
218void VerifyAllPaths(const string& parent, set<string> expected_paths) {
219 FilesystemIterator iter(parent, set<string>());
220 ino_t test_ino = 0;
221 ino_t testlink_ino = 0;
222 while (!iter.IsEnd()) {
223 string path = iter.GetFullPath();
224 EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()) << path;
225 EXPECT_EQ(1, expected_paths.erase(path));
226 if (utils::StringHasSuffix(path, "/hi") ||
227 utils::StringHasSuffix(path, "/hello") ||
228 utils::StringHasSuffix(path, "/test") ||
229 utils::StringHasSuffix(path, "/testlink")) {
230 EXPECT_TRUE(S_ISREG(iter.GetStat().st_mode));
231 if (utils::StringHasSuffix(path, "/test"))
232 test_ino = iter.GetStat().st_ino;
233 else if (utils::StringHasSuffix(path, "/testlink"))
234 testlink_ino = iter.GetStat().st_ino;
235 } else if (utils::StringHasSuffix(path, "/some_dir") ||
236 utils::StringHasSuffix(path, "/empty_dir") ||
237 utils::StringHasSuffix(path, "/mnt") ||
238 utils::StringHasSuffix(path, "/lost+found") ||
239 parent == path) {
240 EXPECT_TRUE(S_ISDIR(iter.GetStat().st_mode));
241 } else if (utils::StringHasSuffix(path, "/fifo")) {
242 EXPECT_TRUE(S_ISFIFO(iter.GetStat().st_mode));
243 } else if (utils::StringHasSuffix(path, "/cdev")) {
244 EXPECT_TRUE(S_ISCHR(iter.GetStat().st_mode));
245 } else if (utils::StringHasSuffix(path, "/sym")) {
246 EXPECT_TRUE(S_ISLNK(iter.GetStat().st_mode));
247 } else {
248 LOG(INFO) << "got non hardcoded path: " << path;
249 }
250 iter.Increment();
251 }
252 EXPECT_EQ(testlink_ino, test_ino);
253 EXPECT_NE(0, test_ino);
254 EXPECT_FALSE(iter.IsErr());
255 EXPECT_TRUE(expected_paths.empty());
256 if (!expected_paths.empty()) {
257 for (set<string>::const_iterator it = expected_paths.begin();
258 it != expected_paths.end(); ++it) {
259 LOG(INFO) << "extra path: " << *it;
260 }
261 }
262}
263
rspangler@google.com49fdf182009-10-10 00:57:34 +0000264} // namespace chromeos_update_engine