• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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