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