未验证 提交 3defc0dc 编写于 作者: O openharmony_ci 提交者: Gitee

!1027 support A/B partition startup

Merge pull request !1027 from cheng_jinsong/slot
......@@ -338,6 +338,16 @@ int GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char
return 0;
}
int GetBlockDeviceByName(const char *deviceName, const Fstab *fstab, char* miscDev, size_t size)
{
for (FstabItem *item = fstab->head; item != NULL; item = item->next) {
if (strstr(item->deviceName, deviceName) != NULL) {
BEGET_CHECK_RETURN_VALUE(strcpy_s(miscDev, size, item->deviceName) != 0, 0);
}
}
return -1;
}
static const struct MountFlags mountFlags[] = {
{ "noatime", MS_NOATIME },
{ "noexec", MS_NOEXEC },
......@@ -487,21 +497,114 @@ unsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpec
return flags;
}
int GetBlockDevicePath(const char *partName, char *path, int size)
int GetBlockDevicePath(const char *partName, char *path, size_t size)
{
char *fstabFile = GetFstabFile(path, size);
if (fstabFile == NULL) {
return -1;
}
Fstab *fstab = ReadFstabFromFile(fstabFile, false);
Fstab *fstab = LoadFstabFromCommandLine();
if (fstab == NULL) {
return -1;
BEGET_LOGI("fstab not found from cmdline, try to get it from file");
char *fstabFile = GetFstabFile(path, size);
BEGET_CHECK_RETURN_VALUE(fstabFile != NULL, -1);
fstab = ReadFstabFromFile(fstabFile, false);
}
BEGET_CHECK_RETURN_VALUE(fstab != NULL, -1);
int ret = GetBlockDeviceByMountPoint(partName, fstab, path, size);
BEGET_INFO_CHECK(ret == 0, ret = GetBlockDeviceByName(partName, fstab, path, size),
"mount point not found, try to get it by device name");
ReleaseFstab(fstab);
return ret;
}
#define OHOS_REQUIRED_MOUNT_PREFIX "ohos.required_mount."
/*
* Fstab includes block device node, mount point, file system type, MNT_ Flags and options.
* We separate them by spaces in fstab.required file, but the separator is '@' in CmdLine.
* The prefix "ohos.required_mount." is the flag of required fstab information in CmdLine.
* Format as shown below:
* <block device>@<mount point>@<fstype>@<mount options>@<fstab options>
* e.g.
* ohos.required_mount.system=/dev/block/xxx/by-name/system@/usr@ext4@ro,barrier=1@wait,required
*/
static int ParseRequiredMountInfo(const char *item, Fstab *fstab)
{
char mountOptions[MAX_BUFFER_LEN] = {};
char partName[NAME_SIZE] = {};
// Sanity checks
BEGET_CHECK(!(item == NULL || *item == '\0' || fstab == NULL), return -1);
char *p = NULL;
const char *q = item;
if ((p = strstr(item, "=")) != NULL) {
q = item + strlen(OHOS_REQUIRED_MOUNT_PREFIX); // Get partition name
BEGET_CHECK(!(q == NULL || *q == '\0' || (p - q) <= 0), return -1);
BEGET_ERROR_CHECK(strncpy_s(partName, NAME_SIZE -1, q, p - q) == EOK,
return -1, "Failed to copy required partition name");
p++; // skip '='
BEGET_ERROR_CHECK(strncpy_s(mountOptions, MAX_BUFFER_LEN -1, p, strlen(p)) == EOK,
return -1, "Failed to copy required mount info: %s", item);
}
BEGET_LOGV("Mount option of partition %s is [%s]", partName, mountOptions);
if (ParseFstabPerLine(mountOptions, fstab, false, "@") < 0) {
BEGET_LOGE("Failed to parse mount options of partition \' %s \', options: %s", partName, mountOptions);
return -1;
}
return 0;
}
Fstab* LoadFstabFromCommandLine(void)
{
Fstab *fstab = NULL;
char *cmdline = ReadFileData(BOOT_CMD_LINE);
bool isDone = false;
BEGET_ERROR_CHECK(cmdline != NULL, return NULL, "Read from \'/proc/cmdline\' failed, err = %d", errno);
TrimTail(cmdline, '\n');
BEGET_ERROR_CHECK((fstab = (Fstab *)calloc(1, sizeof(Fstab))) != NULL, return NULL,
"Allocate memory for FS table failed, err = %d", errno);
char *start = cmdline;
char *end = start + strlen(cmdline);
while (start < end) {
char *token = strstr(start, " ");
if (token == NULL) {
break;
}
// Startswith " "
if (token == start) {
start++;
continue;
}
*token = '\0';
if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
strlen(OHOS_REQUIRED_MOUNT_PREFIX)) != 0) {
start = token + 1;
continue;
}
isDone = true;
if (ParseRequiredMountInfo(start, fstab) < 0) {
BEGET_LOGE("Failed to parse \' %s \'", start);
isDone = false;
break;
}
start = token + 1;
}
// handle last one
if (start < end) {
if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
strlen(OHOS_REQUIRED_MOUNT_PREFIX)) == 0 &&
ParseRequiredMountInfo(start, fstab) < 0) {
BEGET_LOGE("Failed to parse \' %s \'", start);
isDone = false;
}
}
if (!isDone) {
ReleaseFstab(fstab);
fstab = NULL;
}
free(cmdline);
return fstab;
}
#ifdef __cplusplus
#if __cplusplus
}
......
......@@ -21,9 +21,11 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/limits.h>
#include "beget_ext.h"
#include "fs_manager/fs_manager.h"
#include "init_utils.h"
#include "param/init_param.h"
#include "securec.h"
#ifdef __cplusplus
......@@ -35,6 +37,8 @@ extern "C" {
#define FS_MANAGER_BUFFER_SIZE 512
#define BLOCK_SIZE_BUFFER (64)
#define RESIZE_BUFFER_SIZE 1024
const off_t MISC_PARTITION_ACTIVE_SLOT_OFFSET = 1400;
const off_t MISC_PARTITION_ACTIVE_SLOT_SIZE = 4;
bool IsSupportedFilesystem(const char *fsType)
{
......@@ -285,6 +289,68 @@ static int Mount(const char *source, const char *target, const char *fsType,
return rc;
}
static int GetSlotInfoFromParameter(const char *slotInfoName)
{
char name[PARAM_NAME_LEN_MAX] = {0};
BEGET_ERROR_CHECK(sprintf_s(name, sizeof(name), "ohos.boot.%s", slotInfoName) > 0,
return -1, "Failed to format slot parameter name");
char value[PARAM_VALUE_LEN_MAX] = {0};
uint32_t valueLen = PARAM_VALUE_LEN_MAX;
return SystemGetParameter(name, value, &valueLen) == 0 ? atoi(value) : -1;
}
static int GetSlotInfoFromCmdLine(const char *slotInfoName)
{
char value[MAX_BUFFER_LEN] = {0};
char *buffer = ReadFileData(BOOT_CMD_LINE);
BEGET_ERROR_CHECK(buffer != NULL, return -1, "Failed to read cmdline");
BEGET_ERROR_CHECK(GetProcCmdlineValue(slotInfoName, buffer, value, MAX_BUFFER_LEN) == 0,
free(buffer); buffer = NULL; return -1, "Failed to get %s value from cmdline", slotInfoName);
free(buffer);
buffer = NULL;
return atoi(value);
}
static int GetSlotInfoFromMisc(off_t offset, off_t size)
{
char miscDev[MAX_BUFFER_LEN] = {0};
BEGET_ERROR_CHECK(GetBlockDevicePath("/misc", miscDev, MAX_BUFFER_LEN) == 0,
return -1, "Failed to get misc device");
int fd = open(miscDev, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
BEGET_ERROR_CHECK(fd >= 0, return -1, "Failed to open misc device, errno %d", errno);
BEGET_ERROR_CHECK(lseek(fd, offset, SEEK_SET) >= 0, close(fd); return -1,
"Failed to lseek misc device fd, errno %d", errno);
int slotInfo = 0;
BEGET_ERROR_CHECK(read(fd, &slotInfo, size) == size, close(fd); return -1,
"Failed to read current slot from misc, errno %d", errno);
close(fd);
return slotInfo;
}
int GetBootSlots(void)
{
int bootSlots = GetSlotInfoFromParameter("bootslots");
BEGET_CHECK_RETURN_VALUE(bootSlots <= 0, bootSlots);
BEGET_LOGI("No valid slot value found from parameter, try to get it from cmdline");
return GetSlotInfoFromCmdLine("bootslots");
}
int GetCurrentSlot(void)
{
// get current slot from parameter
int currentSlot = GetSlotInfoFromParameter("currentslot");
BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
BEGET_LOGI("No valid slot value found from parameter, try to get it from cmdline");
// get current slot from cmdline
currentSlot = GetSlotInfoFromCmdLine("currentslot");
BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
BEGET_LOGI("No valid slot value found from cmdline, try to get it from misc");
// get current slot from misc
return GetSlotInfoFromMisc(MISC_PARTITION_ACTIVE_SLOT_OFFSET, MISC_PARTITION_ACTIVE_SLOT_SIZE);
}
int MountOneItem(FstabItem *item)
{
if (item == NULL) {
......@@ -333,6 +399,21 @@ int MountOneItem(FstabItem *item)
return rc;
}
static void AdjustPartitionNameByPartitionSlot(FstabItem *item)
{
BEGET_CHECK_ONLY_RETURN(strstr(item->deviceName, "/system") != NULL ||
strstr(item->deviceName, "/vendor") != NULL);
char buffer[MAX_BUFFER_LEN] = {0};
int slot = GetCurrentSlot();
BEGET_ERROR_CHECK(slot > 0 && slot <= MAX_SLOT, slot = 1, "slot value %d is invalid, set default value", slot);
BEGET_INFO_CHECK(slot > 1, return, "default partition doesn't need to add suffix");
BEGET_ERROR_CHECK(sprintf_s(buffer, sizeof(buffer), "%s_%c", item->deviceName, 'a' + slot - 1) > 0,
return, "Failed to format partition name suffix, use default partition name");
free(item->deviceName);
item->deviceName = strdup(buffer);
BEGET_LOGI("partition name with slot suffix: %s", item->deviceName);
}
static int CheckRequiredAndMount(FstabItem *item, bool required)
{
int rc = 0;
......@@ -341,6 +422,9 @@ static int CheckRequiredAndMount(FstabItem *item, bool required)
}
if (required) { // Mount partition during first startup.
if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
int bootSlots = GetBootSlots();
BEGET_INFO_CHECK(bootSlots <= 1, AdjustPartitionNameByPartitionSlot(item),
"boot slots is %d, now adjust partition name according to current slot", bootSlots);
rc = MountOneItem(item);
}
} else { // Mount partition during second startup.
......
......@@ -29,6 +29,8 @@ extern "C" {
#define FS_MANAGER_CHECK 0x00000001
#define FS_MANAGER_WAIT 0x00000002
#define FS_MANAGER_REQUIRED 0x00000004
#define NAME_SIZE 32
#define MAX_SLOT 2
#define VALID_FS_MANAGER_FLAGS (FS_MANAGER_CHECK | FS_MANAGER_WAIT | FS_MANAGER_REQUIRED)
#define FS_MANAGER_FLAGS_ENABLED(fsMgrFlags, flag) (((fsMgrFlags) & FS_MANAGER_##flag) != 0)
......@@ -56,6 +58,21 @@ typedef struct {
struct FstabItem *head;
} Fstab;
typedef enum SlotFlag {
UNBOOT = 0,
ACTIVE = 1,
} SlotFlag;
typedef struct SlotInfo {
int slotName;
char *slotSuffix;
SlotFlag slotFlag;
unsigned int retryCount;
unsigned int reserved;
} SlotInfo;
Fstab* LoadFstabFromCommandLine(void);
int GetSlotInfo(void);
void ReleaseFstab(Fstab *fstab);
Fstab *ReadFstabFromFile(const char *file, bool procMounts);
FstabItem *FindFstabItemForPath(Fstab fstab, const char *path);
......@@ -63,6 +80,7 @@ FstabItem* FindFstabItemForMountPoint(Fstab fstab, const char *mp);
int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts, const char *separator);
int GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char *deviceName, int nameLen);
int GetBlockDeviceByName(const char *deviceName, const Fstab *fstab, char* miscDev, size_t size);
bool IsSupportedFilesystem(const char *fsType);
int DoFormat(const char *devPath, const char *fsType);
int MountOneItem(FstabItem *item);
......@@ -73,7 +91,7 @@ int UmountAllWithFstabFile(const char *file);
unsigned long GetMountFlags(char *mountFlag, char *fsSpecificFlags, size_t fsSpecificFlagSize,
const char *mountPoint);
int GetBlockDevicePath(const char *partName, char *path, int size);
int GetBlockDevicePath(const char *partName, char *path, size_t size);
// Get fscrypt policy if exist
int LoadFscryptPolicy(char *buf, size_t size);
......
......@@ -124,6 +124,14 @@ if (defined(ohos_lite)) {
"sandbox",
"dump_service",
]
if (product_name == "rk3568") {
sources += [ "partitionslot.cpp" ]
external_deps +=
[ "drivers_peripheral_partitionslot:libpartition_slot_manager" ]
symlink_target_name += [ "partitionslot" ]
}
install_images = [ "system" ]
install_enable = true
part_name = "init"
......
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* 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.
*/
#include <iostream>
#include "begetctl.h"
#include "partitionslot_manager.h"
using namespace OHOS::HDI::Partitionslot::V1_0;
const int32_t PARTITION_ARGC = 2;
static int GetSlot(BShellHandle handle, int32_t argc, char *argv[])
{
std::cout << "Command: partitionslot getslot" << std::endl;
int bootSlots = 0;
int currentSlot = PartitionSlotManager::GetInstance()->GetCurrentSlot(bootSlots);
std::cout << "The number of slots: " << bootSlots << "," << "current slot: " << currentSlot << std::endl;
return 0;
}
static int GetSuffix(BShellHandle handle, int32_t argc, char *argv[])
{
if (argc != PARTITION_ARGC) {
BShellCmdHelp(handle, argc, argv);
return 0;
}
std::cout << "Command: partitionslot getsuffix" << std::endl;
int slot = atoi(argv[1]);
std::string suffix = "";
PartitionSlotManager::GetInstance()->GetSlotSuffix(slot, suffix);
std::cout << "The slot " << slot << " matches with suffix: " << suffix << std::endl;
return 0;
}
static int SetActiveSlot(BShellHandle handle, int32_t argc, char *argv[])
{
if (argc != PARTITION_ARGC) {
BShellCmdHelp(handle, argc, argv);
return 0;
}
std::cout << "Command: partitionslot setactive" << std::endl;
int slot = atoi(argv[1]);
PartitionSlotManager::GetInstance()->SetActiveSlot(slot);
std::cout << "Set active slot: " << slot << std::endl;
return 0;
}
static int SetUnbootSlot(BShellHandle handle, int32_t argc, char *argv[])
{
if (argc != PARTITION_ARGC) {
BShellCmdHelp(handle, argc, argv);
return 0;
}
std::cout << "Command: partitionslot setunboot" << std::endl;
int slot = atoi(argv[1]);
PartitionSlotManager::GetInstance()->SetSlotUnbootable(slot);
std::cout << "Set unboot slot: " << slot << std::endl;
return 0;
}
MODULE_CONSTRUCTOR(void)
{
CmdInfo infos[] = {
{
(char *)"partitionslot", GetSlot, (char *)"get the number of slots and current slot",
(char *)"partitionslot getslot", (char *)"partitionslot getslot"
},
{
(char *)"partitionslot", GetSuffix, (char *)"get suffix that matches with the slot",
(char *)"partitionslot getsuffix [slot]", (char *)"partitionslot getsuffix"
},
{
(char *)"partitionslot", SetActiveSlot, (char *)"set active slot",
(char *)"partitionslot setactive [slot]", (char *)"partitionslot setactive"
},
{
(char *)"partitionslot", SetUnbootSlot, (char *)"set unboot slot",
(char *)"partitionslot setunboot [slot]", (char *)"partitionslot setunboot"
}
};
for (size_t i = sizeof(infos) / sizeof(infos[0]); i > 0; i--) {
BShellEnvRegitsterCmd(GetShellHandle(), &infos[i - 1]);
}
}
......@@ -32,98 +32,6 @@ int MountRequriedPartitions(const Fstab *fstab)
return rc;
}
#define OHOS_REQUIRED_MOUNT_PREFIX "ohos.required_mount."
/*
* Fstab includes block device node, mount point, file system type, MNT_ Flags and options.
* We separate them by spaces in fstab.required file, but the separator is '@' in CmdLine.
* The prefix "ohos.required_mount." is the flag of required fstab information in CmdLine.
* Format as shown below:
* <block device>@<mount point>@<fstype>@<mount options>@<fstab options>
* e.g.
* ohos.required_mount.system=/dev/block/xxx/by-name/system@/usr@ext4@ro,barrier=1@wait,required
*/
static int ParseRequiredMountInfo(const char *item, Fstab *fstab)
{
char mountOptions[MAX_BUFFER_LEN] = {};
char partName[PARTITION_NAME_SIZE] = {};
// Sanity checks
INIT_CHECK(!(item == NULL || *item == '\0' || fstab == NULL), return -1);
char *p = NULL;
const char *q = item;
if ((p = strstr(item, "=")) != NULL) {
q = item + strlen(OHOS_REQUIRED_MOUNT_PREFIX); // Get partition name
INIT_CHECK(!(q == NULL || *q == '\0' || (p - q) <= 0), return -1);
INIT_ERROR_CHECK(strncpy_s(partName, PARTITION_NAME_SIZE -1, q, p - q) == EOK,
return -1, "Failed to copy required partition name");
p++; // skip '='
INIT_ERROR_CHECK(strncpy_s(mountOptions, MAX_BUFFER_LEN -1, p, strlen(p)) == EOK,
return -1, "Failed to copy required mount info: %s", item);
}
INIT_LOGV("Mount option of partition %s is [%s]", partName, mountOptions);
if (ParseFstabPerLine(mountOptions, fstab, false, "@") < 0) {
INIT_LOGE("Failed to parse mount options of partition \' %s \', options: %s", partName, mountOptions);
return -1;
}
return 0;
}
static Fstab* LoadFstabFromCommandLine(void)
{
Fstab *fstab = NULL;
char *cmdline = ReadFileData(BOOT_CMD_LINE);
bool isDone = false;
INIT_ERROR_CHECK(cmdline != NULL, return NULL, "Read from \'/proc/cmdline\' failed, err = %d", errno);
TrimTail(cmdline, '\n');
INIT_ERROR_CHECK((fstab = (Fstab *)calloc(1, sizeof(Fstab))) != NULL, return NULL,
"Allocate memory for FS table failed, err = %d", errno);
char *start = cmdline;
char *end = start + strlen(cmdline);
while (start < end) {
char *token = strstr(start, " ");
if (token == NULL) {
break;
}
// Startswith " "
if (token == start) {
start++;
continue;
}
*token = '\0';
if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
strlen(OHOS_REQUIRED_MOUNT_PREFIX)) != 0) {
start = token + 1;
continue;
}
isDone = true;
if (ParseRequiredMountInfo(start, fstab) < 0) {
INIT_LOGE("Failed to parse \' %s \'", start);
isDone = false;
break;
}
start = token + 1;
}
// handle last one
if (start < end) {
if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
strlen(OHOS_REQUIRED_MOUNT_PREFIX)) == 0 &&
ParseRequiredMountInfo(start, fstab) < 0) {
INIT_LOGE("Failed to parse \' %s \'", start);
isDone = false;
}
}
if (!isDone) {
ReleaseFstab(fstab);
fstab = NULL;
}
free(cmdline);
return fstab;
}
Fstab* LoadRequiredFstab(void)
{
Fstab *fstab = NULL;
......
......@@ -23,7 +23,6 @@
extern "C" {
#endif
#endif
#define PARTITION_NAME_SIZE 32
Fstab* LoadRequiredFstab(void);
int MountRequriedPartitions(const Fstab *fstab);
#ifdef __cplusplus
......
......@@ -120,6 +120,8 @@ INIT_LOCAL_API int LoadParamFromCmdLine(void)
},
{OHOS_BOOT"reboot_reason", CommonDealFun
},
{OHOS_BOOT"bootslots", CommonDealFun
},
{OHOS_BOOT"sn", SnDealFun
}
};
......
......@@ -182,7 +182,8 @@ static void HandleRequiredBlockDeviceNodes(const struct Uevent *uevent, char **d
INIT_LOGI("%s match with required partition %s success, now handle it", uevent->syspath, deviceName);
HandleBlockDeviceEvent(uevent);
return;
} else if (strstr(devices[i], uevent->partitionName) != NULL) {
} else if (strstr(devices[i], uevent->partitionName) != NULL ||
strstr(uevent->partitionName, "vendor") != NULL || strstr(uevent->partitionName, "system") != NULL) {
INIT_LOGI("Handle required partitionName %s", uevent->partitionName);
HandleBlockDeviceEvent(uevent);
return;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册