• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-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_cmds.h"
16 
17 #include <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <net/if.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/mount.h>
26 #include <sys/resource.h>
27 #include <sys/stat.h>
28 #include <sys/syscall.h>
29 #include <sys/sysmacros.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 
33 #include "init.h"
34 #include "init_jobs_internal.h"
35 #include "init_log.h"
36 #include "init_cmdexecutor.h"
37 #include "init_service_manager.h"
38 #include "init_utils.h"
39 #include "securec.h"
40 
41 #ifndef OHOS_LITE
42 #include "hookmgr.h"
43 #include "bootstage.h"
44 
45 /**
46  * init cmd hooking execute
47  */
InitCmdHookExecute(const char * cmdName,const char * cmdContent,INIT_TIMING_STAT * cmdTimer)48 static void InitCmdHookExecute(const char *cmdName, const char *cmdContent, INIT_TIMING_STAT *cmdTimer)
49 {
50     INIT_CMD_INFO context;
51 
52     context.cmdName = cmdName;
53     context.cmdContent = cmdContent;
54     context.reserved = (const char *)cmdTimer;
55 
56     (void)HookMgrExecute(GetBootStageHookMgr(), INIT_CMD_RECORD, (void *)(&context), NULL);
57 }
58 #endif
59 
AddOneArg(const char * param,size_t paramLen)60 static char *AddOneArg(const char *param, size_t paramLen)
61 {
62     int valueCount = 1;
63     char *begin = strchr(param, '$');
64     while (begin != NULL) {
65         valueCount++;
66         begin = strchr(begin + 1, '$');
67     }
68     size_t allocSize = paramLen + (PARAM_VALUE_LEN_MAX * valueCount) + 1;
69     char *arg = calloc(sizeof(char), allocSize);
70     INIT_CHECK(arg != NULL, return NULL);
71     int ret = GetParamValue(param, paramLen, arg, allocSize);
72     INIT_ERROR_CHECK(ret == 0, free(arg);
73         return NULL, "Failed to get value for %s", param);
74     return arg;
75 }
76 
BuildStringFromCmdArg(const struct CmdArgs * ctx,int startIndex)77 char *BuildStringFromCmdArg(const struct CmdArgs *ctx, int startIndex)
78 {
79     INIT_ERROR_CHECK(ctx != NULL, return NULL, "Failed to get cmd args ");
80     char *options = (char *)calloc(1, OPTIONS_SIZE + 1);
81     INIT_ERROR_CHECK(options != NULL, return NULL, "Failed to get memory ");
82     options[0] = '\0';
83     int curr = 0;
84     for (int i = startIndex; i < ctx->argc; i++) { // save opt
85         if (ctx->argv[i] == NULL) {
86             continue;
87         }
88         int len = snprintf_s(options + curr, OPTIONS_SIZE - curr, OPTIONS_SIZE - 1 - curr, "%s ", ctx->argv[i]);
89         if (len <= 0) {
90             INIT_LOGE("Failed to format other opt");
91             options[0] = '\0';
92             return options;
93         }
94         curr += len;
95     }
96     if ((curr > 0) && (curr < OPTIONS_SIZE)) {
97         options[curr - 1] = '\0';
98     }
99     return options;
100 }
101 
GetCmdArg(const char * cmdContent,const char * delim,int argsCount)102 const struct CmdArgs *GetCmdArg(const char *cmdContent, const char *delim, int argsCount)
103 {
104     INIT_CHECK_RETURN_VALUE(cmdContent != NULL, NULL);
105     INIT_WARNING_CHECK(argsCount <= SPACES_CNT_IN_CMD_MAX, argsCount = SPACES_CNT_IN_CMD_MAX,
106         "Too much arguments for command, max number is %d", SPACES_CNT_IN_CMD_MAX);
107     struct CmdArgs *ctx = (struct CmdArgs *)calloc(1, sizeof(struct CmdArgs) + sizeof(char *) * (argsCount + 1));
108     INIT_ERROR_CHECK(ctx != NULL, return NULL, "Failed to malloc memory for arg");
109     ctx->argc = 0;
110     const char *p = cmdContent;
111     const char *end = cmdContent + strlen(cmdContent);
112     const char *token = NULL;
113     do {
114         // Skip lead whitespaces
115         while (isspace(*p)) {
116             p++;
117         }
118         token = strstr(p, delim);
119         if (token == NULL) {
120             ctx->argv[ctx->argc] = AddOneArg(p, end - p);
121             INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmdArg(ctx);
122                 return NULL);
123         } else {
124             ctx->argv[ctx->argc] = AddOneArg(p, token - p);
125             INIT_CHECK(ctx->argv[ctx->argc] != NULL, FreeCmdArg(ctx);
126                 return NULL);
127         }
128         ctx->argc++;
129         ctx->argv[ctx->argc] = NULL;
130         if (ctx->argc == argsCount) {
131             break;
132         }
133         p = token;
134     } while (token != NULL);
135     return ctx;
136 }
137 
FreeCmdArg(struct CmdArgs * cmd)138 void FreeCmdArg(struct CmdArgs *cmd)
139 {
140     INIT_CHECK_ONLY_RETURN(cmd != NULL);
141     for (int i = 0; i < cmd->argc; ++i) {
142         if (cmd->argv[i] != NULL) {
143             free(cmd->argv[i]);
144         }
145     }
146     free(cmd);
147     return;
148 }
149 
ExecCmd(const struct CmdTable * cmd,const char * cmdContent)150 void ExecCmd(const struct CmdTable *cmd, const char *cmdContent)
151 {
152     INIT_ERROR_CHECK(cmd != NULL, return, "Invalid cmd for %s", cmdContent);
153     const struct CmdArgs *ctx = GetCmdArg(cmdContent, " ", cmd->maxArg);
154     if (ctx == NULL) {
155         INIT_LOGE("Invalid arguments cmd: %s content: %s", cmd->name, cmdContent);
156     } else if ((ctx->argc <= cmd->maxArg) && (ctx->argc >= cmd->minArg)) {
157         cmd->DoFuncion(ctx);
158     } else {
159         INIT_LOGE("Invalid arguments cmd: %s content: %s argc: %d %d", cmd->name, cmdContent, ctx->argc, cmd->maxArg);
160     }
161     FreeCmdArg((struct CmdArgs *)ctx);
162 }
163 
SetProcName(const struct CmdArgs * ctx,const char * procFile)164 static void SetProcName(const struct CmdArgs *ctx, const char *procFile)
165 {
166     int fd = open(procFile, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, S_IRUSR | S_IWUSR);
167     INIT_ERROR_CHECK(fd >= 0, return, "Failed to set %s errno: %d", procFile, errno);
168 
169     size_t size = strlen(ctx->argv[0]);
170     ssize_t n = write(fd, ctx->argv[0], size);
171     INIT_ERROR_CHECK(n == (ssize_t)size, close(fd);
172         return, "Failed to write domainname errno: %d", errno);
173     close(fd);
174 }
175 
DoSetDomainname(const struct CmdArgs * ctx)176 static void DoSetDomainname(const struct CmdArgs *ctx)
177 {
178     SetProcName(ctx, "/proc/sys/kernel/domainname");
179 }
180 
DoSetHostname(const struct CmdArgs * ctx)181 static void DoSetHostname(const struct CmdArgs *ctx)
182 {
183     SetProcName(ctx, "/proc/sys/kernel/hostname");
184 }
185 
DoSleep(const struct CmdArgs * ctx)186 static void DoSleep(const struct CmdArgs *ctx)
187 {
188     errno = 0;
189     unsigned long sleepTime = strtoul(ctx->argv[0], NULL, DECIMAL_BASE);
190     INIT_ERROR_CHECK(errno == 0, return, "cannot convert sleep time in command \" sleep \"");
191 
192     // Limit sleep time in 5 seconds
193     const unsigned long sleepTimeLimit = 5;
194     INIT_CHECK(sleepTime <= sleepTimeLimit, sleepTime = sleepTimeLimit);
195     INIT_LOGI("Sleeping %d second(s)", sleepTime);
196     sleep((unsigned int)sleepTime);
197 }
198 
DoWait(const struct CmdArgs * ctx)199 static void DoWait(const struct CmdArgs *ctx)
200 {
201     const int filePos = 0;
202     const int timePos = 1;
203     unsigned long waitSecond = WAIT_MAX_SECOND;
204 
205     if (ctx->argc == timePos + 1) {
206         errno = 0;
207         waitSecond = strtoul(ctx->argv[timePos], NULL, DECIMAL_BASE);
208         INIT_ERROR_CHECK(errno == 0,
209         return, "cannot convert sleep time in command \" wait \"");
210     }
211 
212     INIT_LOGI("Waiting %s %lu second(s)", ctx->argv[filePos], waitSecond);
213     WaitForFile(ctx->argv[filePos], waitSecond);
214 }
215 
DoStart(const struct CmdArgs * ctx)216 static void DoStart(const struct CmdArgs *ctx)
217 {
218     INIT_LOGV("DoStart %s", ctx->argv[0]);
219     StartServiceByName(ctx->argv[0]);
220 }
221 
DoStop(const struct CmdArgs * ctx)222 static void DoStop(const struct CmdArgs *ctx)
223 {
224     INIT_LOGV("DoStop %s", ctx->argv[0]);
225     StopServiceByName(ctx->argv[0]);
226     return;
227 }
228 
DoReset(const struct CmdArgs * ctx)229 static void DoReset(const struct CmdArgs *ctx)
230 {
231     INIT_LOGV("DoReset %s", ctx->argv[0]);
232     Service *service = GetServiceByName(ctx->argv[0]);
233     if (service == NULL) {
234         INIT_LOGE("Reset cmd cannot find service %s.", ctx->argv[0]);
235         return;
236     }
237     if (service->pid > 0) {
238         if (kill(service->pid, GetKillServiceSig(ctx->argv[0])) != 0) {
239             INIT_LOGE("stop service %s pid %d failed! err %d.", service->name, service->pid, errno);
240             return;
241         }
242     } else {
243         StartServiceByName(ctx->argv[0]);
244     }
245     return;
246 }
247 
DoCopy(const struct CmdArgs * ctx)248 static void DoCopy(const struct CmdArgs *ctx)
249 {
250     int srcFd = -1;
251     int dstFd = -1;
252     char buf[MAX_COPY_BUF_SIZE] = { 0 };
253     char *realPath1 = NULL;
254     char *realPath2 = NULL;
255     do {
256         realPath1 = GetRealPath(ctx->argv[0]);
257         if (realPath1 == NULL) {
258             INIT_LOGE("Failed to get real path %s", ctx->argv[0]);
259             break;
260         }
261 
262         srcFd = open(realPath1, O_RDONLY);
263         if (srcFd < 0) {
264             INIT_LOGE("Failed to open source path %s  %d", ctx->argv[0], errno);
265             break;
266         }
267 
268         struct stat fileStat = { 0 };
269         if (stat(ctx->argv[0], &fileStat) != 0) {
270             INIT_LOGE("Failed to state source path %s  %d", ctx->argv[0], errno);
271             break;
272         }
273         mode_t mode = fileStat.st_mode;
274         realPath2 = GetRealPath(ctx->argv[1]);
275         if (realPath2 != NULL) {
276             dstFd = open(realPath2, O_WRONLY | O_TRUNC | O_CREAT, mode);
277         } else {
278             dstFd = open(ctx->argv[1], O_WRONLY | O_TRUNC | O_CREAT, mode);
279         }
280         if (dstFd < 0) {
281             INIT_LOGE("Failed to open dest path %s  %d", ctx->argv[1], errno);
282             break;
283         }
284         int rdLen = 0;
285         while ((rdLen = read(srcFd, buf, sizeof(buf) - 1)) > 0) {
286             int rtLen = write(dstFd, buf, rdLen);
287             if (rtLen != rdLen) {
288                 INIT_LOGE("Failed to write to dest path %s  %d", ctx->argv[1], errno);
289                 break;
290             }
291         }
292         fsync(dstFd);
293     } while (0);
294     INIT_CHECK(srcFd < 0, close(srcFd));
295     INIT_CHECK(dstFd < 0, close(dstFd));
296     INIT_CHECK(realPath1 == NULL, free(realPath1));
297     INIT_CHECK(realPath2 == NULL, free(realPath2));
298 }
299 
SetOwner(const char * file,const char * ownerStr,const char * groupStr)300 static int SetOwner(const char *file, const char *ownerStr, const char *groupStr)
301 {
302     INIT_ERROR_CHECK(file != NULL, return -1, "SetOwner invalid file.");
303     INIT_ERROR_CHECK(ownerStr != NULL, return -1, "SetOwner invalid file.");
304     INIT_ERROR_CHECK(groupStr != NULL, return -1, "SetOwner invalid file.");
305 
306     uid_t owner = DecodeUid(ownerStr);
307     INIT_ERROR_CHECK(owner != (uid_t)-1, return -1, "SetOwner invalid uid :%s.", ownerStr);
308     gid_t group = DecodeGid(groupStr);
309     INIT_ERROR_CHECK(group != (gid_t)-1, return -1, "SetOwner invalid gid :%s.", groupStr);
310     return (chown(file, owner, group) != 0) ? -1 : 0;
311 }
312 
DoChown(const struct CmdArgs * ctx)313 static void DoChown(const struct CmdArgs *ctx)
314 {
315     // format: chown owner group /xxx/xxx/xxx
316     const int pathPos = 2;
317     int ret = SetOwner(ctx->argv[pathPos], ctx->argv[0], ctx->argv[1]);
318     if (ret != 0) {
319         INIT_LOGE("Failed to change owner for %s, err %d.", ctx->argv[pathPos], errno);
320     }
321     return;
322 }
323 
DoMkDir(const struct CmdArgs * ctx)324 static void DoMkDir(const struct CmdArgs *ctx)
325 {
326     // mkdir support format:
327     // 1.mkdir path
328     // 2.mkdir path mode
329     // 3.mkdir path mode owner group
330     const int ownerPos = 2;
331     const int groupPos = 3;
332     if (ctx->argc != 1 && ctx->argc != (groupPos + 1) && ctx->argc != ownerPos) {
333         INIT_LOGE("DoMkDir invalid arguments.");
334         return;
335     }
336     mode_t mode = DEFAULT_DIR_MODE;
337     if (mkdir(ctx->argv[0], mode) != 0 && errno != EEXIST) {
338         INIT_LOGE("Create directory '%s' failed, err=%d.", ctx->argv[0], errno);
339         return;
340     }
341 
342     PluginExecCmdByName("restoreContentRecurse", ctx->argv[0]);
343 
344     if (ctx->argc <= 1) {
345         return;
346     }
347 
348     mode = strtoul(ctx->argv[1], NULL, OCTAL_TYPE);
349     INIT_CHECK_ONLY_ELOG(chmod(ctx->argv[0], mode) == 0, "DoMkDir failed for '%s', err %d.", ctx->argv[0], errno);
350 
351     if (ctx->argc <= ownerPos) {
352         return;
353     }
354     int ret = SetOwner(ctx->argv[0], ctx->argv[ownerPos], ctx->argv[groupPos]);
355     if (ret != 0) {
356         INIT_LOGE("Failed to change owner %s, err %d.", ctx->argv[0], errno);
357     }
358     ret = SetFileCryptPolicy(ctx->argv[0]);
359     if (ret != 0) {
360         INIT_LOGW("Failed to set file fscrypt");
361     }
362 
363     return;
364 }
365 
DoChmod(const struct CmdArgs * ctx)366 static void DoChmod(const struct CmdArgs *ctx)
367 {
368     // format: chmod xxxx /xxx/xxx/xxx
369     mode_t mode = strtoul(ctx->argv[0], NULL, OCTAL_TYPE);
370     if (mode == 0) {
371         INIT_LOGE("DoChmod, strtoul failed for %s, er %d.", ctx->argv[1], errno);
372         return;
373     }
374 
375     if (chmod(ctx->argv[1], mode) != 0) {
376         INIT_LOGE("Failed to change mode \" %s \" to %04o, err=%d", ctx->argv[1], mode, errno);
377     }
378 }
379 
GetMountFlag(unsigned long * mountflag,const char * targetStr,const char * source)380 static int GetMountFlag(unsigned long *mountflag, const char *targetStr, const char *source)
381 {
382     INIT_CHECK_RETURN_VALUE(targetStr != NULL && mountflag != NULL, 0);
383     struct {
384         char *flagName;
385         unsigned long value;
386     } mountFlagMap[] = {
387         { "noatime", MS_NOATIME },
388         { "noexec", MS_NOEXEC },
389         { "nosuid", MS_NOSUID },
390         { "nodev", MS_NODEV },
391         { "nodiratime", MS_NODIRATIME },
392         { "ro", MS_RDONLY },
393         { "rdonly", MS_RDONLY },
394         { "rw", 0 },
395         { "sync", MS_SYNCHRONOUS },
396         { "remount", MS_REMOUNT },
397         { "bind", MS_BIND },
398         { "rec", MS_REC },
399         { "unbindable", MS_UNBINDABLE },
400         { "private", MS_PRIVATE },
401         { "slave", MS_SLAVE },
402         { "shared", MS_SHARED },
403         { "defaults", 0 },
404     };
405     for (unsigned int i = 0; i < ARRAY_LENGTH(mountFlagMap); i++) {
406         if (strncmp(targetStr, mountFlagMap[i].flagName, strlen(mountFlagMap[i].flagName)) == 0) {
407             *mountflag |= mountFlagMap[i].value;
408             return 1;
409         }
410     }
411     if (strncmp(targetStr, "wait", strlen("wait")) == 0) {
412         WaitForFile(source, WAIT_MAX_SECOND);
413         return 1;
414     }
415 
416     return 0;
417 }
418 
DoMount(const struct CmdArgs * ctx)419 static void DoMount(const struct CmdArgs *ctx)
420 {
421     INIT_ERROR_CHECK(ctx->argc <= SPACES_CNT_IN_CMD_MAX, return, "Invalid arg number");
422     // format: fileSystemType source target mountFlag1 mountFlag2... data
423     int index = 0;
424     char *fileSysType = (ctx->argc > index) ? ctx->argv[index] : NULL;
425     INIT_ERROR_CHECK(fileSysType != NULL, return, "Failed to get fileSysType.");
426     index++;
427 
428     char *source =  (ctx->argc > index) ? ctx->argv[index] : NULL;
429     INIT_ERROR_CHECK(source != NULL, return, "Failed to get source.");
430     index++;
431 
432     // maybe only has "filesystype source target", 2 spaces
433     char *target = (ctx->argc > index) ? ctx->argv[index] : NULL;
434     INIT_ERROR_CHECK(target != NULL, return, "Failed to get target.");
435     ++index;
436 
437     int ret = 0;
438     unsigned long mountflags = 0;
439     while (index < ctx->argc) {
440         ret = GetMountFlag(&mountflags, ctx->argv[index], source);
441         if (ret == 0) {
442             break;
443         }
444         index++;
445     }
446     if (index >= ctx->argc) {
447         ret = mount(source, target, fileSysType, mountflags, NULL);
448     } else {
449         char *data = BuildStringFromCmdArg(ctx, index);
450         INIT_ERROR_CHECK(data != NULL, return, "Failed to get data.");
451         ret = mount(source, target, fileSysType, mountflags, data);
452         free(data);
453     }
454     if (ret != 0) {
455         INIT_LOGE("Failed to mount for %s, err %d.", target, errno);
456     }
457 }
458 
DoWriteWithMultiArgs(const struct CmdArgs * ctx,int fd)459 static int DoWriteWithMultiArgs(const struct CmdArgs *ctx, int fd)
460 {
461     char buf[MAX_CMD_CONTENT_LEN];
462 
463     /* Write to proc files should be done at once */
464     buf[0] = '\0';
465     INIT_ERROR_CHECK(strcat_s(buf, sizeof(buf), ctx->argv[1]) == 0, return -1, "Failed to format buf");
466     int idx = 2;
467     while (idx < ctx->argc) {
468         INIT_ERROR_CHECK(strcat_s(buf, sizeof(buf), " ") == 0, return -1, "Failed to format buf");
469         INIT_ERROR_CHECK(strcat_s(buf, sizeof(buf), ctx->argv[idx]) == 0, return -1, "Failed to format buf");
470         idx++;
471     }
472     return write(fd, buf, strlen(buf));
473 }
474 
DoWrite(const struct CmdArgs * ctx)475 static void DoWrite(const struct CmdArgs *ctx)
476 {
477     // format: write path content
478     char *realPath = GetRealPath(ctx->argv[0]);
479     int fd = -1;
480     if (realPath != NULL) {
481         fd = open(realPath, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR);
482         free(realPath);
483         realPath = NULL;
484     } else {
485         fd = open(ctx->argv[0], O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR);
486     }
487     if (fd < 0) {
488         return;
489     }
490     ssize_t ret;
491     if (ctx->argc > 2) {
492         ret = DoWriteWithMultiArgs(ctx, fd);
493     } else {
494         ret = write(fd, ctx->argv[1], strlen(ctx->argv[1]));
495     }
496     INIT_CHECK_ONLY_ELOG(ret >= 0, "DoWrite: write to file %s failed: %d", ctx->argv[0], errno);
497     close(fd);
498 }
499 
DoRmdir(const struct CmdArgs * ctx)500 static void DoRmdir(const struct CmdArgs *ctx)
501 {
502     // format: rmdir path
503     int ret = rmdir(ctx->argv[0]);
504     if (ret == -1) {
505         INIT_LOGE("DoRmdir: remove %s failed: %d.", ctx->argv[0], errno);
506     }
507     return;
508 }
509 
DoRebootCmd(const struct CmdArgs * ctx)510 static void DoRebootCmd(const struct CmdArgs *ctx)
511 {
512     ExecReboot(ctx->argv[0]);
513     return;
514 }
515 
DoSetrlimit(const struct CmdArgs * ctx)516 static void DoSetrlimit(const struct CmdArgs *ctx)
517 {
518     static const char *resource[] = {
519         "RLIMIT_CPU", "RLIMIT_FSIZE", "RLIMIT_DATA", "RLIMIT_STACK", "RLIMIT_CORE", "RLIMIT_RSS",
520         "RLIMIT_NPROC", "RLIMIT_NOFILE", "RLIMIT_MEMLOCK", "RLIMIT_AS", "RLIMIT_LOCKS", "RLIMIT_SIGPENDING",
521         "RLIMIT_MSGQUEUE", "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIM_NLIMITS"
522     };
523     // format: setrlimit resource curValue maxValue
524     const int rlimMaxPos = 2;
525     struct rlimit limit;
526     if (strcmp(ctx->argv[1], "unlimited") == 0) {
527         limit.rlim_cur = RLIM_INFINITY;
528     } else {
529         limit.rlim_cur = (rlim_t)atoi(ctx->argv[1]);
530     }
531     if (strcmp(ctx->argv[rlimMaxPos], "unlimited") == 0) {
532         limit.rlim_max = RLIM_INFINITY;
533     } else {
534         limit.rlim_max = (rlim_t)atoi(ctx->argv[rlimMaxPos]);
535     }
536     int rcs = -1;
537     for (unsigned int i = 0; i < ARRAY_LENGTH(resource); ++i) {
538         if (strcmp(ctx->argv[0], resource[i]) == 0) {
539             rcs = (int)i;
540             break;
541         }
542     }
543     if (rcs == -1) {
544         INIT_LOGE("DoSetrlimit failed, resources :%s not support.", ctx->argv[0]);
545         return;
546     }
547     INIT_CHECK_ONLY_ELOG(setrlimit(rcs, &limit) == 0, "Failed setrlimit err=%d", errno);
548     return;
549 }
550 
DoRm(const struct CmdArgs * ctx)551 static void DoRm(const struct CmdArgs *ctx)
552 {
553     // format: rm /xxx/xxx/xxx
554     INIT_CHECK_ONLY_ELOG(unlink(ctx->argv[0]) != -1, "Failed unlink %s err=%d.", ctx->argv[0], errno);
555     return;
556 }
557 
DoExport(const struct CmdArgs * ctx)558 static void DoExport(const struct CmdArgs *ctx)
559 {
560     // format: export xxx /xxx/xxx/xxx
561     INIT_CHECK_ONLY_ELOG(setenv(ctx->argv[0], ctx->argv[1], 1) == 0, "Failed setenv %s with %s err=%d.",
562         ctx->argv[0], ctx->argv[1], errno);
563     return;
564 }
565 
566 static const struct CmdTable g_cmdTable[] = {
567     { "start ", 0, 1, DoStart },
568     { "mkdir ", 1, 4, DoMkDir },
569     { "chmod ", 2, 2, DoChmod },
570     { "chown ", 3, 3, DoChown },
571     { "mount ", 1, 10, DoMount },
572     { "export ", 2, 2, DoExport },
573     { "rm ", 1, 1, DoRm },
574     { "rmdir ", 1, 1, DoRmdir },
575     { "write ", 2, 10, DoWrite },
576     { "stop ", 1, 1, DoStop },
577     { "reset ", 1, 1, DoReset },
578     { "copy ", 2, 2, DoCopy },
579     { "reboot ", 1, 1, DoRebootCmd },
580     { "setrlimit ", 3, 3, DoSetrlimit },
581     { "sleep ", 1, 1, DoSleep },
582     { "wait ", 1, 2, DoWait },
583     { "hostname ", 1, 1, DoSetHostname },
584     { "domainname ", 1, 1, DoSetDomainname }
585 };
586 
GetCommCmdTable(int * number)587 static const struct CmdTable *GetCommCmdTable(int *number)
588 {
589     *number = (int)ARRAY_LENGTH(g_cmdTable);
590     return g_cmdTable;
591 }
592 
GetCmdStart(const char * cmdContent)593 static char *GetCmdStart(const char *cmdContent)
594 {
595     // Skip lead whitespaces
596     char *p = (char *)cmdContent;
597     while (p != NULL && isspace(*p)) {
598         p++;
599     }
600     if (p == NULL) {
601         return NULL;
602     }
603     if (*p == '#') { // start with #
604         return NULL;
605     }
606     return p;
607 }
608 
GetCmdByName(const char * name)609 const struct CmdTable *GetCmdByName(const char *name)
610 {
611     INIT_CHECK_RETURN_VALUE(name != NULL, NULL);
612     char *startCmd = GetCmdStart(name);
613     INIT_CHECK_RETURN_VALUE(startCmd != NULL, NULL);
614     int cmdCnt = 0;
615     const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt);
616     for (int i = 0; i < cmdCnt; ++i) {
617         if (strncmp(startCmd, commCmds[i].name, strlen(commCmds[i].name)) == 0) {
618             return &commCmds[i];
619         }
620     }
621     int number = 0;
622     const struct CmdTable *cmds = GetCmdTable(&number);
623     for (int i = 0; i < number; ++i) {
624         if (strncmp(startCmd, cmds[i].name, strlen(cmds[i].name)) == 0) {
625             return &cmds[i];
626         }
627     }
628     return NULL;
629 }
630 
GetMatchCmd(const char * cmdStr,int * index)631 const char *GetMatchCmd(const char *cmdStr, int *index)
632 {
633     INIT_CHECK_RETURN_VALUE(cmdStr != NULL && index != NULL, NULL);
634     char *startCmd = GetCmdStart(cmdStr);
635     INIT_CHECK_RETURN_VALUE(startCmd != NULL, NULL);
636 
637     int cmdCnt = 0;
638     const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt);
639     for (int i = 0; i < cmdCnt; ++i) {
640         if (strncmp(startCmd, commCmds[i].name, strlen(commCmds[i].name)) == 0) {
641             *index = i;
642             return commCmds[i].name;
643         }
644     }
645     int number = 0;
646     const struct CmdTable *cmds = GetCmdTable(&number);
647     for (int i = 0; i < number; ++i) {
648         if (strncmp(startCmd, cmds[i].name, strlen(cmds[i].name)) == 0) {
649             *index = cmdCnt + i;
650             return cmds[i].name;
651         }
652     }
653     return PluginGetCmdIndex(startCmd, index);
654 }
655 
GetCmdKey(int index)656 const char *GetCmdKey(int index)
657 {
658     int cmdCnt = 0;
659     const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt);
660     if (index < cmdCnt) {
661         return commCmds[index].name;
662     }
663     int number = 0;
664     const struct CmdTable *cmds = GetCmdTable(&number);
665     if (index < (cmdCnt + number)) {
666         return cmds[index - cmdCnt].name;
667     }
668     return NULL;
669 }
670 
GetCmdLinesFromJson(const cJSON * root,CmdLines ** cmdLines)671 int GetCmdLinesFromJson(const cJSON *root, CmdLines **cmdLines)
672 {
673     INIT_CHECK(root != NULL, return -1);
674     INIT_CHECK(cmdLines != NULL, return -1);
675     *cmdLines = NULL;
676     if (!cJSON_IsArray(root)) {
677         return -1;
678     }
679     int cmdCnt = cJSON_GetArraySize(root);
680     INIT_CHECK_RETURN_VALUE(cmdCnt > 0, -1);
681 
682     *cmdLines = (CmdLines *)calloc(1, sizeof(CmdLines) + sizeof(CmdLine) * cmdCnt);
683     INIT_CHECK_RETURN_VALUE(*cmdLines != NULL, -1);
684     (*cmdLines)->cmdNum = 0;
685     for (int i = 0; i < cmdCnt; ++i) {
686         cJSON *line = cJSON_GetArrayItem(root, i);
687         if (!cJSON_IsString(line)) {
688             continue;
689         }
690 
691         char *tmp = cJSON_GetStringValue(line);
692         if (tmp == NULL) {
693             continue;
694         }
695 
696         int index = 0;
697         const char *cmd = GetMatchCmd(tmp, &index);
698         if (cmd == NULL) {
699             INIT_LOGE("Cannot support command: %s", tmp);
700             continue;
701         }
702 
703         int ret = strcpy_s((*cmdLines)->cmds[(*cmdLines)->cmdNum].cmdContent, MAX_CMD_CONTENT_LEN, tmp + strlen(cmd));
704         if (ret != EOK) {
705             INIT_LOGE("Invalid cmd arg: %s", tmp);
706             continue;
707         }
708 
709         (*cmdLines)->cmds[(*cmdLines)->cmdNum].cmdIndex = index;
710         (*cmdLines)->cmdNum++;
711     }
712     return 0;
713 }
714 
InitDiffTime(INIT_TIMING_STAT * stat)715 long long  InitDiffTime(INIT_TIMING_STAT *stat)
716 {
717     long long diff = (long long)((stat->endTime.tv_sec - stat->startTime.tv_sec) * 1000000); // 1000000 1000ms
718     if (stat->endTime.tv_nsec > stat->startTime.tv_nsec) {
719         diff += (stat->endTime.tv_nsec - stat->startTime.tv_nsec) / 1000; // 1000 ms
720     } else {
721         diff -= (stat->startTime.tv_nsec - stat->endTime.tv_nsec) / 1000; // 1000 ms
722     }
723     return diff;
724 }
725 
DoCmdByName(const char * name,const char * cmdContent)726 void DoCmdByName(const char *name, const char *cmdContent)
727 {
728     if (name == NULL || cmdContent == NULL) {
729         return;
730     }
731     INIT_TIMING_STAT cmdTimer;
732     (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.startTime);
733     const struct CmdTable *cmd = GetCmdByName(name);
734     if (cmd != NULL) {
735         ExecCmd(cmd, cmdContent);
736     } else {
737         PluginExecCmdByName(name, cmdContent);
738     }
739     (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.endTime);
740     long long diff = InitDiffTime(&cmdTimer);
741 #ifndef OHOS_LITE
742     InitCmdHookExecute(name, cmdContent, &cmdTimer);
743 #endif
744     INIT_LOGV("Execute command \"%s %s\" took %lld ms", name, cmdContent, diff / 1000); // 1000 is convert us to ms
745 }
746 
DoCmdByIndex(int index,const char * cmdContent)747 void DoCmdByIndex(int index, const char *cmdContent)
748 {
749     if (cmdContent == NULL) {
750         return;
751     }
752     int cmdCnt = 0;
753     INIT_TIMING_STAT cmdTimer;
754     (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.startTime);
755     const struct CmdTable *commCmds = GetCommCmdTable(&cmdCnt);
756     const char *cmdName = NULL;
757     if (index < cmdCnt) {
758         cmdName = commCmds[index].name;
759         ExecCmd(&commCmds[index], cmdContent);
760     } else {
761         int number = 0;
762         const struct CmdTable *cmds = GetCmdTable(&number);
763         if (index < (cmdCnt + number)) {
764             cmdName = cmds[index - cmdCnt].name;
765             ExecCmd(&cmds[index - cmdCnt], cmdContent);
766         } else {
767             PluginExecCmdByCmdIndex(index, cmdContent);
768             cmdName = GetPluginCmdNameByIndex(index);
769             if (cmdName == NULL) {
770                 cmdName = "Unknown";
771             }
772         }
773     }
774     (void)clock_gettime(CLOCK_MONOTONIC, &cmdTimer.endTime);
775     long long diff = InitDiffTime(&cmdTimer);
776 #ifndef OHOS_LITE
777     InitCmdHookExecute(cmdName, cmdContent, &cmdTimer);
778 #endif
779     INIT_LOGV("Execute command \"%s %s\" took %lld ms", cmdName, cmdContent, diff / 1000); // 1000 is convert us to ms
780 }
781