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