• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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