1/*
2 * Copyright (c) 2022 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 "js_process.h"
17
18#include <cstdlib>
19#include <vector>
20
21#include <grp.h>
22#include <mutex>
23#include <pthread.h>
24#include <pwd.h>
25#include <sched.h>
26#include <unistd.h>
27#include <uv.h>
28
29#include <sys/resource.h>
30#include <sys/syscall.h>
31#include <sys/types.h>
32
33#include "securec.h"
34#include "process_helper.h"
35#include "tools/log.h"
36namespace OHOS::JsSysModule::Process {
37
38    using namespace Commonlibrary::Platform;
39    namespace {
40        constexpr int NUM_OF_DATA = 4;
41        constexpr int PER_USER_RANGE = 100000;
42        constexpr int32_t NAPI_RETURN_ZERO = 0;
43        constexpr int32_t NAPI_RETURN_ONE = 1;
44    }
45    constexpr int FIRST_APPLICATION_UID = 10000; // 10000 : bundleId lower limit
46    constexpr int LAST_APPLICATION_UID = 65535; // 65535 : bundleId upper limit
47    thread_local std::multimap<std::string, napi_ref> eventMap;
48    static std::mutex g_sharedTimedMutex;
49    thread_local std::map<napi_ref, napi_ref> pendingUnHandledRejections;
50    // support g_events
51    thread_local std::string g_events = "UnHandleRejection";
52
53    napi_value Process::GetUid(napi_env env) const
54    {
55        napi_value result = nullptr;
56        auto processGetuid = static_cast<uint32_t>(getuid());
57        NAPI_CALL(env, napi_create_uint32(env, processGetuid, &result));
58        return result;
59    }
60
61    napi_value Process::GetGid(napi_env env) const
62    {
63        napi_value result = nullptr;
64        auto processGetgid = static_cast<uint32_t>(getgid());
65        NAPI_CALL(env, napi_create_uint32(env, processGetgid, &result));
66        return result;
67    }
68
69    napi_value Process::GetEUid(napi_env env) const
70    {
71        napi_value result = nullptr;
72        auto processGeteuid = static_cast<uint32_t>(geteuid());
73        NAPI_CALL(env, napi_create_uint32(env, processGeteuid, &result));
74        return result;
75    }
76
77    napi_value Process::GetEGid(napi_env env) const
78    {
79        napi_value result = nullptr;
80        auto processGetegid = static_cast<uint32_t>(getegid());
81        NAPI_CALL(env, napi_create_uint32(env, processGetegid, &result));
82        return result;
83    }
84
85    napi_value Process::GetGroups(napi_env env) const
86    {
87        napi_value result = nullptr;
88        int progroups = getgroups(0, nullptr);
89        if (progroups == -1) {
90            napi_throw_error(env, "-1", "getgroups initialize failed");
91            return nullptr;
92        }
93        std::vector<gid_t> pgrous(progroups);
94        progroups = getgroups(progroups, pgrous.data());
95        if (progroups == -1) {
96            napi_throw_error(env, "-1", "getgroups");
97            return nullptr;
98        }
99        pgrous.resize(static_cast<size_t>(progroups));
100        gid_t proegid = getegid();
101        if (std::find(pgrous.begin(), pgrous.end(), proegid) == pgrous.end()) {
102            pgrous.push_back(proegid);
103        }
104        std::vector<uint32_t> array;
105        for (auto iter = pgrous.begin(); iter != pgrous.end(); iter++) {
106            auto receive = static_cast<uint32_t>(*iter);
107            array.push_back(receive);
108        }
109        NAPI_CALL(env, napi_create_array(env, &result));
110        size_t len = array.size();
111        for (size_t i = 0; i < len; i++) {
112            napi_value numvalue = nullptr;
113            NAPI_CALL(env, napi_create_uint32(env, array[i], &numvalue));
114            NAPI_CALL(env, napi_set_element(env, result, i, numvalue));
115        }
116        return result;
117    }
118
119    napi_value Process::GetPid(napi_env env) const
120    {
121        napi_value result = nullptr;
122        auto proPid = static_cast<int32_t>(getpid());
123        napi_create_int32(env, proPid, &result);
124        return result;
125    }
126
127    napi_value Process::GetPpid(napi_env env) const
128    {
129        napi_value result = nullptr;
130        auto proPpid = static_cast<int32_t>(getppid());
131        napi_create_int32(env, proPpid, &result);
132        return result;
133    }
134
135    void Process::Chdir(napi_env env, napi_value args) const
136    {
137        size_t prolen = 0;
138        if (napi_get_value_string_utf8(env, args, nullptr, 0, &prolen) != napi_ok) {
139            HILOG_ERROR("can not get args size");
140            return;
141        }
142        std::string result = "";
143        result.reserve(prolen + 1);
144        result.resize(prolen);
145        if (napi_get_value_string_utf8(env, args, result.data(), prolen + 1, &prolen) != napi_ok) {
146            HILOG_ERROR("can not get args value");
147            return;
148        }
149        int proerr = 0;
150        proerr = uv_chdir(result.c_str());
151        if (proerr) {
152            napi_throw_error(env, "-1", "chdir");
153            return;
154        }
155    }
156
157    napi_value Process::Kill(napi_env env, napi_value signal, napi_value proid)
158    {
159        int32_t pid = 0;
160        int32_t sig = 0;
161        napi_get_value_int32(env, proid, &pid);
162        napi_get_value_int32(env, signal, &sig);
163        uv_pid_t ownPid = uv_os_getpid();
164        // 64:The maximum valid signal value is 64.
165        if (sig > 64 && (!pid || pid == -1 || pid == ownPid || pid == -ownPid)) {
166            napi_throw_error(env, "0", "process exit");
167            return nullptr;
168        }
169        bool flag = false;
170        int err = uv_kill(pid, sig);
171        if (!err) {
172            flag = true;
173        }
174        napi_value result = nullptr;
175        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
176        return result;
177    }
178
179    napi_value Process::Uptime(napi_env env) const
180    {
181        napi_value result = nullptr;
182        double runsystime = 0.0;
183        auto systimer = GetSysTimer();
184        if (systimer > 0) {
185            runsystime = static_cast<double>(systimer);
186            NAPI_CALL(env, napi_create_double(env, runsystime, &result));
187        } else {
188            napi_throw_error(env, "-1", "Failed to get systimer");
189            return nullptr;
190        }
191        return result;
192    }
193
194    void Process::Exit(napi_env env, napi_value number) const
195    {
196        int32_t result = 0;
197        napi_get_value_int32(env, number, &result);
198        ProcessExit(result);
199    }
200
201    napi_value Process::Cwd(napi_env env) const
202    {
203        napi_value result = nullptr;
204        char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
205        size_t length = sizeof(buf);
206        int err = uv_cwd(buf, &length);
207        if (err) {
208            napi_throw_error(env, "1", "uv_cwd");
209            return nullptr;
210        }
211        napi_create_string_utf8(env, buf, length, &result);
212        return result;
213    }
214
215    void Process::Abort() const
216    {
217        std::abort();
218    }
219
220    void Process::On(napi_env env, napi_value str, napi_value function)
221    {
222        std::string result = "";
223        size_t bufferSize = 0;
224        if (napi_get_value_string_utf8(env, str, nullptr, NAPI_RETURN_ZERO, &bufferSize) != napi_ok) {
225            HILOG_ERROR("can not get str size");
226            return;
227        }
228        result.reserve(bufferSize + NAPI_RETURN_ONE);
229        result.resize(bufferSize);
230        if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + NAPI_RETURN_ONE,
231                                       &bufferSize) != napi_ok) {
232            HILOG_ERROR("can not get str value");
233            return;
234        }
235        if (function == nullptr) {
236            HILOG_ERROR("function is nullptr");
237            return;
238        }
239        napi_ref myCallRef = nullptr;
240        napi_status status = napi_create_reference(env, function, 1, &myCallRef);
241        if (status != napi_ok) {
242            HILOG_ERROR("napi_create_reference is failed");
243            return;
244        }
245        if (!result.empty()) {
246            size_t pos = g_events.find(result);
247            if (pos == std::string::npos) {
248                HILOG_ERROR("illegal event");
249                return;
250            }
251            std::unique_lock<std::mutex> lock(g_sharedTimedMutex);
252            eventMap.insert(std::make_pair(result, myCallRef));
253        }
254    }
255
256    napi_value Process::Off(napi_env env, napi_value str)
257    {
258        size_t bufferSize = 0;
259        bool flag = false;
260        if (napi_get_value_string_utf8(env, str, nullptr, 0, &bufferSize) != napi_ok) {
261            HILOG_ERROR("can not get str size");
262            return nullptr;
263        }
264        std::string result = "";
265        result.reserve(bufferSize + 1);
266        result.resize(bufferSize);
267        if (napi_get_value_string_utf8(env, str, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
268            HILOG_ERROR("can not get str value");
269            return nullptr;
270        }
271        std::string temp = "";
272        temp = result;
273        auto iter = eventMap.equal_range(temp);
274        while (iter.first != iter.second) {
275            NAPI_CALL(env, napi_delete_reference(env, iter.first->second));
276            std::unique_lock<std::mutex> lock(g_sharedTimedMutex);
277            iter.first = eventMap.erase(iter.first);
278            flag = true;
279        }
280        napi_value convertResult = nullptr;
281        NAPI_CALL(env, napi_get_boolean(env, flag, &convertResult));
282        return convertResult;
283    }
284
285    napi_value Process::GetTid(napi_env env) const
286    {
287        napi_value result = nullptr;
288        auto proTid = static_cast<int32_t>(GetThreadId());
289        napi_create_int64(env, proTid, &result);
290        return result;
291    }
292
293    napi_value Process::IsIsolatedProcess(napi_env env) const
294    {
295        napi_value result = nullptr;
296        bool flag = true;
297        auto prouid = static_cast<int32_t>(getuid());
298        auto uid = prouid % PER_USER_RANGE;
299        if ((uid >= 99000 && uid <= 99999) || // 99999:Only isolateuid numbers between 99000 and 99999.
300            (uid >= 9000 && uid <= 98999)) { // 98999:Only appuid numbers between 9000 and 98999.
301            NAPI_CALL(env, napi_get_boolean(env, flag, &result));
302            return result;
303        }
304        flag = false;
305        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
306        return result;
307    }
308
309    napi_value Process::IsAppUid(napi_env env, napi_value uid) const
310    {
311        int32_t number = 0;
312        napi_value result = nullptr;
313        bool flag = true;
314        napi_get_value_int32(env, uid, &number);
315        if (number > 0) {
316            const auto appId = number % PER_USER_RANGE;
317            if (appId >= FIRST_APPLICATION_UID && appId <= LAST_APPLICATION_UID) {
318                napi_get_boolean(env, flag, &result);
319                return result;
320            }
321        }
322        flag = false;
323        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
324        return result;
325    }
326
327    napi_value Process::Is64Bit(napi_env env) const
328    {
329        napi_value result = nullptr;
330        bool flag = true;
331        auto size = sizeof(char*);
332        flag = (size == NUM_OF_DATA) ? false : true;
333        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
334        return result;
335    }
336
337    napi_value Process::GetEnvironmentVar(napi_env env, napi_value name) const
338    {
339        napi_value convertResult = nullptr;
340        char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
341        size_t length = sizeof(buf);
342        size_t bufferSize = 0;
343        if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
344            HILOG_ERROR("can not get name size");
345            return nullptr;
346        }
347        std::string result = "";
348        result.reserve(bufferSize + 1);
349        result.resize(bufferSize);
350        if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
351            HILOG_ERROR("can not get name value");
352            return nullptr;
353        }
354        std::string temp = "";
355        temp = result;
356        auto envNum = uv_os_getenv(temp.c_str(), buf, &length);
357        if (envNum == UV_ENOENT) {
358            NAPI_CALL(env, napi_get_undefined(env, &convertResult));
359            return convertResult;
360        }
361        napi_create_string_utf8(env, buf, strlen(buf), &convertResult);
362        return convertResult;
363    }
364
365    napi_value Process::GetUidForName(napi_env env, napi_value name) const
366    {
367        napi_value convertResult = nullptr;
368        size_t bufferSize = 0;
369        if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
370            HILOG_ERROR("can not get name size");
371            return nullptr;
372        }
373        std::string result = "";
374        result.reserve(bufferSize + 1);
375        result.resize(bufferSize);
376        if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
377            HILOG_ERROR("can not get name value");
378            return nullptr;
379        }
380        struct passwd user;
381        int32_t uid = 0;
382        struct passwd *bufp = nullptr;
383        long bufLen = sysconf(_SC_GETPW_R_SIZE_MAX);
384        if (bufLen == -1) {
385            bufLen = 16384; // 16384:Should be more than enough
386        }
387
388        std::string buf;
389        buf.reserve(bufLen + 1);
390        buf.resize(bufLen);
391        if (getpwnam_r(result.c_str(), &user, buf.data(), bufLen, &bufp) == 0 && bufp != nullptr) {
392            uid = static_cast<int32_t>(bufp->pw_uid);
393            napi_create_int32(env, uid, &convertResult);
394            return convertResult;
395        }
396        napi_create_int32(env, (-1), &convertResult);
397        return convertResult;
398    }
399
400    napi_value Process::GetThreadPriority(napi_env env, napi_value tid) const
401    {
402        errno = 0;
403        napi_value result = nullptr;
404        int32_t proTid = 0;
405        napi_get_value_int32(env, tid, &proTid);
406        int32_t pri = getpriority(PRIO_PROCESS, proTid);
407        if (errno) {
408            napi_throw_error(env, "-1", "Invalid tid");
409            return nullptr;
410        }
411        napi_create_int32(env, pri, &result);
412        return result;
413    }
414
415    napi_value Process::GetStartRealtime(napi_env env) const
416    {
417        napi_value result = nullptr;
418        double startRealtime = GetProcessStartRealtime();
419        napi_create_double(env, startRealtime, &result);
420        return result;
421    }
422
423    int Process::ConvertTime(time_t tvsec, int64_t tvnsec) const
424    {
425        return int(tvsec * 1000) + int(tvnsec / 1000000); // 98999:Only converttime numbers is 1000 and 1000000.
426    }
427
428    napi_value Process::GetPastCputime(napi_env env) const
429    {
430        struct timespec times = {0, 0};
431        napi_value result = nullptr;
432        auto res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &times);
433        if (res) {
434            return 0;
435        }
436        int when =  ConvertTime(times.tv_sec, times.tv_nsec);
437        napi_create_int32(env, when, &result);
438        return result;
439    }
440
441    napi_value Process::GetSystemConfig(napi_env env, napi_value name) const
442    {
443        int32_t number = 0;
444        napi_value result = nullptr;
445        napi_get_value_int32(env, name, &number);
446        auto configinfo = static_cast<int32_t>(sysconf(number));
447        napi_create_int32(env, configinfo, &result);
448        return result;
449    }
450
451    void Process::ClearReference(napi_env env)
452    {
453        auto iter = eventMap.begin();
454        while (iter != eventMap.end()) {
455            napi_status status = napi_delete_reference(env, iter->second);
456            if (status != napi_ok) {
457                napi_throw_error(env, nullptr, "ClearReference failed");
458                return;
459            }
460            iter++;
461        }
462        eventMap.clear();
463    }
464
465    napi_value ProcessManager::IsAppUid(napi_env env, napi_value uid) const
466    {
467        int32_t number = 0;
468        napi_value result = nullptr;
469        bool flag = true;
470        napi_get_value_int32(env, uid, &number);
471        if (number > 0) {
472            const auto appId = number % PER_USER_RANGE;
473            if (appId >= FIRST_APPLICATION_UID && appId <= LAST_APPLICATION_UID) {
474                napi_get_boolean(env, flag, &result);
475                return result;
476            }
477        }
478        flag = false;
479        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
480        return result;
481    }
482
483    napi_value ProcessManager::GetUidForName(napi_env env, napi_value name) const
484    {
485        napi_value convertResult = nullptr;
486        size_t bufferSize = 0;
487        if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
488            HILOG_ERROR("can not get name size");
489            return nullptr;
490        }
491        std::string result = "";
492        result.reserve(bufferSize + 1);
493        result.resize(bufferSize);
494        if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
495            HILOG_ERROR("can not get name value");
496            return nullptr;
497        }
498        struct passwd user;
499        int32_t uid = 0;
500        struct passwd *bufp = nullptr;
501        long bufLen = sysconf(_SC_GETPW_R_SIZE_MAX);
502        if (bufLen == -1) {
503            bufLen = 16384; // 16384:Should be more than enough
504        }
505
506        std::string buf;
507        buf.reserve(bufLen + 1);
508        buf.resize(bufLen);
509        if (getpwnam_r(result.c_str(), &user, buf.data(), bufLen, &bufp) == 0 && bufp != nullptr) {
510            uid = static_cast<int32_t>(bufp->pw_uid);
511            napi_create_int32(env, uid, &convertResult);
512            return convertResult;
513        }
514        napi_create_int32(env, (-1), &convertResult);
515        return convertResult;
516    }
517
518    napi_value ProcessManager::GetThreadPriority(napi_env env, napi_value tid) const
519    {
520        errno = 0;
521        napi_value result = nullptr;
522        int32_t proTid = 0;
523        napi_get_value_int32(env, tid, &proTid);
524        int32_t pri = GetThreadPRY(proTid);
525        if (errno) {
526            napi_throw_error(env, "401", "Parameter error. The type of Parameter must be number and a valid tid.");
527            return nullptr;
528        }
529        napi_create_int32(env, pri, &result);
530        return result;
531    }
532
533    napi_value ProcessManager::GetSystemConfig(napi_env env, napi_value name) const
534    {
535        int32_t number = 0;
536        napi_value result = nullptr;
537        napi_get_value_int32(env, name, &number);
538        int32_t configinfo = GetSysConfig(number);
539        napi_create_int32(env, configinfo, &result);
540        return result;
541    }
542
543    napi_value ProcessManager::GetEnvironmentVar(napi_env env, napi_value name) const
544    {
545        size_t bufferSize = 0;
546        if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
547            HILOG_ERROR("can not get name size");
548            return nullptr;
549        }
550        std::string result = "";
551        result.reserve(bufferSize + 1);
552        result.resize(bufferSize);
553        if (napi_get_value_string_utf8(env, name, result.data(), bufferSize + 1, &bufferSize) != napi_ok) {
554            HILOG_ERROR("can not get name value");
555            return nullptr;
556        }
557        std::string temp = "";
558        temp = result;
559        char buf[260 * NUM_OF_DATA] = { 0 }; // 260:Only numbers path String size is 260.
560        size_t length = sizeof(buf);
561        auto envNum = uv_os_getenv(temp.c_str(), buf, &length);
562        napi_value convertResult = nullptr;
563        if (envNum == UV_ENOENT) {
564            NAPI_CALL(env, napi_get_undefined(env, &convertResult));
565            return convertResult;
566        }
567        napi_create_string_utf8(env, buf, strlen(buf), &convertResult);
568        return convertResult;
569    }
570
571    void ProcessManager::Exit(napi_env env, napi_value number) const
572    {
573        int32_t result = 0;
574        napi_get_value_int32(env, number, &result);
575        ProcessExit(result);
576    }
577
578    napi_value ProcessManager::Kill(napi_env env, napi_value signal, napi_value proid)
579    {
580        int32_t pid = 0;
581        int32_t sig = 0;
582        napi_get_value_int32(env, proid, &pid);
583        napi_get_value_int32(env, signal, &sig);
584        uv_pid_t ownPid = uv_os_getpid();
585        // 64:The maximum valid signal value is 64.
586        if (sig > 64 && (!pid || pid == -1 || pid == ownPid || pid == -ownPid)) {
587            napi_throw_error(env, "401", "Parameter error. The type of signal must be number,and from 1 to 64.");
588            return nullptr;
589        }
590        bool flag = false;
591        int err = uv_kill(pid, sig);
592        if (!err) {
593            flag = true;
594        }
595        napi_value result = nullptr;
596        NAPI_CALL(env, napi_get_boolean(env, flag, &result));
597        return result;
598    }
599} // namespace OHOS::JsSysModule::Process
600