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 "shmsg.h"
34 #include "unistd.h"
35 #include "stdio.h"
36 #include "time.h"
37 #include "los_event.h"
38 #include "los_tick.h"
39 
40 #include "securec.h"
41 
42 #define  timeval64      timeval
43 #define  gettimeofday64 gettimeofday
44 #define  ctime64        ctime
45 
46 #ifdef LOSCFG_SHELL_CMD_DEBUG
47 typedef struct {
48     BOOL title; /* whether to hide the timestamps */
49     UINT32 count; /* the total number of command executions */
50     UINT32 interval; /* running cycle of the command */
51     EVENT_CB_S watchEvent; /* event handle of the watch structure */
52     CHAR cmdbuf[CMD_MAX_LEN]; /* the command to watch */
53 } WatchCB;
54 
55 STATIC WatchCB *g_watchCmd;
56 
57 #define WATCH_COUNT_MAX     0xFFFFFF
58 #define WATCH_INTERTVAL_MAX 0xFFFFFF
59 
PrintTimenull60 STATIC VOID PrintTime(VOID)
61 {
62     struct timeval64 stNowTime = {0};
63 
64     if (gettimeofday64(&stNowTime, NULL) == 0) {
65         PRINTK("%s", ctime64(&(stNowTime.tv_sec)));
66     }
67 }
68 
OsShellCmdDoWatch(UINTPTR arg1)69 STATIC VOID OsShellCmdDoWatch(UINTPTR arg1)
70 {
71     WatchCB *watchItem = (WatchCB *)arg1;
72     UINT32 ret;
73     g_watchCmd = watchItem;
74 
75     while (watchItem->count--) {
76         printf("\033[2J\n");
77         if (watchItem->title) {
78             PrintTime();
79         }
80         (VOID)ShellMsgParse(watchItem->cmdbuf);
81         ret = LOS_EventRead(&watchItem->watchEvent, 0x01, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, watchItem->interval);
82         if (ret == 0x01) {
83             break;
84         }
85     }
86 
87     (VOID)LOS_EventDestroy(&watchItem->watchEvent);
88     free(g_watchCmd);
89     g_watchCmd = NULL;
90 }
91 
OsWatchCmdUsagenull92 STATIC INLINE VOID OsWatchCmdUsage(VOID)
93 {
94     PRINTK("\nUsage: watch\n");
95     PRINTK("watch [options] command\n");
96 }
97 
OsWatchOverFuncnull98 STATIC UINT32 OsWatchOverFunc(VOID)
99 {
100     UINT32 ret;
101     if (g_watchCmd != NULL) {
102         ret = LOS_EventWrite(&g_watchCmd->watchEvent, 0x01);
103         if (ret != LOS_OK) {
104             PRINT_ERR("Write event failed in %s,%d\n", __FUNCTION__, __LINE__);
105             return OS_ERROR;
106         }
107         return LOS_OK;
108     } else {
109         PRINTK("No watch task to turn off.\n");
110         return OS_ERROR;
111     }
112 }
113 
OsWatchOptionParsed(UINT32 argc, UINT32 *argoff, const CHAR **argv, WatchCB *watchItem)114 INT32 OsWatchOptionParsed(UINT32 argc, UINT32 *argoff, const CHAR **argv, WatchCB *watchItem)
115 {
116     long tmpVal;
117     CHAR *strPtr = NULL;
118     UINT32 argcount = argc;
119 
120     while (argv[*argoff][0] == '-') {
121         if (argcount <= 1) {
122             OsWatchCmdUsage();
123             return -1;
124         }
125 
126         if ((strcmp(argv[*argoff], "-n") == 0) || (strcmp(argv[*argoff], "--interval") == 0)) {
127             if (argcount <= 2) { /* 2:count of parameter */
128                 OsWatchCmdUsage();
129                 return -1;
130             }
131             tmpVal = (long)strtoul(argv[*argoff + 1], &strPtr, 0);
132             if ((*strPtr != 0) || (tmpVal <= 0) || (tmpVal > WATCH_INTERTVAL_MAX)) {
133                 PRINTK("\ninterval time is invalid\n");
134                 OsWatchCmdUsage();
135                 return -1;
136             }
137             watchItem->interval = g_tickPerSecond * (UINT32)tmpVal;
138             argcount -= 2; /* 2:offset of argv */
139             (*argoff) += 2; /* 2:offset of argv */
140         } else if ((strcmp(argv[*argoff], "-t") == 0) || (strcmp(argv[*argoff], "-no-title") == 0)) {
141             watchItem->title = FALSE;
142             argcount--;
143             (*argoff)++;
144         } else if ((strcmp(argv[*argoff], "-c") == 0) || (strcmp(argv[*argoff], "--count") == 0)) {
145             if (argcount <= 2) { /* 2:count of parameter */
146                 OsWatchCmdUsage();
147                 return -1;
148             }
149             tmpVal = (long)strtoul(argv[*argoff + 1], &strPtr, 0);
150             if ((*strPtr != 0) || (tmpVal <= 0) || (tmpVal > WATCH_COUNT_MAX)) {
151                 PRINTK("\ncount is invalid\n");
152                 OsWatchCmdUsage();
153                 return -1;
154             }
155             watchItem->count = (UINT32)tmpVal;
156             argcount -= 2; /* 2:offset of argv */
157             (*argoff) += 2; /* 2:offset of argv */
158         } else {
159             PRINTK("Unknown option.\n");
160             return -1;
161         }
162     }
163     return 0;
164 }
165 
OsWatchCmdSplice(UINT32 argc, UINT32 argoff, const CHAR **argv, WatchCB *watchItem)166 INT32 OsWatchCmdSplice(UINT32 argc, UINT32 argoff, const CHAR **argv, WatchCB *watchItem)
167 {
168     INT32 err = 0;
169     if ((argc - argoff) == 0) {
170         PRINT_ERR("no watch command!\n");
171         return -1;
172     }
173     while (argc - argoff) {
174         err = strcat_s(watchItem->cmdbuf, sizeof(watchItem->cmdbuf), argv[argoff]);
175         if (err != EOK) {
176             PRINT_ERR("%s, %d strcat_s failed!\n", __FUNCTION__, __LINE__);
177             return -1;
178         }
179         err = strcat_s(watchItem->cmdbuf, sizeof(watchItem->cmdbuf), " ");
180         if (err != EOK) {
181             PRINT_ERR("%s, %d strcat_s failed!\n", __FUNCTION__, __LINE__);
182             return -1;
183         }
184         argoff++;
185     }
186     return err;
187 }
188 
OsWatchTaskCreate(WatchCB *watchItem)189 UINT32 OsWatchTaskCreate(WatchCB *watchItem)
190 {
191     TSK_INIT_PARAM_S initParam = {0};
192     UINT32 watchTaskId = 0;
193     UINT32 ret;
194 
195     ret = LOS_EventInit(&watchItem->watchEvent);
196     if (ret != 0) {
197         PRINT_ERR("Watch event init failed in %s, %d\n", __FUNCTION__, __LINE__);
198         return ret;
199     }
200 
201     initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsShellCmdDoWatch;
202     initParam.usTaskPrio   = 10; /* 10:shellcmd_watch task priority */
203     initParam.auwArgs[0]   = (UINTPTR)watchItem;
204     initParam.uwStackSize  = 0x3000; /* 0x3000:stack size of shellcmd_watch task */
205     initParam.pcName       = "shellcmd_watch";
206     initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
207 
208     ret = LOS_TaskCreate(&watchTaskId, &initParam);
209     if (ret != 0) {
210         PRINT_ERR("Watch task init failed in %s, %d\n", __FUNCTION__, __LINE__);
211         return ret;
212     }
213     return ret;
214 }
215 
OsShellCmdWatch(UINT32 argc, const CHAR **argv)216 UINT32 OsShellCmdWatch(UINT32 argc, const CHAR **argv)
217 {
218     WatchCB *watchItem = NULL;
219     UINT32 argoff = 0;
220     UINT32 ret;
221     INT32 err;
222 
223     if (argc == 0) {
224         OsWatchCmdUsage();
225         return OS_ERROR;
226     }
227 
228     if (argv == NULL) {
229         OsWatchCmdUsage();
230         return OS_ERROR;
231     }
232 
233     if ((argc == 1) && (strcmp(argv[0], "--over") == 0)) {
234         ret = OsWatchOverFunc();
235         return ret;
236     }
237 
238     if (g_watchCmd != NULL) {
239         PRINTK("Please turn off previous watch before to start a new watch.\n");
240         return OS_ERROR;
241     }
242 
243     watchItem = (WatchCB *)malloc(sizeof(WatchCB));
244     if (watchItem == NULL) {
245         PRINTK("Malloc error!\n");
246         return OS_ERROR;
247     }
248     (VOID)memset_s(watchItem, sizeof(WatchCB), 0, sizeof(WatchCB));
249     watchItem->title = TRUE;
250     watchItem->count = WATCH_COUNT_MAX;
251     watchItem->interval = g_tickPerSecond;
252 
253     err = OsWatchOptionParsed(argc, &argoff, argv, watchItem);
254     if (err != 0) {
255         goto WATCH_ERROR;
256     }
257 
258     err = OsWatchCmdSplice(argc, argoff, argv, watchItem);
259     if (err != 0) {
260         goto WATCH_ERROR;
261     }
262 
263     ret = OsWatchTaskCreate(watchItem);
264     if (ret != 0) {
265         goto WATCH_ERROR;
266     }
267 
268     return LOS_OK;
269 
270 WATCH_ERROR:
271     free(watchItem);
272     return OS_ERROR;
273 }
274 
275 SHELLCMD_ENTRY(watch_shellcmd, CMD_TYPE_EX, "watch", XARGS, (CmdCallBackFunc)OsShellCmdWatch);
276 #endif
277