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