blob: 7965f85eb07843beea786e14a31ab33ead5c2563 [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
Alex Deymo10875d92014-11-10 21:52:57 -08007#include <attr/xattr.h>
Alex Deymo6b9e38e2015-06-05 00:26:37 +02008#include <dirent.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>
Alex Deymo161c4a12014-05-16 15:56:21 -070012#include <sys/stat.h>
13#include <sys/types.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000014#include <unistd.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070015
adlr@google.comc98a7ed2009-12-04 18:54:03 +000016#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000017#include <string>
18#include <vector>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070019
Alex Deymo2b19cfb2015-03-26 00:35:07 -070020#include <base/files/file_util.h>
Alex Deymoc00c98a2015-03-17 17:38:00 -070021#include <base/format_macros.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070022#include <base/logging.h>
Alex Deymo2b19cfb2015-03-26 00:35:07 -070023#include <base/strings/string_util.h>
Alex Deymo30534502015-07-20 15:06:33 -070024#include <base/strings/stringprintf.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070025
rspangler@google.com49fdf182009-10-10 00:57:34 +000026#include "update_engine/file_writer.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000027#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000028
Alex Deymo161c4a12014-05-16 15:56:21 -070029using base::StringPrintf;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000030using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000031using std::string;
32using std::vector;
33
34namespace chromeos_update_engine {
35
Alex Deymo52490e72015-06-04 14:53:44 +020036void PrintTo(const Extent& extent, ::std::ostream* os) {
37 *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
38}
39
Alex Deymo10875d92014-11-10 21:52:57 -080040namespace test_utils {
41
Gilad Arnolda6742b32014-01-11 00:18:34 -080042const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
Gilad Arnold61d9d2c2013-07-22 17:54:52 -070043
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080044const uint8_t kRandomString[] = {
Alex Deymo10875d92014-11-10 21:52:57 -080045 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
46 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
47 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
48 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
49 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
50 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
51 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
52 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
53 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
54 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
55 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
56 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
57 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
58 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
59 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
60 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
61 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
62 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
63 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
64 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
65 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
66 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
67 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
68 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
69 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
70 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
71 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
72 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
73 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
74 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
75 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
76 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
77 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
78 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
79 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
80 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
81 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
82 0xbe, 0x9f, 0xa3, 0x5d,
83};
84
85bool IsXAttrSupported(const base::FilePath& dir_path) {
86 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
87
88 int fd = mkstemp(path);
89 if (fd == -1) {
90 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
91 free(path);
92 return false;
93 }
94
95 if (unlink(path) != 0) {
96 PLOG(ERROR) << "Error unlinking temporary file " << path;
97 close(fd);
98 free(path);
99 return false;
100 }
101
102 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
103 if (xattr_res != 0) {
104 if (errno == ENOTSUP) {
105 // Leave it to call-sites to warn about non-support.
106 } else {
107 PLOG(ERROR) << "Error setting xattr on " << path;
108 }
109 }
110 close(fd);
111 free(path);
112 return xattr_res == 0;
113}
114
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800115bool WriteFileVector(const string& path, const chromeos::Blob& data) {
116 return utils::WriteFile(path.c_str(), data.data(), data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000117}
118
Alex Deymof329b932014-10-30 01:37:48 -0700119bool WriteFileString(const string& path, const string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800120 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000121}
122
Gilad Arnold19a45f02012-07-19 12:36:10 -0700123// Binds provided |filename| to an unused loopback device, whose name is written
124// to the string pointed to by |lo_dev_name_p|. Returns true on success, false
125// otherwise (along with corresponding test failures), in which case the content
126// of |lo_dev_name_p| is unknown.
127bool BindToUnusedLoopDevice(const string& filename, string* lo_dev_name_p) {
128 CHECK(lo_dev_name_p);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800129
Gilad Arnold19a45f02012-07-19 12:36:10 -0700130 // Bind to an unused loopback device, sanity check the device name.
131 lo_dev_name_p->clear();
132 if (!(utils::ReadPipe("losetup --show -f " + filename, lo_dev_name_p) &&
Alex Vakulenko6a9d3492015-06-15 12:53:22 -0700133 base::StartsWithASCII(*lo_dev_name_p, "/dev/loop", true))) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700134 ADD_FAILURE();
135 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000136 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000137
Gilad Arnold19a45f02012-07-19 12:36:10 -0700138 // Strip anything from the first newline char.
139 size_t newline_pos = lo_dev_name_p->find('\n');
140 if (newline_pos != string::npos)
141 lo_dev_name_p->erase(newline_pos);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000142
Gilad Arnold19a45f02012-07-19 12:36:10 -0700143 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000144}
145
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800146bool ExpectVectorsEq(const chromeos::Blob& expected,
147 const chromeos::Blob& actual) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800148 EXPECT_EQ(expected.size(), actual.size());
149 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000150 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700151 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800152 for (unsigned int i = 0; i < expected.size(); i++) {
153 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700154 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000155 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700156 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000157}
158
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800159void FillWithData(chromeos::Blob* buffer) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800160 size_t input_counter = 0;
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800161 for (uint8_t& b : *buffer) {
162 b = kRandomString[input_counter];
Andrew de los Reyes80061062010-02-04 14:25:00 -0800163 input_counter++;
164 input_counter %= sizeof(kRandomString);
165 }
166}
167
Thieu Le5c7d9752010-12-15 16:09:28 -0800168void CreateEmptyExtImageAtPath(const string& path,
169 size_t size,
170 int block_size) {
171 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymoc00c98a2015-03-17 17:38:00 -0700172 " seek=%" PRIuS " bs=1 count=1 status=none",
Thieu Le5c7d9752010-12-15 16:09:28 -0800173 path.c_str(), size)));
Alex Deymo6ded6542015-03-13 15:52:46 -0700174 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b %d -F %s",
Thieu Le5c7d9752010-12-15 16:09:28 -0800175 block_size, path.c_str())));
176}
177
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000178void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700179 // create 10MiB sparse file, mounted at a unique location.
180 string mount_path;
181 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
Alex Deymoa58b62a2013-08-08 21:21:48 -0700182 ScopedDirRemover mount_path_unlinker(mount_path);
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700183
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000184 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700185 " seek=10485759 bs=1 count=1 status=none",
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000186 path.c_str())));
Alex Deymo6ded6542015-03-13 15:52:46 -0700187 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b 4096 -F %s",
188 path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000189 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700190 mount_path.c_str())));
191 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
192 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
193 mount_path.c_str())));
194 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
195 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
196 mount_path.c_str())));
197 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
198 mount_path.c_str())));
199 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
200 mount_path.c_str())));
201 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
202 mount_path.c_str())));
203 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
204 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
205 mount_path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000206 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700207 mount_path.c_str(), mount_path.c_str())));
208 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
209 mount_path.c_str())));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800210 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700211 mount_path.c_str(), mount_path.c_str())));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800212 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700213 mount_path.c_str())));
214 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
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");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800220 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000221 out_paths->push_back("/hello");
222 out_paths->push_back("/some_dir");
223 out_paths->push_back("/some_dir/empty_dir");
224 out_paths->push_back("/some_dir/mnt");
225 out_paths->push_back("/some_dir/test");
226 out_paths->push_back("/some_dir/fifo");
227 out_paths->push_back("/cdev");
228 out_paths->push_back("/testlink");
229 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800230 out_paths->push_back("/srchardlink0");
231 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000232 out_paths->push_back("/lost+found");
233 }
234}
235
Don Garrett58e8b1f2012-01-31 16:38:16 -0800236ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
237 string* mnt_path,
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700238 unsigned long flags) { // NOLINT - long
Gilad Arnolda6742b32014-01-11 00:18:34 -0800239 EXPECT_TRUE(utils::MakeTempDirectory("mnt.XXXXXX", mnt_path));
Thieu Le5c7d9752010-12-15 16:09:28 -0800240 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
241
Don Garrett58e8b1f2012-01-31 16:38:16 -0800242 string loop_dev;
243 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800244
245 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
246 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
247}
248
Alex Deymo10875d92014-11-10 21:52:57 -0800249namespace {
250class ScopedDirCloser {
251 public:
252 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
253 ~ScopedDirCloser() {
254 if (dir_ && *dir_) {
255 int r = closedir(*dir_);
256 TEST_AND_RETURN_ERRNO(r == 0);
257 *dir_ = nullptr;
258 dir_ = nullptr;
259 }
260 }
261 private:
262 DIR** dir_;
263};
264} // namespace
265
266bool RecursiveUnlinkDir(const string& path) {
267 struct stat stbuf;
268 int r = lstat(path.c_str(), &stbuf);
269 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
270 if ((r < 0) && (errno == ENOENT))
271 // path request is missing. that's fine.
272 return true;
273 if (!S_ISDIR(stbuf.st_mode)) {
274 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
275 (errno == ENOENT));
276 // success or path disappeared before we could unlink.
277 return true;
278 }
279 {
280 // We have a dir, unlink all children, then delete dir
281 DIR *dir = opendir(path.c_str());
282 TEST_AND_RETURN_FALSE_ERRNO(dir);
283 ScopedDirCloser dir_closer(&dir);
284 struct dirent dir_entry;
285 struct dirent *dir_entry_p;
286 int err = 0;
287 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
288 if (dir_entry_p == nullptr) {
289 // end of stream reached
290 break;
291 }
292 // Skip . and ..
293 if (!strcmp(dir_entry_p->d_name, ".") ||
294 !strcmp(dir_entry_p->d_name, ".."))
295 continue;
296 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
297 dir_entry_p->d_name));
298 }
299 TEST_AND_RETURN_FALSE(err == 0);
300 }
301 // unlink dir
302 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
303 return true;
304}
305
Alex Deymo2b19cfb2015-03-26 00:35:07 -0700306base::FilePath GetBuildArtifactsPath() {
307 base::FilePath exe_path;
308 base::ReadSymbolicLink(base::FilePath("/proc/self/exe"), &exe_path);
309 return exe_path.DirName();
310}
311
Alex Deymo10875d92014-11-10 21:52:57 -0800312} // namespace test_utils
rspangler@google.com49fdf182009-10-10 00:57:34 +0000313} // namespace chromeos_update_engine