1/*
2 * Copyright (c) 2022-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 "utility.h"
17
18#include <grp.h>
19#include <pwd.h>
20#include <unistd.h>
21
22#include <cerrno>
23#include <chrono>
24#include <limits>
25#include <map>
26#include <regex>
27#include <sstream>
28
29#include <sys/stat.h>
30#include <sys/types.h>
31
32#include "parcel.h"
33#include "securec.h"
34
35#include "devicestatus_common.h"
36#include "devicestatus_define.h"
37
38#undef LOG_TAG
39#define LOG_TAG "Utility"
40
41namespace OHOS {
42namespace Msdp {
43namespace DeviceStatus {
44namespace {
45constexpr size_t SUBSTR_ID_LENGTH { 5 };
46constexpr int32_t MULTIPLES { 2 };
47} // namespace
48
49size_t Utility::CopyNulstr(char *dest, size_t size, const char *src)
50{
51    CHKPR(dest, 0);
52    CHKPR(src, 0);
53
54    size_t len = strlen(src);
55    if (len >= size) {
56        if (size > 1) {
57            len = size - 1;
58        } else {
59            len = 0;
60        }
61    }
62    if (len > 0) {
63        errno_t ret = memcpy_s(dest, size, src, len);
64        if (ret != EOK) {
65            FI_HILOGW("memcpy_s:bounds checking failed");
66        }
67    }
68    if (size > 0) {
69        dest[len] = '\0';
70    }
71    return len;
72}
73
74bool Utility::StartWith(const char *str, const char *prefix)
75{
76    size_t prefixlen = strlen(prefix);
77    return (prefixlen > 0 ? (strncmp(str, prefix, strlen(prefix)) == 0) : false);
78}
79
80bool Utility::StartWith(const std::string &str, const std::string &prefix)
81{
82    if (str.size() < prefix.size()) {
83        return false;
84    }
85    return (str.compare(0, prefix.size(), prefix) == 0);
86}
87
88void Utility::RemoveTrailingChars(char c, char *path)
89{
90    CHKPV(path);
91    size_t len = strlen(path);
92    while (len > 0 && path[len-1] == c) {
93        path[--len] = '\0';
94    }
95}
96
97void Utility::RemoveTrailingChars(const std::string &toRemoved, std::string &path)
98{
99    while (!path.empty() && (toRemoved.find(path.back()) != std::string::npos)) {
100        path.pop_back();
101    }
102}
103
104void Utility::RemoveSpace(std::string &str)
105{
106    str.erase(remove_if(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c);}), str.end());
107}
108
109bool Utility::IsInteger(const std::string &target)
110{
111    std::regex pattern("^\\s*-?(0|([1-9]\\d*))\\s*$");
112    return std::regex_match(target, pattern);
113}
114
115std::string Utility::Anonymize(const char* id)
116{
117    if (id == nullptr) {
118        return std::string(MULTIPLES * SUBSTR_ID_LENGTH, '*');
119    }
120    std::string idStr(id);
121    if (idStr.empty() || idStr.length() < SUBSTR_ID_LENGTH) {
122        return std::string(MULTIPLES * SUBSTR_ID_LENGTH, '*');
123    }
124    return idStr.substr(0, SUBSTR_ID_LENGTH) + std::string(SUBSTR_ID_LENGTH, '*') +
125        idStr.substr(idStr.length() - SUBSTR_ID_LENGTH);
126}
127
128bool Utility::DoesFileExist(const char *path)
129{
130    return (access(path, F_OK) == 0);
131}
132
133ssize_t Utility::GetFileSize(const std::string &filePath)
134{
135    return GetFileSize(filePath.c_str());
136}
137
138ssize_t Utility::GetFileSize(const char *path)
139{
140    struct stat buf {};
141    ssize_t sz { 0 };
142
143    if (stat(path, &buf) == 0) {
144        if (S_ISREG(buf.st_mode)) {
145            sz = buf.st_size;
146        } else {
147            FI_HILOGE("Not regular file:\'%{public}s\'", path);
148        }
149    } else {
150        FI_HILOGE("stat(\'%{public}s\') failed:%{public}s", path, strerror(errno));
151    }
152    return sz;
153}
154
155void Utility::ShowFileAttributes(const char *path)
156{
157    CALL_DEBUG_ENTER;
158    FI_HILOGD("======================= File Attributes ========================");
159    FI_HILOGD("%{public}20s:%{public}s", "FILE NAME", path);
160
161    struct stat buf {};
162    if (stat(path, &buf) != 0) {
163        FI_HILOGE("stat(\'%{public}s\') failed:%{public}s", path, strerror(errno));
164        return;
165    }
166    if (S_ISDIR(buf.st_mode)) {
167        FI_HILOGD("%{public}20s: directory", "TYPE");
168    } else if (S_ISCHR(buf.st_mode)) {
169        FI_HILOGD("%{public}20s: character special file", "TYPE");
170    } else if (S_ISREG(buf.st_mode)) {
171        FI_HILOGD("%{public}20s: regular file", "TYPE");
172    }
173
174    std::ostringstream ss;
175    std::map<mode_t, std::string> modes {{S_IRUSR, "U+R "}, {S_IWUSR, "U+W "}, {S_IXUSR, "U+X "}, {S_IRGRP, "G+R "},
176        {S_IWGRP, "G+W "}, {S_IXGRP, "G+X "}, {S_IROTH, "O+R "}, {S_IWOTH, "O+W "}, {S_IXOTH, "O+X "}};
177    for (const auto &element : modes) {
178        if (buf.st_mode & element.first) {
179            ss << element.second;
180            break;
181        }
182    }
183
184    FI_HILOGD("%{public}20s:%{public}s", "PERMISSIONS", ss.str().c_str());
185}
186
187void Utility::ShowUserAndGroup()
188{
189    CALL_DEBUG_ENTER;
190    static constexpr size_t BUFSIZE { 1024 };
191    char buffer[BUFSIZE];
192    struct passwd buf;
193    struct passwd *pbuf = nullptr;
194    struct group grp;
195    struct group *pgrp = nullptr;
196
197    FI_HILOGD("======================= Users and Groups =======================");
198    uid_t uid = getuid();
199    if (getpwuid_r(uid, &buf, buffer, sizeof(buffer), &pbuf) != 0) {
200        FI_HILOGE("getpwuid_r failed:%{public}s", strerror(errno));
201    } else {
202        FI_HILOGD("%{public}20s:%{public}10u%{public}20s", "USER", uid, buf.pw_name);
203    }
204
205    gid_t gid = getgid();
206    if (getgrgid_r(gid, &grp, buffer, sizeof(buffer), &pgrp) != 0) {
207        FI_HILOGE("getgrgid_r failed:%{public}s", strerror(errno));
208    } else {
209        FI_HILOGD("%{public}20s:%{public}10u%{public}20s", "GROUP", gid, grp.gr_name);
210    }
211
212    uid = geteuid();
213    if (getpwuid_r(uid, &buf, buffer, sizeof(buffer), &pbuf) != 0) {
214        FI_HILOGE("getpwuid_r failed:%{public}s", strerror(errno));
215    } else {
216        FI_HILOGD("%{public}20s:%{public}10u%{public}20s", "EFFECTIVE USER", uid, buf.pw_name);
217    }
218
219    gid = getegid();
220    if (getgrgid_r(gid, &grp, buffer, sizeof(buffer), &pgrp) != 0) {
221        FI_HILOGE("getgrgid_r failed:%{public}s", strerror(errno));
222    } else {
223        FI_HILOGD("%{public}20s:%{public}10u%{public}20s", "EFFECTIVE GROUP", gid, grp.gr_name);
224    }
225
226    gid_t groups[NGROUPS_MAX + 1];
227    int32_t ngrps = getgroups(sizeof(groups), groups);
228    for (int32_t i = 0; i < ngrps; ++i) {
229        if (getgrgid_r(groups[i], &grp, buffer, sizeof(buffer), &pgrp) != 0) {
230            FI_HILOGE("getgrgid_r failed:%{public}s", strerror(errno));
231        } else {
232            FI_HILOGD("%{public}20s:%{public}10u%{public}20s", "SUPPLEMENTARY GROUP", groups[i], grp.gr_name);
233        }
234    }
235}
236
237int64_t Utility::GetSysClockTime()
238{
239    return std::chrono::time_point_cast<std::chrono::microseconds>(
240            std::chrono::steady_clock::now()).time_since_epoch().count();
241}
242} // namespace DeviceStatus
243} // namespace Msdp
244} // namespace OHOS
245