1 /*
2  * Copyright (C) 2018 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 "liblp/partition_opener.h"
18 
19 #if defined(__linux__)
20 #include <linux/fs.h>
21 #endif
22 #if !defined(_WIN32)
23 #include <sys/ioctl.h>
24 #endif
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include <android-base/file.h>
29 #include <android-base/strings.h>
30 
31 #include "utility.h"
32 
33 namespace android {
34 namespace fs_mgr {
35 
36 using android::base::unique_fd;
37 
38 namespace {
39 
GetPartitionAbsolutePath(const std::string & path)40 std::string GetPartitionAbsolutePath(const std::string& path) {
41 #if !defined(__ANDROID__)
42     return path;
43 #else
44     if (android::base::StartsWith(path, "/")) {
45         return path;
46     }
47 
48     auto by_name = "/dev/block/by-name/" + path;
49     if (access(by_name.c_str(), F_OK) != 0) {
50         // If the by-name symlink doesn't exist, as a special case we allow
51         // certain devices to be used as partition names. This can happen if a
52         // Dynamic System Update is installed to an sdcard, which won't be in
53         // the boot device list.
54         //
55         // mmcblk* is allowed because most devices in /dev/block are not valid for
56         // storing fiemaps.
57         if (android::base::StartsWith(path, "mmcblk")) {
58             return "/dev/block/" + path;
59         }
60     }
61     return by_name;
62 #endif
63 }
64 
GetBlockDeviceInfo(const std::string & block_device,BlockDeviceInfo * device_info)65 bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
66 #if defined(__linux__)
67     unique_fd fd = GetControlFileOrOpen(block_device.c_str(), O_RDONLY);
68     if (fd < 0) {
69         PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
70         return false;
71     }
72     if (!GetDescriptorSize(fd, &device_info->size)) {
73         return false;
74     }
75     if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
76         PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed on " << block_device;
77         return false;
78     }
79 
80     int alignment_offset;
81     if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
82         PERROR << __PRETTY_FUNCTION__ << "BLKALIGNOFF failed on " << block_device;
83         return false;
84     }
85     // The kernel can return -1 here when misaligned devices are stacked (i.e.
86     // device-mapper).
87     if (alignment_offset == -1) {
88         alignment_offset = 0;
89     }
90 
91     int logical_block_size;
92     if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
93         PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed on " << block_device;
94         return false;
95     }
96 
97     device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
98     device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
99     device_info->partition_name = android::base::Basename(block_device);
100     return true;
101 #else
102     (void)block_device;
103     (void)device_info;
104     LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
105     return false;
106 #endif
107 }
108 
109 }  // namespace
110 
Open(const std::string & partition_name,int flags) const111 unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
112     std::string path = GetPartitionAbsolutePath(partition_name);
113     return GetControlFileOrOpen(path.c_str(), flags | O_CLOEXEC);
114 }
115 
GetInfo(const std::string & partition_name,BlockDeviceInfo * info) const116 bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
117     std::string path = GetPartitionAbsolutePath(partition_name);
118     return GetBlockDeviceInfo(path, info);
119 }
120 
GetDeviceString(const std::string & partition_name) const121 std::string PartitionOpener::GetDeviceString(const std::string& partition_name) const {
122     return GetPartitionAbsolutePath(partition_name);
123 }
124 
125 }  // namespace fs_mgr
126 }  // namespace android
127