blob: 0e7a8efc4ca1ad81c6fdb6f146d2c83956064e21 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
rspangler@google.com49fdf182009-10-10 00:57:34 +000016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/common/test_utils.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070018
Alex Deymo6b9e38e2015-06-05 00:26:37 +020019#include <dirent.h>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000020#include <errno.h>
Alex Deymocbc22742016-03-04 17:53:02 -080021#include <fcntl.h>
22#include <linux/loop.h>
23#include <linux/major.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000024#include <stdio.h>
25#include <stdlib.h>
Alex Deymocbc22742016-03-04 17:53:02 -080026#include <sys/ioctl.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070027#include <sys/stat.h>
28#include <sys/types.h>
Alex Deymo6f20dd42015-08-18 16:42:46 -070029#include <sys/xattr.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000030#include <unistd.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070031
adlr@google.comc98a7ed2009-12-04 18:54:03 +000032#include <set>
rspangler@google.com49fdf182009-10-10 00:57:34 +000033#include <string>
34#include <vector>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070035
Alex Deymo2b19cfb2015-03-26 00:35:07 -070036#include <base/files/file_util.h>
Alex Deymoc00c98a2015-03-17 17:38:00 -070037#include <base/format_macros.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070038#include <base/logging.h>
Alex Deymo2b19cfb2015-03-26 00:35:07 -070039#include <base/strings/string_util.h>
Alex Deymo30534502015-07-20 15:06:33 -070040#include <base/strings/stringprintf.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070041
Alex Deymo64d98782016-02-05 18:03:48 -080042#include "update_engine/common/error_code_utils.h"
Alex Deymo39910dc2015-11-09 17:04:30 -080043#include "update_engine/common/utils.h"
44#include "update_engine/payload_consumer/file_writer.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000045
Alex Deymo161c4a12014-05-16 15:56:21 -070046using base::StringPrintf;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000047using std::set;
rspangler@google.com49fdf182009-10-10 00:57:34 +000048using std::string;
49using std::vector;
50
51namespace chromeos_update_engine {
52
Alex Deymo52490e72015-06-04 14:53:44 +020053void PrintTo(const Extent& extent, ::std::ostream* os) {
54 *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
55}
56
Alex Deymo64d98782016-02-05 18:03:48 -080057void PrintTo(const ErrorCode& error_code, ::std::ostream* os) {
58 *os << utils::ErrorCodeToString(error_code);
59}
60
Alex Deymo10875d92014-11-10 21:52:57 -080061namespace test_utils {
62
Gilad Arnolda6742b32014-01-11 00:18:34 -080063const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
Gilad Arnold61d9d2c2013-07-22 17:54:52 -070064
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -080065const uint8_t kRandomString[] = {
Alex Deymo10875d92014-11-10 21:52:57 -080066 0xf2, 0xb7, 0x55, 0x92, 0xea, 0xa6, 0xc9, 0x57,
67 0xe0, 0xf8, 0xeb, 0x34, 0x93, 0xd9, 0xc4, 0x8f,
68 0xcb, 0x20, 0xfa, 0x37, 0x4b, 0x40, 0xcf, 0xdc,
69 0xa5, 0x08, 0x70, 0x89, 0x79, 0x35, 0xe2, 0x3d,
70 0x56, 0xa4, 0x75, 0x73, 0xa3, 0x6d, 0xd1, 0xd5,
71 0x26, 0xbb, 0x9c, 0x60, 0xbd, 0x2f, 0x5a, 0xfa,
72 0xb7, 0xd4, 0x3a, 0x50, 0xa7, 0x6b, 0x3e, 0xfd,
73 0x61, 0x2b, 0x3a, 0x31, 0x30, 0x13, 0x33, 0x53,
74 0xdb, 0xd0, 0x32, 0x71, 0x5c, 0x39, 0xed, 0xda,
75 0xb4, 0x84, 0xca, 0xbc, 0xbd, 0x78, 0x1c, 0x0c,
76 0xd8, 0x0b, 0x41, 0xe8, 0xe1, 0xe0, 0x41, 0xad,
77 0x03, 0x12, 0xd3, 0x3d, 0xb8, 0x75, 0x9b, 0xe6,
78 0xd9, 0x01, 0xd0, 0x87, 0xf4, 0x36, 0xfa, 0xa7,
79 0x0a, 0xfa, 0xc5, 0x87, 0x65, 0xab, 0x9a, 0x7b,
80 0xeb, 0x58, 0x23, 0xf0, 0xa8, 0x0a, 0xf2, 0x33,
81 0x3a, 0xe2, 0xe3, 0x35, 0x74, 0x95, 0xdd, 0x3c,
82 0x59, 0x5a, 0xd9, 0x52, 0x3a, 0x3c, 0xac, 0xe5,
83 0x15, 0x87, 0x6d, 0x82, 0xbc, 0xf8, 0x7d, 0xbe,
84 0xca, 0xd3, 0x2c, 0xd6, 0xec, 0x38, 0xeb, 0xe4,
85 0x53, 0xb0, 0x4c, 0x3f, 0x39, 0x29, 0xf7, 0xa4,
86 0x73, 0xa8, 0xcb, 0x32, 0x50, 0x05, 0x8c, 0x1c,
87 0x1c, 0xca, 0xc9, 0x76, 0x0b, 0x8f, 0x6b, 0x57,
88 0x1f, 0x24, 0x2b, 0xba, 0x82, 0xba, 0xed, 0x58,
89 0xd8, 0xbf, 0xec, 0x06, 0x64, 0x52, 0x6a, 0x3f,
90 0xe4, 0xad, 0xce, 0x84, 0xb4, 0x27, 0x55, 0x14,
91 0xe3, 0x75, 0x59, 0x73, 0x71, 0x51, 0xea, 0xe8,
92 0xcc, 0xda, 0x4f, 0x09, 0xaf, 0xa4, 0xbc, 0x0e,
93 0xa6, 0x1f, 0xe2, 0x3a, 0xf8, 0x96, 0x7d, 0x30,
94 0x23, 0xc5, 0x12, 0xb5, 0xd8, 0x73, 0x6b, 0x71,
95 0xab, 0xf1, 0xd7, 0x43, 0x58, 0xa7, 0xc9, 0xf0,
96 0xe4, 0x85, 0x1c, 0xd6, 0x92, 0x50, 0x2c, 0x98,
97 0x36, 0xfe, 0x87, 0xaf, 0x43, 0x8f, 0x8f, 0xf5,
98 0x88, 0x48, 0x18, 0x42, 0xcf, 0x42, 0xc1, 0xa8,
99 0xe8, 0x05, 0x08, 0xa1, 0x45, 0x70, 0x5b, 0x8c,
100 0x39, 0x28, 0xab, 0xe9, 0x6b, 0x51, 0xd2, 0xcb,
101 0x30, 0x04, 0xea, 0x7d, 0x2f, 0x6e, 0x6c, 0x3b,
102 0x5f, 0x82, 0xd9, 0x5b, 0x89, 0x37, 0x65, 0x65,
103 0xbe, 0x9f, 0xa3, 0x5d,
104};
105
106bool IsXAttrSupported(const base::FilePath& dir_path) {
107 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
108
109 int fd = mkstemp(path);
110 if (fd == -1) {
111 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
112 free(path);
113 return false;
114 }
115
116 if (unlink(path) != 0) {
117 PLOG(ERROR) << "Error unlinking temporary file " << path;
118 close(fd);
119 free(path);
120 return false;
121 }
122
123 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
124 if (xattr_res != 0) {
125 if (errno == ENOTSUP) {
126 // Leave it to call-sites to warn about non-support.
127 } else {
128 PLOG(ERROR) << "Error setting xattr on " << path;
129 }
130 }
131 close(fd);
132 free(path);
133 return xattr_res == 0;
134}
135
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700136bool WriteFileVector(const string& path, const brillo::Blob& data) {
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800137 return utils::WriteFile(path.c_str(), data.data(), data.size());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000138}
139
Alex Deymof329b932014-10-30 01:37:48 -0700140bool WriteFileString(const string& path, const string& data) {
Andrew de los Reyes970bb282009-12-09 16:34:04 -0800141 return utils::WriteFile(path.c_str(), data.data(), data.size());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000142}
143
Alex Deymocbc22742016-03-04 17:53:02 -0800144bool BindToUnusedLoopDevice(const string& filename,
145 bool writable,
146 string* out_lo_dev_name) {
147 CHECK(out_lo_dev_name);
148 // Get the next available loop-device.
149 int control_fd =
150 HANDLE_EINTR(open("/dev/loop-control", O_RDWR | O_LARGEFILE));
151 TEST_AND_RETURN_FALSE_ERRNO(control_fd >= 0);
152 int loop_number = ioctl(control_fd, LOOP_CTL_GET_FREE);
153 IGNORE_EINTR(close(control_fd));
154 *out_lo_dev_name = StringPrintf("/dev/loop%d", loop_number);
Don Garrett58e8b1f2012-01-31 16:38:16 -0800155
Alex Deymocbc22742016-03-04 17:53:02 -0800156 // Double check that the loop exists and is free.
157 int loop_device_fd =
158 HANDLE_EINTR(open(out_lo_dev_name->c_str(), O_RDWR | O_LARGEFILE));
159 if (loop_device_fd == -1 && errno == ENOENT) {
160 // Workaround the case when the loop device doesn't exist.
161 TEST_AND_RETURN_FALSE_ERRNO(mknod(out_lo_dev_name->c_str(),
162 S_IFBLK | 0660,
163 makedev(LOOP_MAJOR, loop_number)) == 0);
164 loop_device_fd =
165 HANDLE_EINTR(open(out_lo_dev_name->c_str(), O_RDWR | O_LARGEFILE));
166 }
167 TEST_AND_RETURN_FALSE_ERRNO(loop_device_fd != -1);
168 ScopedFdCloser loop_device_fd_closer(&loop_device_fd);
169
170 struct loop_info64 device_info;
171 if (ioctl(loop_device_fd, LOOP_GET_STATUS64, &device_info) != -1 ||
172 errno != ENXIO) {
173 PLOG(ERROR) << "Loop device " << out_lo_dev_name->c_str()
174 << " already in use";
Gilad Arnold19a45f02012-07-19 12:36:10 -0700175 return false;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000176 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000177
Alex Deymocbc22742016-03-04 17:53:02 -0800178 // Open our data file and assign it to the loop device.
179 int data_fd = open(filename.c_str(),
180 (writable ? O_RDWR : O_RDONLY) | O_LARGEFILE | O_CLOEXEC);
181 TEST_AND_RETURN_FALSE_ERRNO(data_fd >= 0);
182 ScopedFdCloser data_fd_closer(&data_fd);
183 TEST_AND_RETURN_FALSE_ERRNO(ioctl(loop_device_fd, LOOP_SET_FD, data_fd) == 0);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000184
Alex Deymocbc22742016-03-04 17:53:02 -0800185 memset(&device_info, 0, sizeof(device_info));
186 device_info.lo_offset = 0;
187 device_info.lo_sizelimit = 0; // 0 means whole file.
188 device_info.lo_flags = (writable ? 0 : LO_FLAGS_READ_ONLY);
189 device_info.lo_number = loop_number;
190 strncpy(reinterpret_cast<char*>(device_info.lo_file_name),
191 base::FilePath(filename).BaseName().value().c_str(),
192 LO_NAME_SIZE - 1);
193 device_info.lo_file_name[LO_NAME_SIZE - 1] = '\0';
194 TEST_AND_RETURN_FALSE_ERRNO(
195 ioctl(loop_device_fd, LOOP_SET_STATUS64, &device_info) == 0);
196 return true;
197}
198
199bool UnbindLoopDevice(const string& lo_dev_name) {
200 int loop_device_fd =
201 HANDLE_EINTR(open(lo_dev_name.c_str(), O_RDWR | O_LARGEFILE));
202 if (loop_device_fd == -1 && errno == ENOENT)
203 return true;
204 TEST_AND_RETURN_FALSE_ERRNO(loop_device_fd != -1);
205 ScopedFdCloser loop_device_fd_closer(&loop_device_fd);
206
207 struct loop_info64 device_info;
208 // Check if the device is bound before trying to unbind it.
209 int get_stat_err = ioctl(loop_device_fd, LOOP_GET_STATUS64, &device_info);
210 if (get_stat_err == -1 && errno == ENXIO)
211 return true;
212
213 TEST_AND_RETURN_FALSE_ERRNO(ioctl(loop_device_fd, LOOP_CLR_FD) == 0);
Gilad Arnold19a45f02012-07-19 12:36:10 -0700214 return true;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000215}
216
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700217bool ExpectVectorsEq(const brillo::Blob& expected,
218 const brillo::Blob& actual) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800219 EXPECT_EQ(expected.size(), actual.size());
220 if (expected.size() != actual.size())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000221 return false;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700222 bool is_all_eq = true;
Andrew de los Reyes80061062010-02-04 14:25:00 -0800223 for (unsigned int i = 0; i < expected.size(); i++) {
224 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
Gilad Arnold617bbc22012-05-15 08:48:13 -0700225 is_all_eq = is_all_eq && (expected[i] == actual[i]);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000226 }
Gilad Arnold617bbc22012-05-15 08:48:13 -0700227 return is_all_eq;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000228}
229
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700230void FillWithData(brillo::Blob* buffer) {
Andrew de los Reyes80061062010-02-04 14:25:00 -0800231 size_t input_counter = 0;
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800232 for (uint8_t& b : *buffer) {
233 b = kRandomString[input_counter];
Andrew de los Reyes80061062010-02-04 14:25:00 -0800234 input_counter++;
235 input_counter %= sizeof(kRandomString);
236 }
237}
238
Thieu Le5c7d9752010-12-15 16:09:28 -0800239void CreateEmptyExtImageAtPath(const string& path,
240 size_t size,
241 int block_size) {
242 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymoc00c98a2015-03-17 17:38:00 -0700243 " seek=%" PRIuS " bs=1 count=1 status=none",
Thieu Le5c7d9752010-12-15 16:09:28 -0800244 path.c_str(), size)));
Alex Deymo6ded6542015-03-13 15:52:46 -0700245 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b %d -F %s",
Thieu Le5c7d9752010-12-15 16:09:28 -0800246 block_size, path.c_str())));
247}
248
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000249void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700250 // create 10MiB sparse file, mounted at a unique location.
251 string mount_path;
252 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
Alex Deymoa58b62a2013-08-08 21:21:48 -0700253 ScopedDirRemover mount_path_unlinker(mount_path);
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700254
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000255 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
Alex Deymo1f93d032015-03-10 18:58:32 -0700256 " seek=10485759 bs=1 count=1 status=none",
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000257 path.c_str())));
Alex Deymo6ded6542015-03-13 15:52:46 -0700258 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b 4096 -F %s",
259 path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000260 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700261 mount_path.c_str())));
262 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
263 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
264 mount_path.c_str())));
265 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
266 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
267 mount_path.c_str())));
268 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
269 mount_path.c_str())));
270 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
271 mount_path.c_str())));
272 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
273 mount_path.c_str())));
274 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
275 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
276 mount_path.c_str())));
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000277 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700278 mount_path.c_str(), mount_path.c_str())));
279 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
280 mount_path.c_str())));
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800281 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700282 mount_path.c_str(), mount_path.c_str())));
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800283 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
Gilad Arnold61d9d2c2013-07-22 17:54:52 -0700284 mount_path.c_str())));
285 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
Thieu Le5c7d9752010-12-15 16:09:28 -0800286
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000287 if (out_paths) {
288 out_paths->clear();
289 out_paths->push_back("");
290 out_paths->push_back("/hi");
Andrew de los Reyes48a0a482011-02-22 15:32:11 -0800291 out_paths->push_back("/boguslink");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000292 out_paths->push_back("/hello");
293 out_paths->push_back("/some_dir");
294 out_paths->push_back("/some_dir/empty_dir");
295 out_paths->push_back("/some_dir/mnt");
296 out_paths->push_back("/some_dir/test");
297 out_paths->push_back("/some_dir/fifo");
298 out_paths->push_back("/cdev");
299 out_paths->push_back("/testlink");
300 out_paths->push_back("/sym");
Andrew de los Reyes29da8aa2011-02-15 13:34:57 -0800301 out_paths->push_back("/srchardlink0");
302 out_paths->push_back("/srchardlink1");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000303 out_paths->push_back("/lost+found");
304 }
305}
306
Don Garrett58e8b1f2012-01-31 16:38:16 -0800307ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
308 string* mnt_path,
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700309 unsigned long flags) { // NOLINT - long
Gilad Arnolda6742b32014-01-11 00:18:34 -0800310 EXPECT_TRUE(utils::MakeTempDirectory("mnt.XXXXXX", mnt_path));
Thieu Le5c7d9752010-12-15 16:09:28 -0800311 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
312
Don Garrett58e8b1f2012-01-31 16:38:16 -0800313 string loop_dev;
Alex Deymocbc22742016-03-04 17:53:02 -0800314 loop_binder_.reset(
315 new ScopedLoopbackDeviceBinder(file_path, true, &loop_dev));
Thieu Le5c7d9752010-12-15 16:09:28 -0800316
Sen Jiang2c413572016-03-07 12:55:09 -0800317 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags, "", ""));
Thieu Le5c7d9752010-12-15 16:09:28 -0800318 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
319}
320
Alex Deymo2b19cfb2015-03-26 00:35:07 -0700321base::FilePath GetBuildArtifactsPath() {
322 base::FilePath exe_path;
323 base::ReadSymbolicLink(base::FilePath("/proc/self/exe"), &exe_path);
324 return exe_path.DirName();
325}
326
Alex Deymo10875d92014-11-10 21:52:57 -0800327} // namespace test_utils
rspangler@google.com49fdf182009-10-10 00:57:34 +0000328} // namespace chromeos_update_engine