test_utils.cc revision d15c546ed794293d0a63770467a0f3c4c84c6214
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
46using base::StringPrintf;
47using std::set;
48using std::string;
49using std::vector;
50
51namespace chromeos_update_engine {
52
53void PrintTo(const Extent& extent, ::std::ostream* os) {
54  *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
55}
56
57void PrintTo(const ErrorCode& error_code, ::std::ostream* os) {
58  *os << utils::ErrorCodeToString(error_code);
59}
60
61namespace test_utils {
62
63const char* const kMountPathTemplate = "UpdateEngineTests_mnt-XXXXXX";
64
65const 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
106string 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
115bool 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
145bool WriteFileVector(const string& path, const brillo::Blob& data) {
146  return utils::WriteFile(path.c_str(), data.data(), data.size());
147}
148
149bool WriteFileString(const string& path, const string& data) {
150  return utils::WriteFile(path.c_str(), data.data(), data.size());
151}
152
153bool 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
208bool 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
226bool 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
239void 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
248void 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
258void 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
316ScopedLoopMounter::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, "", ""));
327  unmounter_.reset(new ScopedFilesystemUnmounter(*mnt_path));
328}
329
330base::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