xref: /base/startup/init/services/utils/init_utils.c (revision d9f0492f)
1/*
2 * Copyright (c) 2021 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 "init_utils.h"
16
17#include <ctype.h>
18#include <errno.h>
19#include <dirent.h>
20#include <fcntl.h>
21#include <grp.h>
22#include <limits.h>
23#include <pwd.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/ioctl.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <time.h>
30
31#include "init_log.h"
32#include "securec.h"
33#include "service_control.h"
34
35#define MAX_BUF_SIZE  1024
36#define MAX_SMALL_BUFFER 4096
37
38#define MAX_JSON_FILE_LEN 102400    // max init.cfg size 100KB
39#define CONVERT_MICROSEC_TO_SEC(x) ((x) / 1000 / 1000.0)
40#ifndef DT_DIR
41#define DT_DIR 4
42#endif
43
44#define THOUSAND_UNIT_INT 1000
45#define THOUSAND_UNIT_FLOAT 1000.0
46
47float ConvertMicrosecondToSecond(int x)
48{
49    return ((x / THOUSAND_UNIT_INT) / THOUSAND_UNIT_FLOAT);
50}
51
52#ifndef __LITEOS_M__
53static bool CheckDigit(const char *name)
54{
55    size_t nameLen = strlen(name);
56    for (size_t i = 0; i < nameLen; ++i) {
57        if (!isdigit(name[i])) {
58            return false;
59        }
60    }
61    return true;
62}
63#endif
64
65int StringToUint(const char *name, unsigned int *value)
66{
67    errno = 0;
68    *value = (unsigned int)strtoul(name, 0, DECIMAL_BASE);
69    INIT_CHECK_RETURN_VALUE(errno == 0, -1);
70    return 0;
71}
72
73uid_t DecodeUid(const char *name)
74{
75#ifndef __LITEOS_M__
76    INIT_CHECK_RETURN_VALUE(name != NULL, -1);
77    uid_t uid = -1;
78    if (CheckDigit(name)) {
79        if (!StringToUint(name, &uid)) {
80            return uid;
81        } else {
82            return -1;
83        }
84    }
85    struct passwd *p = getpwnam(name);
86    if (p == NULL) {
87        return -1;
88    }
89    return p->pw_uid;
90#else
91    (void)name;
92    return -1;
93#endif
94}
95
96gid_t DecodeGid(const char *name)
97{
98#ifndef __LITEOS_M__
99    INIT_CHECK_RETURN_VALUE(name != NULL, -1);
100    gid_t gid = -1;
101    if (CheckDigit(name)) {
102        if (!StringToUint(name, &gid)) {
103            return gid;
104        } else {
105            return -1;
106        }
107    }
108    struct group *data = getgrnam(name);
109    if (data != NULL) {
110        return data->gr_gid;
111    }
112    while ((data = getgrent()) != NULL) {
113        if ((data->gr_name != NULL) && (strcmp(data->gr_name, name) == 0)) {
114            gid = data->gr_gid;
115            break;
116        }
117    }
118    endgrent();
119    return gid;
120#else
121    (void)name;
122    return -1;
123#endif
124}
125
126char *ReadFileToBuf(const char *configFile)
127{
128    char *buffer = NULL;
129    FILE *fd = NULL;
130    struct stat fileStat = {0};
131    INIT_CHECK_RETURN_VALUE(configFile != NULL && *configFile != '\0', NULL);
132    do {
133        if (stat(configFile, &fileStat) != 0 ||
134            fileStat.st_size <= 0 || fileStat.st_size > MAX_JSON_FILE_LEN) {
135            break;
136        }
137        fd = fopen(configFile, "r");
138        if (fd == NULL) {
139            INIT_LOGE("Open %s failed. err = %d", configFile, errno);
140            break;
141        }
142        buffer = (char*)calloc((size_t)(fileStat.st_size + 1), sizeof(char));
143        if (buffer == NULL) {
144            INIT_LOGE("Failed to allocate memory for config file, err = %d", errno);
145            break;
146        }
147
148        if (fread(buffer, fileStat.st_size, 1, fd) != 1) {
149            free(buffer);
150            buffer = NULL;
151            break;
152        }
153        buffer[fileStat.st_size] = '\0';
154    } while (0);
155
156    if (fd != NULL) {
157        (void)fclose(fd);
158        fd = NULL;
159    }
160    return buffer;
161}
162
163void CloseStdio(void)
164{
165#ifndef STARTUP_INIT_TEST
166#ifndef __LITEOS_M__
167    int fd = open("/dev/null", O_RDWR);
168    if (fd < 0) {
169        return;
170    }
171    dup2(fd, 0);
172    dup2(fd, 1);
173    dup2(fd, STDERR_HANDLE);
174    if (fd > STDERR_HANDLE) {
175        close(fd);
176    }
177#endif
178#endif
179}
180
181char *ReadFileData(const char *fileName)
182{
183    if (fileName == NULL) {
184        return NULL;
185    }
186    char *buffer = NULL;
187    int fd = -1;
188    fd = open(fileName, O_RDONLY);
189    INIT_ERROR_CHECK(fd >= 0, return NULL, "Failed to read file %s errno:%d", fileName, errno);
190    buffer = (char *)calloc(1, MAX_SMALL_BUFFER); // fsmanager not create, can not get fileStat st_size
191    INIT_ERROR_CHECK(buffer != NULL, close(fd);
192        return NULL, "Failed to allocate memory for %s", fileName);
193    ssize_t readLen = read(fd, buffer, MAX_SMALL_BUFFER - 1);
194    INIT_ERROR_CHECK((readLen > 0) && (readLen <= (MAX_SMALL_BUFFER - 1)), close(fd);
195        free(buffer);
196        return NULL, "Failed to read data for %s", fileName);
197    buffer[readLen] = '\0';
198    if (fd != -1) {
199        close(fd);
200    }
201    return buffer;
202}
203
204int IterateNameValuePairs(const char *src, void (*iterator)(const NAME_VALUE_PAIR *nv, void *context), void *context)
205{
206    int cnt = 0;
207    const char *seperator;
208    const char *tmp = src;
209    NAME_VALUE_PAIR nv;
210    if ((src == NULL) || (iterator == NULL)) {
211        return -1;
212    }
213
214    do {
215        // Find space seperator
216        nv.name = tmp;
217        seperator = strchr(tmp, ' ');
218        if (seperator == NULL) {
219            // Last nv
220            nv.valueEnd = tmp + strlen(tmp);
221            tmp = NULL;
222        } else {
223            nv.valueEnd = seperator;
224            tmp = seperator + 1;
225        }
226
227        // Find equal seperator
228        seperator = strchr(nv.name, '=');
229        if (seperator == NULL) {
230            // Invalid name value pair
231            continue;
232        }
233        if (seperator > nv.valueEnd) {
234            // name without value, just ignore
235            continue;
236        }
237        nv.nameEnd = seperator;
238        nv.value = seperator + 1;
239
240        iterator(&nv, context);
241        cnt += 1;
242    } while (tmp != NULL);
243
244    return cnt;
245}
246
247int GetProcCmdlineValue(const char *name, const char *buffer, char *value, int length)
248{
249    INIT_ERROR_CHECK(name != NULL && buffer != NULL && value != NULL, return -1, "Failed get parameters");
250    char *endData = (char *)buffer + strlen(buffer);
251    char *tmp = strstr(buffer, name);
252    do {
253        if (tmp == NULL) {
254            return -1;
255        }
256        tmp = tmp + strlen(name);
257        while (tmp < endData && *tmp == ' ') {
258            tmp++;
259        }
260        if (tmp >= endData) {
261            return -1;
262        }
263        if (*tmp == '=') {
264            break;
265        }
266        tmp = strstr(tmp + 1, name);
267    } while (tmp < endData);
268    tmp++;
269    size_t i = 0;
270    size_t endIndex = 0;
271    while (tmp < endData && *tmp == ' ') {
272        tmp++;
273    }
274    for (; i < (size_t)length; tmp++) {
275        if (tmp >= endData || *tmp == ' ' || *tmp == '\n' || *tmp == '\r' || *tmp == '\t') {
276            endIndex = i;
277            break;
278        }
279        if (*tmp == '=') {
280            if (endIndex != 0) { // for root=uuid=xxxx
281                break;
282            }
283            i = 0;
284            endIndex = 0;
285            continue;
286        }
287        value[i++] = *tmp;
288    }
289    if (i >= (size_t)length) {
290        return -1;
291    }
292    value[endIndex] = '\0';
293    return 0;
294}
295
296int SplitString(char *srcPtr, const char *del, char **dstPtr, int maxNum)
297{
298    INIT_CHECK_RETURN_VALUE(srcPtr != NULL && dstPtr != NULL && del != NULL, -1);
299    char *buf = NULL;
300    dstPtr[0] = strtok_r(srcPtr, del, &buf);
301    int counter = 0;
302    while ((counter < maxNum) && (dstPtr[counter] != NULL)) {
303        counter++;
304        if (counter >= maxNum) {
305            break;
306        }
307        dstPtr[counter] = strtok_r(NULL, del, &buf);
308    }
309    return counter;
310}
311
312void FreeStringVector(char **vector, int count)
313{
314    if (vector != NULL) {
315        for (int i = 0; i < count; i++) {
316            if (vector[i] != NULL) {
317                free(vector[i]);
318            }
319        }
320        free(vector);
321    }
322}
323
324char **SplitStringExt(char *buffer, const char *del, int *returnCount, int maxItemCount)
325{
326    INIT_CHECK_RETURN_VALUE((maxItemCount >= 0) && (buffer != NULL) && (del != NULL) && (returnCount != NULL), NULL);
327    // Why is this number?
328    // Now we use this function to split a string with a given delimiter
329    // We do not know how many sub-strings out there after splitting.
330    // 50 is just a guess value.
331    const int defaultItemCounts = 50;
332    int itemCounts = maxItemCount;
333
334    if (maxItemCount > defaultItemCounts) {
335        itemCounts = defaultItemCounts;
336    }
337    char **items = (char **)malloc(sizeof(char*) * itemCounts);
338    INIT_ERROR_CHECK(items != NULL, return NULL, "No enough memory to store items");
339    char *rest = NULL;
340    char *p = strtok_r(buffer, del, &rest);
341    int count = 0;
342    while (p != NULL) {
343        if (count > itemCounts - 1) {
344            itemCounts += (itemCounts / 2) + 1; // 2 Request to increase the original memory by half.
345            INIT_LOGV("Too many items,expand size");
346            char **expand = (char **)(realloc(items, sizeof(char *) * itemCounts));
347            INIT_ERROR_CHECK(expand != NULL, FreeStringVector(items, count);
348                return NULL, "Failed to expand memory");
349            items = expand;
350        }
351        size_t len = strlen(p);
352        items[count] = (char *)calloc(len + 1, sizeof(char));
353        INIT_CHECK(items[count] != NULL, FreeStringVector(items, count);
354            return NULL);
355        if (strncpy_s(items[count], len + 1, p, len) != EOK) {
356            INIT_LOGE("Copy string failed");
357            FreeStringVector(items, count);
358            return NULL;
359        }
360        count++;
361        p = strtok_r(NULL, del, &rest);
362    }
363    *returnCount = count;
364    return items;
365}
366
367long long InitDiffTime(INIT_TIMING_STAT *stat)
368{
369    long long diff = (long long)(stat->endTime.tv_sec - stat->startTime.tv_sec) * 1000000; // 1000000 1000ms
370    if (stat->endTime.tv_nsec > stat->startTime.tv_nsec) {
371        diff += (stat->endTime.tv_nsec - stat->startTime.tv_nsec) / BASE_MS_UNIT;
372    } else {
373        diff -= (stat->startTime.tv_nsec - stat->endTime.tv_nsec) / BASE_MS_UNIT;
374    }
375    return diff;
376}
377
378void WaitForFile(const char *source, unsigned int maxSecond)
379{
380    INIT_ERROR_CHECK(maxSecond <= WAIT_MAX_SECOND, maxSecond = WAIT_MAX_SECOND,
381        "WaitForFile max time is %us", WAIT_MAX_SECOND);
382    struct stat sourceInfo = {0};
383    unsigned int waitTime = 10 * BASE_MS_UNIT; // 10ms
384    long long maxDuration = maxSecond * BASE_MS_UNIT * BASE_MS_UNIT; // 5s
385#ifdef STARTUP_INIT_TEST
386    maxDuration = 0;
387#endif
388    long long duration = 0;
389    INIT_TIMING_STAT cmdTimer;
390    (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.startTime);
391    while ((stat(source, &sourceInfo) < 0) && (errno == ENOENT) && (duration < maxDuration)) {
392        usleep(waitTime);
393        (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.endTime);
394        duration = InitDiffTime(&cmdTimer);
395    }
396    INIT_CHECK_ONLY_ELOG(duration < maxDuration, "wait for file:%s failed after %d second.", source, maxSecond);
397    return;
398}
399
400size_t WriteAll(int fd, const char *buffer, size_t size)
401{
402    INIT_CHECK_RETURN_VALUE(buffer != NULL && fd >= 0 && *buffer != '\0', 0);
403    const char *p = buffer;
404    size_t left = size;
405    ssize_t written;
406    while (left > 0) {
407        do {
408            written = write(fd, p, left);
409        } while (written < 0 && errno == EINTR);
410        if (written < 0) {
411            INIT_LOGE("Failed to write %lu bytes, err = %d", left, errno);
412            break;
413        }
414        p += written;
415        left -= written;
416    }
417    return size - left;
418}
419
420char *GetRealPath(const char *source)
421{
422    INIT_CHECK_RETURN_VALUE(source != NULL, NULL);
423    char *path = realpath(source, NULL);
424    if (path == NULL) {
425        INIT_ERROR_CHECK(errno == ENOENT, return NULL, "Failed to resolve %s real path err=%d", source, errno);
426    }
427    return path;
428}
429
430int MakeDir(const char *dir, mode_t mode)
431{
432    int rc = -1;
433    if (dir == NULL || *dir == '\0') {
434        errno = EINVAL;
435        return rc;
436    }
437    rc = mkdir(dir, mode);
438    INIT_ERROR_CHECK(!(rc < 0 && errno != EEXIST), return rc,
439        "Create directory \" %s \" failed, err = %d", dir, errno);
440    // create dir success or it already exist.
441    return 0;
442}
443
444int MakeDirRecursive(const char *dir, mode_t mode)
445{
446    int rc = -1;
447    char buffer[PATH_MAX] = {0};
448    const char *p = NULL;
449    if (dir == NULL || *dir == '\0') {
450        errno = EINVAL;
451        return rc;
452    }
453    p = dir;
454    char *slash = strchr(dir, '/');
455    while (slash != NULL) {
456        int gap = slash - p;
457        p = slash + 1;
458        if (gap == 0) {
459            slash = strchr(p, '/');
460            continue;
461        }
462        if (gap < 0) { // end with '/'
463            break;
464        }
465        INIT_CHECK_RETURN_VALUE(memcpy_s(buffer, PATH_MAX, dir, p - dir - 1) == 0, -1);
466        rc = MakeDir(buffer, mode);
467        INIT_CHECK_RETURN_VALUE(rc >= 0, rc);
468        slash = strchr(p, '/');
469    }
470    return MakeDir(dir, mode);
471}
472
473void CheckAndCreateDir(const char *fileName)
474{
475#ifndef __LITEOS_M__
476    if (fileName == NULL || *fileName == '\0') {
477        return;
478    }
479    char *path = strndup(fileName, strrchr(fileName, '/') - fileName);
480    if (path == NULL) {
481        return;
482    }
483    if (access(path, F_OK) == 0) {
484        free(path);
485        return;
486    }
487    MakeDirRecursive(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
488    free(path);
489#else
490    (void)fileName;
491#endif
492}
493
494int CheckAndCreatFile(const char *file, mode_t mode)
495{
496    if (access(file, F_OK) == 0) {
497        BEGET_LOGW("File \' %s \' already exist", file);
498        return 0;
499    } else {
500        if (errno == ENOENT) {
501            CheckAndCreateDir(file);
502            int fd = open(file, O_CREAT, mode);
503            if (fd < 0) {
504                BEGET_LOGE("Failed create %s, err=%d", file, errno);
505                return -1;
506            } else {
507                close(fd);
508            }
509        } else {
510            BEGET_LOGW("Failed to access \' %s \', err = %d", file, errno);
511            return -1;
512        }
513    }
514    return 0;
515}
516
517int StringToInt(const char *str, int defaultValue)
518{
519    if (str == NULL || *str == '\0') {
520        return defaultValue;
521    }
522    errno = 0;
523    int value = (int)strtoul(str, NULL, DECIMAL_BASE);
524    return (errno != 0) ? defaultValue : value;
525}
526
527int ReadFileInDir(const char *dirPath, const char *includeExt,
528    int (*processFile)(const char *fileName, void *context), void *context)
529{
530    INIT_CHECK_RETURN_VALUE(dirPath != NULL && processFile != NULL, -1);
531    DIR *pDir = opendir(dirPath);
532    INIT_ERROR_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", dirPath, errno);
533    char *fileName = calloc(1, MAX_BUF_SIZE);
534    INIT_ERROR_CHECK(fileName != NULL, closedir(pDir);
535        return -1, "Failed to malloc for %s", dirPath);
536
537    struct dirent *dp;
538    uint32_t count = 0;
539    while ((dp = readdir(pDir)) != NULL) {
540        if (dp->d_type == DT_DIR) {
541            continue;
542        }
543        if (includeExt != NULL) {
544            char *tmp = strstr(dp->d_name, includeExt);
545            if (tmp == NULL) {
546                continue;
547            }
548            if (strcmp(tmp, includeExt) != 0) {
549                continue;
550            }
551        }
552        int ret = snprintf_s(fileName, MAX_BUF_SIZE, MAX_BUF_SIZE - 1, "%s/%s", dirPath, dp->d_name);
553        if (ret <= 0) {
554            INIT_LOGE("Failed to get file name for %s", dp->d_name);
555            continue;
556        }
557        struct stat st;
558        if (stat(fileName, &st) == 0) {
559            count++;
560            processFile(fileName, context);
561        }
562    }
563    INIT_LOGV("ReadFileInDir dirPath %s %d", dirPath, count);
564    free(fileName);
565    closedir(pDir);
566    return 0;
567}
568
569// Check if in updater mode.
570int InUpdaterMode(void)
571{
572#ifdef OHOS_LITE
573    return 0;
574#else
575    const char * const updaterExecutableFile = "/bin/updater";
576    if (access(updaterExecutableFile, X_OK) == 0) {
577        return 1;
578    } else {
579        return 0;
580    }
581#endif
582}
583
584// Check if in rescue mode.
585int InRescueMode(void)
586{
587#ifdef OHOS_LITE
588    return 1;
589#else
590    char value[MAX_BUFFER_LEN] = {0};
591    int ret = GetParameterFromCmdLine("rescue_mode", value, MAX_BUFFER_LEN);
592    if (ret == 0 && strcmp(value, "true") == 0) {
593        return 0;
594    }
595    return 1;
596#endif
597}
598
599int StringReplaceChr(char *strl, char oldChr, char newChr)
600{
601    INIT_ERROR_CHECK(strl != NULL, return -1, "Invalid parament");
602    char *p = strl;
603    while (*p != '\0') {
604        if (*p == oldChr) {
605            *p = newChr;
606        }
607        p++;
608    }
609    INIT_LOGV("strl is %s", strl);
610    return 0;
611}
612
613#ifndef __LITEOS_M__
614static void RedirectStdio(int fd)
615{
616    const int stdError = 2;
617    dup2(fd, 0);
618    dup2(fd, 1);
619    dup2(fd, stdError); // Redirect fd to 0, 1, 2
620}
621#endif
622
623#ifndef __LITEOS_M__
624static int OpenStdioDevice(const char *dev, int flag)
625{
626    setsid();
627    WaitForFile(dev, WAIT_MAX_SECOND);
628    int fd = open(dev, O_RDWR);
629    if (fd >= 0) {
630        ioctl(fd, TIOCSCTTY, flag);
631        RedirectStdio(fd);
632        if (fd > 2) {
633            close(fd);
634        }
635    } else {
636        return errno;
637    }
638    return 0;
639}
640#endif
641
642int OpenConsole(void)
643{
644#ifndef __LITEOS_M__
645    return OpenStdioDevice("/dev/console", 1);
646#else
647    return 0;
648#endif
649}
650
651int OpenKmsg(void)
652{
653#ifndef __LITEOS_M__
654    return OpenStdioDevice("/dev/kmsg", 0);
655#else
656    return 0;
657#endif
658}
659
660INIT_LOCAL_API int StringToLL(const char *str, long long int *out)
661{
662    INIT_ERROR_CHECK(str != NULL && out != NULL, return -1, "Invalid parament");
663    const char *s = str;
664    while (isspace(*s)) {
665        s++;
666    }
667
668    size_t len = strlen(s);
669    int positiveHex = (len > 1 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
670    int negativeHex = (len > 2 && s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')); // 2: shorttest
671    int base = (positiveHex || negativeHex) ? HEX_BASE : DECIMAL_BASE;
672    char *end = NULL;
673    errno = 0;
674    *out = strtoll(s, &end, base);
675    if (errno != 0) {
676        INIT_LOGE("StringToLL %s err = %d", str, errno);
677        return -1;
678    }
679    BEGET_CHECK(!(s == end || *end != '\0'), return -1);
680    return 0;
681}
682
683INIT_LOCAL_API int StringToULL(const char *str, unsigned long long int *out)
684{
685    INIT_ERROR_CHECK(str != NULL && out != NULL, return -1, "Invalid parament");
686    const char *s = str;
687    while (isspace(*s)) {
688        s++;
689    }
690    BEGET_CHECK(s[0] != '-', return -1);
691    int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? HEX_BASE : DECIMAL_BASE;
692    char *end = NULL;
693    errno = 0;
694    *out = strtoull(s, &end, base);
695    if (errno != 0) {
696        INIT_LOGE("StringToULL %s err = %d", str, errno);
697        return -1;
698    }
699    BEGET_CHECK(end != s, return -1);
700    BEGET_CHECK(*end == '\0', return -1);
701    return 0;
702}
703
704void TrimTail(char *str, char c)
705{
706    char *end = str + strlen(str) - 1;
707    while (end >= str && *end == c) {
708        *end = '\0';
709        end--;
710    }
711}
712
713char *TrimHead(char *str, char c)
714{
715    char *head = str;
716    const char *end = str + strlen(str);
717    while (head < end && *head == c) {
718        *head = '\0';
719        head++;
720    }
721    return head;
722}
723
724int GetParameterFromCmdLine(const char *paramName, char *value, size_t valueLen)
725{
726    char *buffer = ReadFileData(BOOT_CMD_LINE);
727    BEGET_ERROR_CHECK(buffer != NULL, return -1, "Failed to read /proc/cmdline");
728    int ret = GetProcCmdlineValue(paramName, buffer, value, valueLen);
729    free(buffer);
730    return ret;
731}
732
733uint32_t IntervalTime(struct timespec *startTime, struct timespec *endTime)
734{
735    uint32_t diff = 0;
736    if (endTime->tv_sec > startTime->tv_sec) {
737        diff = (uint32_t)(endTime->tv_sec - startTime->tv_sec);
738    } else {
739        diff = (uint32_t)(startTime->tv_sec - endTime->tv_sec);
740    }
741    return diff;
742}
743
744typedef int (*str_compare)(const char *s1, const char *s2);
745int OH_ExtendableStrArrayGetIndex(const char *strArray[], const char *target, int ignoreCase, const char *extend[])
746{
747    int i;
748    int idx;
749    str_compare cmp = strcmp;
750
751    if ((strArray == NULL) || (target == NULL) || (target[0] == '\0')) {
752        return -1;
753    }
754
755    if (ignoreCase) {
756        cmp = strcasecmp;
757    }
758
759    for (i = 0; strArray[i] != NULL; i++) {
760        if (cmp(strArray[i], target) == 0) {
761            return i;
762        }
763    }
764    if (extend == NULL) {
765        return -1;
766    }
767    idx = 0;
768    while (extend[idx] != NULL) {
769        if (cmp(extend[idx], target) == 0) {
770            return i + idx;
771        }
772        idx++;
773    }
774    return -1;
775}
776
777int OH_StrArrayGetIndex(const char *strArray[], const char *target, int ignoreCase)
778{
779    return OH_ExtendableStrArrayGetIndex(strArray, target, ignoreCase, NULL);
780}
781
782void *OH_ExtendableStrDictGet(void **strDict, int dictSize, const char *target, int ignoreCase, void **extendStrDict)
783{
784    int i;
785    const char *pos;
786    str_compare cmp = strcmp;
787
788    if ((strDict == NULL) || dictSize < 0 || ((size_t)dictSize < sizeof(const char *)) ||
789        (target == NULL) || (target[0] == '\0')) {
790        return NULL;
791    }
792
793    if (ignoreCase) {
794        cmp = strcasecmp;
795    }
796
797    i = 0;
798    pos = (const char *)strDict;
799    while (*(const char **)pos != NULL) {
800        if (cmp(*(const char **)pos, target) == 0) {
801            return (void *)pos;
802        }
803        i++;
804        pos = pos + dictSize;
805    }
806    if (extendStrDict == NULL) {
807        return NULL;
808    }
809    pos = (const char *)extendStrDict;
810    while (*(const char **)pos != NULL) {
811        if (cmp(*(const char **)pos, target) == 0) {
812            return (void *)pos;
813        }
814        i++;
815        pos = pos + dictSize;
816    }
817    return NULL;
818}
819
820void *OH_StrDictGet(void **strDict, int dictSize, const char *target, int ignoreCase)
821{
822    return OH_ExtendableStrDictGet(strDict, dictSize, target, ignoreCase, NULL);
823}
824
825long long GetUptimeInMicroSeconds(const struct timespec *uptime)
826{
827    struct timespec now;
828
829    if (uptime == NULL) {
830        clock_gettime(CLOCK_MONOTONIC, &now);
831        uptime = &now;
832    }
833
834    #define SECOND_TO_MICRO_SECOND (1000000)
835    #define MICRO_SECOND_TO_NANOSECOND (1000)
836
837    return ((long long)uptime->tv_sec * SECOND_TO_MICRO_SECOND) +
838            (uptime->tv_nsec / MICRO_SECOND_TO_NANOSECOND);
839}
840