1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <cstdlib>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/mount.h>
21 #include <securec.h>
22 #include <sys/wait.h>
23 
24 #include "log.h"
25 #include "mount.h"
26 
27 using namespace Hdc;
28 
FindMountDeviceByPath(const char *toQuery, char *dev)29 bool FindMountDeviceByPath(const char *toQuery, char *dev)
30 {
31     int ret = false;
32     int len = BUF_SIZE_DEFAULT2;
33     char buf[BUF_SIZE_DEFAULT2];
34 
35     FILE *fp = fopen("/proc/mounts", "r");
36     if (fp == nullptr) {
37         WRITE_LOG(LOG_FATAL, "fopen /proc/mounts error:%d", errno);
38         return false;
39     }
40 
41     while (fgets(buf, len, fp) != nullptr) {
42         char dir[BUF_SIZE_SMALL] = "";
43         int freq;
44         int passnno;
45         int res = 0;
46         // clang-format off
47         res = sscanf_s(buf, "%255s %255s %*s %*s %d %d\n", dev, BUF_SIZE_SMALL - 1,
48                        dir, BUF_SIZE_SMALL - 1, &freq, &passnno);
49         // clang-format on
50         dev[BUF_SIZE_SMALL - 1] = '\0';
51         dir[BUF_SIZE_SMALL - 1] = '\0';
52         if (res == 4 && (strcmp(toQuery, dir) == 0)) {  // 4 : The correct number of parameters
53             WRITE_LOG(LOG_DEBUG, "FindMountDeviceByPath dev:%s dir:%s", dev, dir);
54             ret = true;
55             break;
56         }
57     }
58     int rc = fclose(fp);
59     if (rc != 0) {
60         WRITE_LOG(LOG_WARN, "fclose rc:%d error:%d", rc, errno);
61     }
62     if (!ret) {
63         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath not found %s", toQuery);
64     }
65     return ret;
66 }
67 
RemountPartition(const char *dir)68 bool RemountPartition(const char *dir)
69 {
70     int fd;
71     int off = 0;
72     int ret = 0;
73     char dev[BUF_SIZE_SMALL] = "";
74 
75     if (!FindMountDeviceByPath(dir, dev) || strlen(dev) < 4) {  // 4 : file count
76         WRITE_LOG(LOG_FATAL, "FindMountDeviceByPath dir:%s failed", dir);
77         return false;
78     }
79 
80     if ((fd = open(dev, O_RDONLY | O_CLOEXEC)) < 0) {
81         WRITE_LOG(LOG_FATAL, "open dev:%s failed, error:%d", dev, errno);
82         return false;
83     }
84     ioctl(fd, BLKROSET, &off);
85     close(fd);
86 
87     ret = mount(dev, dir, "none", MS_REMOUNT, nullptr);
88     if (ret < 0) {
89         WRITE_LOG(LOG_FATAL, "mount %s failed, reason is %s", dev, strerror(errno));
90         return false;
91     }
92     return true;
93 }
94 
RemountDevice()95 bool RemountDevice()
96 {
97     if (getuid() != 0) {
98         return false;
99     }
100     struct stat info;
101     if (!lstat("/vendor", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
102         if (!RemountPartition("/vendor")) {
103             WRITE_LOG(LOG_FATAL, "Mount failed /vendor (via mount)");
104         }
105     }
106     if (!lstat("/system", &info) && (info.st_mode & S_IFMT) == S_IFDIR) {
107         if (!RemountPartition("/")) {
108             WRITE_LOG(LOG_FATAL, "Mount failed /system (via mount)");
109         }
110     }
111 
112     int exitStatus = system("/bin/remount");
113     if (exitStatus == -1) {
114         WRITE_LOG(LOG_FATAL, "Failed to execute /bin/remount: %s", strerror(errno));
115         return false;
116     } else if (WIFEXITED(exitStatus) && WEXITSTATUS(exitStatus) != 0) {
117         WRITE_LOG(LOG_FATAL, "Remount failed with exit code: %d", WEXITSTATUS(exitStatus));
118         return false;
119     }
120     return true;
121 }