4f7dd7be7c
boot [<image path> [<header size>]] Boot a new firmware image. This command depends on hardware support CONFIG_BOARDCTL_BOOT_IMAGE. <image path> may point to a partion or file which contain the firmware to boot. The optional, numeric argument <header size> may be useful for skipping metadata information preprended to the firmware image. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
689 lines
17 KiB
C
689 lines
17 KiB
C
/****************************************************************************
|
|
* apps/nshlib/nsh_syscmds.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <nuttx/rptun/rptun.h>
|
|
#include <nuttx/streams.h>
|
|
#include <sys/boardctl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/utsname.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#include "nsh.h"
|
|
#include "nsh_console.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ARCH_BOARD_CUSTOM
|
|
# ifndef CONFIG_ARCH_BOARD_CUSTOM_NAME
|
|
# define BOARD_NAME g_unknown
|
|
# else
|
|
# define BOARD_NAME CONFIG_ARCH_BOARD_CUSTOM_NAME
|
|
# endif
|
|
#else
|
|
# ifndef CONFIG_ARCH_BOARD
|
|
# define BOARD_NAME g_unknown
|
|
# else
|
|
# define BOARD_NAME CONFIG_ARCH_BOARD
|
|
# endif
|
|
#endif
|
|
|
|
#define UNAME_KERNEL (1 << 0)
|
|
#define UNAME_NODE (1 << 1)
|
|
#define UNAME_RELEASE (1 << 2)
|
|
#define UNAME_VERSION (1 << 3)
|
|
#define UNAME_MACHINE (1 << 4)
|
|
#define UNAME_PLATFORM (1 << 5)
|
|
#define UNAME_UNKNOWN (1 << 6)
|
|
|
|
#ifdef CONFIG_NET
|
|
# define UNAME_ALL (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | \
|
|
UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM)
|
|
#else
|
|
# define UNAME_ALL (UNAME_KERNEL | UNAME_RELEASE | UNAME_VERSION | \
|
|
UNAME_MACHINE | UNAME_PLATFORM)
|
|
#endif
|
|
|
|
#ifndef CONFIG_NSH_PROC_MOUNTPOINT
|
|
# define CONFIG_NSH_PROC_MOUNTPOINT "/proc"
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_NSH_DISABLE_UNAME
|
|
static const char g_unknown[] = "unknown";
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_shutdown
|
|
****************************************************************************/
|
|
|
|
#if (defined(CONFIG_BOARDCTL_POWEROFF) || defined(CONFIG_BOARDCTL_RESET)) && \
|
|
!defined(CONFIG_NSH_DISABLE_SHUTDOWN)
|
|
|
|
int cmd_shutdown(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
#if defined(CONFIG_BOARDCTL_POWEROFF) && defined(CONFIG_BOARDCTL_RESET)
|
|
/* If both shutdown and reset are supported, then a single option may
|
|
* be provided to select the reset behavior (--reboot). We know here
|
|
* that argc is either 1 or 2.
|
|
*/
|
|
|
|
if (argc == 2)
|
|
{
|
|
/* Verify that the single argument is --reboot */
|
|
|
|
if (strcmp(argv[1], "--reboot") != 0)
|
|
{
|
|
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Invoke the BOARDIOC_RESET board control to reset the board. If
|
|
* the board_reset() function returns, then it was not possible to
|
|
* reset the board due to some constraints.
|
|
*/
|
|
|
|
boardctl(BOARDIOC_RESET, 0);
|
|
}
|
|
else
|
|
{
|
|
/* Invoke the BOARDIOC_POWEROFF board control to shutdown the board.
|
|
* If the board_power_off function returns, then it was not possible
|
|
* to power-off the* board due to some constraints.
|
|
*/
|
|
|
|
boardctl(BOARDIOC_POWEROFF, 0);
|
|
}
|
|
|
|
#elif defined(CONFIG_BOARDCTL_RESET)
|
|
/* Only reset behavior is supported and we already know that exactly one
|
|
* argument has been provided.
|
|
*/
|
|
|
|
/* Verify that the single argument is --reboot */
|
|
|
|
if (strcmp(argv[1], "--reboot") != 0)
|
|
{
|
|
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Invoke the BOARDIOC_RESET board control to reset the board. If
|
|
* the board_reset() function returns, then it was not possible to
|
|
* reset the board due to some constraints.
|
|
*/
|
|
|
|
boardctl(BOARDIOC_RESET, 0);
|
|
|
|
#else
|
|
/* Only the reset behavior is supported and we already know that there is
|
|
* no argument to the command.
|
|
*/
|
|
|
|
/* Invoke the BOARDIOC_POWEROFF board control to shutdown the board. If
|
|
* the board_power_off function returns, then it was not possible to power-
|
|
* off the board due to some constraints.
|
|
*/
|
|
|
|
boardctl(BOARDIOC_POWEROFF, 0);
|
|
#endif
|
|
|
|
/* boardctl() will not return in any case. It if does, it means that
|
|
* there was a problem with the shutdown/reset operation.
|
|
*/
|
|
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "boardctl", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
#endif /* CONFIG_BOARDCTL_POWEROFF && !CONFIG_NSH_DISABLE_SHUTDOWN */
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_pmconfig
|
|
****************************************************************************/
|
|
|
|
#if defined(CONFIG_PM) && !defined(CONFIG_NSH_DISABLE_PMCONFIG)
|
|
static int cmd_pmconfig_recursive(FAR struct nsh_vtbl_s *vtbl,
|
|
FAR const char *dirpath,
|
|
FAR struct dirent *entryp,
|
|
FAR void *pvarg)
|
|
{
|
|
FAR char *path;
|
|
int ret = ERROR;
|
|
|
|
if (DIRENT_ISDIRECTORY(entryp->d_type))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
path = nsh_getdirpath(vtbl, dirpath, entryp->d_name);
|
|
if (path)
|
|
{
|
|
nsh_output(vtbl, "\n%s:\n", path);
|
|
ret = nsh_catfile(vtbl, pvarg, path);
|
|
free(path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cmd_pmconfig(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
struct boardioc_pm_ctrl_s ctrl =
|
|
{
|
|
};
|
|
|
|
if (argc <= 2)
|
|
{
|
|
int next_state;
|
|
int last_state;
|
|
|
|
if (argc == 2)
|
|
{
|
|
ctrl.domain = atoi(argv[1]);
|
|
}
|
|
|
|
ctrl.action = BOARDIOC_PM_QUERYSTATE;
|
|
boardctl(BOARDIOC_PM_CONTROL, (uintptr_t)&ctrl);
|
|
last_state = ctrl.state;
|
|
|
|
ctrl.action = BOARDIOC_PM_CHECKSTATE;
|
|
boardctl(BOARDIOC_PM_CONTROL, (uintptr_t)&ctrl);
|
|
next_state = ctrl.state;
|
|
|
|
nsh_output(vtbl, "Last state %d, Next state %d\n",
|
|
last_state, next_state);
|
|
|
|
return nsh_foreach_direntry(vtbl, argv[0],
|
|
CONFIG_NSH_PROC_MOUNTPOINT "/pm",
|
|
cmd_pmconfig_recursive, argv[0]);
|
|
}
|
|
else if (argc <= 4)
|
|
{
|
|
if (argc == 4)
|
|
{
|
|
ctrl.domain = atoi(argv[3]);
|
|
}
|
|
|
|
if (strcmp(argv[1], "stay") == 0)
|
|
{
|
|
ctrl.action = BOARDIOC_PM_STAY;
|
|
}
|
|
else if (strcmp(argv[1], "relax") == 0)
|
|
{
|
|
ctrl.action = BOARDIOC_PM_RELAX;
|
|
}
|
|
else
|
|
{
|
|
nsh_output(vtbl, g_fmtarginvalid, argv[1]);
|
|
return ERROR;
|
|
}
|
|
|
|
if (strcmp(argv[2], "normal") == 0)
|
|
{
|
|
ctrl.state = PM_NORMAL;
|
|
}
|
|
else if (strcmp(argv[2], "idle") == 0)
|
|
{
|
|
ctrl.state = PM_IDLE;
|
|
}
|
|
else if (strcmp(argv[2], "standby") == 0)
|
|
{
|
|
ctrl.state = PM_STANDBY;
|
|
}
|
|
else if (strcmp(argv[2], "sleep") == 0)
|
|
{
|
|
ctrl.state = PM_SLEEP;
|
|
}
|
|
else
|
|
{
|
|
nsh_output(vtbl, g_fmtarginvalid, argv[2]);
|
|
return ERROR;
|
|
}
|
|
|
|
boardctl(BOARDIOC_PM_CONTROL, (uintptr_t)&ctrl);
|
|
}
|
|
else
|
|
{
|
|
nsh_error(vtbl, g_fmttoomanyargs, argv[0]);
|
|
return ERROR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_poweroff
|
|
****************************************************************************/
|
|
|
|
#if defined(CONFIG_BOARDCTL_POWEROFF) && !defined(CONFIG_NSH_DISABLE_POWEROFF)
|
|
int cmd_poweroff(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
/* Invoke the BOARDIOC_POWEROFF board control to shutdown the board. If
|
|
* the board_power_off function returns, then it was not possible to power-
|
|
* off the board due to some constraints.
|
|
*/
|
|
|
|
if (argc > 1)
|
|
{
|
|
boardctl(BOARDIOC_POWEROFF, atoi(argv[1]));
|
|
}
|
|
else
|
|
{
|
|
boardctl(BOARDIOC_POWEROFF, 0);
|
|
}
|
|
|
|
/* boardctl() will not return in any case. It if does, it means that
|
|
* there was a problem with the shutdown operation.
|
|
*/
|
|
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "boardctl", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_boot
|
|
****************************************************************************/
|
|
|
|
#if defined(CONFIG_BOARDCTL_BOOT_IMAGE) && !defined(CONFIG_NSH_DISABLE_BOOT)
|
|
int cmd_boot(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
struct boardioc_boot_info_s info;
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
/* Invoke the BOARDIOC_BOOT_IMAGE board control to reset the board. If
|
|
* the board_boot_image() function returns, then it was not possible to
|
|
* boot the image due to some constraints.
|
|
*/
|
|
|
|
switch (argc)
|
|
{
|
|
default:
|
|
info.header_size = strtoul(argv[2], NULL, 0);
|
|
|
|
/* Go through */
|
|
|
|
case 1:
|
|
info.path = argv[1];
|
|
|
|
/* Go through */
|
|
|
|
case 0:
|
|
|
|
/* Nothing to do */
|
|
|
|
break;
|
|
}
|
|
|
|
boardctl(BOARDIOC_BOOT_IMAGE, (uintptr_t)&info);
|
|
|
|
/* boardctl() will not return in this case. It if does, it means that
|
|
* there was a problem with the boot operation.
|
|
*/
|
|
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "boardctl", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_reboot
|
|
****************************************************************************/
|
|
|
|
#if defined(CONFIG_BOARDCTL_RESET) && !defined(CONFIG_NSH_DISABLE_REBOOT)
|
|
int cmd_reboot(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
/* Invoke the BOARDIOC_RESET board control to reset the board. If
|
|
* the board_reset() function returns, then it was not possible to
|
|
* reset the board due to some constraints.
|
|
*/
|
|
|
|
if (argc > 1)
|
|
{
|
|
boardctl(BOARDIOC_RESET, atoi(argv[1]));
|
|
}
|
|
else
|
|
{
|
|
boardctl(BOARDIOC_RESET, 0);
|
|
}
|
|
|
|
/* boardctl() will not return in this case. It if does, it means that
|
|
* there was a problem with the reset operation.
|
|
*/
|
|
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "boardctl", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_BOARDCTL_RESET_CAUSE) && !defined(CONFIG_NSH_DISABLE_RESET_CAUSE)
|
|
int cmd_reset_cause(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
UNUSED(argc);
|
|
|
|
int ret;
|
|
struct boardioc_reset_cause_s cause;
|
|
|
|
memset(&cause, 0, sizeof(cause));
|
|
ret = boardctl(BOARDIOC_RESET_CAUSE, (uintptr_t)&cause);
|
|
if (ret < 0)
|
|
{
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "boardctl", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
|
|
nsh_output(vtbl, "cause:0x%x,flag:0x%" PRIx32 "\n",
|
|
cause.cause, cause.flag);
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_rptun
|
|
****************************************************************************/
|
|
|
|
#if defined(CONFIG_RPTUN) && !defined(CONFIG_NSH_DISABLE_RPTUN)
|
|
static int cmd_rptun_once(FAR struct nsh_vtbl_s *vtbl,
|
|
FAR const char *path, FAR char **argv)
|
|
{
|
|
struct rptun_ping_s ping;
|
|
unsigned long val = 0;
|
|
int cmd;
|
|
int fd;
|
|
|
|
if (strcmp(argv[1], "start") == 0)
|
|
{
|
|
cmd = RPTUNIOC_START;
|
|
}
|
|
else if (strcmp(argv[1], "stop") == 0)
|
|
{
|
|
cmd = RPTUNIOC_STOP;
|
|
}
|
|
else if (strcmp(argv[1], "reset") == 0)
|
|
{
|
|
val = atoi(argv[3]);
|
|
cmd = RPTUNIOC_RESET;
|
|
}
|
|
else if (strcmp(argv[1], "panic") == 0)
|
|
{
|
|
cmd = RPTUNIOC_PANIC;
|
|
}
|
|
else if (strcmp(argv[1], "dump") == 0)
|
|
{
|
|
cmd = RPTUNIOC_DUMP;
|
|
}
|
|
else if (strcmp(argv[1], "ping") == 0)
|
|
{
|
|
if (argv[3] == 0 || argv[4] == 0 ||
|
|
argv[5] == 0 || argv[6] == 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
ping.times = atoi(argv[3]);
|
|
ping.len = atoi(argv[4]);
|
|
ping.ack = atoi(argv[5]);
|
|
ping.sleep = atoi(argv[6]);
|
|
|
|
cmd = RPTUNIOC_PING;
|
|
val = (unsigned long)&ping;
|
|
}
|
|
else
|
|
{
|
|
nsh_output(vtbl, g_fmtarginvalid, argv[1]);
|
|
return ERROR;
|
|
}
|
|
|
|
fd = open(path, 0);
|
|
if (fd < 0)
|
|
{
|
|
nsh_output(vtbl, g_fmtarginvalid, path);
|
|
return ERROR;
|
|
}
|
|
|
|
cmd = ioctl(fd, cmd, val);
|
|
|
|
close(fd);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
static int cmd_rptun_recursive(FAR struct nsh_vtbl_s *vtbl,
|
|
FAR const char *dirpath,
|
|
FAR struct dirent *entryp,
|
|
FAR void *pvarg)
|
|
{
|
|
FAR char *path;
|
|
int ret = ERROR;
|
|
|
|
if (DIRENT_ISDIRECTORY(entryp->d_type))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
path = nsh_getdirpath(vtbl, dirpath, entryp->d_name);
|
|
if (path)
|
|
{
|
|
ret = cmd_rptun_once(vtbl, path, pvarg);
|
|
free(path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cmd_rptun(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
if (argc < 3)
|
|
{
|
|
nsh_output(vtbl, g_fmtargrequired, argv[0]);
|
|
return ERROR;
|
|
}
|
|
|
|
if (strcmp(argv[2], "all") == 0)
|
|
{
|
|
return nsh_foreach_direntry(vtbl, "rptun", "/dev/rptun",
|
|
cmd_rptun_recursive, argv);
|
|
}
|
|
|
|
return cmd_rptun_once(vtbl, argv[2], argv);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: cmd_uname
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_NSH_DISABLE_UNAME
|
|
int cmd_uname(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
|
|
{
|
|
FAR const char *str;
|
|
struct lib_memoutstream_s stream;
|
|
struct utsname info;
|
|
unsigned int set;
|
|
int option;
|
|
bool badarg;
|
|
bool first;
|
|
int ret;
|
|
int i;
|
|
|
|
/* Get the uname options */
|
|
|
|
set = 0;
|
|
badarg = false;
|
|
|
|
while ((option = getopt(argc, argv, "asonrvmpi")) != ERROR)
|
|
{
|
|
switch (option)
|
|
{
|
|
case 'a':
|
|
set = UNAME_ALL;
|
|
break;
|
|
|
|
case 'o':
|
|
case 's':
|
|
set |= UNAME_KERNEL;
|
|
break;
|
|
|
|
#ifdef CONFIG_NET
|
|
case 'n':
|
|
set |= UNAME_NODE;
|
|
break;
|
|
#endif
|
|
|
|
case 'r':
|
|
set |= UNAME_RELEASE;
|
|
break;
|
|
|
|
case 'v':
|
|
set |= UNAME_VERSION;
|
|
break;
|
|
|
|
case 'm':
|
|
set |= UNAME_MACHINE;
|
|
break;
|
|
|
|
case 'p':
|
|
if (set != UNAME_ALL)
|
|
{
|
|
set |= UNAME_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case 'i':
|
|
set |= UNAME_PLATFORM;
|
|
break;
|
|
|
|
case '?':
|
|
default:
|
|
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
|
|
badarg = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If a bad argument was encountered, then return without processing the
|
|
* command
|
|
*/
|
|
|
|
if (badarg)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/* If nothing is provided on the command line, the default is -s */
|
|
|
|
if (set == 0)
|
|
{
|
|
set = UNAME_KERNEL;
|
|
}
|
|
|
|
/* Get uname data */
|
|
|
|
ret = uname(&info);
|
|
if (ret < 0)
|
|
{
|
|
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "uname", NSH_ERRNO);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Process each option */
|
|
|
|
first = true;
|
|
lib_memoutstream(&stream, alloca(sizeof(struct utsname)),
|
|
sizeof(struct utsname));
|
|
for (i = 0; set != 0; i++)
|
|
{
|
|
unsigned int mask = (1 << i);
|
|
if ((set & mask) != 0)
|
|
{
|
|
set &= ~mask;
|
|
switch (i)
|
|
{
|
|
case 0: /* print the kernel/operating system name */
|
|
str = info.sysname;
|
|
break;
|
|
|
|
#ifdef CONFIG_NET
|
|
case 1: /* Print noname */
|
|
str = info.nodename;
|
|
break;
|
|
#endif
|
|
case 2: /* Print the kernel release */
|
|
str = info.release;
|
|
break;
|
|
|
|
case 3: /* Print the kernel version */
|
|
str = info.version;
|
|
break;
|
|
|
|
case 4: /* Print the machine hardware name */
|
|
str = info.machine;
|
|
break;
|
|
|
|
case 5: /* Print the machine platform name */
|
|
str = BOARD_NAME;
|
|
break;
|
|
|
|
case 6: /* Print "unknown" */
|
|
str = g_unknown;
|
|
break;
|
|
|
|
default:
|
|
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
|
|
return ERROR;
|
|
}
|
|
|
|
if (!first)
|
|
{
|
|
lib_stream_putc(&stream, ' ');
|
|
}
|
|
|
|
lib_stream_puts(&stream, str, strlen(str));
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
lib_stream_putc(&stream, '\n');
|
|
nsh_write(vtbl, stream.buffer, stream.public.nput);
|
|
return OK;
|
|
}
|
|
#endif
|