1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 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 "shmsg.h"
35#include "stdlib.h"
36#include "unistd.h"
37#include "dirent.h"
38#include "securec.h"
39#include "los_mux.h"
40#include "los_memory.h"
41
42#if (LOSCFG_DEBUG_TOOLS == 1)
43#include "los_debugtools.h"
44#endif
45
46#if (LOSCFG_KERNEL_TRACE == 1)
47#include "los_trace_pri.h"
48#endif
49
50#define SHELL_INIT_MAGIC_FLAG 0xABABABAB
51
52STATIC CmdModInfo cmdInfo;
53ShellCB *g_shellCB = NULL;
54CmdItem g_shellcmdAll[] = {
55    {CMD_TYPE_STD, "date", XARGS, (CmdCallBackFunc)OsShellCmdDate},
56    {CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask},
57    {CMD_TYPE_EX, "free", XARGS, (CmdCallBackFunc)OsShellCmdFree},
58#if (LOSCFG_MEM_WATERLINE == 1)
59    {CMD_TYPE_EX, "memusage", XARGS, (CmdCallBackFunc)OsShellCmdWaterLine},
60#endif
61#ifdef LWIP_SHELLCMD_ENABLE
62    {CMD_TYPE_EX, "ifconfig", XARGS, (CmdCallBackFunc)lwip_ifconfig},
63    {CMD_TYPE_EX, "ping", XARGS, (CmdCallBackFunc)OsShellPing},
64#endif
65#if (LOSCFG_FS_VFS == 1)
66    {CMD_TYPE_EX, "touch", XARGS, (CmdCallBackFunc)OsShellCmdTouch},
67    {CMD_TYPE_EX, "ls", XARGS, (CmdCallBackFunc)OsShellCmdLs},
68    {CMD_TYPE_EX, "pwd", XARGS, (CmdCallBackFunc)OsShellCmdPwd},
69    {CMD_TYPE_EX, "cd", XARGS, (CmdCallBackFunc)OsShellCmdCd},
70    {CMD_TYPE_EX, "cat", XARGS, (CmdCallBackFunc)OsShellCmdCat},
71    {CMD_TYPE_EX, "rm", XARGS, (CmdCallBackFunc)OsShellCmdRm},
72    {CMD_TYPE_EX, "rmdir", XARGS, (CmdCallBackFunc)OsShellCmdRmdir},
73    {CMD_TYPE_EX, "mkdir", XARGS, (CmdCallBackFunc)OsShellCmdMkdir},
74    {CMD_TYPE_EX, "cp", XARGS, (CmdCallBackFunc)OsShellCmdCp},
75#endif
76#if (LOSCFG_DEBUG_TOOLS == 1)
77    {CMD_TYPE_EX, "stack", 1, (CmdCallBackFunc)OsShellCmdStackDump},
78    {CMD_TYPE_EX, "hwi", 1, (CmdCallBackFunc)OsShellCmdHwiDump},
79    {CMD_TYPE_EX, "st", 1, (CmdCallBackFunc)OsShellCmdSchedTrace},
80#endif
81    {CMD_TYPE_EX, "help", 0, (CmdCallBackFunc)OsShellCmdHelp},
82#if (LOSCFG_KERNEL_TRACE == 1)
83    {CMD_TYPE_EX, "trace_start", 0, (CmdCallBackFunc)LOS_TraceStart},
84    {CMD_TYPE_EX, "trace_stop",  0, (CmdCallBackFunc)LOS_TraceStop},
85    {CMD_TYPE_EX, "trace_mask",  1, (CmdCallBackFunc)OsShellCmdTraceSetMask},
86    {CMD_TYPE_EX, "trace_reset", 0, (CmdCallBackFunc)LOS_TraceReset},
87    {CMD_TYPE_EX, "trace_dump", 1, (CmdCallBackFunc)OsShellCmdTraceDump},
88#endif
89};
90
91CmdModInfo *OsCmdInfoGet(VOID)
92{
93    return &cmdInfo;
94}
95
96/*
97 * Description: Pass in the string and clear useless space ,which include:
98 *                1) The overmatch space which is not be marked by Quote's area
99 *                   Squeeze the overmatch space into one space
100 *                2) Clear all space before first valid character
101 * Input:       cmdKey : Pass in the buff string, which is ready to be operated
102 *              cmdOut : Pass out the buffer string ,which has already been operated
103 *              size : cmdKey length
104 */
105LITE_OS_SEC_TEXT_MINOR UINT32 OsCmdKeyShift(const CHAR *cmdKey, CHAR *cmdOut, UINT32 size)
106{
107    CHAR *output = NULL;
108    CHAR *outputBak = NULL;
109    UINT32 len;
110    INT32 ret;
111    BOOL quotes = FALSE;
112
113    if ((cmdKey == NULL) || (cmdOut == NULL)) {
114        return (UINT32)OS_ERROR;
115    }
116
117    len = strlen(cmdKey);
118    if (len >= size) {
119        return (UINT32)OS_ERROR;
120    }
121    output = (CHAR*)LOS_MemAlloc(m_aucSysMem0, len + 1);
122    if (output == NULL) {
123        PRINTK("malloc failure in %s[%d]", __FUNCTION__, __LINE__);
124        return (UINT32)OS_ERROR;
125    }
126    (VOID)memset_s(output, len + 1, 0, len + 1);
127    /* Backup the 'output' start address */
128    outputBak = output;
129    /* Scan each charactor in 'cmdKey',and squeeze the overmuch space and ignore invalid charactor */
130    for (; *cmdKey != '\0'; cmdKey++) {
131        /* Detected a Double Quotes, switch the matching status */
132        if (*(cmdKey) == '\"') {
133            SWITCH_QUOTES_STATUS(quotes);
134        }
135        /* Ignore the current charactor in following situation */
136        /* 1) Quotes matching status is FALSE (which said that the space is not been marked by double quotes) */
137        /* 2) Current charactor is a space */
138        /* 3) Next charactor is a space too, or the string is been seeked to the end already(\0) */
139        /* 4) Invalid charactor, such as single quotes */
140        if ((*cmdKey == ' ') && ((*(cmdKey + 1) == ' ') || (*(cmdKey + 1) == '\0')) && QUOTES_STATUS_CLOSE(quotes)) {
141            continue;
142        }
143        if (*cmdKey == '\'') {
144            continue;
145        }
146        *output = *cmdKey;
147        output++;
148    }
149    *output = '\0';
150    /* Restore the 'output' start address */
151    output = outputBak;
152    len = strlen(output);
153    /* Clear the space which is located at the first charactor in buffer */
154    if (*outputBak == ' ') {
155        output++;
156        len--;
157    }
158    /* Copy out the buffer which is been operated already */
159    ret = strncpy_s(cmdOut, size, output, len);
160    if (ret != EOK) {
161        PRINT_ERR("%s,%d strncpy_s failed, err:%d!\n", __FUNCTION__, __LINE__, ret);
162        (VOID)LOS_MemFree(m_aucSysMem0, output);
163        return OS_ERROR;
164    }
165    cmdOut[len] = '\0';
166
167    (VOID)LOS_MemFree(m_aucSysMem0, output);
168
169    return LOS_OK;
170}
171
172LITE_OS_SEC_TEXT_MINOR BOOL OsCmdKeyCheck(const CHAR *cmdKey)
173{
174    const CHAR *temp = cmdKey;
175    enum Stat {
176        STAT_NONE,
177        STAT_DIGIT,
178        STAT_OTHER
179    } state = STAT_NONE;
180
181    if (strlen(cmdKey) >= CMD_KEY_LEN) {
182        return FALSE;
183    }
184
185    while (*temp != '\0') {
186        if (!((*temp <= '9') && (*temp >= '0')) &&
187            !((*temp <= 'z') && (*temp >= 'a')) &&
188            !((*temp <= 'Z') && (*temp >= 'A')) &&
189            (*temp != '_') && (*temp != '-')) {
190            return FALSE;
191        }
192
193        if ((*temp >= '0') && (*temp <= '9')) {
194            if (state == STAT_NONE) {
195                state = STAT_DIGIT;
196            }
197        } else {
198            state = STAT_OTHER;
199        }
200
201        temp++;
202    }
203
204    if (state == STAT_DIGIT) {
205        return FALSE;
206    }
207
208    return TRUE;
209}
210
211LITE_OS_SEC_TEXT_MINOR VOID OsCmdAscendingInsert(CmdItemNode *cmd)
212{
213    CmdItemNode *cmdItem = NULL;
214    CmdItemNode *cmdNext = NULL;
215
216    if (cmd == NULL) {
217        return;
218    }
219
220    for (cmdItem = LOS_DL_LIST_ENTRY((&cmdInfo.cmdList.list)->pstPrev, CmdItemNode, list);
221        &cmdItem->list != &(cmdInfo.cmdList.list);) {
222        cmdNext = LOS_DL_LIST_ENTRY(cmdItem->list.pstPrev, CmdItemNode, list);
223        if (&cmdNext->list != &(cmdInfo.cmdList.list)) {
224            if ((strncmp(cmdItem->cmd->cmdKey, cmd->cmd->cmdKey, strlen(cmd->cmd->cmdKey)) >= 0) &&
225                (strncmp(cmdNext->cmd->cmdKey, cmd->cmd->cmdKey, strlen(cmd->cmd->cmdKey)) < 0)) {
226                LOS_ListTailInsert(&(cmdItem->list), &(cmd->list));
227                return;
228            }
229            cmdItem = cmdNext;
230        } else {
231            if (strncmp(cmd->cmd->cmdKey, cmdItem->cmd->cmdKey, strlen(cmd->cmd->cmdKey)) > 0) {
232                cmdItem = cmdNext;
233            }
234            break;
235        }
236    }
237
238    LOS_ListTailInsert(&(cmdItem->list), &(cmd->list));
239}
240
241LITE_OS_SEC_TEXT_MINOR UINT32 OsShellKeyInit(ShellCB *shellCB)
242{
243    CmdKeyLink *cmdKeyLink = NULL;
244    CmdKeyLink *cmdHistoryLink = NULL;
245
246    if (shellCB == NULL) {
247        return OS_ERROR;
248    }
249    cmdKeyLink = (CmdKeyLink *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdKeyLink));
250    if (cmdKeyLink == NULL) {
251        PRINT_ERR("Shell CmdKeyLink memory alloc error!\n");
252        return OS_ERROR;
253    }
254    cmdHistoryLink = (CmdKeyLink *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdKeyLink));
255    if (cmdHistoryLink == NULL) {
256        (VOID)LOS_MemFree(m_aucSysMem0, cmdKeyLink);
257        PRINT_ERR("Shell CmdHistoryLink memory alloc error!\n");
258        return OS_ERROR;
259    }
260
261    cmdKeyLink->count = 0;
262    LOS_ListInit(&(cmdKeyLink->list));
263    shellCB->cmdKeyLink = (VOID *)cmdKeyLink;
264
265    cmdHistoryLink->count = 0;
266    LOS_ListInit(&(cmdHistoryLink->list));
267    shellCB->cmdHistoryKeyLink = (VOID *)cmdHistoryLink;
268    shellCB->cmdMaskKeyLink = (VOID *)cmdHistoryLink;
269    return LOS_OK;
270}
271
272LITE_OS_SEC_TEXT_MINOR VOID OsShellKeyDeInit(CmdKeyLink *cmdKeyLink)
273{
274    CmdKeyLink *cmdtmp = NULL;
275    if (cmdKeyLink == NULL) {
276        return;
277    }
278
279    while (!LOS_ListEmpty(&(cmdKeyLink->list))) {
280        cmdtmp = LOS_DL_LIST_ENTRY(cmdKeyLink->list.pstNext, CmdKeyLink, list);
281        LOS_ListDelete(&cmdtmp->list);
282        (VOID)LOS_MemFree(m_aucSysMem0, cmdtmp);
283    }
284
285    cmdKeyLink->count = 0;
286    (VOID)LOS_MemFree(m_aucSysMem0, cmdKeyLink);
287}
288
289LITE_OS_SEC_TEXT_MINOR UINT32 OsShellSysCmdRegister(VOID)
290{
291    UINT32 i;
292    UINT8 *cmdItemGroup = NULL;
293    UINT32 index = sizeof(g_shellcmdAll) / sizeof(CmdItem);
294    CmdItemNode *cmdItem = NULL;
295
296    cmdItemGroup = (UINT8 *)LOS_MemAlloc(m_aucSysMem0, index * sizeof(CmdItemNode));
297    if (cmdItemGroup == NULL) {
298        PRINT_ERR("[%s]System memory allocation failure!\n", __FUNCTION__);
299        return (UINT32)OS_ERROR;
300    }
301
302    for (i = 0; i < index; ++i) {
303        cmdItem = (CmdItemNode *)(cmdItemGroup + i * sizeof(CmdItemNode));
304        cmdItem->cmd = &g_shellcmdAll[i];
305        OsCmdAscendingInsert(cmdItem);
306    }
307    cmdInfo.listNum += index;
308    return LOS_OK;
309}
310
311LITE_OS_SEC_TEXT_MINOR UINT32 OsCmdExec(CmdParsed *cmdParsed)
312{
313    UINT32 ret;
314    CmdCallBackFunc cmdHook = NULL;
315    CmdItemNode *curCmdItem = NULL;
316    UINT32 i;
317    const CHAR *cmdKey = NULL;
318
319    if (cmdParsed == NULL) {
320        return (UINT32)OS_ERROR;
321    }
322
323    LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(cmdInfo.cmdList.list), CmdItemNode, list) {
324        cmdKey = curCmdItem->cmd->cmdKey;
325        if ((cmdParsed->cmdType == curCmdItem->cmd->cmdType) &&
326            (strlen(cmdKey) == strlen(cmdParsed->cmdKeyword)) &&
327            (strncmp(cmdKey, (CHAR *)(cmdParsed->cmdKeyword), strlen(cmdKey)) == 0)) {
328            cmdHook = curCmdItem->cmd->cmdHook;
329            break;
330        }
331    }
332
333    ret = OS_ERROR;
334    if (cmdHook != NULL) {
335        ret = (cmdHook)(cmdParsed->paramCnt, (const CHAR **)cmdParsed->paramArray);
336    }
337
338    for (i = 0; i < cmdParsed->paramCnt; i++) {
339        if (cmdParsed->paramArray[i] != NULL) {
340            (VOID)LOS_MemFree(m_aucSysMem0, cmdParsed->paramArray[i]);
341            cmdParsed->paramArray[i] = NULL;
342        }
343    }
344
345    return (UINT32)ret;
346}
347
348ShellCB *OsGetShellCb(VOID)
349{
350    return g_shellCB;
351}
352
353CHAR *OsShellGetWorkingDirtectory(VOID)
354{
355    return OsGetShellCb()->shellWorkingDirectory;
356}
357
358VOID OsShellCBInit(VOID)
359{
360    INT32 ret;
361    ShellCB *shellCB = NULL;
362
363    shellCB = (ShellCB *)malloc(sizeof(ShellCB));
364    if (shellCB == NULL) {
365        goto ERR_OUT1;
366    }
367    ret = memset_s(shellCB, sizeof(ShellCB), 0, sizeof(ShellCB));
368    if (ret != SH_OK) {
369        goto ERR_OUT1;
370    }
371
372    ret = (INT32)OsShellKeyInit(shellCB);
373    if (ret != SH_OK) {
374        goto ERR_OUT1;
375    }
376    (VOID)strncpy_s(shellCB->shellWorkingDirectory, PATH_MAX, "/", 2); /* 2:space for "/" */
377
378    g_shellCB = shellCB;
379    return;
380
381ERR_OUT1:
382    (VOID)free(shellCB);
383    return;
384}
385
386LITE_OS_SEC_TEXT_MINOR UINT32 OsCmdInit(VOID)
387{
388    UINT32 ret;
389    LOS_ListInit(&(cmdInfo.cmdList.list));
390    cmdInfo.listNum = 0;
391    cmdInfo.initMagicFlag = SHELL_INIT_MAGIC_FLAG;
392    ret = LOS_MuxCreate(&cmdInfo.muxLock);
393    if (ret != LOS_OK) {
394        PRINT_ERR("Create mutex for shell cmd info failed\n");
395        return OS_ERROR;
396    }
397    OsShellCBInit();
398
399    return LOS_OK;
400}
401
402STATIC UINT32 OsCmdItemCreate(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNum, CmdCallBackFunc cmdProc)
403{
404    CmdItem *cmdItem = NULL;
405    CmdItemNode *cmdItemNode = NULL;
406
407    cmdItem = (CmdItem *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItem));
408    if (cmdItem == NULL) {
409        return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;
410    }
411    (VOID)memset_s(cmdItem, sizeof(CmdItem), '\0', sizeof(CmdItem));
412
413    cmdItemNode = (CmdItemNode *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItemNode));
414    if (cmdItemNode == NULL) {
415        (VOID)LOS_MemFree(m_aucSysMem0, cmdItem);
416        return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;
417    }
418    (VOID)memset_s(cmdItemNode, sizeof(CmdItemNode), '\0', sizeof(CmdItemNode));
419    cmdItemNode->cmd = cmdItem;
420    cmdItemNode->cmd->cmdHook = cmdProc;
421    cmdItemNode->cmd->paraNum = paraNum;
422    cmdItemNode->cmd->cmdType = cmdType;
423    cmdItemNode->cmd->cmdKey = cmdKey;
424
425    (VOID)LOS_MuxPend(cmdInfo.muxLock, LOS_WAIT_FOREVER);
426    OsCmdAscendingInsert(cmdItemNode);
427    cmdInfo.listNum++;
428    (VOID)LOS_MuxPost(cmdInfo.muxLock);
429
430    return LOS_OK;
431}
432
433/* open API */
434LITE_OS_SEC_TEXT_MINOR UINT32 osCmdReg(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNum, CmdCallBackFunc cmdProc)
435{
436    CmdItemNode *cmdItemNode = NULL;
437
438    (VOID)LOS_MuxPend(cmdInfo.muxLock, LOS_WAIT_FOREVER);
439    if (cmdInfo.initMagicFlag != SHELL_INIT_MAGIC_FLAG) {
440        (VOID)LOS_MuxPost(cmdInfo.muxLock);
441        PRINT_ERR("[%s] shell is not yet initialized!\n", __FUNCTION__);
442        return OS_ERRNO_SHELL_NOT_INIT;
443    }
444    (VOID)LOS_MuxPost(cmdInfo.muxLock);
445
446    if ((cmdProc == NULL) || (cmdKey == NULL) ||
447        (cmdType >= CMD_TYPE_BUTT) || (strlen(cmdKey) >= CMD_KEY_LEN) || !strlen(cmdKey)) {
448        return OS_ERRNO_SHELL_CMDREG_PARA_ERROR;
449    }
450
451    if (paraNum > CMD_MAX_PARAS) {
452        if (paraNum != XARGS) {
453            return OS_ERRNO_SHELL_CMDREG_PARA_ERROR;
454        }
455    }
456
457    if (OsCmdKeyCheck(cmdKey) != TRUE) {
458        return OS_ERRNO_SHELL_CMDREG_CMD_ERROR;
459    }
460
461    (VOID)LOS_MuxPend(cmdInfo.muxLock, LOS_WAIT_FOREVER);
462    LOS_DL_LIST_FOR_EACH_ENTRY(cmdItemNode, &(cmdInfo.cmdList.list), CmdItemNode, list) {
463        if ((cmdType == cmdItemNode->cmd->cmdType) &&
464            ((strlen(cmdKey) == strlen(cmdItemNode->cmd->cmdKey)) &&
465            (strncmp((CHAR *)(cmdItemNode->cmd->cmdKey), cmdKey, strlen(cmdKey)) == 0))) {
466            (VOID)LOS_MuxPost(cmdInfo.muxLock);
467            return OS_ERRNO_SHELL_CMDREG_CMD_EXIST;
468        }
469    }
470    (VOID)LOS_MuxPost(cmdInfo.muxLock);
471
472    return OsCmdItemCreate(cmdType, cmdKey, paraNum, cmdProc);
473}
474
475