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