1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "shcmd.h"
33 #include "show.h"
34 #include "stdlib.h"
35 #include "unistd.h"
36 #include "dirent.h"
37 #include "securec.h"
38
39 #define SHELL_INIT_MAGIC_FLAG 0xABABABAB
40 #define CTRL_C 0x03 /* 0x03: ctrl+c ASCII */
41
OsFreeCmdPara(CmdParsed * cmdParsed)42 static void OsFreeCmdPara(CmdParsed *cmdParsed)
43 {
44 unsigned int i;
45 for (i = 0; i < cmdParsed->paramCnt; i++) {
46 if ((cmdParsed->paramArray[i]) != NULL) {
47 free((cmdParsed->paramArray[i]));
48 cmdParsed->paramArray[i] = NULL;
49 }
50 }
51 }
52
OsStrSeparateTabStrGet(const char ** tabStr,CmdParsed * parsed,unsigned int tabStrLen)53 static int OsStrSeparateTabStrGet(const char **tabStr, CmdParsed *parsed, unsigned int tabStrLen)
54 {
55 char *shiftStr = NULL;
56 char *tempStr = (char *)malloc(SHOW_MAX_LEN << 1);
57 if (tempStr == NULL) {
58 return (int)SH_ERROR;
59 }
60
61 (void)memset_s(tempStr, SHOW_MAX_LEN << 1, 0, SHOW_MAX_LEN << 1);
62 shiftStr = tempStr + SHOW_MAX_LEN;
63
64 if (strncpy_s(tempStr, SHOW_MAX_LEN - 1, *tabStr, tabStrLen)) {
65 free(tempStr);
66 return (int)SH_ERROR;
67 }
68
69 parsed->cmdType = CMD_TYPE_STD;
70
71 /* cut useless or repeat space */
72 if (OsCmdKeyShift(tempStr, shiftStr, SHOW_MAX_LEN - 1)) {
73 free(tempStr);
74 return (int)SH_ERROR;
75 }
76
77 /* get exact position of string to complete */
78 /* situation different if end space lost or still exist */
79 if ((strlen(shiftStr) == 0) || (tempStr[strlen(tempStr) - 1] != shiftStr[strlen(shiftStr) - 1])) {
80 *tabStr = "";
81 } else {
82 if (OsCmdParse(shiftStr, parsed)) {
83 free(tempStr);
84 return (int)SH_ERROR;
85 }
86 *tabStr = parsed->paramArray[parsed->paramCnt - 1];
87 }
88
89 free(tempStr);
90 return SH_OK;
91 }
92
OsShellGetWorkingDirectory(void)93 char *OsShellGetWorkingDirectory(void)
94 {
95 return OsGetShellCb()->shellWorkingDirectory;
96 }
97
OsShellSetWorkingDirectory(const char * dir,size_t len)98 int OsShellSetWorkingDirectory(const char *dir, size_t len)
99 {
100 if (dir == NULL) {
101 return SH_NOK;
102 }
103
104 int ret = strncpy_s(OsGetShellCb()->shellWorkingDirectory, sizeof(OsGetShellCb()->shellWorkingDirectory),
105 dir, len);
106 if (ret != SH_OK) {
107 return SH_NOK;
108 }
109 return SH_OK;
110 }
111
OsStrSeparate(const char * tabStr,char * strPath,char * nameLooking,unsigned int tabStrLen)112 static int OsStrSeparate(const char *tabStr, char *strPath, char *nameLooking, unsigned int tabStrLen)
113 {
114 char *strEnd = NULL;
115 char *cutPos = NULL;
116 CmdParsed parsed = {0};
117 char *shellWorkingDirectory = OsShellGetWorkingDirectory();
118 int ret;
119
120 ret = OsStrSeparateTabStrGet(&tabStr, &parsed, tabStrLen);
121 if (ret != SH_OK) {
122 return ret;
123 }
124
125 /* get fullpath str */
126 if (*tabStr != '/') {
127 if (strncpy_s(strPath, CMD_MAX_PATH, shellWorkingDirectory, CMD_MAX_PATH - 1)) {
128 OsFreeCmdPara(&parsed);
129 return (int)SH_ERROR;
130 }
131 if (strcmp(shellWorkingDirectory, "/")) {
132 if (strncat_s(strPath, CMD_MAX_PATH - 1, "/", CMD_MAX_PATH - strlen(strPath) - 1)) {
133 OsFreeCmdPara(&parsed);
134 return (int)SH_ERROR;
135 }
136 }
137 }
138
139 if (strncat_s(strPath, CMD_MAX_PATH - 1, tabStr, CMD_MAX_PATH - strlen(strPath) - 1)) {
140 OsFreeCmdPara(&parsed);
141 return (int)SH_ERROR;
142 }
143
144 /* split str by last '/' */
145 strEnd = strrchr(strPath, '/');
146 if (strEnd != NULL) {
147 if (strncpy_s(nameLooking, CMD_MAX_PATH, strEnd + 1, CMD_MAX_PATH - 1)) { /* get cmp str */
148 OsFreeCmdPara(&parsed);
149 return (int)SH_ERROR;
150 }
151 }
152
153 cutPos = strrchr(strPath, '/');
154 if (cutPos != NULL) {
155 *(cutPos + 1) = '\0';
156 }
157
158 OsFreeCmdPara(&parsed);
159 return SH_OK;
160 }
161
OsShowPageInputControl(void)162 static int OsShowPageInputControl(void)
163 {
164 char readChar;
165
166 while (1) {
167 if (read(STDIN_FILENO, &readChar, 1) != 1) { /* get one char from stdin */
168 printf("\n");
169 return (int)SH_ERROR;
170 }
171 if ((readChar == 'q') || (readChar == 'Q') || (readChar == CTRL_C)) {
172 printf("\n");
173 return 0;
174 } else if (readChar == '\r') {
175 printf("\b \b\b \b\b \b\b \b\b \b\b \b\b \b\b \b");
176 return 1;
177 }
178 }
179 }
180
OsShowPageControl(unsigned int timesPrint,unsigned int lineCap,unsigned int count)181 static int OsShowPageControl(unsigned int timesPrint, unsigned int lineCap, unsigned int count)
182 {
183 if (NEED_NEW_LINE(timesPrint, lineCap)) {
184 printf("\n");
185 if (SCREEN_IS_FULL(timesPrint, lineCap) && (timesPrint < count)) {
186 printf("--More--");
187 return OsShowPageInputControl();
188 }
189 }
190 return 1;
191 }
192
OsSurePrintAll(unsigned int count)193 static int OsSurePrintAll(unsigned int count)
194 {
195 char readChar = 0;
196 printf("\nDisplay all %u possibilities?(y/n)", count);
197 while (1) {
198 if (read(STDIN_FILENO, &readChar, 1) != 1) {
199 return (int)SH_ERROR;
200 }
201 if ((readChar == 'n') || (readChar == 'N') || (readChar == CTRL_C)) {
202 printf("\n");
203 return 0;
204 } else if ((readChar == 'y') || (readChar == 'Y') || (readChar == '\r')) {
205 return 1;
206 }
207 }
208 }
209
OsPrintMatchList(unsigned int count,const char * strPath,const char * nameLooking,unsigned int printLen)210 static int OsPrintMatchList(unsigned int count, const char *strPath, const char *nameLooking, unsigned int printLen)
211 {
212 unsigned int timesPrint = 0;
213 unsigned int lineCap;
214 int ret;
215 DIR *openDir = NULL;
216 struct dirent *readDir = NULL;
217 char formatChar[10] = {0}; /* 10:for formatChar length */
218
219 printLen = (printLen > (DEFAULT_SCREEN_WIDTH - 2)) ? (DEFAULT_SCREEN_WIDTH - 2) : printLen; /* 2:revered 2 bytes */
220 lineCap = DEFAULT_SCREEN_WIDTH / (printLen + 2); /* 2:DEFAULT_SCREEN_WIDTH revered 2 bytes */
221 if (snprintf_s(formatChar, sizeof(formatChar) - 1, 7, "%%-%us ", printLen) < 0) { /* 7:format-len */
222 return (int)SH_ERROR;
223 }
224
225 if (count > (lineCap * DEFAULT_SCREEN_HEIGHT)) {
226 ret = OsSurePrintAll(count);
227 if (ret != 1) {
228 return ret;
229 }
230 }
231 openDir = opendir(strPath);
232 if (openDir == NULL) {
233 return (int)SH_ERROR;
234 }
235
236 printf("\n");
237 for (readDir = readdir(openDir); readDir != NULL; readDir = readdir(openDir)) {
238 if (strncmp(nameLooking, readDir->d_name, strlen(nameLooking)) != 0) {
239 continue;
240 }
241 printf(formatChar, readDir->d_name);
242 timesPrint++;
243 ret = OsShowPageControl(timesPrint, lineCap, count);
244 if (ret != 1) {
245 if (closedir(openDir) < 0) {
246 return (int)SH_ERROR;
247 }
248 return ret;
249 }
250 }
251
252 printf("\n");
253 if (closedir(openDir) < 0) {
254 return (int)SH_ERROR;
255 }
256
257 return SH_OK;
258 }
259
StrncmpCut(const char * s1,char * s2,size_t n)260 static void StrncmpCut(const char *s1, char *s2, size_t n)
261 {
262 if ((n == 0) || (s1 == NULL) || (s2 == NULL)) {
263 return;
264 }
265 do {
266 if (*s1 && *s2 && (*s1 == *s2)) {
267 s1++;
268 s2++;
269 } else {
270 break;
271 }
272 } while (--n != 0);
273 if (n > 0) {
274 /* NULL pad the remaining n-1 bytes */
275 while (n-- != 0) {
276 *s2++ = 0;
277 }
278 }
279 return;
280 }
281
OsCompleteStr(char * result,const char * target,char * cmdKey,unsigned int * len)282 static void OsCompleteStr(char *result, const char *target, char *cmdKey, unsigned int *len)
283 {
284 unsigned int size = strlen(result) - strlen(target);
285 char *des = cmdKey + *len;
286 char *src = result + strlen(target);
287
288 while (size-- > 0) {
289 printf("%c", *src);
290 if (*len == (SHOW_MAX_LEN - 1)) {
291 *des = '\0';
292 break;
293 }
294 *des++ = *src++;
295 (*len)++;
296 }
297 }
298
OsExecNameMatch(const char * strPath,const char * nameLooking,char * strObj,unsigned int * maxLen)299 static int OsExecNameMatch(const char *strPath, const char *nameLooking, char *strObj, unsigned int *maxLen)
300 {
301 int count = 0;
302 DIR *openDir = NULL;
303 struct dirent *readDir = NULL;
304
305 openDir = opendir(strPath);
306 if (openDir == NULL) {
307 return (int)SH_ERROR;
308 }
309
310 for (readDir = readdir(openDir); readDir != NULL; readDir = readdir(openDir)) {
311 if (strncmp(nameLooking, readDir->d_name, strlen(nameLooking)) != 0) {
312 continue;
313 }
314 if (count == 0) {
315 if (strncpy_s(strObj, CMD_MAX_PATH, readDir->d_name, CMD_MAX_PATH - 1)) {
316 (void)closedir(openDir);
317 return (int)SH_ERROR;
318 }
319 *maxLen = strlen(readDir->d_name);
320 } else {
321 /* strncmp&cut the same strings of name matched */
322 StrncmpCut(readDir->d_name, strObj, strlen(strObj));
323 if (strlen(readDir->d_name) > *maxLen) {
324 *maxLen = strlen(readDir->d_name);
325 }
326 }
327 count++;
328 }
329
330 if (closedir(openDir) < 0) {
331 return (int)SH_ERROR;
332 }
333
334 return count;
335 }
336
OsTabMatchFile(char * cmdKey,unsigned int * len)337 static int OsTabMatchFile(char *cmdKey, unsigned int *len)
338 {
339 unsigned int maxLen = 0;
340 int count;
341 char *strOutput = NULL;
342 char *strCmp = NULL;
343 char *dirOpen = (char *)malloc(CMD_MAX_PATH * 3); /* 3:dirOpen\strOutput\strCmp */
344 if (dirOpen == NULL) {
345 return (int)SH_ERROR;
346 }
347
348 (void)memset_s(dirOpen, CMD_MAX_PATH * 3, 0, CMD_MAX_PATH * 3); /* 3:dirOpen\strOutput\strCmp */
349 strOutput = dirOpen + CMD_MAX_PATH;
350 strCmp = strOutput + CMD_MAX_PATH;
351
352 if (OsStrSeparate(cmdKey, dirOpen, strCmp, *len)) {
353 free(dirOpen);
354 return (int)SH_ERROR;
355 }
356
357 count = OsExecNameMatch(dirOpen, strCmp, strOutput, &maxLen);
358 /* one or more matched */
359 if (count >= 1) {
360 OsCompleteStr(strOutput, strCmp, cmdKey, len);
361
362 if (count == 1) {
363 free(dirOpen);
364 return 1;
365 }
366 if (OsPrintMatchList((unsigned int)count, dirOpen, strCmp, maxLen) == -1) {
367 free(dirOpen);
368 return (int)SH_ERROR;
369 }
370 }
371
372 free(dirOpen);
373 return count;
374 }
375
376 /*
377 * Description: Pass in the string and clear useless space ,which include:
378 * 1) The overmatch space which is not be marked by Quote's area
379 * Squeeze the overmatch space into one space
380 * 2) Clear all space before first valid character
381 * Input: cmdKey : Pass in the buff string, which is ready to be operated
382 * cmdOut : Pass out the buffer string ,which has already been operated
383 * size : cmdKey length
384 */
OsCmdKeyShift(const char * cmdKey,char * cmdOut,unsigned int size)385 unsigned int OsCmdKeyShift(const char *cmdKey, char *cmdOut, unsigned int size)
386 {
387 char *output = NULL;
388 char *outputBak = NULL;
389 unsigned int len;
390 int ret;
391 bool quotes = FALSE;
392
393 if ((cmdKey == NULL) || (cmdOut == NULL)) {
394 return (unsigned int)SH_ERROR;
395 }
396
397 len = strlen(cmdKey);
398 if ((*cmdKey == '\n') || (len >= size)) {
399 return (unsigned int)SH_ERROR;
400 }
401 output = (char *)malloc(len + 1);
402 if (output == NULL) {
403 printf("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
404 return (unsigned int)SH_ERROR;
405 }
406
407 /* Backup the 'output' start address */
408 outputBak = output;
409 /* Scan each character in 'cmdKey',and squeeze the overmuch space and ignore invalid character */
410 for (; *cmdKey != '\0'; cmdKey++) {
411 /* Detected a Double Quotes, switch the matching status */
412 if (*(cmdKey) == '\"') {
413 SWITCH_QUOTES_STATUS(quotes);
414 }
415 /* Ignore the current character in following situation */
416 /* 1) Quotes matching status is FALSE (which said that the space is not been marked by double quotes) */
417 /* 2) Current character is a space */
418 /* 3) Next character is a space too, or the string is been seeked to the end already(\0) */
419 /* 4) Invalid character, such as single quotes */
420 if ((*cmdKey == ' ') && ((*(cmdKey + 1) == ' ') || (*(cmdKey + 1) == '\0')) && QUOTES_STATUS_CLOSE(quotes)) {
421 continue;
422 }
423 if (*cmdKey == '\'') {
424 continue;
425 }
426 *output = *cmdKey;
427 output++;
428 }
429 *output = '\0';
430 /* Restore the 'output' start address */
431 output = outputBak;
432 len = strlen(output);
433 /* Clear the space which is located at the first character in buffer */
434 if (*output == ' ') {
435 output++;
436 len--;
437 }
438 /* Copy out the buffer which is been operated already */
439 ret = strncpy_s(cmdOut, size, output, len);
440 if (ret != SH_OK) {
441 printf("%s,%d strncpy_s failed, err:%d!\n", __FUNCTION__, __LINE__, ret);
442 free(outputBak);
443 return SH_ERROR;
444 }
445 cmdOut[len] = '\0';
446
447 free(outputBak);
448 return SH_OK;
449 }
450
OsTabCompletion(char * cmdKey,unsigned int * len)451 int OsTabCompletion(char *cmdKey, unsigned int *len)
452 {
453 int count;
454
455 if ((cmdKey == NULL) || (len == NULL)) {
456 return (int)SH_ERROR;
457 }
458
459 count = OsTabMatchFile(cmdKey, len);
460
461 return count;
462 }
463
OsShellKeyInit(ShellCB * shellCB)464 unsigned int OsShellKeyInit(ShellCB *shellCB)
465 {
466 CmdKeyLink *cmdKeyLink = NULL;
467 CmdKeyLink *cmdHistoryLink = NULL;
468
469 if (shellCB == NULL) {
470 return SH_ERROR;
471 }
472
473 cmdKeyLink = (CmdKeyLink *)malloc(sizeof(CmdKeyLink));
474 if (cmdKeyLink == NULL) {
475 printf("Shell CmdKeyLink memory alloc error!\n");
476 return SH_ERROR;
477 }
478 cmdHistoryLink = (CmdKeyLink *)malloc(sizeof(CmdKeyLink));
479 if (cmdHistoryLink == NULL) {
480 free(cmdKeyLink);
481 printf("Shell CmdHistoryLink memory alloc error!\n");
482 return SH_ERROR;
483 }
484
485 cmdKeyLink->count = 0;
486 SH_ListInit(&(cmdKeyLink->list));
487 shellCB->cmdKeyLink = (void *)cmdKeyLink;
488
489 cmdHistoryLink->count = 0;
490 SH_ListInit(&(cmdHistoryLink->list));
491 shellCB->cmdHistoryKeyLink = (void *)cmdHistoryLink;
492 shellCB->cmdMaskKeyLink = (void *)cmdHistoryLink;
493 return SH_OK;
494 }
495
OsShellKeyDeInit(CmdKeyLink * cmdKeyLink)496 void OsShellKeyDeInit(CmdKeyLink *cmdKeyLink)
497 {
498 CmdKeyLink *cmdtmp = NULL;
499 if (cmdKeyLink == NULL) {
500 return;
501 }
502
503 while (!SH_ListEmpty(&(cmdKeyLink->list))) {
504 cmdtmp = SH_LIST_ENTRY(cmdKeyLink->list.pstNext, CmdKeyLink, list);
505 SH_ListDelete(&cmdtmp->list);
506 free(cmdtmp);
507 }
508
509 cmdKeyLink->count = 0;
510 free(cmdKeyLink);
511 }
512
OsShellCmdPush(const char * string,CmdKeyLink * cmdKeyLink)513 void OsShellCmdPush(const char *string, CmdKeyLink *cmdKeyLink)
514 {
515 CmdKeyLink *cmdNewNode = NULL;
516 unsigned int len;
517
518 if ((string == NULL) || (strlen(string) == 0)) {
519 return;
520 }
521
522 len = strlen(string);
523 cmdNewNode = (CmdKeyLink *)malloc(sizeof(CmdKeyLink) + len + 1);
524 if (cmdNewNode == NULL) {
525 return;
526 }
527
528 (void)memset_s(cmdNewNode, sizeof(CmdKeyLink) + len + 1, 0, sizeof(CmdKeyLink) + len + 1);
529 if (strncpy_s(cmdNewNode->cmdString, len + 1, string, len)) {
530 free(cmdNewNode);
531 return;
532 }
533
534 SH_ListTailInsert(&(cmdKeyLink->list), &(cmdNewNode->list));
535
536 return;
537 }
538
OsShellHistoryShow(unsigned int value,ShellCB * shellCB)539 void OsShellHistoryShow(unsigned int value, ShellCB *shellCB)
540 {
541 CmdKeyLink *cmdtmp = NULL;
542 CmdKeyLink *cmdNode = shellCB->cmdHistoryKeyLink;
543 CmdKeyLink *cmdMask = shellCB->cmdMaskKeyLink;
544 int ret;
545
546 (void)pthread_mutex_lock(&shellCB->historyMutex);
547 if (value == CMD_KEY_DOWN) {
548 if (cmdMask == cmdNode) {
549 goto END;
550 }
551
552 cmdtmp = SH_LIST_ENTRY(cmdMask->list.pstNext, CmdKeyLink, list);
553 if (cmdtmp != cmdNode) {
554 cmdMask = cmdtmp;
555 } else {
556 goto END;
557 }
558 } else if (value == CMD_KEY_UP) {
559 cmdtmp = SH_LIST_ENTRY(cmdMask->list.pstPrev, CmdKeyLink, list);
560 if (cmdtmp != cmdNode) {
561 cmdMask = cmdtmp;
562 } else {
563 goto END;
564 }
565 }
566
567 while (shellCB->shellBufOffset--) {
568 printf("\b \b");
569 }
570 printf("%s", cmdMask->cmdString);
571 shellCB->shellBufOffset = strlen(cmdMask->cmdString);
572 (void)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN);
573 ret = memcpy_s(shellCB->shellBuf, SHOW_MAX_LEN, cmdMask->cmdString, shellCB->shellBufOffset);
574 if (ret != SH_OK) {
575 printf("%s, %d memcpy failed!\n", __FUNCTION__, __LINE__);
576 goto END;
577 }
578 shellCB->cmdMaskKeyLink = (void *)cmdMask;
579
580 END:
581 (void)pthread_mutex_unlock(&shellCB->historyMutex);
582 return;
583 }
584
OsCmdExec(CmdParsed * cmdParsed,char * cmdStr)585 unsigned int OsCmdExec(CmdParsed *cmdParsed, char *cmdStr)
586 {
587 unsigned int ret = SH_OK;
588 if (cmdParsed && cmdStr) {
589 ret = SH_NOK;
590 }
591
592 return ret;
593 }
594
595