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 "securec.h"
34#include "shcmd.h"
35#include "show.h"
36#if (LOSCFG_USE_SHELL == 1)
37#include "uart.h"
38#endif
39#include "los_event.h"
40#include "los_task.h"
41
42EVENT_CB_S g_shellInputEvent;
43#define SHELL_CMD_MAX_SIZE 64
44
45#define VISIABLE_CHAR(ch) ((ch) > 0x1F && (ch) < 0x7F)
46
47UINT32 ShellMsgTypeGet(CmdParsed *cmdParsed, const CHAR *cmdType)
48{
49    CmdItemNode *curCmdItem = (CmdItemNode *)NULL;
50    UINT32 len;
51    UINT32 minLen;
52    CmdModInfo *cmdInfo = OsCmdInfoGet();
53
54    if ((cmdParsed == NULL) || (cmdType == NULL)) {
55        return OS_INVALID;
56    }
57
58    len = strlen(cmdType);
59    LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(cmdInfo->cmdList.list), CmdItemNode, list) {
60        if ((len == strlen(curCmdItem->cmd->cmdKey)) &&
61            (strncmp((CHAR *)(curCmdItem->cmd->cmdKey), cmdType, len) == 0)) {
62            minLen = (len < CMD_KEY_LEN) ? len : CMD_KEY_LEN;
63            (VOID)memcpy_s((CHAR *)(cmdParsed->cmdKeyword), CMD_KEY_LEN, cmdType, minLen);
64            cmdParsed->cmdType = curCmdItem->cmd->cmdType;
65            return LOS_OK;
66        }
67    }
68
69    return OS_INVALID;
70}
71
72CHAR *GetCmdName(const CHAR *cmdline, UINT32 len)
73{
74    UINT32 loop;
75    const CHAR *tmpStr = NULL;
76    BOOL quotes = FALSE;
77    CHAR *cmdName = NULL;
78    if (cmdline == NULL) {
79        return NULL;
80    }
81
82    cmdName = (CHAR *)malloc(len + 1);
83    if (cmdName == NULL) {
84        PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
85        return NULL;
86    }
87
88    /* Scan the 'cmdline' string for command */
89    /* Notice: Command string must not have any special name */
90    for (tmpStr = cmdline, loop = 0; (*tmpStr != '\0') && (loop < len); ) {
91        /* If reach a double quotes, switch the quotes matching status */
92        if (*tmpStr == '\"') {
93            SWITCH_QUOTES_STATUS(quotes);
94            /* Ignore the double quote charactor itself */
95            tmpStr++;
96            continue;
97        }
98        /* If detected a space which the quotes matching status is false */
99        /* which said has detected the first space for separator, finish this scan operation */
100        if ((*tmpStr == ' ') && (QUOTES_STATUS_CLOSE(quotes))) {
101            break;
102        }
103        cmdName[loop] = *tmpStr++;
104        loop++;
105    }
106    cmdName[loop] = '\0';
107
108    return cmdName;
109}
110
111
112UINT32 PreHandleCmdline(const CHAR *input, CHAR **output, UINT32 *outputlen)
113{
114    UINT32 shiftLen;
115    UINT32 ret;
116    const CHAR *cmdBuf = input;
117    UINT32 cmdBufLen = strlen(cmdBuf);
118    CHAR *shiftStr = (CHAR *)malloc(cmdBufLen + 1);
119
120    if (shiftStr == NULL) {
121        PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
122        return SH_NOK;
123    }
124    (VOID)memset_s(shiftStr, cmdBufLen + 1, 0, cmdBufLen + 1);
125
126    /* Call function 'OsCmdKeyShift' to squeeze and clear useless or overmuch space if string buffer */
127    ret = OsCmdKeyShift(cmdBuf, shiftStr, cmdBufLen + 1);
128    shiftLen = strlen(shiftStr);
129    if ((ret != SH_OK) || (shiftLen == 0)) {
130        ret = SH_NOK;
131        goto END_FREE_SHIFTSTR;
132    }
133    *output = shiftStr;
134    *outputlen = shiftLen;
135
136    ret = SH_OK;
137    goto END;
138
139END_FREE_SHIFTSTR:
140    free(shiftStr);
141END:
142    return ret;
143}
144
145STATIC VOID ParseAndExecCmdline(CmdParsed *cmdParsed, const CHAR *cmdline, UINT32 len)
146{
147    INT32 i;
148    UINT32 ret;
149    CHAR *cmdName = NULL;
150
151    cmdName = GetCmdName(cmdline, len);
152    if (cmdName == NULL) {
153        PRINTK("malloc failure in %s[%d]\n", __FUNCTION__, __LINE__);
154        return;
155    }
156
157    ret = ShellMsgTypeGet(cmdParsed, cmdName);
158    if (ret != LOS_OK) {
159        PRINTK("%s:command not found\n", cmdName);
160        free(cmdName);
161        return;
162    }
163
164    ret = OsCmdParse((CHAR *)cmdline, cmdParsed);
165    if (ret != SH_OK) {
166        PRINTK("cmd parse failure in %s[%d]\n", __FUNCTION__, __LINE__);
167        goto OUT;
168    }
169
170    (VOID)OsCmdExec(cmdParsed);
171
172OUT:
173    for (i = 0; i < cmdParsed->paramCnt; i++) {
174        if (cmdParsed->paramArray[i] != NULL) {
175            free(cmdParsed->paramArray[i]);
176            cmdParsed->paramArray[i] = NULL;
177        }
178    }
179    free(cmdName);
180}
181
182LITE_OS_SEC_TEXT_MINOR VOID ExecCmdline(const CHAR *cmdline)
183{
184    UINT32 ret;
185    CHAR *output = NULL;
186    UINT32 outputlen;
187    CmdParsed cmdParsed;
188
189    if (cmdline == NULL) {
190        return;
191    }
192
193    (VOID)OsShellInit();
194
195    /* strip out unnecessary characters */
196    ret = PreHandleCmdline(cmdline, &output, &outputlen);
197    if (ret == SH_NOK) {
198        return;
199    }
200
201    (VOID)memset_s(&cmdParsed, sizeof(CmdParsed), 0, sizeof(CmdParsed));
202    ParseAndExecCmdline(&cmdParsed, output, outputlen);
203    free(output);
204}
205
206#if (LOSCFG_USE_SHELL == 1)
207VOID ShellTaskEntry(VOID)
208{
209    CHAR buf[SHELL_CMD_MAX_SIZE] = {0};
210    CHAR *ptr = buf;
211    PRINTK("OHOS # ");
212    while (1) {
213        (VOID)LOS_EventRead(&g_shellInputEvent, 0x1, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
214        while ((*ptr = (UINT8)UartGetc()) != 0 && *ptr != 13) {
215            if (*ptr == '\x03') { /* ctrl + c */
216                PRINTK("^C\n\rOHOS # ");
217                ptr = buf;
218                break;
219            }
220            if (*ptr == '\b' && ptr != buf) { /* support backspace */
221                PRINTK("\b \b");
222                ptr--;
223                break;
224            }
225            if (!VISIABLE_CHAR(*ptr)) {
226                break;
227            }
228            PRINTK("%c", *ptr);
229            if ((ptr - buf) == (sizeof(buf) - 1)) {
230                break;
231            }
232            ptr++;
233        }
234        if (ptr != buf) {
235            if (*ptr == 13 || ((ptr - buf) == (sizeof(buf) - 1))) {
236                *ptr = '\0';
237                ptr = buf;
238                PRINTK("\n\r");
239                ExecCmdline(buf);
240                PRINTK("OHOS # ");
241            }
242        } else if (*ptr == 13) {
243            PRINTK("\n\rOHOS # ");
244        }
245    }
246}
247
248LITE_OS_SEC_TEXT_MINOR UINT32 LosShellInit(VOID)
249{
250    UINT32 ret;
251    UINT32 taskID1;
252    TSK_INIT_PARAM_S task1 = { 0 };
253
254    ret = LOS_EventInit(&g_shellInputEvent);
255    if (ret != LOS_OK) {
256        PRINTK("Init shellInputEvent failed! ERROR: 0x%x\n", ret);
257        return ret;
258    }
259
260    task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTaskEntry;
261    task1.uwStackSize  = LOSCFG_SHELL_STACK_SIZE;
262    task1.pcName       = "ShellTaskEntry";
263    task1.usTaskPrio   = LOSCFG_SHELL_PRIO;
264    ret = LOS_TaskCreate(&taskID1, &task1);
265    if (ret != LOS_OK) {
266        PRINTK("Create Shell Task failed! ERROR: 0x%x\n", ret);
267        return ret;
268    }
269
270    return ret;
271}
272#endif
273