Home | History | Annotate | Download | only in common
      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 
     53 void PrintTo(const Extent& extent, ::std::ostream* os) {
     54   *os << "(" << extent.start_block() << ", " << extent.num_blocks() << ")";
     55 }
     56 
     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 
    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 
    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 
    145 bool WriteFileVector(const string& path, const brillo::Blob& data) {
    146   return utils::WriteFile(path.c_str(), data.data(), data.size());
    147 }
    148 
    149 bool WriteFileString(const string& path, const string& data) {
    150   return utils::WriteFile(path.c_str(), data.data(), data.size());
    151 }
    152 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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