blob: 0c02279483b00ec6db0bc1d3df2c5af51c8c566b [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 Deymo161c4a12014-05-16 15:56:21 -070021#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070022#include <base/strings/stringprintf.h>
Alex Deymo2b19cfb2015-03-26 00:35:07 -070023#include <base/strings/string_util.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070024
rspangler@google.com49fdf182009-10-10 00:57:34 +000025#include "update_engine/file_writer.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000026#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000027
Alex Deymo161c4a12014-05-16 15:56:21 -070028using base::StringPrintf;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000029using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000030using std::string;
31using std::vector;
32
33namespace chromeos_update_engine {
34
Alex Deymo52490e72015-06-04 14:53:44 +020035void PrintTo(const Extent& extent, ::std::ostream* os) {
36 *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
37}
38
Alex Deymo10875d92014-11-10 21:52:57 -080039namespace test_utils {
40
Gilad Arnolda6742b32014-01-11 00:18:34 -080041const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
Gilad Arnold61d9d2c2013-07-22 17:54:52 -070042
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080043const uint8_t kRandomString[] = {
Alex Deymo10875d92014-11-10 21:52:57 -080044 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
45 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
46 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
47 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
48 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
49 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
50 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
51 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
52 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
53 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
54 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
55 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
56 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
57 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
58 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
59 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
60 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
61 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
62 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
63 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
64 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
65 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
66 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
67 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
68 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
69 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
70 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
71 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
72 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
73 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
74 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
75 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
76 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
77 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
78 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
79 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
80 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
81 0xbe, 0x9f, 0xa3, 0x5d,
82};
83
84bool IsXAttrSupported(const base::FilePath& dir_path) {
85 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
86
87 int fd = mkstemp(path);
88 if (fd == -1) {
89 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
90 free(path);
91 return false;
92 }
93
94 if (unlink(path) != 0) {
95 PLOG(ERROR) << "Error unlinking temporary file " << path;
96 close(fd);
97 free(path);
98 return false;
99 }
100
101 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
102 if (xattr_res != 0) {
103 if (errno == ENOTSUP) {
104 // Leave it to call-sites to warn about non-support.
105 } else {
106 PLOG(ERROR) << "Error setting xattr on " << path;
107 }
108 }
109 close(fd);
110 free(path);
111 return xattr_res == 0;
112}
113
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800114bool WriteFileVector(const string& path, const chromeos::Blob& data) {
115 return utils::WriteFile(path.c_str(), data.data(), data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000116}
117
Alex Deymof329b932014-10-30 01:37:48 -0700118bool WriteFileString(const string& path, const string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800119 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120}
121
Gilad Arnold19a45f02012-07-19 12:36:10 -0700122// Binds provided |filename| to an unused loopback device, whose name is written
123// to the string pointed to by |lo_dev_name_p|. Returns true on success, false
124// otherwise (along with corresponding test failures), in which case the content
125// of |lo_dev_name_p| is unknown.
126bool BindToUnusedLoopDevice(const string& filename, string* lo_dev_name_p) {
127 CHECK(lo_dev_name_p);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800128
Gilad Arnold19a45f02012-07-19 12:36:10 -0700129 // Bind to an unused loopback device, sanity check the device name.
130 lo_dev_name_p->clear();
131 if (!(utils::ReadPipe("losetup --show -f " + filename, lo_dev_name_p) &&
Alex Vakulenko6a9d3492015-06-15 12:53:22 -0700132 base::StartsWithASCII(*lo_dev_name_p, "/dev/loop", true))) {
Gilad Arnold19a45f02012-07-19 12:36:10 -0700133 ADD_FAILURE();
134 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000135 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000136
Gilad Arnold19a45f02012-07-19 12:36:10 -0700137 // Strip anything from the first newline char.
138 size_t newline_pos = lo_dev_name_p->find('\n');
139 if (newline_pos != string::npos)
140 lo_dev_name_p->erase(newline_pos);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000141
Gilad Arnold19a45f02012-07-19 12:36:10 -0700142 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000143}
144
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800145bool ExpectVectorsEq(const chromeos::Blob& expected,
146 const chromeos::Blob& actual) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800147 EXPECT_EQ(expected.size(), actual.size());
148 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000149 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700150 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800151 for (unsigned int i = 0; i < expected.size(); i++) {
152 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700153 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000154 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700155 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000156}
157
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800158void FillWithData(chromeos::Blob* buffer) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800159 size_t input_counter = 0;
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800160 for (uint8_t& b : *buffer) {
161 b = kRandomString[input_counter];
Andrew de los Reyes80061062010-02-04 14:25:00 -0800162 input_counter++;
163 input_counter %= sizeof(kRandomString);
164 }
165}
166
Thieu Le5c7d9752010-12-15 16:09:28 -0800167void CreateEmptyExtImageAtPath(const string& path,
168 size_t size,
169 int block_size) {
170 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700171 " seek=%zu bs=1 count=1 status=none",
Thieu Le5c7d9752010-12-15 16:09:28 -0800172 path.c_str(), size)));
Alex Deymo6ded6542015-03-13 15:52:46 -0700173 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b %d -F %s",
Thieu Le5c7d9752010-12-15 16:09:28 -0800174 block_size, path.c_str())));
175}
176
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000177void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700178 // create 10MiB sparse file, mounted at a unique location.
179 string mount_path;
180 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
Alex Deymoa58b62a2013-08-08 21:21:48 -0700181 ScopedDirRemover mount_path_unlinker(mount_path);
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700182
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000183 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700184 " seek=10485759 bs=1 count=1 status=none",
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000185 path.c_str())));
Alex Deymo6ded6542015-03-13 15:52:46 -0700186 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b 4096 -F %s",
187 path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000188 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700189 mount_path.c_str())));
190 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
191 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
192 mount_path.c_str())));
193 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
194 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
195 mount_path.c_str())));
196 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
197 mount_path.c_str())));
198 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
199 mount_path.c_str())));
200 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
201 mount_path.c_str())));
202 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
203 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
204 mount_path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700206 mount_path.c_str(), mount_path.c_str())));
207 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
208 mount_path.c_str())));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800209 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700210 mount_path.c_str(), mount_path.c_str())));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800211 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700212 mount_path.c_str())));
213 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
Thieu Le5c7d9752010-12-15 16:09:28 -0800214
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000215 if (out_paths) {
216 out_paths->clear();
217 out_paths->push_back("");
218 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800219 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000220 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
Don Garrett58e8b1f2012-01-31 16:38:16 -0800235ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
236 string* mnt_path,
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700237 unsigned long flags) { // NOLINT - long
Gilad Arnolda6742b32014-01-11 00:18:34 -0800238 EXPECT_TRUE(utils::MakeTempDirectory("mnt.XXXXXX", mnt_path));
Thieu Le5c7d9752010-12-15 16:09:28 -0800239 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
240
Don Garrett58e8b1f2012-01-31 16:38:16 -0800241 string loop_dev;
242 loop_binder_.reset(new ScopedLoopbackDeviceBinder(file_path, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800243
244 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags));
245 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
246}
247
Alex Deymo10875d92014-11-10 21:52:57 -0800248namespace {
249class ScopedDirCloser {
250 public:
251 explicit ScopedDirCloser(DIR** dir) : dir_(dir) {}
252 ~ScopedDirCloser() {
253 if (dir_ && *dir_) {
254 int r = closedir(*dir_);
255 TEST_AND_RETURN_ERRNO(r == 0);
256 *dir_ = nullptr;
257 dir_ = nullptr;
258 }
259 }
260 private:
261 DIR** dir_;
262};
263} // namespace
264
265bool RecursiveUnlinkDir(const string& path) {
266 struct stat stbuf;
267 int r = lstat(path.c_str(), &stbuf);
268 TEST_AND_RETURN_FALSE_ERRNO((r == 0) || (errno == ENOENT));
269 if ((r < 0) && (errno == ENOENT))
270 // path request is missing. that's fine.
271 return true;
272 if (!S_ISDIR(stbuf.st_mode)) {
273 TEST_AND_RETURN_FALSE_ERRNO((unlink(path.c_str()) == 0) ||
274 (errno == ENOENT));
275 // success or path disappeared before we could unlink.
276 return true;
277 }
278 {
279 // We have a dir, unlink all children, then delete dir
280 DIR *dir = opendir(path.c_str());
281 TEST_AND_RETURN_FALSE_ERRNO(dir);
282 ScopedDirCloser dir_closer(&dir);
283 struct dirent dir_entry;
284 struct dirent *dir_entry_p;
285 int err = 0;
286 while ((err = readdir_r(dir, &dir_entry, &dir_entry_p)) == 0) {
287 if (dir_entry_p == nullptr) {
288 // end of stream reached
289 break;
290 }
291 // Skip . and ..
292 if (!strcmp(dir_entry_p->d_name, ".") ||
293 !strcmp(dir_entry_p->d_name, ".."))
294 continue;
295 TEST_AND_RETURN_FALSE(RecursiveUnlinkDir(path + "/" +
296 dir_entry_p->d_name));
297 }
298 TEST_AND_RETURN_FALSE(err == 0);
299 }
300 // unlink dir
301 TEST_AND_RETURN_FALSE_ERRNO((rmdir(path.c_str()) == 0) || (errno == ENOENT));
302 return true;
303}
304
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700305GValue* GValueNewString(const char* str) {
Alex Deymo5665d0c2014-05-28 17:45:43 -0700306 GValue* gval = g_new0(GValue, 1);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700307 g_value_init(gval, G_TYPE_STRING);
308 g_value_set_string(gval, str);
309 return gval;
310}
311
312void GValueFree(gpointer arg) {
313 auto gval = reinterpret_cast<GValue*>(arg);
314 g_value_unset(gval);
Alex Deymo5665d0c2014-05-28 17:45:43 -0700315 g_free(gval);
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700316}
317
Alex Deymo2b19cfb2015-03-26 00:35:07 -0700318base::FilePath GetBuildArtifactsPath() {
319 base::FilePath exe_path;
320 base::ReadSymbolicLink(base::FilePath("/proc/self/exe"), &exe_path);
321 return exe_path.DirName();
322}
323
Alex Deymo10875d92014-11-10 21:52:57 -0800324} // namespace test_utils
rspangler@google.com49fdf182009-10-10 00:57:34 +0000325} // namespace chromeos_update_engine