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