summaryrefslogtreecommitdiff
path: root/fastboot/device/utility.h
blob: 6e1453f8363bcf17d2ca0ca38f1b6713e06187cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#include <optional>
#include <string>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <fstab/fstab.h>
#include <liblp/liblp.h>

// Logical partitions are only mapped to a block device as needed, and
// immediately unmapped when no longer needed. In order to enforce this we
// require accessing partitions through a Handle abstraction, which may perform
// additional operations after closing its file descriptor.
class PartitionHandle {
  public:
    PartitionHandle() {}
    explicit PartitionHandle(const std::string& path) : path_(path) {}
    PartitionHandle(const std::string& path, std::function<void()>&& closer)
        : path_(path), closer_(std::move(closer)) {}
    PartitionHandle(PartitionHandle&& other) = default;
    PartitionHandle& operator=(PartitionHandle&& other) = default;
    ~PartitionHandle() {
        if (closer_) {
            // Make sure the device is closed first.
            fd_ = {};
            closer_();
        }
    }
    const std::string& path() const { return path_; }
    int fd() const { return fd_.get(); }
    bool Open(int flags) {
        flags |= (O_EXCL | O_CLOEXEC | O_BINARY);

        // Attempts to open a second device can fail with EBUSY if the device is already open.
        // Explicitly close any previously opened devices as unique_fd won't close them until
        // after the attempt to open.
        fd_.reset();

        fd_ = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path_.c_str(), flags)));
        if (fd_ < 0) {
            PLOG(ERROR) << "Failed to open block device: " << path_;
            return false;
        }
        flags_ = flags;

        return true;
    }
    bool Reset(int flags) {
        if (fd_.ok() && (flags | O_EXCL | O_CLOEXEC | O_BINARY) == flags_) {
            return true;
        }

        off_t offset = fd_.ok() ? lseek(fd_.get(), 0, SEEK_CUR) : 0;
        if (offset < 0) {
            PLOG(ERROR) << "Failed lseek on block device: " << path_;
            return false;
        }

        sync();

        if (Open(flags) == false) {
            return false;
        }

        if (lseek(fd_.get(), offset, SEEK_SET) != offset) {
            PLOG(ERROR) << "Failed lseek on block device: " << path_;
            return false;
        }

        return true;
    }
  private:
    std::string path_;
    android::base::unique_fd fd_;
    int flags_;
    std::function<void()> closer_;
};

class AutoMountMetadata {
  public:
    AutoMountMetadata();
    ~AutoMountMetadata();
    explicit operator bool() const { return mounted_; }

  private:
    android::fs_mgr::Fstab fstab_;
    bool mounted_ = false;
    bool should_unmount_ = false;
};

class FastbootDevice;

// On normal devices, the super partition is always named "super". On retrofit
// devices, the name must be derived from the partition name or current slot.
// This helper assists in choosing the correct super for a given partition
// name.
std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name);

std::optional<std::string> FindPhysicalPartition(const std::string& name);
bool LogicalPartitionExists(FastbootDevice* device, const std::string& name,
                            bool* is_zero_length = nullptr);

// Partition is O_WRONLY by default, caller should pass O_RDONLY for reading.
// Caller may pass additional flags if needed. (O_EXCL | O_CLOEXEC | O_BINARY)
// will be logically ORed internally.
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle,
                   int flags = O_WRONLY);

bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
std::vector<std::string> ListPartitions(FastbootDevice* device);
bool GetDeviceLockStatus();

// Update all copies of metadata.
bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
                                const android::fs_mgr::LpMetadata& metadata);