• 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 "shmsg.h"
33 #include "shell_pri.h"
34 #include "shcmd.h"
35 #include "stdlib.h"
36 #include "stdio.h"
37 #include "unistd.h"
38 #include "securec.h"
39 #include "los_base.h"
40 #include "los_task.h"
41 #include "los_event.h"
42 #include "los_list.h"
43 #include "los_printf.h"
44 
45 #ifdef LOSCFG_FS_VFS
46 #include "console.h"
47 #endif
48 
49 
ShellGetInputBuf(ShellCB * shellCB)50 CHAR *ShellGetInputBuf(ShellCB *shellCB)
51 {
52     CmdKeyLink *cmdkey = shellCB->cmdKeyLink;
53     CmdKeyLink *cmdNode = NULL;
54 
55     (VOID)pthread_mutex_lock(&shellCB->keyMutex);
56     if ((cmdkey == NULL) || LOS_ListEmpty(&cmdkey->list)) {
57         (VOID)pthread_mutex_unlock(&shellCB->keyMutex);
58         return NULL;
59     }
60 
61     cmdNode = LOS_DL_LIST_ENTRY(cmdkey->list.pstNext, CmdKeyLink, list);
62     LOS_ListDelete(&(cmdNode->list)); /* 'cmdNode' freed in history save process */
63     (VOID)pthread_mutex_unlock(&shellCB->keyMutex);
64 
65     return cmdNode->cmdString;
66 }
67 
ShellSaveHistoryCmd(const CHAR * string,ShellCB * shellCB)68 STATIC VOID ShellSaveHistoryCmd(const CHAR *string, ShellCB *shellCB)
69 {
70     CmdKeyLink *cmdHistory = shellCB->cmdHistoryKeyLink;
71     CmdKeyLink *cmdkey = LOS_DL_LIST_ENTRY(string, CmdKeyLink, cmdString);
72     CmdKeyLink *cmdNxt = NULL;
73 
74     if ((string == NULL) || (strlen(string) == 0)) {
75         return;
76     }
77 
78     (VOID)pthread_mutex_lock(&shellCB->historyMutex);
79     if (cmdHistory->count != 0) {
80         cmdNxt = LOS_DL_LIST_ENTRY(cmdHistory->list.pstPrev, CmdKeyLink, list);
81         if (strcmp(string, cmdNxt->cmdString) == 0) {
82             (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)cmdkey);
83             (VOID)pthread_mutex_unlock(&shellCB->historyMutex);
84             return;
85         }
86     }
87 
88     if (cmdHistory->count == CMD_HISTORY_LEN) {
89         cmdNxt = LOS_DL_LIST_ENTRY(cmdHistory->list.pstNext, CmdKeyLink, list);
90         LOS_ListDelete(&(cmdNxt->list));
91         LOS_ListTailInsert(&(cmdHistory->list), &(cmdkey->list));
92         (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)cmdNxt);
93         (VOID)pthread_mutex_unlock(&shellCB->historyMutex);
94         return;
95     }
96 
97     LOS_ListTailInsert(&(cmdHistory->list), &(cmdkey->list));
98     cmdHistory->count++;
99 
100     (VOID)pthread_mutex_unlock(&shellCB->historyMutex);
101     return;
102 }
103 
ShellNotify(ShellCB * shellCB)104 STATIC VOID ShellNotify(ShellCB *shellCB)
105 {
106     (VOID)LOS_EventWrite(&shellCB->shellEvent, SHELL_CMD_PARSE_EVENT);
107 }
108 
109 enum {
110     STAT_NORMAL_KEY,
111     STAT_ESC_KEY,
112     STAT_MULTI_KEY
113 };
114 
ShellCmdLineCheckUDRL(const CHAR ch,ShellCB * shellCB)115 STATIC INT32 ShellCmdLineCheckUDRL(const CHAR ch, ShellCB *shellCB)
116 {
117     INT32 ret = LOS_OK;
118     if (ch == 0x1b) { /* 0x1b: ESC */
119         shellCB->shellKeyType = STAT_ESC_KEY;
120         return ret;
121     } else if (ch == 0x5b) { /* 0x5b: first Key combination */
122         if (shellCB->shellKeyType == STAT_ESC_KEY) {
123             shellCB->shellKeyType = STAT_MULTI_KEY;
124             return ret;
125         }
126     } else if (ch == 0x41) { /* up */
127         if (shellCB->shellKeyType == STAT_MULTI_KEY) {
128             OsShellHistoryShow(CMD_KEY_UP, shellCB);
129             shellCB->shellKeyType = STAT_NORMAL_KEY;
130             return ret;
131         }
132     } else if (ch == 0x42) { /* down */
133         if (shellCB->shellKeyType == STAT_MULTI_KEY) {
134             shellCB->shellKeyType = STAT_NORMAL_KEY;
135             OsShellHistoryShow(CMD_KEY_DOWN, shellCB);
136             return ret;
137         }
138     } else if (ch == 0x43) { /* right */
139         if (shellCB->shellKeyType == STAT_MULTI_KEY) {
140             shellCB->shellKeyType = STAT_NORMAL_KEY;
141             return ret;
142         }
143     } else if (ch == 0x44) { /* left */
144         if (shellCB->shellKeyType == STAT_MULTI_KEY) {
145             shellCB->shellKeyType = STAT_NORMAL_KEY;
146             return ret;
147         }
148     }
149     return LOS_NOK;
150 }
151 
ShellCmdLineParse(CHAR c,pf_OUTPUT outputFunc,ShellCB * shellCB)152 LITE_OS_SEC_TEXT_MINOR VOID ShellCmdLineParse(CHAR c, pf_OUTPUT outputFunc, ShellCB *shellCB)
153 {
154     const CHAR ch = c;
155     INT32 ret;
156 
157     if ((shellCB->shellBufOffset == 0) && (ch != '\n') && (ch != '\0')) {
158         (VOID)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN);
159     }
160 
161     if ((ch == '\r') || (ch == '\n')) {
162         if (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1)) {
163             shellCB->shellBuf[shellCB->shellBufOffset] = '\0';
164         }
165         shellCB->shellBufOffset = 0;
166         (VOID)pthread_mutex_lock(&shellCB->keyMutex);
167         OsShellCmdPush(shellCB->shellBuf, shellCB->cmdKeyLink);
168         (VOID)pthread_mutex_unlock(&shellCB->keyMutex);
169         ShellNotify(shellCB);
170         return;
171     } else if ((ch == '\b') || (ch == 0x7F)) { /* backspace or delete(0x7F) */
172         if ((shellCB->shellBufOffset > 0) && (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1))) {
173             shellCB->shellBuf[shellCB->shellBufOffset - 1] = '\0';
174             shellCB->shellBufOffset--;
175             outputFunc("\b \b");
176         }
177         return;
178     } else if (ch == 0x09) { /* 0x09: tab */
179         if ((shellCB->shellBufOffset > 0) && (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1))) {
180             ret = OsTabCompletion(shellCB->shellBuf, &shellCB->shellBufOffset);
181             if (ret > 1) {
182                 outputFunc("OHOS # %s", shellCB->shellBuf);
183             }
184         }
185         return;
186     }
187     /* parse the up/down/right/left key */
188     ret = ShellCmdLineCheckUDRL(ch, shellCB);
189     if (ret == LOS_OK) {
190         return;
191     }
192 
193     if ((ch != '\n') && (ch != '\0')) {
194         if (shellCB->shellBufOffset < (SHOW_MAX_LEN - 1)) {
195             shellCB->shellBuf[shellCB->shellBufOffset] = ch;
196         } else {
197             shellCB->shellBuf[SHOW_MAX_LEN - 1] = '\0';
198         }
199         shellCB->shellBufOffset++;
200         outputFunc("%c", ch);
201     }
202 
203     shellCB->shellKeyType = STAT_NORMAL_KEY;
204 }
205 
ShellMsgTypeGet(CmdParsed * cmdParsed,const CHAR * cmdType)206 LITE_OS_SEC_TEXT_MINOR UINT32 ShellMsgTypeGet(CmdParsed *cmdParsed, const CHAR *cmdType)
207 {
208     CmdItemNode *curCmdItem = (CmdItemNode *)NULL;
209     UINT32 len;
210     UINT32 minLen;
211     CmdModInfo *cmdInfo = OsCmdInfoGet();
212 
213     if ((cmdParsed == NULL) || (cmdType == NULL)) {
214         return OS_INVALID;
215     }
216 
217     len = strlen(cmdType);
218     LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(cmdInfo->cmdList.list), CmdItemNode, list) {
219         if ((len == strlen(curCmdItem->cmd->cmdKey)) &&
220             (strncmp((CHAR *)(curCmdItem->cmd->cmdKey), cmdType, len) == 0)) {
221             minLen = (len < CMD_KEY_LEN) ? len : CMD_KEY_LEN;
222             (VOID)memcpy_s((CHAR *)(cmdParsed->cmdKeyword), CMD_KEY_LEN, cmdType, minLen);
223             cmdParsed->cmdType = curCmdItem->cmd->cmdType;
224             return LOS_OK;
225         }
226     }
227 
228     return OS_INVALID;
229 }
230 
ShellMsgNameGetAndExec(CmdParsed * cmdParsed,const CHAR * output,UINT32 len)231 STATIC UINT32 ShellMsgNameGetAndExec(CmdParsed *cmdParsed, const CHAR *output, UINT32 len)
232 {
233     UINT32 loop;
234     UINT32 ret;
235     const CHAR *tmpStr = NULL;
236     BOOL quotes = FALSE;
237     CHAR *msgName = (CHAR *)LOS_MemAlloc(m_aucSysMem0, len + 1);
238     if (msgName == NULL) {
239         PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
240         return OS_INVALID;
241     }
242     /* Scan the 'output' string for command */
243     /* Notice: Command string must not have any special name */
244     for (tmpStr = output, loop = 0; (*tmpStr != '\0') && (loop < len);) {
245         /* If reach a double quotes, switch the quotes matching status */
246         if (*tmpStr == '\"') {
247             SWITCH_QUOTES_STATUS(quotes);
248             /* Ignore the double quote CHARactor itself */
249             tmpStr++;
250             continue;
251         }
252         /* If detected a space which the quotes matching status is false */
253         /* which said has detected the first space for separator, finish this scan operation */
254         if ((*tmpStr == ' ') && (QUOTES_STATUS_CLOSE(quotes))) {
255             break;
256         }
257         msgName[loop] = *tmpStr++;
258         loop++;
259     }
260     msgName[loop] = '\0';
261     /* Scan the command list to check whether the command can be found */
262     ret = ShellMsgTypeGet(cmdParsed, msgName);
263     PRINTK("\n");
264     if (ret != LOS_OK) {
265         PRINTK("%s:command not found", msgName);
266     } else {
267         (VOID)OsCmdExec(cmdParsed, (CHAR *)output);
268     }
269     (VOID)LOS_MemFree(m_aucSysMem0, msgName);
270     return ret;
271 }
272 
ShellMsgParse(const VOID * msg)273 LITE_OS_SEC_TEXT_MINOR UINT32 ShellMsgParse(const VOID *msg)
274 {
275     CHAR *output = NULL;
276     UINT32 len, cmdLen, newLen;
277     CmdParsed cmdParsed;
278     UINT32 ret = OS_INVALID;
279     CHAR *buf = (CHAR *)msg;
280     CHAR *newMsg = NULL;
281     CHAR *cmd = "exec";
282 
283     if (msg == NULL) {
284         goto END;
285     }
286 
287     len = strlen(msg);
288     /* 2: strlen("./") */
289     if ((len > 2) && (buf[0] == '.') && (buf[1] == '/')) {
290         cmdLen = strlen(cmd);
291         newLen = len + 1 + cmdLen + 1;
292         newMsg = (CHAR *)LOS_MemAlloc(m_aucSysMem0, newLen);
293         if (newMsg == NULL) {
294             PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
295             goto END;
296         }
297         (VOID)memcpy_s(newMsg, newLen, cmd, cmdLen);
298         newMsg[cmdLen] = ' ';
299         (VOID)memcpy_s(newMsg + cmdLen + 1, newLen - cmdLen - 1,  (CHAR *)msg + 1, len);
300         msg = newMsg;
301         len = newLen - 1;
302     }
303     output = (CHAR *)LOS_MemAlloc(m_aucSysMem0, len + 1);
304     if (output == NULL) {
305         PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
306         goto END;
307     }
308     /* Call function 'OsCmdKeyShift' to squeeze and clear useless or overmuch space if string buffer */
309     ret = OsCmdKeyShift((CHAR *)msg, output, len + 1);
310     if ((ret != LOS_OK) || (strlen(output) == 0)) {
311         ret = OS_INVALID;
312         goto END_FREE_OUTPUT;
313     }
314 
315     (VOID)memset_s(&cmdParsed, sizeof(CmdParsed), 0, sizeof(CmdParsed));
316 
317     ret = ShellMsgNameGetAndExec(&cmdParsed, output, len);
318 
319 END_FREE_OUTPUT:
320     (VOID)LOS_MemFree(m_aucSysMem0, output);
321 END:
322     if (newMsg != NULL) {
323         (VOID)LOS_MemFree(m_aucSysMem0, newMsg);
324     }
325     return ret;
326 }
327 
328 #ifdef LOSCFG_FS_VFS
ShellEntry(UINTPTR param)329 LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntry(UINTPTR param)
330 {
331     CHAR ch;
332     INT32 n;
333     ShellCB *shellCB = (ShellCB *)param;
334 
335     CONSOLE_CB *consoleCB = OsGetConsoleByID((INT32)shellCB->consoleID);
336     if (consoleCB == NULL) {
337         PRINT_ERR("Shell task init error!\n");
338         return 1;
339     }
340 
341     (VOID)memset_s(shellCB->shellBuf, SHOW_MAX_LEN, 0, SHOW_MAX_LEN);
342 
343     while (1) {
344 #ifdef LOSCFG_PLATFORM_CONSOLE
345         if (!IsConsoleOccupied(consoleCB)) {
346 #endif
347             /* is console ready for shell ? */
348             n = read(consoleCB->fd, &ch, 1);
349             if (n == 1) {
350                 ShellCmdLineParse(ch, (pf_OUTPUT)dprintf, shellCB);
351             }
352             if (is_nonblock(consoleCB)) {
353                 LOS_Msleep(50); /* 50: 50MS for sleep */
354             }
355 #ifdef LOSCFG_PLATFORM_CONSOLE
356         }
357 #endif
358     }
359 }
360 #endif
361 
ShellCmdProcess(ShellCB * shellCB)362 STATIC VOID ShellCmdProcess(ShellCB *shellCB)
363 {
364     CHAR *buf = NULL;
365     while (1) {
366         buf = ShellGetInputBuf(shellCB);
367         if (buf == NULL) {
368             break;
369         }
370         (VOID)ShellMsgParse(buf);
371         ShellSaveHistoryCmd(buf, shellCB);
372         shellCB->cmdMaskKeyLink = shellCB->cmdHistoryKeyLink;
373     }
374 }
375 
ShellTask(UINTPTR param1,UINTPTR param2,UINTPTR param3,UINTPTR param4)376 LITE_OS_SEC_TEXT_MINOR UINT32 ShellTask(UINTPTR param1,
377                                         UINTPTR param2,
378                                         UINTPTR param3,
379                                         UINTPTR param4)
380 {
381     UINT32 ret;
382     ShellCB *shellCB = (ShellCB *)param1;
383     (VOID)param2;
384     (VOID)param3;
385     (VOID)param4;
386 
387     while (1) {
388         PRINTK("\nOHOS # ");
389         ret = LOS_EventRead(&shellCB->shellEvent,
390                             0xFFF, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
391         if (ret == SHELL_CMD_PARSE_EVENT) {
392             ShellCmdProcess(shellCB);
393         } else if (ret == CONSOLE_SHELL_KEY_EVENT) {
394             break;
395         }
396     }
397     OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdKeyLink);
398     OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdHistoryKeyLink);
399     (VOID)LOS_EventDestroy(&shellCB->shellEvent);
400     (VOID)LOS_MemFree((VOID *)m_aucSysMem0, shellCB);
401     return 0;
402 }
403 
404 #define SERIAL_SHELL_TASK_NAME "SerialShellTask"
405 #define SERIAL_ENTRY_TASK_NAME "SerialEntryTask"
406 #define TELNET_SHELL_TASK_NAME "TelnetShellTask"
407 #define TELNET_ENTRY_TASK_NAME "TelnetEntryTask"
408 
ShellTaskInit(ShellCB * shellCB)409 LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
410 {
411     CHAR *name = NULL;
412     TSK_INIT_PARAM_S initParam = {0};
413 
414     if (shellCB->consoleID == CONSOLE_SERIAL) {
415         name = SERIAL_SHELL_TASK_NAME;
416     } else if (shellCB->consoleID == CONSOLE_TELNET) {
417         name = TELNET_SHELL_TASK_NAME;
418     } else {
419         return LOS_NOK;
420     }
421 
422     initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;
423     initParam.usTaskPrio   = 9; /* 9:shell task priority */
424     initParam.auwArgs[0]   = (UINTPTR)shellCB;
425     initParam.uwStackSize  = 0x3000;
426     initParam.pcName       = name;
427     initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
428 
429     (VOID)LOS_EventInit(&shellCB->shellEvent);
430 
431     return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);
432 }
433 
ShellEntryInit(ShellCB * shellCB)434 LITE_OS_SEC_TEXT_MINOR UINT32 ShellEntryInit(ShellCB *shellCB)
435 {
436     UINT32 ret;
437     CHAR *name = NULL;
438     TSK_INIT_PARAM_S initParam = {0};
439 
440     if (shellCB->consoleID == CONSOLE_SERIAL) {
441         name = SERIAL_ENTRY_TASK_NAME;
442     } else if (shellCB->consoleID == CONSOLE_TELNET) {
443         name = TELNET_ENTRY_TASK_NAME;
444     } else {
445         return LOS_NOK;
446     }
447 
448     initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellEntry;
449     initParam.usTaskPrio   = 9; /* 9:shell task priority */
450     initParam.auwArgs[0]   = (UINTPTR)shellCB;
451     initParam.uwStackSize  = 0x1000;
452     initParam.pcName       = name;
453     initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
454 
455     ret = LOS_TaskCreate(&shellCB->shellEntryHandle, &initParam);
456 #ifdef LOSCFG_PLATFORM_CONSOLE
457     (VOID)ConsoleTaskReg((INT32)shellCB->consoleID, shellCB->shellEntryHandle);
458 #endif
459 
460     return ret;
461 }
462 
463