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
16 #include "quota/quota_manager.h"
17
18 #include <cstdint>
19 #include <cstdlib>
20 #include <fstream>
21 #include <sstream>
22 #include <map>
23 #include <linux/quota.h>
24 #include <sys/quota.h>
25 #include <sys/statvfs.h>
26 #include <linux/fs.h>
27 #include <linux/dqblk_xfs.h>
28
29 #include "storage_service_errno.h"
30 #include "storage_service_log.h"
31
32 namespace OHOS {
33 namespace StorageDaemon {
34 const std::string QUOTA_DEVICE_DATA_PATH = "/data";
35 const std::string PROC_MOUNTS_PATH = "/proc/mounts";
36 const std::string DEV_BLOCK_PATH = "/dev/block/";
37 const int32_t DEV_BLOCK_PATH_LEN = DEV_BLOCK_PATH.length();
38 const uint64_t ONE_KB = int64_t(1);
39 const uint64_t ONE_MB = int64_t(1024 * ONE_KB);
40 static std::map<std::string, std::string> mQuotaReverseMounts;
41 std::recursive_mutex mMountsLock;
42
43 QuotaManager* QuotaManager::instance_ = nullptr;
GetInstance()44 QuotaManager* QuotaManager::GetInstance()
45 {
46 if (instance_ == nullptr) {
47 instance_ = new QuotaManager();
48 }
49
50 return instance_;
51 }
52
InitialiseQuotaMounts()53 static bool InitialiseQuotaMounts()
54 {
55 std::lock_guard<std::recursive_mutex> lock(mMountsLock);
56 mQuotaReverseMounts.clear();
57 std::ifstream in(PROC_MOUNTS_PATH);
58
59 if (!in.is_open()) {
60 LOGE("Failed to open mounts file");
61 return false;
62 }
63 std::string source;
64 std::string target;
65 std::string ignored;
66
67 while (!in.eof()) {
68 std::getline(in, source, ' ');
69 std::getline(in, target, ' ');
70 std::getline(in, ignored);
71 if (source.compare(0, DEV_BLOCK_PATH_LEN, DEV_BLOCK_PATH) == 0) {
72 struct dqblk dq;
73 if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, reinterpret_cast<char*>(&dq)) == 0) {
74 mQuotaReverseMounts[target] = source;
75 }
76 }
77 }
78
79 return true;
80 }
81
SetBundleQuota(const std::string & bundleName,int32_t uid,const std::string & bundleDataDirPath,int32_t limitSizeMb)82 int32_t QuotaManager::SetBundleQuota(const std::string &bundleName, int32_t uid,
83 const std::string &bundleDataDirPath, int32_t limitSizeMb)
84 {
85 if (bundleName.empty() || bundleDataDirPath.empty() || uid < 0 || limitSizeMb <= 0) {
86 LOGE("Calling the function PrepareBundleDirQuotaWithSize with invalid param");
87 return E_NON_EXIST;
88 }
89
90 if (InitialiseQuotaMounts() != true) {
91 LOGE("Failed to initialise quota mounts");
92 return E_NON_EXIST;
93 }
94
95 std::string device = "";
96 if (bundleDataDirPath.find(QUOTA_DEVICE_DATA_PATH) == 0) {
97 device = mQuotaReverseMounts[QUOTA_DEVICE_DATA_PATH];
98 }
99 if (device.empty()) {
100 LOGE("skip when device no quotas present");
101 return E_OK;
102 }
103
104 struct dqblk dq;
105 if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) {
106 LOGE("Failed to get hard quota, errno : %{public}d", errno);
107 return E_SYS_CALL;
108 }
109
110 // dqb_bhardlimit is count of 1kB blocks, dqb_curspace is bytes
111 struct statvfs stat;
112 if (statvfs(bundleDataDirPath.c_str(), &stat) != 0) {
113 LOGE("Failed to statvfs, errno : %{public}d", errno);
114 return E_SYS_CALL;
115 }
116
117 dq.dqb_valid = QIF_LIMITS;
118 dq.dqb_bhardlimit = (uint32_t)limitSizeMb * ONE_MB;
119 if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) {
120 LOGE("Failed to set hard quota, errno : %{public}d", errno);
121 return E_SYS_CALL;
122 } else {
123 LOGE("Applied hard quotas ok");
124 return E_OK;
125 }
126 }
127
128 } // StorageDaemon
129 } // OHOS
130