• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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