* Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
* 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 "u_mount.h"
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include "securec.h"
#include "basic.h"
#include "utils.h"
#include "options.h"
#include "logger.h"
STATIC bool CheckSrcFile(const char *src)
{
struct stat fileStat;
if (lstat(src, &fileStat) != 0) {
return false;
}
if ((S_ISREG(fileStat.st_mode) != 0) || (S_ISDIR(fileStat.st_mode) != 0)) {
const size_t maxFileSzieMb = 10 * 1024;
if (!CheckExternalFile(src, strlen(src), maxFileSzieMb, false)) {
char* str = FormatLogMessage("failed to mount src: %s.", src);
Logger(str, LEVEL_ERROR, SCREEN_YES);
free(str);
str = NULL;
return false;
}
}
if (S_ISDIR(fileStat.st_mode) != 0) {
if (!GetFileSubsetAndCheck(src, strlen(src))) {
char* str = FormatLogMessage("Check file subset failed: %s.", src);
Logger(str, LEVEL_ERROR, SCREEN_YES);
free(str);
str = NULL;
return false;
}
}
return true;
}
int Mount(const char *src, const char *dst)
{
if (src == NULL || dst == NULL) {
Logger("src pointer or dst pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
static const unsigned long MOUNT_FLAGS = MS_BIND;
static const unsigned long REMOUNT_FLAGS = MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID;
if (!CheckSrcFile(src)) {
return -1;
}
int ret = mount(src, dst, NULL, MOUNT_FLAGS, NULL);
if (ret < 0) {
Logger("failed to mount src.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
ret = mount(NULL, dst, NULL, REMOUNT_FLAGS, NULL);
if (ret < 0) {
Logger("failed to re-mount. dst.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
return 0;
}
STATIC int MountFile(const char *rootfs, const char *filepath)
{
if (rootfs == NULL || filepath == NULL) {
Logger("rootfs, filepath pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
int ret;
char dst[BUF_SIZE] = {0};
ret = sprintf_s(dst, BUF_SIZE, "%s%s", rootfs, filepath);
if (ret < 0) {
Logger("failed to assemble file mounting path.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
struct stat srcStat;
ret = stat(filepath, &srcStat);
if (ret < 0) {
return 0;
}
ret = MakeMountPoints(dst, srcStat.st_mode);
if (ret < 0) {
Logger("failed to create mount dst file.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
ret = Mount(filepath, dst);
if (ret < 0) {
Logger("failed to mount dev.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
return 0;
}
int MountDir(const char *rootfs, const char *src)
{
if (rootfs == NULL || src == NULL) {
Logger("rootfs, src pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
int ret;
char dst[BUF_SIZE] = {0};
ret = sprintf_s(dst, BUF_SIZE, "%s%s", rootfs, src);
if (ret < 0) {
return -1;
}
struct stat srcStat;
ret = stat(src, &srcStat);
if (ret < 0) {
return 0;
}
ret = MakeDirWithParent(dst, DEFAULT_DIR_MODE);
if (ret < 0) {
char* str = FormatLogMessage("failed to make dir: %s.", dst);
Logger(str, LEVEL_ERROR, SCREEN_YES);
free(str);
str = NULL;
return -1;
}
ret = Mount(src, dst);
if (ret < 0) {
char* str = FormatLogMessage("failed to mount src dir: %s to dst dir: %s.", src, dst);
Logger(str, LEVEL_ERROR, SCREEN_YES);
free(str);
str = NULL;
return -1;
}
return 0;
}
int DoDirectoryMounting(const char *rootfs, const struct MountList *list)
{
if (rootfs == NULL || list == NULL) {
Logger("rootfs, list pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
int ret;
for (unsigned int i = 0; i < list->count; i++) {
ret = MountDir(rootfs, (const char *)&list->list[i][0]);
if (ret < 0) {
Logger("failed to do directory mounting", LEVEL_ERROR, SCREEN_YES);
return -1;
}
}
return 0;
}
int DoFileMounting(const char *rootfs, const struct MountList *list)
{
if (rootfs == NULL || list == NULL) {
Logger("rootfs, list pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
int ret;
for (unsigned int i = 0; i < list->count; i++) {
ret = MountFile(rootfs, (const char *)&list->list[i][0]);
if (ret < 0) {
Logger("failed to do file mounting for.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
}
return 0;
}
int DoMounting(const struct ParsedConfig *config)
{
if (config == NULL) {
Logger("config pointer is null!", LEVEL_ERROR, SCREEN_YES);
return -1;
}
int ret;
if (IsOptionNoDrvSet()) {
return 0;
}
ret = DoFileMounting(config->rootfs, config->files);
if (ret < 0) {
Logger("failed to mount files.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
ret = DoDirectoryMounting(config->rootfs, config->dirs);
if (ret < 0) {
Logger("failed to do mount directories.", LEVEL_ERROR, SCREEN_YES);
return -1;
}
return 0;
}