1 //
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 //
16
17 #include "update_engine/common/test_utils.h"
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <linux/loop.h>
23 #include <linux/major.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/xattr.h>
30 #include <unistd.h>
31
32 #include <set>
33 #include <string>
34 #include <vector>
35
36 #include <base/files/file_util.h>
37 #include <base/format_macros.h>
38 #include <base/logging.h>
39 #include <base/strings/string_util.h>
40 #include <base/strings/stringprintf.h>
41
42 #include "update_engine/common/error_code_utils.h"
43 #include "update_engine/common/utils.h"
44 #include "update_engine/payload_consumer/file_writer.h"
45
46 using base::StringPrintf;
47 using std::set;
48 using std::string;
49 using std::vector;
50
51 namespace chromeos_update_engine {
52
PrintTo(const Extent & extent,::std::ostream * os)53 void PrintTo(const Extent& extent, ::std::ostream* os) {
54 *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
55 }
56
PrintTo(const ErrorCode & error_code,::std::ostream * os)57 void PrintTo(const ErrorCode& error_code, ::std::ostream* os) {
58 *os << utils::ErrorCodeToString(error_code);
59 }
60
61 namespace test_utils {
62
63 const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
64
65 const uint8_t kRandomString[] = {
66 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
Readlink(const string & path)106 string Readlink(const string& path) {
107 vector<char> buf(PATH_MAX + 1);
108 ssize_t r = readlink(path.c_str(), buf.data(), buf.size());
109 if (r < 0)
110 return "";
111 CHECK_LT(r, static_cast<ssize_t>(buf.size()));
112 return string(buf.begin(), buf.begin() + r);
113 }
114
IsXAttrSupported(const base::FilePath & dir_path)115 bool IsXAttrSupported(const base::FilePath& dir_path) {
116 char *path = strdup(dir_path.Append("xattr_test_XXXXXX").value().c_str());
117
118 int fd = mkstemp(path);
119 if (fd == -1) {
120 PLOG(ERROR) << "Error creating temporary file in " << dir_path.value();
121 free(path);
122 return false;
123 }
124
125 if (unlink(path) != 0) {
126 PLOG(ERROR) << "Error unlinking temporary file " << path;
127 close(fd);
128 free(path);
129 return false;
130 }
131
132 int xattr_res = fsetxattr(fd, "user.xattr-test", "value", strlen("value"), 0);
133 if (xattr_res != 0) {
134 if (errno == ENOTSUP) {
135 // Leave it to call-sites to warn about non-support.
136 } else {
137 PLOG(ERROR) << "Error setting xattr on " << path;
138 }
139 }
140 close(fd);
141 free(path);
142 return xattr_res == 0;
143 }
144
WriteFileVector(const string & path,const brillo::Blob & data)145 bool WriteFileVector(const string& path, const brillo::Blob& data) {
146 return utils::WriteFile(path.c_str(), data.data(), data.size());
147 }
148
WriteFileString(const string & path,const string & data)149 bool WriteFileString(const string& path, const string& data) {
150 return utils::WriteFile(path.c_str(), data.data(), data.size());
151 }
152
BindToUnusedLoopDevice(const string & filename,bool writable,string * out_lo_dev_name)153 bool BindToUnusedLoopDevice(const string& filename,
154 bool writable,
155 string* out_lo_dev_name) {
156 CHECK(out_lo_dev_name);
157 // Get the next available loop-device.
158 int control_fd =
159 HANDLE_EINTR(open("/dev/loop-control", O_RDWR | O_LARGEFILE));
160 TEST_AND_RETURN_FALSE_ERRNO(control_fd >= 0);
161 int loop_number = ioctl(control_fd, LOOP_CTL_GET_FREE);
162 IGNORE_EINTR(close(control_fd));
163 *out_lo_dev_name = StringPrintf("/dev/loop%d", loop_number);
164
165 // Double check that the loop exists and is free.
166 int loop_device_fd =
167 HANDLE_EINTR(open(out_lo_dev_name->c_str(), O_RDWR | O_LARGEFILE));
168 if (loop_device_fd == -1 && errno == ENOENT) {
169 // Workaround the case when the loop device doesn't exist.
170 TEST_AND_RETURN_FALSE_ERRNO(mknod(out_lo_dev_name->c_str(),
171 S_IFBLK | 0660,
172 makedev(LOOP_MAJOR, loop_number)) == 0);
173 loop_device_fd =
174 HANDLE_EINTR(open(out_lo_dev_name->c_str(), O_RDWR | O_LARGEFILE));
175 }
176 TEST_AND_RETURN_FALSE_ERRNO(loop_device_fd != -1);
177 ScopedFdCloser loop_device_fd_closer(&loop_device_fd);
178
179 struct loop_info64 device_info;
180 if (ioctl(loop_device_fd, LOOP_GET_STATUS64, &device_info) != -1 ||
181 errno != ENXIO) {
182 PLOG(ERROR) << "Loop device " << out_lo_dev_name->c_str()
183 << " already in use";
184 return false;
185 }
186
187 // Open our data file and assign it to the loop device.
188 int data_fd = open(filename.c_str(),
189 (writable ? O_RDWR : O_RDONLY) | O_LARGEFILE | O_CLOEXEC);
190 TEST_AND_RETURN_FALSE_ERRNO(data_fd >= 0);
191 ScopedFdCloser data_fd_closer(&data_fd);
192 TEST_AND_RETURN_FALSE_ERRNO(ioctl(loop_device_fd, LOOP_SET_FD, data_fd) == 0);
193
194 memset(&device_info, 0, sizeof(device_info));
195 device_info.lo_offset = 0;
196 device_info.lo_sizelimit = 0; // 0 means whole file.
197 device_info.lo_flags = (writable ? 0 : LO_FLAGS_READ_ONLY);
198 device_info.lo_number = loop_number;
199 strncpy(reinterpret_cast<char*>(device_info.lo_file_name),
200 base::FilePath(filename).BaseName().value().c_str(),
201 LO_NAME_SIZE - 1);
202 device_info.lo_file_name[LO_NAME_SIZE - 1] = '\0';
203 TEST_AND_RETURN_FALSE_ERRNO(
204 ioctl(loop_device_fd, LOOP_SET_STATUS64, &device_info) == 0);
205 return true;
206 }
207
UnbindLoopDevice(const string & lo_dev_name)208 bool UnbindLoopDevice(const string& lo_dev_name) {
209 int loop_device_fd =
210 HANDLE_EINTR(open(lo_dev_name.c_str(), O_RDWR | O_LARGEFILE));
211 if (loop_device_fd == -1 && errno == ENOENT)
212 return true;
213 TEST_AND_RETURN_FALSE_ERRNO(loop_device_fd != -1);
214 ScopedFdCloser loop_device_fd_closer(&loop_device_fd);
215
216 struct loop_info64 device_info;
217 // Check if the device is bound before trying to unbind it.
218 int get_stat_err = ioctl(loop_device_fd, LOOP_GET_STATUS64, &device_info);
219 if (get_stat_err == -1 && errno == ENXIO)
220 return true;
221
222 TEST_AND_RETURN_FALSE_ERRNO(ioctl(loop_device_fd, LOOP_CLR_FD) == 0);
223 return true;
224 }
225
ExpectVectorsEq(const brillo::Blob & expected,const brillo::Blob & actual)226 bool ExpectVectorsEq(const brillo::Blob& expected,
227 const brillo::Blob& actual) {
228 EXPECT_EQ(expected.size(), actual.size());
229 if (expected.size() != actual.size())
230 return false;
231 bool is_all_eq = true;
232 for (unsigned int i = 0; i < expected.size(); i++) {
233 EXPECT_EQ(expected[i], actual[i]) << "offset: " << i;
234 is_all_eq = is_all_eq && (expected[i] == actual[i]);
235 }
236 return is_all_eq;
237 }
238
FillWithData(brillo::Blob * buffer)239 void FillWithData(brillo::Blob* buffer) {
240 size_t input_counter = 0;
241 for (uint8_t& b : *buffer) {
242 b = kRandomString[input_counter];
243 input_counter++;
244 input_counter %= sizeof(kRandomString);
245 }
246 }
247
CreateEmptyExtImageAtPath(const string & path,size_t size,int block_size)248 void CreateEmptyExtImageAtPath(const string& path,
249 size_t size,
250 int block_size) {
251 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
252 " seek=%" PRIuS " bs=1 count=1 status=none",
253 path.c_str(), size)));
254 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b %d -F %s",
255 block_size, path.c_str())));
256 }
257
CreateExtImageAtPath(const string & path,vector<string> * out_paths)258 void CreateExtImageAtPath(const string& path, vector<string>* out_paths) {
259 // create 10MiB sparse file, mounted at a unique location.
260 string mount_path;
261 CHECK(utils::MakeTempDirectory(kMountPathTemplate, &mount_path));
262 ScopedDirRemover mount_path_unlinker(mount_path);
263
264 EXPECT_EQ(0, System(StringPrintf("dd if=/dev/zero of=%s"
265 " seek=10485759 bs=1 count=1 status=none",
266 path.c_str())));
267 EXPECT_EQ(0, System(StringPrintf("mkfs.ext3 -q -b 4096 -F %s",
268 path.c_str())));
269 EXPECT_EQ(0, System(StringPrintf("mount -o loop %s %s", path.c_str(),
270 mount_path.c_str())));
271 EXPECT_EQ(0, System(StringPrintf("echo hi > %s/hi", mount_path.c_str())));
272 EXPECT_EQ(0, System(StringPrintf("echo hello > %s/hello",
273 mount_path.c_str())));
274 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir", mount_path.c_str())));
275 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/empty_dir",
276 mount_path.c_str())));
277 EXPECT_EQ(0, System(StringPrintf("mkdir %s/some_dir/mnt",
278 mount_path.c_str())));
279 EXPECT_EQ(0, System(StringPrintf("echo T > %s/some_dir/test",
280 mount_path.c_str())));
281 EXPECT_EQ(0, System(StringPrintf("mkfifo %s/some_dir/fifo",
282 mount_path.c_str())));
283 EXPECT_EQ(0, System(StringPrintf("mknod %s/cdev c 2 3", mount_path.c_str())));
284 EXPECT_EQ(0, System(StringPrintf("ln -s /some/target %s/sym",
285 mount_path.c_str())));
286 EXPECT_EQ(0, System(StringPrintf("ln %s/some_dir/test %s/testlink",
287 mount_path.c_str(), mount_path.c_str())));
288 EXPECT_EQ(0, System(StringPrintf("echo T > %s/srchardlink0",
289 mount_path.c_str())));
290 EXPECT_EQ(0, System(StringPrintf("ln %s/srchardlink0 %s/srchardlink1",
291 mount_path.c_str(), mount_path.c_str())));
292 EXPECT_EQ(0, System(StringPrintf("ln -s bogus %s/boguslink",
293 mount_path.c_str())));
294 EXPECT_TRUE(utils::UnmountFilesystem(mount_path.c_str()));
295
296 if (out_paths) {
297 out_paths->clear();
298 out_paths->push_back("");
299 out_paths->push_back("/hi");
300 out_paths->push_back("/boguslink");
301 out_paths->push_back("/hello");
302 out_paths->push_back("/some_dir");
303 out_paths->push_back("/some_dir/empty_dir");
304 out_paths->push_back("/some_dir/mnt");
305 out_paths->push_back("/some_dir/test");
306 out_paths->push_back("/some_dir/fifo");
307 out_paths->push_back("/cdev");
308 out_paths->push_back("/testlink");
309 out_paths->push_back("/sym");
310 out_paths->push_back("/srchardlink0");
311 out_paths->push_back("/srchardlink1");
312 out_paths->push_back("/lost+found");
313 }
314 }
315
ScopedLoopMounter(const string & file_path,string * mnt_path,unsigned long flags)316 ScopedLoopMounter::ScopedLoopMounter(const string& file_path,
317 string* mnt_path,
318 unsigned long flags) { // NOLINT - long
319 EXPECT_TRUE(utils::MakeTempDirectory("mnt.XXXXXX", mnt_path));
320 dir_remover_.reset(new ScopedDirRemover(*mnt_path));
321
322 string loop_dev;
323 loop_binder_.reset(
324 new ScopedLoopbackDeviceBinder(file_path, true, &loop_dev));
325
326 EXPECT_TRUE(utils::MountFilesystem(loop_dev, *mnt_path, flags, "", nullptr));
327 unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
328 }
329
GetBuildArtifactsPath()330 base::FilePath GetBuildArtifactsPath() {
331 base::FilePath exe_path;
332 base::ReadSymbolicLink(base::FilePath("/proc/self/exe"), &exe_path);
333 return exe_path.DirName();
334 }
335
336 } // namespace test_utils
337 } // namespace chromeos_update_engine
338