Funpack5-1:基于MCXA346并利用AI辅助实现实现串口shell
该项目使用了mcxa346开发板,实现了串口shell的设计,它的主要功能为:通过mcxa346开发板串口实现了一个串口shell输入输出控制功能。
标签
Funpack活动
串口
Shell
MCXA346
流水源
更新2026-03-16
7

一、项目介绍

本次任务使用MCXA346开发板并利用AI辅助实现一个带缓冲区的shell,核心是实现一个能读取、解析并执行用户输入命令的简易命令行解释器,并管理好输入缓冲区。基本要求:程序需能显示命令提示符,并循环接收用户输入(\n换行符为断句符号)。管理好输入缓冲区,妥善处理字符,并能进行基本的命令解析。

1.1、硬件介绍

NXP FRDM-MCXA346 开发板简介:

image.png

FRDM-MCXA346是一款紧凑且可扩展的开发板,可以快速基于MCX A346 MCU开展原型设计。它们提供行业标准的接口,可轻松访问MCU的I/O,配备集成的开放标准串行接口、外部闪存和板载MCU-Link调试器。

关键参数:

  • MCX A346 Arm® Cortex®-M33内核,运行频率高达180MHz,1MB闪存,256KB RAM,带8KB的纠错码(ECC)
  • 拥有双FlexPWM、4组16位ADC、专用MAU数学加速器以及SmartDMA
  • 高速通用串行总线(HS USB)Type-C连接器(板载MCU-Link调试器),支持CAN/I3C/SPI/I²C/UART连接器(Arduino、PMOD/mikroBUS、DNP)
  • 带有CMSIS-DAP的板载MCU-Link调试器 ,JTAG/SWD连接器
  • 兼容Arduino、mikroBUS、Pmod多种生态
  • 适合:工业自动化、电机控制、IoT边缘计算

1.2、任务功能设计目标思路

本次任务是实现一个串口shell。需要实现串口的发送和接收。然后解析串口接收的字符实现命令解析。计划支持上下左右按键,tab按钮等控制字符解析。然后就是上下翻历史记录功能,最后就是shell用户控制权限命令功能。

二、任务实现

2.1、软件流程

image.png

2.2、实现过程

首先新建基于MCXA346的串口的工程模板,实现串口发送接收。

image.png

然后利用AI实现shell代码核心功能。下面是使用deepseek的实现shell过程。

image.png

image.png

image.png

image.png

image.png

最终经过多轮对话实现了完整的shell核心代码和实例。


#ifndef _LSY_SHELL_CORE_H_
#define _LSY_SHELL_CORE_H_

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "lsy_shell_config.h"

// 错误码定义
typedef enum {
SHELL_OK = 0,
SHELL_ERR,
SHELL_ERR_CMD_NOT_FOUND,
SHELL_ERR_PARAM,
SHELL_ERR_BUFFER_FULL,
SHELL_ERR_CMD_EXISTS,
SHELL_ERR_CMD_TABLE_FULL,
SHELL_ERR_MEMORY,
// ==================== 新增:权限相关错误码 ========
SHELL_ERR_PERMISSION_DENIED, // 权限不足
SHELL_ERR_USER_NOT_FOUND, // 用户不存在
SHELL_ERR_INVALID_PASSWORD, // 密码错误
SHELL_ERR_USER_LOCKED, // 用户被锁定
SHELL_ERR_NOT_LOGGED_IN, // 未登录
SHELL_ERR_LOGIN_TIMEOUT, // 登录超时
// ==================== 新增结束 ====================

} shell_status_t;

// ==================== 新增:权限级别枚举 ====================
typedef enum {
SHELL_PERMISSION_NONE = 0, // 无权限
SHELL_PERMISSION_GUEST = 1, // 访客权限
SHELL_PERMISSION_USER = 2, // 普通用户权限
SHELL_PERMISSION_ADMIN = 3, // 管理员权限
SHELL_PERMISSION_ROOT = 8, // 超级用户权限

} shell_permission_level_t;

// 权限位掩码定义(用于命令权限控制)
#define SHELL_PERM_MASK_GUEST 0x01 // 访客位
#define SHELL_PERM_MASK_USER 0x02 // 普通用户位
#define SHELL_PERM_MASK_ADMIN 0x04 // 管理员位
#define SHELL_PERM_MASK_ROOT 0x80 // 超级用户位
#define SHELL_PERM_MASK_ALL (SHELL_PERM_MASK_USER | SHELL_PERM_MASK_ADMIN | \
SHELL_PERM_MASK_ROOT | SHELL_PERM_MASK_GUEST) // 所有权限

// 默认权限配置
#define SHELL_PERM_DEFAULT_GUEST SHELL_PERM_MASK_GUEST // 访客默认权限
#define SHELL_PERM_DEFAULT_USER SHELL_PERM_MASK_USER // 普通用户默认权限
#define SHELL_PERM_DEFAULT_ADMIN SHELL_PERM_MASK_ADMIN // 管理员默认权限
#define SHELL_PERM_DEFAULT_ROOT SHELL_PERM_MASK_ROOT // 超级用户默认权限
// ==================== 新增结束 ====================

// IO操作结构体
typedef struct {
int (*init)(void);
int (*send)(const char *data, size_t len);
int (*receive)(char *buffer, size_t max_len);
int (*ctrl)(uint32_t cmd,uint8_t *para);
} shell_io_ops_t;

// 命令处理函数类型
typedef shell_status_t (*shell_cmd_handler_t)(int argc, char **argv);

// 命令项结构
typedef struct shell_command {
const char *name; // 命令名
const char *description; // 命令描述
shell_cmd_handler_t handler; // 处理函数
void *user_data; // 用户数据
struct shell_command *next; // 链表指针
uint8_t is_static; // 静态命令标志

// ========== 新增:命令权限字段 ====================
uint32_t permission_mask; // 命令所需权限掩码(哪些权限级别的用户可以执行)

} shell_command_t;

// ==================== 新增:用户信息结构体 ====================
typedef struct shell_user {
char username[SHELL_USERNAME_MAX_LEN]; // 用户名
char password[SHELL_PASSWORD_MAX_LEN]; // 密码(实际使用中应存储哈希值)
shell_permission_level_t permission_level; // 用户权限级别
uint32_t permission_mask; // 用户权限掩码(可访问的权限位)
uint32_t last_login_time; // 最后登录时间
uint8_t is_locked; // 是否被锁定
uint8_t login_attempts; // 登录尝试次数
uint8_t is_logged_in; // 当前是否已登录
struct shell_user *next; // 链表指针
} shell_user_t;

// 登录状态枚举
typedef enum {
LOGIN_STATE_LOGGED_OUT = 0, // 未登录
LOGIN_STATE_LOGGED_IN, // 已登录
LOGIN_STATE_WAITING_PASSWORD, // 等待输入密码
LOGIN_STATE_CHANGING_PASSWORD // 正在修改密码
} shell_login_state_t;
// ==================== 新增结束 ====================

// Shell上下文结构
typedef struct {
shell_io_ops_t io; // IO操作
char input_buffer[SHELL_BUFFER_SIZE]; // 输入缓冲区
size_t buf_pos; // 缓冲区位置
shell_command_t *cur_cmd; // 记录当前的命令
shell_command_t *cmd_list; // 命令链表头
shell_command_t *static_cmds;// 静态命令表
size_t static_cmd_count; // 静态命令数量
char prompt[32]; // 提示符
void *user_context; // 用户上下文

uint8_t echo_enabled; // 回显使能
uint8_t initialized; // 初始化标志

#if SHELL_HISTORY_SIZE > 0
// 历史记录相关字段
char history_buffer[SHELL_HISTORY_BUFFER_SIZE]; // 历史记录存储缓冲区
char *history[SHELL_HISTORY_SIZE]; // 历史记录索引数组
size_t history_count; // 当前历史记录数量
size_t history_pos; // 当前浏览位置
int history_index; // 最新命令索引
#endif

#if SHELL_USERS_ENABLE == 1
// ==================== 新增:用户和权限管理相关字段 ====================
shell_user_t *user_list; // 用户链表头
shell_user_t *current_user; // 当前登录用户
shell_login_state_t login_state; // 登录状态
char login_username[SHELL_USERNAME_MAX_LEN]; // 登录中的用户名
uint32_t login_start_time; // 登录开始时间
uint8_t login_attempts; // 当前登录尝试次数
uint8_t require_login; // 是否需要登录才能使用shell
// ==================== 新增结束 ====================
#endif

} shell_context_t;

// 初始化Shell
shell_status_t shell_init(shell_context_t *ctx,
shell_io_ops_t *io_ops,
const char *prompt);

// 注册静态命令表
shell_status_t shell_register_static_table(shell_context_t *ctx,
shell_command_t *cmd_table,
size_t cmd_count);

// 动态注册命令
shell_status_t shell_register_user_cmd(shell_context_t *ctx,
const char *name,
const char *description,
shell_cmd_handler_t handler,
void *user_data,
uint32_t permission_mask // 新增:命令所需权限
);
#define shell_register_command(ctx,name,desc,handler,usr_data) \
shell_register_user_cmd(ctx,name,desc,handler,usr_data,SHELL_PERM_MASK_ALL)

// 动态删除命令
shell_status_t shell_unregister_command(shell_context_t *ctx,
const char *name);

// 获取当前命令
shell_command_t* shell_get_current_cmd(shell_context_t *ctx);

// 查找命令
shell_command_t* shell_find_command(shell_context_t *ctx,
const char *name);

// 处理输入字符
shell_status_t shell_process_char(shell_context_t *ctx, char ch);

// 处理字符串
shell_status_t shell_process_string(shell_context_t *ctx, const char *str);

// 打印帮助信息
void shell_print_help(shell_context_t *ctx);

// 列出所有命令
void shell_list_commands(shell_context_t *ctx);

// 输出字符串
void shell_print(shell_context_t *ctx, const char *str);

// 输出格式化字符串
void shell_printf(shell_context_t *ctx, const char *format, ...);

// 设置回显
void shell_set_echo(shell_context_t *ctx, uint8_t enable);

// 获取命令数量
size_t shell_get_command_count(shell_context_t *ctx);

// 清理所有动态命令
shell_status_t shell_cleanup_dynamic_commands(shell_context_t *ctx);

// 获取静态命令表
shell_command_t* get_static_commands(size_t *count);
// 初始化内存保护配置
void memory_view_init(shell_context_t *ctx);

// ==================== 新增:用户和权限管理API ====================
#if SHELL_USERS_ENABLE == 1
// 用户管理
shell_status_t shell_user_add(shell_context_t *ctx,
const char *username,
const char *password,
shell_permission_level_t level);

shell_status_t shell_user_remove(shell_context_t *ctx, const char *username);

shell_status_t shell_user_change_password(shell_context_t *ctx,
const char *username,
const char *old_password,
const char *new_password);

shell_status_t shell_user_set_permission(shell_context_t *ctx,
const char *username,
shell_permission_level_t level);

shell_status_t shell_user_lock(shell_context_t *ctx, const char *username);

shell_status_t shell_user_unlock(shell_context_t *ctx, const char *username);

shell_user_t* shell_user_find(shell_context_t *ctx, const char *username);

// 登录/登出
shell_status_t shell_login(shell_context_t *ctx,
const char *username,
const char *password);

shell_status_t shell_logout(shell_context_t *ctx);

uint8_t shell_is_logged_in(shell_context_t *ctx);

shell_permission_level_t shell_get_current_permission(shell_context_t *ctx);

// 权限检查
uint8_t shell_check_command_permission(shell_context_t *ctx,
shell_command_t *cmd);

// 初始化默认用户(管理员和访客)
shell_status_t shell_init_default_users(shell_context_t *ctx);

// 列出所有用户
void shell_list_users(shell_context_t *ctx);

#endif
// ==================== 新增结束 ====================


//ls shell port API
int lsy_shell_init(shell_io_ops_t * io_ops);
int lsy_shell_input(uint8_t ch);
extern shell_context_t g_lsy_shell;

#endif // _LSY_SHELL_CORE_H_

核心代码


#include "lsy_shell_core.h"

// 内部函数声明
static int shell_split_args(char *str, char *argv[], int max_args);
static void shell_execute_command(shell_context_t *ctx,
shell_command_t *cmd,
int argc, char **argv);
static void shell_redisplay_line(shell_context_t *ctx);

#if SHELL_HISTORY_SIZE > 0
// 历史记录功能函数声明
static void shell_history_add(shell_context_t *ctx, const char *cmd);
static void shell_history_prev(shell_context_t *ctx);
static void shell_history_next(shell_context_t *ctx);
static void shell_history_clear(shell_context_t *ctx); // 清除历史记录
static void shell_history_list(shell_context_t *ctx); // 显示历史记录
static void shell_history_compact(shell_context_t *ctx); // 整理历史记录缓冲区

static void shell_history_save(shell_context_t *ctx);
static void shell_history_load(shell_context_t *ctx);
#endif

// ==================== 新增:用户管理内部函数声明 ====================
#if SHELL_USERS_ENABLE == 1
static shell_user_t* shell_user_alloc(void);
static void shell_user_free(shell_user_t *user);
static uint32_t shell_permission_level_to_mask(shell_permission_level_t level);
static void shell_prompt_update(shell_context_t *ctx);
static shell_status_t shell_handle_login_sequence(shell_context_t *ctx, const char *input);
static uint8_t shell_verify_password(const char *input_pass, const char *stored_pass);
#endif
// ==================== 新增结束 ====================

// 分配新命令节点
static shell_command_t* shell_alloc_command(void)
{
shell_command_t *cmd = (shell_command_t*)malloc(sizeof(shell_command_t));
if (cmd) {
memset(cmd, 0, sizeof(shell_command_t));
}
return cmd;
}

// 释放命令节点
static void shell_free_command(shell_command_t *cmd)
{
if (cmd && !cmd->is_static) {
free(cmd);
}
}

// 初始化Shell
shell_status_t shell_init(shell_context_t *ctx,
shell_io_ops_t *io_ops,
const char *prompt)
{
if (!ctx || !io_ops) {
return SHELL_ERR;
}

memset(ctx, 0, sizeof(shell_context_t));
ctx->io = *io_ops;
ctx->buf_pos = 0;
ctx->cur_cmd = NULL;
ctx->cmd_list = NULL;
ctx->static_cmds = NULL;
ctx->static_cmd_count = 0;
ctx->echo_enabled = 1;
ctx->initialized = 1;

#if SHELL_HISTORY_SIZE > 0
// 初始化历史记录
ctx->history_count = 0;
ctx->history_pos = 0;
ctx->history_index = -1;
memset(ctx->history_buffer, 0, sizeof(ctx->history_buffer));
memset(ctx->history, 0, sizeof(ctx->history));
#endif

#if SHELL_USERS_ENABLE == 1
// ==================== 新增:初始化用户管理 ====================
ctx->user_list = NULL;
ctx->current_user = NULL;
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
ctx->login_attempts = 0;
ctx->require_login = 1; // 默认需要登录

// 初始化默认用户
shell_init_default_users(ctx);

// 设置初始提示符
if (ctx->require_login) {
strcpy(ctx->prompt, "login: ");
} else
#endif
if (prompt) {
strncpy(ctx->prompt, prompt, sizeof(ctx->prompt) - 1);
ctx->prompt[sizeof(ctx->prompt) - 1] = '\0';
} else {
strcpy(ctx->prompt, "lsy:>");
}
// ==================== 新增结束 ====================

// 打印欢迎信息
shell_print(ctx, "\r\n=== Little Simple Dynamic Shell By LiuShuiyuan===\r\n");
shell_print(ctx, "Commands can be registered and unregistered dynamically\r\n");
#if SHELL_HISTORY_SIZE > 0
shell_printf(ctx, "History support: %d commands can be saved\r\n", SHELL_HISTORY_SIZE);
#endif

#if SHELL_USERS_ENABLE == 1
// ==================== 新增:显示登录提示 ====================
if (ctx->require_login) {
shell_print(ctx, "Please login with username and password\r\n");
shell_printf(ctx, "%s", ctx->prompt);
} else
#endif
{
shell_print(ctx, "Type 'help' or 'list' for available commands\r\n");
shell_printf(ctx, "%s", ctx->prompt);
}

return SHELL_OK;
}

// 注册静态命令表
shell_status_t shell_register_static_table(shell_context_t *ctx,
shell_command_t *cmd_table,
size_t cmd_count) {
if (!ctx || !cmd_table) {
return SHELL_ERR;
}

ctx->static_cmds = cmd_table;
ctx->static_cmd_count = cmd_count;

// 标记静态命令
for (size_t i = 0; i < cmd_count; i++) {
cmd_table[i].is_static = 1;
}

return SHELL_OK;
}

// 动态注册命令
shell_status_t shell_register_user_cmd(shell_context_t *ctx,
const char *name,
const char *description,
shell_cmd_handler_t handler,
void *user_data,
uint32_t permission_mask // 新增:命令所需权限
)
{
if (!ctx || !name || !handler) {
return SHELL_ERR;
}

// 检查命令是否已存在
shell_command_t *existing = shell_find_command(ctx, name);
if (existing) {
return SHELL_ERR_CMD_EXISTS;
}

// 创建新命令节点
shell_command_t *new_cmd = shell_alloc_command();
if (!new_cmd) {
return SHELL_ERR_MEMORY;
}

// 填充命令信息
new_cmd->name = name;
new_cmd->description = description ? description : "No description";
new_cmd->handler = handler;
new_cmd->user_data = user_data;
new_cmd->is_static = 0;
new_cmd->next = NULL;
// ==================== 新增:设置命令权限 ====================
new_cmd->permission_mask = permission_mask;
// ==================== 新增结束 ====================
// 添加到链表头部
new_cmd->next = ctx->cmd_list;
ctx->cmd_list = new_cmd;

return SHELL_OK;
}

// 动态删除命令
shell_status_t shell_unregister_command(shell_context_t *ctx,
const char *name)
{
if (!ctx || !name) {
return SHELL_ERR;
}

// 跳过内置命令
// if (strcmp(name, "help") == 0 || strcmp(name, "list") == 0 || strcmp(name, "echo") == 0) {
// shell_printf(ctx, "Cannot unregister built-in command '%s'\r\n", name);
// return SHELL_ERR;
// }

shell_command_t *prev = NULL;
shell_command_t *curr = ctx->cmd_list;

// 查找要删除的命令
while (curr) {
if (strcmp(curr->name, name) == 0) {
if (curr->is_static) {
shell_printf(ctx, "Cannot unregister static command '%s'\r\n", name);
return SHELL_ERR;
}

// 从链表中删除
if (prev) {
prev->next = curr->next;
} else {
ctx->cmd_list = curr->next;
}

// 释放内存
shell_free_command(curr);

shell_printf(ctx, "Command '%s' unregistered successfully\r\n", name);
return SHELL_OK;
}

prev = curr;
curr = curr->next;
}

// 检查静态命令表
if (ctx->static_cmds) {
for (size_t i = 0; i < ctx->static_cmd_count; i++) {
if (strcmp(ctx->static_cmds[i].name, name) == 0) {
shell_printf(ctx, "Cannot unregister static command '%s'\r\n", name);
return SHELL_ERR;
}
}
}

shell_printf(ctx, "Command '%s' not found\r\n", name);
return SHELL_ERR_CMD_NOT_FOUND;
}

// 获取当前命令
shell_command_t* shell_get_current_cmd(shell_context_t *ctx)
{
return ctx->cur_cmd;
}

// 查找命令
shell_command_t* shell_find_command(shell_context_t *ctx,
const char *name)
{
if (!ctx || !name) {
return NULL;
}

// 首先检查动态命令链表
shell_command_t *cmd = ctx->cmd_list;
while (cmd) {
if (strcmp(cmd->name, name) == 0) {
return cmd;
}
cmd = cmd->next;
}

// 然后检查静态命令表
if (ctx->static_cmds) {
for (size_t i = 0; i < ctx->static_cmd_count; i++) {
if (strcmp(ctx->static_cmds[i].name, name) == 0) {
return &ctx->static_cmds[i];
}
}
}

#if 0
// ==================== 修改:内置命令列表,添加用户管理命令 ====================
#if SHELL_USERS_ENABLE == 1
if (strcmp(name, "help") == 0) {
static shell_command_t cmd_help = {
.name = "help",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL // 所有用户可访问
};
return &cmd_help;
} else if (strcmp(name, "list") == 0) {
static shell_command_t cmd_list = {
.name = "list",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_list;
} else if (strcmp(name, "echo") == 0) {
static shell_command_t cmd_echo = {
.name = "echo",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_echo;
} else if (strcmp(name, "history") == 0) {
static shell_command_t cmd_history = {
.name = "history",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_history;
} else if (strcmp(name, "login") == 0) {
static shell_command_t cmd_login = {
.name = "login",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_login;
} else if (strcmp(name, "logout") == 0) {
static shell_command_t cmd_logout = {
.name = "logout",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_logout;
} else if (strcmp(name, "passwd") == 0) {
static shell_command_t cmd_passwd = {
.name = "passwd",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ALL
};
return &cmd_passwd;
} else if (strcmp(name, "users") == 0) {
static shell_command_t cmd_users = {
.name = "users",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ADMIN | SHELL_PERM_MASK_ROOT
};
return &cmd_users;
} else if (strcmp(name, "useradd") == 0) {
static shell_command_t cmd_useradd = {
.name = "useradd",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ADMIN | SHELL_PERM_MASK_ROOT
};
return &cmd_useradd;
} else if (strcmp(name, "userdel") == 0) {
static shell_command_t cmd_userdel = {
.name = "userdel",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ADMIN | SHELL_PERM_MASK_ROOT
};
return &cmd_userdel;
} else if (strcmp(name, "userlock") == 0) {
static shell_command_t cmd_userlock = {
.name = "userlock",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ADMIN | SHELL_PERM_MASK_ROOT
};
return &cmd_userlock;
} else if (strcmp(name, "userunlock") == 0) {
static shell_command_t cmd_userunlock = {
.name = "userunlock",
.handler = NULL,
.is_static = 1,
.permission_mask = SHELL_PERM_MASK_ADMIN | SHELL_PERM_MASK_ROOT
};
return &cmd_userunlock;
}
// ==================== 修改结束 ====================
#else
// 检查内置命令
if (strcmp(name, "help") == 0) {
// 返回一个虚拟命令结构
static shell_command_t cmd_help = {
.name = "help",
.handler = NULL,
.is_static = 1
};
return &cmd_help;
}else if (strcmp(name, "list") == 0) {
// 返回一个虚拟命令结构
static shell_command_t cmd_list = {
.name = "list",
.handler = NULL,
.is_static = 1
};
return &cmd_list;
}else if (strcmp(name, "echo") == 0) {
// 返回一个虚拟命令结构
static shell_command_t cmd_echo = {
.name = "echo",
.handler = NULL,
.is_static = 1
};
return &cmd_echo;
}
#if SHELL_HISTORY_SIZE > 0
else if (strcmp(name, "history") == 0) {
static shell_command_t cmd_history = {
.name = "history",
.handler = NULL,
.is_static = 1
};
return &cmd_history;
}
#endif
#endif
#endif
return NULL;
}
/**
* @brief 字符串分割函数(增强版,支持转义字符)
* @param str 输入字符串(会被修改)
* @param argv 输出参数数组
* @param max_args 最大参数个数
* @return 解析出的参数个数
*
* 支持的特性:
* 1. 空格分隔参数
* 2. 双引号内的内容作为一个参数(支持转义)
* 3. 转义字符:\" 表示一个字面双引号,\\ 表示一个字面反斜杠
* 4. 支持转义空格(如:a\ b 作为一个参数 "a b")
*
*/
static int shell_split_args(char *str, char *argv[], int max_args)
{
int argc = 0;
int in_arg = 0;
int in_quote = 0;
int escape = 0; // 转义标志:1表示当前字符需要被转义

char *p = str; // 当前读取位置
char *q = str; // 当前写入位置

while (*p && argc < max_args)
{
if (escape) {
// 转义模式:直接复制字符,不进行特殊处理
if (in_arg) {
//已开始新参数
}else
{
//未开始新参数
argv[argc] = q; // 记录参数起始位置
argc++;
in_arg = 1;
}
*q++ = *p++;
escape = 0;
continue;
}

if (*p == '\\') {
// 遇到反斜杠,设置转义标志
escape = 1;
p++;
continue;
}

if (*p == '"') {
if (in_quote) {
// 结束引号
in_quote = 0;
*q = '\0'; // 添加字符串结束符
q++; // 跳过结束符位置(保持q和p的同步)
} else {
// 开始引号,不将引号写入目标缓冲区
in_quote = 1;
if (in_arg) {
//已开始新参数,双引号不在新参数最前面

}else
{
//未开始新参数,双引号在新参数最前面
}
}
p++;
continue;
}

// 处理空格(仅在非引号模式下作为分隔符)
if (!in_quote && (*p == ' ' || *p == '\t' || *p == '\r')) {
if (in_arg) {
// 结束当前参数
*q = '\0';
q++;
in_arg = 0;
}
p++;
continue;
}

// 开始一个新参数
if (!in_arg) {
argv[argc] = q; // 记录参数起始位置
argc++;
in_arg = 1;
}

// 复制普通字符
*q++ = *p++;
}

// 处理最后一个参数
if (in_arg) {
*q = '\0';
}

// 检查是否有未闭合的引号
if (in_quote) {
// 可以选择报错,这里简单处理为忽略最后一个不完整的参数
if (argc > 0) {
argc--; // 移除最后一个不完整的参数
}
}

argv[argc] = NULL;
return argc;
}
#if 0
// 字符串分割函数
static int shell_split_args(char *str, char *argv[], int max_args)
{
int argc = 0;
int in_arg = 0;
int in_quote = 0;

while (*str && argc < max_args) {
// 处理引号
if (*str == '"') {
in_quote = !in_quote;
*str = '\0';
str++;
continue;
}

// 跳过空白字符(不在引号内时)
if (!in_quote && (*str == ' ' || *str == '\t' || *str == '\r')) {
*str = '\0';
in_arg = 0;
str++;
continue;
}

// 开始一个新参数
if (!in_arg) {
argv[argc++] = str;
in_arg = 1;
}

str++;
}

argv[argc] = NULL;
return argc;
}
#endif

// 重新显示当前行
static void shell_redisplay_line(shell_context_t *ctx)
{
if (!ctx || !ctx->echo_enabled)
{
return;
}

// 清除当前行
shell_print(ctx, "\r\033[K");

// 显示提示符
shell_printf(ctx, "%s", ctx->prompt);

#if SHELL_USERS_ENABLE == 1
if(ctx->login_state != LOGIN_STATE_WAITING_PASSWORD){
#endif
// 显示当前输入缓冲区内容
shell_print(ctx, ctx->input_buffer);

#if SHELL_USERS_ENABLE == 1
}else
{
for (int i = 0; i < strlen(ctx->input_buffer); i++) {
shell_print(ctx, "*");
}
}
#endif
// 将光标移动到正确位置
int cursor_move = strlen(ctx->input_buffer) - ctx->buf_pos;
for (int i = 0; i < cursor_move; i++) {
shell_print(ctx, "\033[D");
}
}

// 终端控制字符状态机状态
typedef enum {
STATE_NORMAL, // 正常状态
STATE_ESC, // 收到ESC
STATE_CSI, // 收到'['
STATE_CSI_PARAM, // 解析CSI参数
STATE_SS3 // 收到'O' (SS3状态)
} shell_input_state_t;

// 处理输入字符 - 增强版,支持终端控制字符识别
shell_status_t shell_process_char(shell_context_t *ctx, char ch)
{
if (!ctx || !ctx->initialized) {
return SHELL_ERR;
}

static shell_input_state_t input_state = STATE_NORMAL;
static char csi_buffer[16]; // CSI参数缓冲区
static int csi_pos = 0;
static int esc_param1 = 0; // CSI参数1
static int esc_param2 = 0; // CSI参数2

// 状态机处理终端控制序列
switch (input_state) {
case STATE_NORMAL:
// 检查是否ESC字符
if (ch == '\x1b') {
input_state = STATE_ESC;
csi_pos = 0;
esc_param1 = 0;
esc_param2 = 0;
return SHELL_OK;
}
break;

case STATE_ESC:
// ESC后的字符
if (ch == '[') {
input_state = STATE_CSI;
csi_pos = 0;
esc_param1 = 0;
esc_param2 = 0;
return SHELL_OK;
} else if (ch == 'O') {
input_state = STATE_SS3;
return SHELL_OK;
} else {
// 未知ESC序列,重置状态
input_state = STATE_NORMAL;
return SHELL_OK;
}

case STATE_SS3:
// SS3状态:处理 F1-F4 等按键
input_state = STATE_NORMAL;

switch (ch) {
// 可以根据需要处理F1,F2,F3,F4
case 'P': // F1

return SHELL_OK;
case 'Q': // F2

return SHELL_OK;
case 'R': // F3

return SHELL_OK;
case 'S': // F4

return SHELL_OK;
case 'H': // Home
// 移动光标到行首
ctx->buf_pos = 0;
shell_redisplay_line(ctx);
return SHELL_OK;
case 'F': // End
// 移动光标到行尾
ctx->buf_pos = strlen(ctx->input_buffer);
shell_redisplay_line(ctx);
return SHELL_OK;
}
return SHELL_OK;

case STATE_CSI:
// CSI状态:处理 '[' 后的字符
if (ch >= '0' && ch <= '9') {
// 解析参数
if (csi_pos == 0) {
esc_param1 = esc_param1 * 10 + (ch - '0');
} else if (csi_pos == 1) {
esc_param2 = esc_param2 * 10 + (ch - '0');
}
csi_buffer[csi_pos++] = ch;
return SHELL_OK;
} else if (ch == ';') {
// 参数分隔符
csi_pos++;
csi_buffer[csi_pos] = '\0';
return SHELL_OK;
} else {
// 命令字符
input_state = STATE_NORMAL;

// 处理各种CSI命令
switch (ch) {
case 'A': // 上箭头 历史记录上一条
#if SHELL_HISTORY_SIZE > 0
shell_history_prev(ctx);
#endif
break;

case 'B': // 下箭头 历史记录下一条
#if SHELL_HISTORY_SIZE > 0
shell_history_next(ctx);
#endif
break;

case 'C': // 右箭头
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
ctx->buf_pos++;
if (ctx->echo_enabled) {
// 发送光标右移序列
const char *move_right = "\033[C";
ctx->io.send(move_right, strlen(move_right));
}
}
break;

case 'D': // 左箭头
if (ctx->buf_pos > 0) {
ctx->buf_pos--;
if (ctx->echo_enabled) {
// 发送光标左移序列
const char *move_left = "\033[D";
ctx->io.send(move_left, strlen(move_left));
}
}
break;

case 'H': // Home键
ctx->buf_pos = 0;
shell_redisplay_line(ctx);
break;

case 'F': // End键
ctx->buf_pos = strlen(ctx->input_buffer);
shell_redisplay_line(ctx);
break;

case '~': // 带数字前缀的命令
if (esc_param1 == 3)
{
// Del键
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
// 删除当前位置的字符
memmove(&ctx->input_buffer[ctx->buf_pos],
&ctx->input_buffer[ctx->buf_pos + 1],
strlen(ctx->input_buffer) - ctx->buf_pos);

shell_redisplay_line(ctx);
}
} else if (esc_param1 == 5) { // Page Up
// 可扩展功能

} else if (esc_param1 == 6) { // Page Down
// 可扩展功能

}
break;

case 'Z': // Shift+Tab 反向补全


break;
}
return SHELL_OK;
}

default:
input_state = STATE_NORMAL;
break;
}

// 处理普通字符
if (input_state == STATE_NORMAL) {
// 处理回车
if (ch == '\r' || ch == '\n')
{
if (strlen(ctx->input_buffer) > 0) {
//ctx->input_buffer[ctx->buf_pos] = '\0';
#if SHELL_HISTORY_SIZE > 0

#if SHELL_USERS_ENABLE == 1
if(ctx->login_state != LOGIN_STATE_WAITING_PASSWORD){
#endif
// 将命令添加到历史记录
shell_history_add(ctx, ctx->input_buffer);
#if SHELL_USERS_ENABLE == 1
}
#endif
#endif
// 回显输入
if (ctx->echo_enabled) {
shell_print(ctx, "\r\n");
}

// 处理命令
shell_process_string(ctx, ctx->input_buffer);

// 重置缓冲区
ctx->buf_pos = 0;
memset(ctx->input_buffer,0,SHELL_BUFFER_SIZE);
ctx->input_buffer[0] = '\0';

// 显示新提示符
if (ctx->echo_enabled) {
shell_printf(ctx, "%s", ctx->prompt);
}
} else {
// 空行,只显示提示符
if (ctx->echo_enabled) {
shell_printf(ctx, "\r\n%s", ctx->prompt);
}
}

return SHELL_OK;
}

// 处理退格
if (ch == '\b' || ch == 0x7F)
{
if (ctx->buf_pos > 0) {
// 删除当前位置的字符
memmove(&ctx->input_buffer[ctx->buf_pos - 1],
&ctx->input_buffer[ctx->buf_pos],
strlen(ctx->input_buffer) - ctx->buf_pos + 1);
ctx->buf_pos--;

shell_redisplay_line(ctx);
}
return SHELL_OK;
}

// 处理Tab键(命令补全)
if (ch == '\t') {
if(0 ==strlen(ctx->input_buffer))
{
shell_list_commands(ctx);
shell_printf(ctx, "%s", ctx->prompt);
}else {
// 这里可以实现命令补全功能

}
return SHELL_OK;
}

// 普通字符 - 插入到当前光标位置
if (ctx->buf_pos < sizeof(ctx->input_buffer) - 1) {
// 如果有字符在当前光标位置之后,需要移动它们
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
// 将光标后的字符向后移动
memmove(&ctx->input_buffer[ctx->buf_pos + 1],
&ctx->input_buffer[ctx->buf_pos],
strlen(ctx->input_buffer) - ctx->buf_pos + 1);
}

// 插入新字符
ctx->input_buffer[ctx->buf_pos] = ch;
ctx->buf_pos++;

// 回显字符
if (ctx->echo_enabled && ctx->io.send)
{
if (ctx->buf_pos == strlen(ctx->input_buffer)) {
#if SHELL_USERS_ENABLE == 1
if(ctx->login_state != LOGIN_STATE_WAITING_PASSWORD){
#endif
// 在行尾,直接回显
char echo[2] = {ch, '\0'};
ctx->io.send(echo, 1);
#if SHELL_USERS_ENABLE == 1
}else{
// 在行尾,直接回显
char echo[2] = {'*', '\0'};
ctx->io.send(echo, 1);
}
#endif
} else {
// 在行中插入,需要重新显示整行
shell_redisplay_line(ctx);
}
}
}
}
return SHELL_OK;
}

// 处理字符串
shell_status_t shell_process_string(shell_context_t *ctx, const char *str)
{
char buffer[SHELL_BUFFER_SIZE];
char *argv[SHELL_MAX_ARGS];
int argc;

if (!ctx || !str) {
return SHELL_ERR;
}

// ==================== 新增:处理登录序列 ====================
#if SHELL_USERS_ENABLE == 1
if (ctx->require_login && !ctx->current_user) {
// 未登录状态,处理登录序列
return shell_handle_login_sequence(ctx, str);
}
#endif
// ==================== 新增结束 ====================

// 复制字符串以便修改
strncpy(buffer, str, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';

// 分割参数
argc = shell_split_args(buffer, argv, sizeof(argv)/sizeof(argv[0]));

if (argc == 0) {
return SHELL_OK;
}

// ==================== 新增:登出命令 ====================
#if SHELL_USERS_ENABLE == 1
if (strcmp(argv[0], "logout") == 0) {
shell_logout(ctx);
return SHELL_OK;
}
#endif
// ==================== 新增结束 ====================
// 处理内置命令
if (((strcmp(argv[0], "help") == 0)||(strcmp(argv[0], "?") == 0)) && (argc == 1)) {
shell_print_help(ctx);
return SHELL_OK;
}

if ((strcmp(argv[0], "list") == 0) && (argc == 1)) {
shell_list_commands(ctx);
return SHELL_OK;
}

if ((strcmp(argv[0], "clear") == 0) && (argc == 1)) {
// 发送清屏序列
shell_print(ctx, "\033[2J\033[H");
return SHELL_OK;
}

if ((strcmp(argv[0], "echo") == 0) && (argc > 2)) {
if (argc == 2) {
if (strcmp(argv[1], "on") == 0) {
ctx->echo_enabled = 1;
shell_print(ctx, "Echo enabled\r\n");
} else if (strcmp(argv[1], "off") == 0) {
ctx->echo_enabled = 0;
shell_print(ctx, "Echo disabled\r\n");
} else {
shell_print(ctx, "Usage: echo <on|off>\r\n");
}
} else {
shell_printf(ctx, "Echo is %s\r\n",
ctx->echo_enabled ? "enabled" : "disabled");
}
return SHELL_OK;
}

#if SHELL_HISTORY_SIZE > 0
// 添加历史记录相关命令
if ((strcmp(argv[0], "history") == 0) && (argc == 1)) {
// // ==================== 新增:权限检查 ====================
//#if SHELL_USERS_ENABLE == 1
// if (ctx->current_user && ctx->current_user->permission_level < SHELL_PERMISSION_USER) {
// shell_print(ctx, "Permission denied\r\n");
// shell_printf(ctx, "%s", ctx->prompt);
// return SHELL_ERR_PERMISSION_DENIED;
// }
//#endif
// // ==================== 新增结束 ====================
if (argc == 1) {
shell_history_list(ctx);
} else if (argc == 2) {
if (strcmp(argv[1], "clear") == 0) {
shell_history_clear(ctx);
} else {
shell_print(ctx, "Usage: history [clear]\r\n");
}
}
return SHELL_OK;
}
#endif

// ==================== 新增:用户管理命令 ====================
#if SHELL_USERS_ENABLE == 1
if (strcmp(argv[0], "users") == 0) {
shell_list_users(ctx);
return SHELL_OK;
}

if (strcmp(argv[0], "passwd") == 0) {
// 修改密码
// 修改当前用户密码
shell_print(ctx, "Changing password for current user\r\n");
if (argc == 1) {
// 简化处理,实际应该交互式输入
shell_print(ctx, "Usage: passwd <old_password> <new_password>\r\n");
} else if (argc == 3) {
shell_user_change_password(ctx,
ctx->current_user->username,
argv[1], argv[2]);
} else {
shell_print(ctx, "Usage: passwd <old_password> <new_password>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "useradd") == 0) {
// 添加用户(需要管理员权限)
if (argc >= 3) {
shell_permission_level_t level = SHELL_PERMISSION_USER;
if (argc >= 4) {
level = (shell_permission_level_t)atoi(argv[3]);
//if(level > SHELL_PERMISSION_USER) level = SHELL_PERMISSION_USER;
}
//检查当前添加的用户权限不能超过当前用户权限
if(level > ctx->current_user->permission_level) level = ctx->current_user->permission_level;
shell_user_add(ctx, argv[1], argv[2], level);
} else {
shell_print(ctx, "Usage: useradd <username> <password> [permission_level:0/1/2/3]\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userdel") == 0) {
// 删除用户(需要管理员权限)
if (argc == 2) {
shell_user_remove(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userdel <username>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userlock") == 0) {
// 锁定用户(需要管理员权限)
if (argc == 2) {
shell_user_lock(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userlock <username>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userunlock") == 0) {
// 解锁用户(需要管理员权限)
if (argc == 2) {
shell_user_unlock(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userunlock <username>\r\n");
}
return SHELL_OK;
}
#endif
// ==================== 新增结束 ====================

// 查找命令
shell_command_t *cmd = shell_find_command(ctx, argv[0]);
if (!cmd) {
shell_printf(ctx, "Error: Command '%s' not found\r\n", argv[0]);
return SHELL_ERR_CMD_NOT_FOUND;
}

// ==================== 新增:权限检查 ====================
#if SHELL_USERS_ENABLE == 1
if (!shell_check_command_permission(ctx, cmd)) {
shell_printf(ctx, "Error: Permission denied for command '%s'\r\n", argv[0]);
shell_printf(ctx, "%s", ctx->prompt);
return SHELL_ERR_PERMISSION_DENIED;
}
#endif
// ==================== 新增结束 ====================

ctx->cur_cmd = cmd;
// 执行命令
if (cmd->handler) {
shell_execute_command(ctx, ctx->cur_cmd, argc, argv);
}
ctx->cur_cmd = NULL;
return SHELL_OK;
}

// 执行命令
static void shell_execute_command(shell_context_t *ctx,
shell_command_t *cmd,
int argc, char **argv)
{
shell_status_t status = cmd->handler(argc, argv);

if (status != SHELL_OK) {
shell_printf(ctx, "Command returned error: %d\r\n", status);
}
}

// 打印帮助信息
void shell_print_help(shell_context_t *ctx)
{
if (!ctx) {
return;
}

shell_print(ctx, "\r\n===LSY Shell Help ===\r\n");
shell_print(ctx, "Built-in commands:\r\n");
shell_print(ctx, " help - Show this help message\r\n");
shell_print(ctx, " list - List all registered commands\r\n");
shell_print(ctx, " echo <on|off> - Enable/disable input echo\r\n");
shell_print(ctx, " clear - Clear display\r\n");

#if SHELL_HISTORY_SIZE > 0
shell_print(ctx, " history [clear] - Show or clear command history\r\n");
#endif
// ==================== 新增:用户管理命令帮助 ====================
#if SHELL_USERS_ENABLE == 1
shell_print(ctx, "\r\nUser management commands:\r\n");
shell_print(ctx, " login - Login to shell\r\n");
shell_print(ctx, " logout - Logout from shell\r\n");
shell_print(ctx, " passwd - Change password\r\n");
shell_print(ctx, " users - List all users (admin only)\r\n");
shell_print(ctx, " useradd - Add new user (admin only)\r\n");
shell_print(ctx, " userdel - Delete user (admin only)\r\n");
shell_print(ctx, " userlock - Lock user account (admin only)\r\n");
shell_print(ctx, " userunlock - Unlock user account (admin only)\r\n");
#endif
// ==================== 新增结束 ====================

shell_print(ctx, "\r\nNavigation:\r\n");
shell_print(ctx, " Up/Down - Browse command history\r\n");
shell_print(ctx, " Left/Right - Move cursor\r\n");
shell_print(ctx, " Home/End - Jump to start/end\r\n");
shell_print(ctx, " Backspace/Del - Delete character\r\n");
shell_print(ctx, "\r\n");

}

// 列出所有命令
void shell_list_commands(shell_context_t *ctx)
{
if (!ctx) {
return;
}

shell_print(ctx, "\r\n=== Registered Commands ===\r\n");
int count = 0;

// ==================== 修改:内置命令权限显示 ====================
#if SHELL_USERS_ENABLE == 1
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "help", "Show help information");
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "list", "List all commands");
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "echo", "Control input echo");
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "clear", "Clear display");
count += 4;

#if SHELL_HISTORY_SIZE > 0
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "history", "Show/clear command history");
count += 1;
#endif

shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "login", "Login to shell");
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "logout", "Logout from shell");
shell_printf(ctx, "%-15s - %-30s [B] Perm: all\r\n", "passwd", "Change password");
shell_printf(ctx, "%-15s - %-30s [B] Perm: admin\r\n", "users", "List all users");
shell_printf(ctx, "%-15s - %-30s [B] Perm: admin\r\n", "useradd", "Add new user");
shell_printf(ctx, "%-15s - %-30s [B] Perm: admin\r\n", "userdel", "Delete user");
shell_printf(ctx, "%-15s - %-30s [B] Perm: admin\r\n", "userlock", "Lock user");
shell_printf(ctx, "%-15s - %-30s [B] Perm: admin\r\n", "userunlock", "Unlock user");
count += 8;
// ==================== 修改结束 ====================
#else
// 内置命令
shell_printf(ctx, "%-15s - Show help information [B]\r\n", "help");
shell_printf(ctx, "%-15s - List all commands [B]\r\n", "list");
shell_printf(ctx, "%-15s - Control input echo [B]\r\n", "echo");
shell_printf(ctx, "%-15s - Clear display [B]\r\n", "clear");
count += 4;
#if SHELL_HISTORY_SIZE > 0
shell_printf(ctx, "%-15s - Show/clear command history [B]\r\n", "history");
count += 1;
#endif
#endif

// 列出静态命令
if (ctx->static_cmds) {
for (size_t i = 0; i < ctx->static_cmd_count; i++) {
// ==================== 新增:显示静态命令权限 ====================
#if SHELL_USERS_ENABLE == 1
char perm_str[32] = "";
if (0 == ctx->static_cmds[i].permission_mask) {
strcat(perm_str, "all");
}else
{
if (ctx->static_cmds[i].permission_mask & SHELL_PERM_MASK_ROOT) {
strcat(perm_str, "root+");
}
if (ctx->static_cmds[i].permission_mask & SHELL_PERM_MASK_ADMIN) {
strcat(perm_str, "admin+");
}
if (ctx->static_cmds[i].permission_mask & SHELL_PERM_MASK_USER) {
strcat(perm_str, "user+");
}
if (ctx->static_cmds[i].permission_mask & SHELL_PERM_MASK_GUEST) {
strcat(perm_str, "guest+");
}
}
shell_printf(ctx, "%-15s - %-30s [S] Perm: %s\r\n",
ctx->static_cmds[i].name,
ctx->static_cmds[i].description,
perm_str);

// ==================== 新增结束 ====================
#else
shell_printf(ctx, "%-15s - %s [S]\r\n",
ctx->static_cmds[i].name,
ctx->static_cmds[i].description);
#endif
count++;
}
}

// 列出动态命令
shell_command_t *cmd = ctx->cmd_list;
while (cmd) {
#if SHELL_USERS_ENABLE == 1
// ==================== 新增:显示动态命令权限 ====================
char perm_str[32] = "";
if (0 == cmd->permission_mask) {
strcat(perm_str, "all");
}else
{
if (cmd->permission_mask & SHELL_PERM_MASK_ROOT) {
strcat(perm_str, "root+");
}
if (cmd->permission_mask & SHELL_PERM_MASK_ADMIN) {
strcat(perm_str, "admin+");
}
if (cmd->permission_mask & SHELL_PERM_MASK_USER) {
strcat(perm_str, "user+");
}
if (cmd->permission_mask & SHELL_PERM_MASK_GUEST) {
strcat(perm_str, "guest+");
}
}
shell_printf(ctx, "%-15s - %-30s [D] Perm: %s\r\n",
cmd->name, cmd->description, perm_str);
// ==================== 新增结束 ====================
#else
shell_printf(ctx, "%-15s - %s [D]\r\n",
cmd->name, cmd->description);
#endif

cmd = cmd->next;
count++;
}

shell_printf(ctx, "\r\nTotal: %d commands (D=Dynamic, S=Static, B=Built-in)\r\n", count);
}

// 输出字符串
void shell_print(shell_context_t *ctx, const char *str) {
if (ctx && ctx->io.send && str) {
ctx->io.send(str, strlen(str));
}
}

// 输出格式化字符串
void shell_printf(shell_context_t *ctx, const char *format, ...) {

char buffer[256];
va_list args;

if (!ctx || !ctx->io.send) {
va_start(args, format);
printf(format, args);
va_end(args);
return;
}

va_start(args, format);
int len = vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);

if (len > 0 && len < (int)sizeof(buffer)) {
ctx->io.send(buffer, len);
}
}

// 设置回显
void shell_set_echo(shell_context_t *ctx, uint8_t enable) {
if (ctx) {
ctx->echo_enabled = enable;
}
}

// 获取命令数量
size_t shell_get_command_count(shell_context_t *ctx) {
if (!ctx) {
return 0;
}

size_t count = 0;

// 动态命令
shell_command_t *cmd = ctx->cmd_list;
while (cmd) {
count++;
cmd = cmd->next;
}

// 静态命令
if (ctx->static_cmds) {
count += ctx->static_cmd_count;
}

// 内置命令
count += 4; // help, list, echo, clear
#if SHELL_HISTORY_SIZE > 0
count += 1; // history
#endif

#if SHELL_USERS_ENABLE == 1
count += 8;
#endif
return count;
}

// 清理所有动态命令
shell_status_t shell_cleanup_dynamic_commands(shell_context_t *ctx) {
if (!ctx) {
return SHELL_ERR;
}

shell_command_t *curr = ctx->cmd_list;
shell_command_t *next;

while (curr) {
next = curr->next;
if (!curr->is_static) {
shell_free_command(curr);
}
curr = next;
}

ctx->cmd_list = NULL;

return SHELL_OK;
}

////////////////////////////////////////////////////////////////////////////
#if SHELL_HISTORY_SIZE > 0
// 添加命令到历史记录
static void shell_history_add(shell_context_t *ctx, const char *cmd)
{
if (!ctx || !cmd || strlen(cmd) == 0) {
return;
}

// 检查是否与上一条历史记录重复
if (ctx->history_count > 0) {
int last_idx = (ctx->history_index + ctx->history_count - 1) % SHELL_HISTORY_SIZE;
if (ctx->history[last_idx] && strcmp(ctx->history[last_idx], cmd) == 0) {
return; // 重复命令,不添加
}
}

size_t cmd_len = strlen(cmd) + 1;

// 检查缓冲区空间
if (ctx->history_count >= SHELL_HISTORY_SIZE) {
// 历史已满,释放最旧的一条
char *oldest = ctx->history[ctx->history_index];
if (oldest) {
size_t oldest_len = strlen(oldest) + 1;
// 移动缓冲区数据(简化处理,实际可以使用环形缓冲区)
memmove(oldest, oldest + oldest_len,
ctx->history_buffer + sizeof(ctx->history_buffer) - (oldest + oldest_len));

// 调整所有指针
for (size_t i = 1; i < SHELL_HISTORY_SIZE; i++) {
if (ctx->history[i] && ctx->history[i] > oldest) {
ctx->history[i-1] = ctx->history[i] - oldest_len;
}
}
}
ctx->history_count--;
}

// 找到可用的存储位置
char *store_pos;
if (ctx->history_count == 0) {
store_pos = ctx->history_buffer;
ctx->history_index = 0;
} else {
// 计算下一个存储位置
int last_idx = (ctx->history_index + ctx->history_count - 1) % SHELL_HISTORY_SIZE;
char *last_cmd = ctx->history[last_idx];
store_pos = last_cmd + strlen(last_cmd) + 1;

// 检查是否超出缓冲区
if ((store_pos + cmd_len) > (ctx->history_buffer + sizeof(ctx->history_buffer))) {
// 缓冲区满,重新整理
shell_history_clear(ctx);
store_pos = ctx->history_buffer;
ctx->history_index = 0;

// shell_history_compact(ctx);
// // 重新计算存储位置
// if (ctx->history_count > 0) {
// last_idx = (ctx->history_index + ctx->history_count - 1) % SHELL_HISTORY_SIZE;
// last_cmd = ctx->history[last_idx];
// store_pos = last_cmd + strlen(last_cmd) + 1;
// } else {
// store_pos = ctx->history_buffer;
// }
}
}

// 存储命令
if ((store_pos + cmd_len) < (ctx->history_buffer + sizeof(ctx->history_buffer)))
{
strcpy(store_pos, cmd);

// 更新索引数组
int new_idx = (ctx->history_index + ctx->history_count) % SHELL_HISTORY_SIZE;
ctx->history[new_idx] = store_pos;
ctx->history_count++;

// 重置浏览位置
ctx->history_pos = ctx->history_count;
}
}

/*
// 整理历史记录缓冲区
static void shell_history_compact(shell_context_t *ctx)
{
if (ctx->history_count == 0) return;

char temp_buffer[SHELL_HISTORY_BUFFER_SIZE];
char *temp_ptr = temp_buffer;
char *new_history[SHELL_HISTORY_SIZE];
size_t new_count = 0;

// 按顺序整理历史记录
for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
size_t len = strlen(ctx->history[idx]) + 1;
if (temp_ptr + len <= temp_buffer + sizeof(temp_buffer)) {
strcpy(temp_ptr, ctx->history[idx]);
new_history[new_count++] = temp_ptr;
temp_ptr += len;
}
}
}

// 复制回原缓冲区
memcpy(ctx->history_buffer, temp_buffer, temp_ptr - temp_buffer);
memcpy(ctx->history, new_history, new_count * sizeof(char*));

ctx->history_count = new_count;
ctx->history_index = 0;
}
*/

// 获取上一条历史命令
static void shell_history_prev(shell_context_t *ctx)
{
if (!ctx || ctx->history_count == 0) {
return;
}

if (ctx->history_pos > 0) {
ctx->history_pos--;
}

size_t idx = (ctx->history_index + ctx->history_pos) % SHELL_HISTORY_SIZE;
const char *history_cmd = ctx->history[idx];

if (history_cmd) {
// 保存当前输入(用于下箭头恢复)
if (ctx->history_pos == ctx->history_count - 1) {
// 可以保存当前编辑的命令

}

// 替换输入缓冲区
strncpy(ctx->input_buffer, history_cmd, sizeof(ctx->input_buffer) - 1);
ctx->input_buffer[sizeof(ctx->input_buffer) - 1] = '\0';
ctx->buf_pos = strlen(ctx->input_buffer);

// 重新显示
shell_redisplay_line(ctx);
}
}

// 获取下一条历史命令
static void shell_history_next(shell_context_t *ctx)
{
if (!ctx) {
return;
}

if (ctx->history_pos < ctx->history_count - 1) {
ctx->history_pos++;

size_t idx = (ctx->history_index + ctx->history_pos) % SHELL_HISTORY_SIZE;
const char *history_cmd = ctx->history[idx];

if (history_cmd) {
strncpy(ctx->input_buffer, history_cmd, sizeof(ctx->input_buffer) - 1);
ctx->input_buffer[sizeof(ctx->input_buffer) - 1] = '\0';
ctx->buf_pos = strlen(ctx->input_buffer);
}
} else {
// 已经到最后一条历史记录,清空输入
ctx->history_pos = ctx->history_count;
memset(ctx->input_buffer,0,SHELL_BUFFER_SIZE);
ctx->buf_pos = 0;
}

// 重新显示
shell_redisplay_line(ctx);
}

// 清除历史记录
static void shell_history_clear(shell_context_t *ctx)
{
if (!ctx) {
return;
}

memset(ctx->history_buffer, 0, sizeof(ctx->history_buffer));
memset(ctx->history, 0, sizeof(ctx->history));
ctx->history_count = 0;
ctx->history_pos = 0;
ctx->history_index = -1;

shell_print(ctx, "History cleared\r\n");
}

// 显示历史记录
static void shell_history_list(shell_context_t *ctx)
{
if (!ctx) {
return;
}

if (ctx->history_count == 0) {
shell_print(ctx, "No history commands\r\n");
return;
}

shell_print(ctx, "\r\n=== Command History ===\r\n");
shell_printf(ctx, "History Item:%d\r\n",ctx->history_count);
for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
shell_printf(ctx, "%3zu: %s\r\n", i + 1, ctx->history[idx]);
}
}
}

// 添加保存历史记录到文件的功能(可选)
shell_status_t shell_history_save_to_file(shell_context_t *ctx, const char *filename)
{
if (!ctx || !filename) {
return SHELL_ERR;
}

FILE *fp = fopen(filename, "w");
if (!fp) {
return SHELL_ERR;
}

for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
fprintf(fp, "%s\n", ctx->history[idx]);
}
}

fclose(fp);
return SHELL_OK;
}

// 从文件加载历史记录(可选)
shell_status_t shell_history_load_from_file(shell_context_t *ctx, const char *filename)
{
if (!ctx || !filename) {
return SHELL_ERR;
}

FILE *fp = fopen(filename, "r");
if (!fp) {
return SHELL_ERR;
}

char buffer[SHELL_BUFFER_SIZE];
while (fgets(buffer, sizeof(buffer), fp)) {
// 去除换行符
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
}

shell_history_add(ctx, buffer);
}

fclose(fp);
return SHELL_OK;
}

#endif

// ==================== 新增:用户管理内部函数实现 ====================
#if SHELL_USERS_ENABLE == 1
/**
* @brief 分配新的用户节点
* @return 分配的用户节点指针,失败返回NULL
*/
static shell_user_t* shell_user_alloc(void)
{
shell_user_t *user = (shell_user_t*)malloc(sizeof(shell_user_t));
if (user) {
memset(user, 0, sizeof(shell_user_t));
}
return user;
}

/**
* @brief 释放用户节点
* @param user 要释放的用户节点
*/
static void shell_user_free(shell_user_t *user)
{
if (user) {
free(user);
}
}

/**
* @brief 将权限级别转换为权限掩码
* @param level 权限级别
* @return 权限掩码
*/
static uint32_t shell_permission_level_to_mask(shell_permission_level_t level)
{
switch (level) {
case SHELL_PERMISSION_USER:
return SHELL_PERM_MASK_USER;
case SHELL_PERMISSION_ADMIN:
return SHELL_PERM_MASK_ADMIN;
case SHELL_PERMISSION_ROOT:
return SHELL_PERM_MASK_ROOT;
case SHELL_PERMISSION_GUEST:
return SHELL_PERM_MASK_GUEST;
default:
return 0;
}
}

/**
* @brief 更新提示符,显示当前用户名
*/
static void shell_prompt_update(shell_context_t *ctx)
{
if (!ctx) return;

if (ctx->current_user) {
// 已登录,显示 [用户名@主机]$
snprintf(ctx->prompt, sizeof(ctx->prompt), "[%s@shell]$ ",
ctx->current_user->username);
} else if (ctx->login_state == LOGIN_STATE_WAITING_PASSWORD) {
// 等待输入密码,显示 Password:
strcpy(ctx->prompt, "Password: ");
} else {
// 未登录,显示 login:
strcpy(ctx->prompt, "login: ");
}
}

/**
* @brief 简单的密码验证(实际应用中应使用哈希比较)
* @param input_pass 输入的密码
* @param stored_pass 存储的密码
* @return 1表示验证通过,0表示失败
*/
static uint8_t shell_verify_password(const char *input_pass, const char *stored_pass)
{
// TODO: 实际应用中应使用安全的密码哈希比较,如bcrypt、scrypt等
// 这里仅作演示,直接比较字符串
return (strcmp(input_pass, stored_pass) == 0) ? 1 : 0;
}

/**
* @brief 处理登录序列(用户名/密码输入)
* @param ctx Shell上下文
* @param input 用户输入
* @return SHELL_OK表示登录处理完成,SHELL_ERR表示需要继续
*/
static shell_status_t shell_handle_login_sequence(shell_context_t *ctx, const char *input)
{
if (!ctx || !input) {
return SHELL_ERR;
}

switch (ctx->login_state) {
case LOGIN_STATE_LOGGED_OUT:
// 未登录状态,等待输入用户名
if (strlen(input) > 0) {
// 保存用户名
strncpy(ctx->login_username, input, sizeof(ctx->login_username) - 1);
ctx->login_username[sizeof(ctx->login_username) - 1] = '\0';

// 查找用户
shell_user_t *user = shell_user_find(ctx, ctx->login_username);
if (!user) {
shell_print(ctx, "\r\nUser not found\r\n");
ctx->login_attempts++;
if (ctx->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
shell_print(ctx, "Too many login attempts\r\n");
// 可以在这里添加延时防止暴力破解
}
return SHELL_OK;
}

if (user->is_locked) {
shell_print(ctx, "\r\nUser account is locked\r\n");
return SHELL_OK;
}

// 切换到等待密码状态
ctx->login_state = LOGIN_STATE_WAITING_PASSWORD;
ctx->login_start_time = 0; // 实际应用中应获取系统时间
shell_prompt_update(ctx);

}
break;

case LOGIN_STATE_WAITING_PASSWORD:
// 等待密码状态,验证密码
{
shell_user_t *user = shell_user_find(ctx, ctx->login_username);
if (!user) {
// 用户不存在,返回登录状态
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
shell_prompt_update(ctx);
return SHELL_OK;
}

// 验证密码
if (shell_verify_password(input, user->password)) {
// 登录成功
ctx->current_user = user;
user->is_logged_in = 1;
user->login_attempts = 0;
ctx->login_state = LOGIN_STATE_LOGGED_IN;

// 更新提示符
shell_prompt_update(ctx);

// 显示欢迎信息
shell_printf(ctx, "\r\nWelcome, %s!\r\n", user->username);
shell_printf(ctx, "Permission level: %d\r\n", user->permission_level);

} else {
// 密码错误
user->login_attempts++;
ctx->login_attempts++;

shell_print(ctx, "\r\nInvalid password\r\n");

if (user->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
// 锁定用户
user->is_locked = 1;
shell_print(ctx, "User account locked due to too many failed attempts\r\n");
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
} else {
// 继续等待密码
return SHELL_OK; // 保持等待密码状态,不显示提示符
}

// 返回登录状态
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
shell_prompt_update(ctx);
}
}
break;

default:
break;
}

return SHELL_OK;
}

/**
* @brief 初始化默认用户(管理员和访客)
* @param ctx Shell上下文
* @return SHELL_OK表示成功
*/
shell_status_t shell_init_default_users(shell_context_t *ctx)
{
if (!ctx) {
return SHELL_ERR;
}

// 添加管理员用户(密码:admin)
shell_user_add(ctx, "admin", "pwd_admin", SHELL_PERMISSION_ADMIN);

// 添加普通用户(密码:user)
shell_user_add(ctx, "user", "pwd_user", SHELL_PERMISSION_USER);

// 添加普通用户(密码:lsy)
shell_user_add(ctx, "lsy", "pwd_lsy", SHELL_PERMISSION_USER);

// 添加访客用户(密码:guest,无密码)
shell_user_add(ctx, "guest", "", SHELL_PERMISSION_GUEST);

// 添加超级用户(密码:root)
shell_user_add(ctx, "root", "pwd_root", SHELL_PERMISSION_ROOT);

return SHELL_OK;
}

/**
* @brief 列出所有用户(需要管理员权限)
* @param ctx Shell上下文
*/
void shell_list_users(shell_context_t *ctx)
{
if (!ctx) {
return;
}

// 检查权限(只有管理员和root可以查看用户列表)
if (!ctx->current_user ||
(ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN)) {
shell_print(ctx, "Permission denied\r\n");
return;
}

shell_print(ctx, "\r\n=== User List ===\r\n");
shell_printf(ctx, "%-20s %-10s %-8s %-8s\r\n",
"Username", "Level", "Locked", "Logged In");
shell_print(ctx, "------------------------------------------------\r\n");

shell_user_t *user = ctx->user_list;
while (user) {
const char *level_str;
switch (user->permission_level) {
case SHELL_PERMISSION_ROOT: level_str = "root"; break;
case SHELL_PERMISSION_ADMIN: level_str = "admin"; break;
case SHELL_PERMISSION_USER: level_str = "user"; break;
case SHELL_PERMISSION_GUEST: level_str = "guest"; break;
default: level_str = "none"; break;
}

shell_printf(ctx, "%-20s %-10s %-8s %-8s\r\n",
user->username,
level_str,
user->is_locked ? "Yes" : "No",
user->is_logged_in ? "Yes" : "No");

user = user->next;
}

shell_print(ctx, "\r\n");
}

// ==================== 新增:用户管理API实现 ====================
/**
* @brief 添加新用户
* @param ctx Shell上下文
* @param username 用户名
* @param password 密码
* @param level 权限级别
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_add(shell_context_t *ctx,
const char *username,
const char *password,
shell_permission_level_t level)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 检查用户是否已存在
if (shell_user_find(ctx, username)) {
return SHELL_ERR_CMD_EXISTS; // 用户已存在
}

// 分配新用户节点
shell_user_t *new_user = shell_user_alloc();
if (!new_user) {
return SHELL_ERR_MEMORY;
}

// 填充用户信息
strncpy(new_user->username, username, sizeof(new_user->username) - 1);
new_user->username[sizeof(new_user->username) - 1] = '\0';

if (password) {
strncpy(new_user->password, password, sizeof(new_user->password) - 1);
new_user->password[sizeof(new_user->password) - 1] = '\0';
}

new_user->permission_level = level;
new_user->permission_mask = shell_permission_level_to_mask(level);
new_user->is_locked = 0;
new_user->login_attempts = 0;
new_user->last_login_time = 0;
new_user->is_logged_in = 0;

// 添加到用户链表头部
new_user->next = ctx->user_list;
ctx->user_list = new_user;

return SHELL_OK;
}

/**
* @brief 删除用户
* @param ctx Shell上下文
* @param username 要删除的用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_remove(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 不能删除当前登录用户
if (ctx->current_user && strcmp(ctx->current_user->username, username) == 0) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *prev = NULL;
shell_user_t *curr = ctx->user_list;

while (curr) {
if (strcmp(curr->username, username) == 0) {

//检查用户权限,不能删除大等于当前用户等级权限的用户
if(ctx->current_user && ctx->current_user->permission_level <= curr->permission_level){
return SHELL_ERR_PERMISSION_DENIED;
}

if (prev) {
prev->next = curr->next;
} else {
ctx->user_list = curr->next;
}
shell_user_free(curr);
return SHELL_OK;
}
prev = curr;
curr = curr->next;
}

return SHELL_ERR_USER_NOT_FOUND;
}

/**
* @brief 修改用户密码
* @param ctx Shell上下文
* @param username 用户名
* @param old_password 旧密码
* @param new_password 新密码
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_change_password(shell_context_t *ctx,
const char *username,
const char *old_password,
const char *new_password)
{
if (!ctx || !username || !new_password) {
return SHELL_ERR;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

// 验证旧密码(如果是修改自己的密码)
if (ctx->current_user && strcmp(ctx->current_user->username, username) == 0) {
if (!shell_verify_password(old_password, user->password)) {
return SHELL_ERR_INVALID_PASSWORD;
}
} else {
// 修改其他用户密码需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}
}

// 设置新密码
strncpy(user->password, new_password, sizeof(user->password) - 1);
user->password[sizeof(user->password) - 1] = '\0';

return SHELL_OK;
}

/**
* @brief 设置用户权限级别
* @param ctx Shell上下文
* @param username 用户名
* @param level 新的权限级别
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_set_permission(shell_context_t *ctx,
const char *username,
shell_permission_level_t level)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->permission_level = level;
user->permission_mask = shell_permission_level_to_mask(level);

return SHELL_OK;
}

/**
* @brief 锁定用户账户
* @param ctx Shell上下文
* @param username 用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_lock(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->is_locked = 1;
return SHELL_OK;
}

/**
* @brief 解锁用户账户
* @param ctx Shell上下文
* @param username 用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_unlock(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->is_locked = 0;
user->login_attempts = 0;
return SHELL_OK;
}

/**
* @brief 查找用户
* @param ctx Shell上下文
* @param username 用户名
* @return 用户指针,未找到返回NULL
*/
shell_user_t* shell_user_find(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return NULL;
}

shell_user_t *user = ctx->user_list;
while (user) {
if (strcmp(user->username, username) == 0) {
return user;
}
user = user->next;
}

return NULL;
}

/**
* @brief 用户登录
* @param ctx Shell上下文
* @param username 用户名
* @param password 密码
* @return SHELL_OK表示成功
*/
shell_status_t shell_login(shell_context_t *ctx,
const char *username,
const char *password)
{
if (!ctx || !username || !password) {
return SHELL_ERR;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

if (user->is_locked) {
return SHELL_ERR_USER_LOCKED;
}

if (!shell_verify_password(password, user->password)) {
user->login_attempts++;
if (user->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
user->is_locked = 1;
}
return SHELL_ERR_INVALID_PASSWORD;
}

// 登录成功
ctx->current_user = user;
user->is_logged_in = 1;
user->login_attempts = 0;
ctx->login_state = LOGIN_STATE_LOGGED_IN;

// 更新提示符
shell_prompt_update(ctx);

return SHELL_OK;
}

/**
* @brief 用户登出
* @param ctx Shell上下文
* @return SHELL_OK表示成功
*/
shell_status_t shell_logout(shell_context_t *ctx)
{
if (!ctx) {
return SHELL_ERR;
}

if (ctx->current_user) {
ctx->current_user->is_logged_in = 0;
ctx->current_user = NULL;
}

ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
ctx->login_attempts = 0;

// 更新提示符
shell_prompt_update(ctx);

return SHELL_OK;
}

/**
* @brief 检查是否已登录
* @param ctx Shell上下文
* @return 1表示已登录,0表示未登录
*/
uint8_t shell_is_logged_in(shell_context_t *ctx)
{
return (ctx && ctx->current_user) ? 1 : 0;
}

/**
* @brief 获取当前用户权限级别
* @param ctx Shell上下文
* @return 权限级别,未登录返回SHELL_PERMISSION_NONE
*/
shell_permission_level_t shell_get_current_permission(shell_context_t *ctx)
{
if (!ctx || !ctx->current_user) {
return SHELL_PERMISSION_NONE;
}

return ctx->current_user->permission_level;
}

/**
* @brief 检查用户是否有权限执行命令
* @param ctx Shell上下文
* @param cmd 命令指针
* @return 1表示有权限,0表示无权限
*/
uint8_t shell_check_command_permission(shell_context_t *ctx, shell_command_t *cmd)
{
if (!ctx || !cmd) {
return 0;
}

// 如果不需要登录,则所有命令都可执行
if (!ctx->require_login) {
return 1;
}

// 未登录状态只能执行登录相关命令
if (!ctx->current_user) {
// 允许登录和帮助命令
if (strcmp(cmd->name, "login") == 0 ||
strcmp(cmd->name, "help") == 0)
{
return 1;
}
return 0;
}

// 检查命令权限掩码
if (cmd->permission_mask == 0) {
// 权限掩码为0表示所有用户都可执行
return 1;
}

// 检查当前用户权限掩码是否包含命令所需的权限
return (ctx->current_user->permission_mask & cmd->permission_mask) ? 1 : 0;
}

#endif
// ==================== 新增结束 ====================


其中核心字符解析函数:

支持的按键识别

  1. 上下左右箭头
    • 上箭头(\x1b[A) - 可扩展历史命令
    • 下箭头(\x1b[B) - 可扩展历史命令
    • 右箭头(\x1b[C) - 光标右移
    • 左箭头(\x1b[D) - 光标左移
  2. Del键\x1b[3~) - 删除光标所在位置的字符
  3. Backspace\b0x7F) - 删除光标前的字符
  4. ESC键 - 作为控制序列的开始标记
  5. Home/End键
    • Home(\x1b[H\x1b[1~\x1bOH
    • End(\x1b[F\x1b[4~\x1bOF
  6. F1-F4功能键 - 通过SS3序列识别

主要特性

  • 光标移动:支持左右箭头在命令行中移动光标位置
  • 字符插入:支持在光标位置插入字符
  • 字符删除:支持Del和Backspace删除字符
  • 状态机设计:使用有限状态机处理终端控制序列
  • 回显适配:根据光标位置正确显示命令行内容

// 终端控制字符状态机状态
typedef enum {
STATE_NORMAL, // 正常状态
STATE_ESC, // 收到ESC
STATE_CSI, // 收到'['
STATE_CSI_PARAM, // 解析CSI参数
STATE_SS3 // 收到'O' (SS3状态)
} shell_input_state_t;

/**
* @brief 字符串分割函数(增强版,支持转义字符)
* @param str 输入字符串(会被修改)
* @param argv 输出参数数组
* @param max_args 最大参数个数
* @return 解析出的参数个数
*
* 支持的特性:
* 1. 空格分隔参数
* 2. 双引号内的内容作为一个参数(支持转义)
* 3. 转义字符:\" 表示一个字面双引号,\\ 表示一个字面反斜杠
* 4. 支持转义空格(如:a\ b 作为一个参数 "a b")
*
*/
static int shell_split_args(char *str, char *argv[], int max_args)
{
int argc = 0;
int in_arg = 0;
int in_quote = 0;
int escape = 0; // 转义标志:1表示当前字符需要被转义

char *p = str; // 当前读取位置
char *q = str; // 当前写入位置

while (*p && argc < max_args)
{
if (escape) {
// 转义模式:直接复制字符,不进行特殊处理
if (in_arg) {
//已开始新参数
}else
{
//未开始新参数
argv[argc] = q; // 记录参数起始位置
argc++;
in_arg = 1;
}
*q++ = *p++;
escape = 0;
continue;
}

if (*p == '\\') {
// 遇到反斜杠,设置转义标志
escape = 1;
p++;
continue;
}

if (*p == '"') {
if (in_quote) {
// 结束引号
in_quote = 0;
*q = '\0'; // 添加字符串结束符
q++; // 跳过结束符位置(保持q和p的同步)
} else {
// 开始引号,不将引号写入目标缓冲区
in_quote = 1;
if (in_arg) {
//已开始新参数,双引号不在新参数最前面

}else
{
//未开始新参数,双引号在新参数最前面
}
}
p++;
continue;
}

// 处理空格(仅在非引号模式下作为分隔符)
if (!in_quote && (*p == ' ' || *p == '\t' || *p == '\r')) {
if (in_arg) {
// 结束当前参数
*q = '\0';
q++;
in_arg = 0;
}
p++;
continue;
}

// 开始一个新参数
if (!in_arg) {
argv[argc] = q; // 记录参数起始位置
argc++;
in_arg = 1;
}

// 复制普通字符
*q++ = *p++;
}

// 处理最后一个参数
if (in_arg) {
*q = '\0';
}

// 检查是否有未闭合的引号
if (in_quote) {
// 可以选择报错,这里简单处理为忽略最后一个不完整的参数
if (argc > 0) {
argc--; // 移除最后一个不完整的参数
}
}

argv[argc] = NULL;
return argc;
}

// 重新显示当前行
static void shell_redisplay_line(shell_context_t *ctx)
{
if (!ctx || !ctx->echo_enabled)
{
return;
}

// 清除当前行
shell_print(ctx, "\r\033[K");

// 显示提示符
shell_printf(ctx, "%s", ctx->prompt);

#if SHELL_USERS_ENABLE == 1
if(ctx->login_state != LOGIN_STATE_WAITING_PASSWORD){
#endif
// 显示当前输入缓冲区内容
shell_print(ctx, ctx->input_buffer);

#if SHELL_USERS_ENABLE == 1
}else
{
for (int i = 0; i < strlen(ctx->input_buffer); i++) {
shell_print(ctx, "*");
}
}
#endif
// 将光标移动到正确位置
int cursor_move = strlen(ctx->input_buffer) - ctx->buf_pos;
for (int i = 0; i < cursor_move; i++) {
shell_print(ctx, "\033[D");
}
}

// 处理输入字符 - 增强版,支持终端控制字符识别
shell_status_t shell_process_char(shell_context_t *ctx, char ch)
{
if (!ctx || !ctx->initialized) {
return SHELL_ERR;
}

static shell_input_state_t input_state = STATE_NORMAL;
static char csi_buffer[16]; // CSI参数缓冲区
static int csi_pos = 0;
static int esc_param1 = 0; // CSI参数1
static int esc_param2 = 0; // CSI参数2

// 状态机处理终端控制序列
switch (input_state) {
case STATE_NORMAL:
// 检查是否ESC字符
if (ch == '\x1b') {
input_state = STATE_ESC;
csi_pos = 0;
esc_param1 = 0;
esc_param2 = 0;
return SHELL_OK;
}
break;

case STATE_ESC:
// ESC后的字符
if (ch == '[') {
input_state = STATE_CSI;
csi_pos = 0;
esc_param1 = 0;
esc_param2 = 0;
return SHELL_OK;
} else if (ch == 'O') {
input_state = STATE_SS3;
return SHELL_OK;
} else {
// 未知ESC序列,重置状态
input_state = STATE_NORMAL;
return SHELL_OK;
}

case STATE_SS3:
// SS3状态:处理 F1-F4 等按键
input_state = STATE_NORMAL;

switch (ch) {
// 可以根据需要处理F1,F2,F3,F4
case 'P': // F1

return SHELL_OK;
case 'Q': // F2

return SHELL_OK;
case 'R': // F3

return SHELL_OK;
case 'S': // F4

return SHELL_OK;
case 'H': // Home
// 移动光标到行首
ctx->buf_pos = 0;
shell_redisplay_line(ctx);
return SHELL_OK;
case 'F': // End
// 移动光标到行尾
ctx->buf_pos = strlen(ctx->input_buffer);
shell_redisplay_line(ctx);
return SHELL_OK;
}
return SHELL_OK;

case STATE_CSI:
// CSI状态:处理 '[' 后的字符
if (ch >= '0' && ch <= '9') {
// 解析参数
if (csi_pos == 0) {
esc_param1 = esc_param1 * 10 + (ch - '0');
} else if (csi_pos == 1) {
esc_param2 = esc_param2 * 10 + (ch - '0');
}
csi_buffer[csi_pos++] = ch;
return SHELL_OK;
} else if (ch == ';') {
// 参数分隔符
csi_pos++;
csi_buffer[csi_pos] = '\0';
return SHELL_OK;
} else {
// 命令字符
input_state = STATE_NORMAL;

// 处理各种CSI命令
switch (ch) {
case 'A': // 上箭头 历史记录上一条
#if SHELL_HISTORY_SIZE > 0
shell_history_prev(ctx);
#endif
break;

case 'B': // 下箭头 历史记录下一条
#if SHELL_HISTORY_SIZE > 0
shell_history_next(ctx);
#endif
break;

case 'C': // 右箭头
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
ctx->buf_pos++;
if (ctx->echo_enabled) {
// 发送光标右移序列
const char *move_right = "\033[C";
ctx->io.send(move_right, strlen(move_right));
}
}
break;

case 'D': // 左箭头
if (ctx->buf_pos > 0) {
ctx->buf_pos--;
if (ctx->echo_enabled) {
// 发送光标左移序列
const char *move_left = "\033[D";
ctx->io.send(move_left, strlen(move_left));
}
}
break;

case 'H': // Home键
ctx->buf_pos = 0;
shell_redisplay_line(ctx);
break;

case 'F': // End键
ctx->buf_pos = strlen(ctx->input_buffer);
shell_redisplay_line(ctx);
break;

case '~': // 带数字前缀的命令
if (esc_param1 == 3)
{
// Del键
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
// 删除当前位置的字符
memmove(&ctx->input_buffer[ctx->buf_pos],
&ctx->input_buffer[ctx->buf_pos + 1],
strlen(ctx->input_buffer) - ctx->buf_pos);

shell_redisplay_line(ctx);
}
} else if (esc_param1 == 5) { // Page Up
// 可扩展功能

} else if (esc_param1 == 6) { // Page Down
// 可扩展功能

}
break;

case 'Z': // Shift+Tab 反向补全


break;
}
return SHELL_OK;
}

default:
input_state = STATE_NORMAL;
break;
}

// 处理普通字符
if (input_state == STATE_NORMAL) {
// 处理回车
if (ch == '\r' || ch == '\n')
{
if (strlen(ctx->input_buffer) > 0) {
//ctx->input_buffer[ctx->buf_pos] = '\0';
#if SHELL_HISTORY_SIZE > 0
// 将命令添加到历史记录
shell_history_add(ctx, ctx->input_buffer);
#endif

// 回显输入
if (ctx->echo_enabled) {
shell_print(ctx, "\r\n");
}

// 处理命令
shell_process_string(ctx, ctx->input_buffer);

// 重置缓冲区
ctx->buf_pos = 0;
memset(ctx->input_buffer,0,SHELL_BUFFER_SIZE);
ctx->input_buffer[0] = '\0';

// 显示新提示符
if (ctx->echo_enabled) {
shell_printf(ctx, "%s", ctx->prompt);
}
} else {
// 空行,只显示提示符
if (ctx->echo_enabled) {
shell_printf(ctx, "\r\n%s", ctx->prompt);
}
}

return SHELL_OK;
}

// 处理退格
if (ch == '\b' || ch == 0x7F)
{
if (ctx->buf_pos > 0) {
// 删除当前位置的字符
memmove(&ctx->input_buffer[ctx->buf_pos - 1],
&ctx->input_buffer[ctx->buf_pos],
strlen(ctx->input_buffer) - ctx->buf_pos + 1);
ctx->buf_pos--;

shell_redisplay_line(ctx);
}
return SHELL_OK;
}

// 处理Tab键(命令补全)
if (ch == '\t') {
if(0 ==strlen(ctx->input_buffer))
{
shell_list_commands(ctx);
shell_printf(ctx, "%s", ctx->prompt);
}else {
// 这里可以实现命令补全功能

}
return SHELL_OK;
}

// 普通字符 - 插入到当前光标位置
if (ctx->buf_pos < sizeof(ctx->input_buffer) - 1) {
// 如果有字符在当前光标位置之后,需要移动它们
if (ctx->buf_pos < strlen(ctx->input_buffer)) {
// 将光标后的字符向后移动
memmove(&ctx->input_buffer[ctx->buf_pos + 1],
&ctx->input_buffer[ctx->buf_pos],
strlen(ctx->input_buffer) - ctx->buf_pos + 1);
}

// 插入新字符
ctx->input_buffer[ctx->buf_pos] = ch;
ctx->buf_pos++;

// 回显字符
if (ctx->echo_enabled && ctx->io.send) {
if (ctx->buf_pos == strlen(ctx->input_buffer)) {
#if SHELL_USERS_ENABLE == 1
if(ctx->login_state != LOGIN_STATE_WAITING_PASSWORD){
#endif
// 在行尾,直接回显
char echo[2] = {ch, '\0'};
ctx->io.send(echo, 1);
#if SHELL_USERS_ENABLE == 1
}else{
// 在行尾,直接回显
char echo[2] = {'*', '\0'};
ctx->io.send(echo, 1);
}
#endif
} else {
// 在行中插入,需要重新显示整行
shell_redisplay_line(ctx);
}
}
}
}
return SHELL_OK;
}

然后就是处理一帧命令字符串,解析并执行命令。


// 处理字符串
shell_status_t shell_process_string(shell_context_t *ctx, const char *str)
{
char buffer[SHELL_BUFFER_SIZE];
char *argv[SHELL_MAX_ARGS];
int argc;

if (!ctx || !str) {
return SHELL_ERR;
}

// ==================== 新增:处理登录序列 ====================
#if SHELL_USERS_ENABLE == 1
if (ctx->require_login && !ctx->current_user) {
// 未登录状态,处理登录序列
return shell_handle_login_sequence(ctx, str);
}
#endif
// ==================== 新增结束 ====================

// 复制字符串以便修改
strncpy(buffer, str, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';

// 分割参数
argc = shell_split_args(buffer, argv, sizeof(argv)/sizeof(argv[0]));

if (argc == 0) {
return SHELL_OK;
}

// ==================== 新增:登出命令 ====================
#if SHELL_USERS_ENABLE == 1
if (strcmp(argv[0], "logout") == 0) {
shell_logout(ctx);
return SHELL_OK;
}
#endif
// ==================== 新增结束 ====================

// 处理内置命令
if (strcmp(argv[0], "help") == 0) {
shell_print_help(ctx);
return SHELL_OK;
}

if (strcmp(argv[0], "list") == 0) {
shell_list_commands(ctx);
return SHELL_OK;
}

if (strcmp(argv[0], "echo") == 0) {
// ==================== 新增:权限检查 ====================
#if SHELL_USERS_ENABLE == 1
if (ctx->current_user && ctx->current_user->permission_level < SHELL_PERMISSION_USER) {
shell_print(ctx, "Permission denied\r\n");
shell_printf(ctx, "%s", ctx->prompt);
return SHELL_ERR_PERMISSION_DENIED;
}
#endif
// ==================== 新增结束 ====================

if (argc == 2) {
if (strcmp(argv[1], "on") == 0) {
ctx->echo_enabled = 1;
shell_print(ctx, "Echo enabled\r\n");
} else if (strcmp(argv[1], "off") == 0) {
ctx->echo_enabled = 0;
shell_print(ctx, "Echo disabled\r\n");
} else {
shell_print(ctx, "Usage: echo <on|off>\r\n");
}
} else {
shell_printf(ctx, "Echo is %s\r\n",
ctx->echo_enabled ? "enabled" : "disabled");
}
return SHELL_OK;
}

#if SHELL_HISTORY_SIZE > 0
// 添加历史记录相关命令
if (strcmp(argv[0], "history") == 0) {
// ==================== 新增:权限检查 ====================
#if SHELL_USERS_ENABLE == 1
if (ctx->current_user && ctx->current_user->permission_level < SHELL_PERMISSION_USER) {
shell_print(ctx, "Permission denied\r\n");
shell_printf(ctx, "%s", ctx->prompt);
return SHELL_ERR_PERMISSION_DENIED;
}
#endif
// ==================== 新增结束 ====================

if (argc == 1) {
shell_history_list(ctx);
} else if (argc == 2) {
if (strcmp(argv[1], "clear") == 0) {
shell_history_clear(ctx);
} else {
shell_print(ctx, "Usage: history [clear]\r\n");
}
}
return SHELL_OK;
}
#endif

// ==================== 新增:用户管理命令 ====================
#if SHELL_USERS_ENABLE == 1
if (strcmp(argv[0], "users") == 0) {
shell_list_users(ctx);
return SHELL_OK;
}

if (strcmp(argv[0], "passwd") == 0) {
// 修改密码
if (argc == 1) {
// 修改当前用户密码
shell_print(ctx, "Changing password for current user\r\n");
// 简化处理,实际应该交互式输入
shell_print(ctx, "Usage: passwd <old_password> <new_password>\r\n");
} else if (argc == 3) {
shell_user_change_password(ctx,
ctx->current_user->username,
argv[1], argv[2]);
} else {
shell_print(ctx, "Usage: passwd <old_password> <new_password>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "useradd") == 0) {
// 添加用户(需要管理员权限)
if (argc >= 3) {
shell_permission_level_t level = SHELL_PERMISSION_USER;
if (argc >= 4) {
level = (shell_permission_level_t)atoi(argv[3]);
}
shell_user_add(ctx, argv[1], argv[2], level);
} else {
shell_print(ctx, "Usage: useradd <username> <password> [permission_level]\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userdel") == 0) {
// 删除用户(需要管理员权限)
if (argc == 2) {
shell_user_remove(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userdel <username>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userlock") == 0) {
// 锁定用户(需要管理员权限)
if (argc == 2) {
shell_user_lock(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userlock <username>\r\n");
}
return SHELL_OK;
}

if (strcmp(argv[0], "userunlock") == 0) {
// 解锁用户(需要管理员权限)
if (argc == 2) {
shell_user_unlock(ctx, argv[1]);
} else {
shell_print(ctx, "Usage: userunlock <username>\r\n");
}
return SHELL_OK;
}
#endif
// ==================== 新增结束 ====================

// 查找命令
shell_command_t *cmd = shell_find_command(ctx, argv[0]);
if (!cmd) {
shell_printf(ctx, "Error: Command '%s' not found\r\n", argv[0]);
return SHELL_ERR_CMD_NOT_FOUND;
}

// ==================== 新增:权限检查 ====================
#if SHELL_USERS_ENABLE == 1
if (!shell_check_command_permission(ctx, cmd)) {
shell_printf(ctx, "Error: Permission denied for command '%s'\r\n", argv[0]);
shell_printf(ctx, "%s", ctx->prompt);
return SHELL_ERR_PERMISSION_DENIED;
}
#endif
// ==================== 新增结束 ====================

ctx->cur_cmd = cmd;
// 执行命令
if (cmd->handler) {
shell_execute_command(ctx, ctx->cur_cmd, argc, argv);
}
ctx->cur_cmd = NULL;
return SHELL_OK;
}

// 执行命令
static void shell_execute_command(shell_context_t *ctx,
shell_command_t *cmd,
int argc, char **argv)
{
shell_status_t status = cmd->handler(argc, argv);

if (status != SHELL_OK) {
shell_printf(ctx, "Command returned error: %d\r\n", status);
}
}

接着是增加历史记录功能和用户管理功能。

历史记录主要功能特点

  1. 历史记录存储:使用环形缓冲区存储最近执行的命令
  2. 历史浏览:通过上下箭头浏览历史命令
  3. 命令去重:自动过滤连续重复的命令
  4. 历史命令管理:支持 history 命令显示历史记录,history clear 清除历史
  5. 内存优化:自动整理历史记录缓冲区,避免内存碎片
  6. 状态保持:历史浏览时可以保持当前编辑状态
  7. 扩展性:预留了保存/加载历史记录到文件的功能


//历史记录配置
#define SHELL_HISTORY_SIZE 10 //=0时关闭该功能,历史记录最大条数
#define SHELL_HISTORY_BUFFER_SIZE (SHELL_BUFFER_SIZE * SHELL_HISTORY_SIZE) // 历史记录缓冲区总大小

#if SHELL_HISTORY_SIZE > 0
// 历史记录相关字段
char history_buffer[SHELL_HISTORY_BUFFER_SIZE]; // 历史记录存储缓冲区
char *history[SHELL_HISTORY_SIZE]; // 历史记录索引数组
size_t history_count; // 当前历史记录数量
size_t history_pos; // 当前浏览位置
int history_index; // 最新命令索引
#endif

#if SHELL_HISTORY_SIZE > 0
// 历史记录功能函数声明
static void shell_history_add(shell_context_t *ctx, const char *cmd);
static void shell_history_prev(shell_context_t *ctx);
static void shell_history_next(shell_context_t *ctx);
static void shell_history_clear(shell_context_t *ctx); // 清除历史记录
static void shell_history_list(shell_context_t *ctx); // 显示历史记录
static void shell_history_compact(shell_context_t *ctx); // 整理历史记录缓冲区

static void shell_history_save(shell_context_t *ctx);
static void shell_history_load(shell_context_t *ctx);
#endif

////////////////////////////////////////////////////////////////////////////
#if SHELL_HISTORY_SIZE > 0
// 添加命令到历史记录
static void shell_history_add(shell_context_t *ctx, const char *cmd)
{
if (!ctx || !cmd || strlen(cmd) == 0) {
return;
}

// 检查是否与上一条历史记录重复
if (ctx->history_count > 0) {
int last_idx = (ctx->history_index - 1 + SHELL_HISTORY_SIZE) % SHELL_HISTORY_SIZE;
if (ctx->history[last_idx] && strcmp(ctx->history[last_idx], cmd) == 0) {
return; // 重复命令,不添加
}
}

size_t cmd_len = strlen(cmd) + 1;

// 检查缓冲区空间
if (ctx->history_count >= SHELL_HISTORY_SIZE) {
// 历史已满,释放最旧的一条
char *oldest = ctx->history[ctx->history_index];
if (oldest) {
size_t oldest_len = strlen(oldest) + 1;
// 移动缓冲区数据(简化处理,实际可以使用环形缓冲区)
memmove(oldest, oldest + oldest_len,
ctx->history_buffer + sizeof(ctx->history_buffer) - (oldest + oldest_len));

// 调整所有指针
for (size_t i = 0; i < SHELL_HISTORY_SIZE; i++) {
if (ctx->history[i] && ctx->history[i] > oldest) {
ctx->history[i] -= oldest_len;
}
}
}
ctx->history_count--;
}

// 找到可用的存储位置
char *store_pos;
if (ctx->history_count == 0) {
store_pos = ctx->history_buffer;
ctx->history_index = 0;
} else {
// 计算下一个存储位置
int last_idx = (ctx->history_index + ctx->history_count - 1) % SHELL_HISTORY_SIZE;
char *last_cmd = ctx->history[last_idx];
store_pos = last_cmd + strlen(last_cmd) + 1;

// 检查是否超出缓冲区
if (store_pos + cmd_len > ctx->history_buffer + sizeof(ctx->history_buffer)) {
// 缓冲区满,重新整理
shell_history_compact(ctx);
// 重新计算存储位置
if (ctx->history_count > 0) {
last_idx = (ctx->history_index + ctx->history_count - 1) % SHELL_HISTORY_SIZE;
last_cmd = ctx->history[last_idx];
store_pos = last_cmd + strlen(last_cmd) + 1;
} else {
store_pos = ctx->history_buffer;
}
}
}

// 存储命令
strcpy(store_pos, cmd);

// 更新索引数组
int new_idx = (ctx->history_index + ctx->history_count) % SHELL_HISTORY_SIZE;
ctx->history[new_idx] = store_pos;
ctx->history_count++;

// 重置浏览位置
ctx->history_pos = ctx->history_count;
}

// 整理历史记录缓冲区
static void shell_history_compact(shell_context_t *ctx)
{
if (ctx->history_count == 0) return;

char temp_buffer[SHELL_HISTORY_BUFFER_SIZE];
char *temp_ptr = temp_buffer;
char *new_history[SHELL_HISTORY_SIZE];
size_t new_count = 0;

// 按顺序整理历史记录
for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
size_t len = strlen(ctx->history[idx]) + 1;
if (temp_ptr + len <= temp_buffer + sizeof(temp_buffer)) {
strcpy(temp_ptr, ctx->history[idx]);
new_history[new_count++] = temp_ptr;
temp_ptr += len;
}
}
}

// 复制回原缓冲区
memcpy(ctx->history_buffer, temp_buffer, temp_ptr - temp_buffer);
memcpy(ctx->history, new_history, new_count * sizeof(char*));

ctx->history_count = new_count;
ctx->history_index = 0;
}

// 获取上一条历史命令
static void shell_history_prev(shell_context_t *ctx)
{
if (!ctx || ctx->history_count == 0) {
return;
}

if (ctx->history_pos > 0) {
ctx->history_pos--;
}

size_t idx = (ctx->history_index + ctx->history_pos) % SHELL_HISTORY_SIZE;
const char *history_cmd = ctx->history[idx];

if (history_cmd) {
// 保存当前输入(用于下箭头恢复)
if (ctx->history_pos == ctx->history_count - 1) {
// 可以保存当前编辑的命令

}

// 替换输入缓冲区
strncpy(ctx->input_buffer, history_cmd, sizeof(ctx->input_buffer) - 1);
ctx->input_buffer[sizeof(ctx->input_buffer) - 1] = '\0';
ctx->buf_pos = strlen(ctx->input_buffer);

// 重新显示
shell_redisplay_line(ctx);
}
}

// 获取下一条历史命令
static void shell_history_next(shell_context_t *ctx)
{
if (!ctx) {
return;
}

if (ctx->history_pos < ctx->history_count - 1) {
ctx->history_pos++;

size_t idx = (ctx->history_index + ctx->history_pos) % SHELL_HISTORY_SIZE;
const char *history_cmd = ctx->history[idx];

if (history_cmd) {
strncpy(ctx->input_buffer, history_cmd, sizeof(ctx->input_buffer) - 1);
ctx->input_buffer[sizeof(ctx->input_buffer) - 1] = '\0';
ctx->buf_pos = strlen(ctx->input_buffer);
}
} else {
// 已经到最后一条历史记录,清空输入
ctx->history_pos = ctx->history_count;
memset(ctx->input_buffer,0,SHELL_BUFFER_SIZE);
ctx->buf_pos = 0;
}

// 重新显示
shell_redisplay_line(ctx);
}

// 清除历史记录
static void shell_history_clear(shell_context_t *ctx)
{
if (!ctx) {
return;
}

memset(ctx->history_buffer, 0, sizeof(ctx->history_buffer));
memset(ctx->history, 0, sizeof(ctx->history));
ctx->history_count = 0;
ctx->history_pos = 0;
ctx->history_index = -1;

shell_print(ctx, "History cleared\r\n");
}

// 显示历史记录
static void shell_history_list(shell_context_t *ctx)
{
if (!ctx) {
return;
}

if (ctx->history_count == 0) {
shell_print(ctx, "No history commands\r\n");
return;
}

shell_print(ctx, "\r\n=== Command History ===\r\n");

for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
shell_printf(ctx, "%3zu: %s\r\n", i + 1, ctx->history[idx]);
}
}
}

// 添加保存历史记录到文件的功能(可选)
shell_status_t shell_history_save_to_file(shell_context_t *ctx, const char *filename)
{
if (!ctx || !filename) {
return SHELL_ERR;
}

FILE *fp = fopen(filename, "w");
if (!fp) {
return SHELL_ERR;
}

for (size_t i = 0; i < ctx->history_count; i++) {
int idx = (ctx->history_index + i) % SHELL_HISTORY_SIZE;
if (ctx->history[idx]) {
fprintf(fp, "%s\n", ctx->history[idx]);
}
}

fclose(fp);
return SHELL_OK;
}

// 从文件加载历史记录(可选)
shell_status_t shell_history_load_from_file(shell_context_t *ctx, const char *filename)
{
if (!ctx || !filename) {
return SHELL_ERR;
}

FILE *fp = fopen(filename, "r");
if (!fp) {
return SHELL_ERR;
}

char buffer[SHELL_BUFFER_SIZE];
while (fgets(buffer, sizeof(buffer), fp)) {
// 去除换行符
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
}

shell_history_add(ctx, buffer);
}

fclose(fp);
return SHELL_OK;
}

#endif

用户管理主要功能特点

  1. 用户管理
    • 支持多用户
    • 用户增删改查
    • 密码管理
    • 账户锁定/解锁
  2. 权限级别
    • 超级用户(root):最高权限
    • 管理员(admin):管理权限
    • 普通用户(user):基本权限
    • 访客(guest):受限权限
  3. 命令权限控制
    • 每个命令可以设置所需的权限掩码
    • 自动检查用户权限
    • 权限不足时拒绝执行
  4. 登录系统
    • 交互式登录
    • 密码验证
    • 登录尝试次数限制
    • 账户自动锁定
  5. 安全特性
    • 密码不回显
    • 登录超时
    • 暴力破解防护
    • 权限隔离
  6. 内置命令
    • login:登录
    • logout:登出
    • passwd:修改密码
    • users:查看用户列表
    • useradd:添加用户
    • userdel:删除用户
    • userlock:锁定用户
    • userunlock:解锁用户
// ==================== 新增:权限管理配置 ====================
#define SHELL_USERS_ENABLE 1 // 用户权限功能开关
#define SHELL_MAX_USERS 10 // 最大用户数
#define SHELL_USERNAME_MAX_LEN 32 // 用户名最大长度
#define SHELL_PASSWORD_MAX_LEN 32 // 密码最大长度
#define SHELL_MAX_LOGIN_ATTEMPTS 3 // 最大登录尝试次数
#define SHELL_LOGIN_TIMEOUT 30000 // 登录超时时间(ms)
// ==================== 新增结束 ====================

// ==================== 新增:权限相关错误码 ========
SHELL_ERR_PERMISSION_DENIED, // 权限不足
SHELL_ERR_USER_NOT_FOUND, // 用户不存在
SHELL_ERR_INVALID_PASSWORD, // 密码错误
SHELL_ERR_USER_LOCKED, // 用户被锁定
SHELL_ERR_NOT_LOGGED_IN, // 未登录
SHELL_ERR_LOGIN_TIMEOUT, // 登录超时
// ==================== 新增结束 ====================

// ==================== 新增:权限级别枚举 ====================
typedef enum {
SHELL_PERMISSION_NONE = 0, // 无权限
SHELL_PERMISSION_GUEST = 1, // 访客权限
SHELL_PERMISSION_USER = 2, // 普通用户权限
SHELL_PERMISSION_ADMIN = 3, // 管理员权限
SHELL_PERMISSION_ROOT = 8, // 超级用户权限

} shell_permission_level_t;

// 权限位掩码定义(用于命令权限控制)
#define SHELL_PERM_MASK_GUEST 0x01 // 访客位
#define SHELL_PERM_MASK_USER 0x02 // 普通用户位
#define SHELL_PERM_MASK_ADMIN 0x04 // 管理员位
#define SHELL_PERM_MASK_ROOT 0x80 // 超级用户位
#define SHELL_PERM_MASK_ALL (SHELL_PERM_MASK_USER | SHELL_PERM_MASK_ADMIN | \
SHELL_PERM_MASK_ROOT | SHELL_PERM_MASK_GUEST) // 所有权限

// 默认权限配置
#define SHELL_PERM_DEFAULT_GUEST SHELL_PERM_MASK_GUEST // 访客默认权限
#define SHELL_PERM_DEFAULT_USER SHELL_PERM_MASK_USER // 普通用户默认权限
#define SHELL_PERM_DEFAULT_ADMIN SHELL_PERM_MASK_ADMIN // 管理员默认权限
#define SHELL_PERM_DEFAULT_ROOT SHELL_PERM_MASK_ROOT // 超级用户默认权限
// ==================== 新增结束 ====================

// ==================== 新增:用户信息结构体 ====================
typedef struct shell_user {
char username[SHELL_USERNAME_MAX_LEN]; // 用户名
char password[SHELL_PASSWORD_MAX_LEN]; // 密码(实际使用中应存储哈希值)
shell_permission_level_t permission_level; // 用户权限级别
uint32_t permission_mask; // 用户权限掩码(可访问的权限位)
uint32_t last_login_time; // 最后登录时间
uint8_t is_locked; // 是否被锁定
uint8_t login_attempts; // 登录尝试次数
uint8_t is_logged_in; // 当前是否已登录
struct shell_user *next; // 链表指针
} shell_user_t;

// 登录状态枚举
typedef enum {
LOGIN_STATE_LOGGED_OUT = 0, // 未登录
LOGIN_STATE_LOGGED_IN, // 已登录
LOGIN_STATE_WAITING_PASSWORD, // 等待输入密码
LOGIN_STATE_CHANGING_PASSWORD // 正在修改密码
} shell_login_state_t;
// ==================== 新增结束 ====================

#if SHELL_USERS_ENABLE == 1
// ==================== 新增:用户和权限管理相关字段 ====================
shell_user_t *user_list; // 用户链表头
shell_user_t *current_user; // 当前登录用户
shell_login_state_t login_state; // 登录状态
char login_username[SHELL_USERNAME_MAX_LEN]; // 登录中的用户名
uint32_t login_start_time; // 登录开始时间
uint8_t login_attempts; // 当前登录尝试次数
uint8_t require_login; // 是否需要登录才能使用shell
// ==================== 新增结束 ====================
#endif

// ==================== 新增:用户管理内部函数声明 ====================
#if SHELL_USERS_ENABLE == 1
static shell_user_t* shell_user_alloc(void);
static void shell_user_free(shell_user_t *user);
static uint32_t shell_permission_level_to_mask(shell_permission_level_t level);
static void shell_prompt_update(shell_context_t *ctx);
static shell_status_t shell_handle_login_sequence(shell_context_t *ctx, const char *input);
static uint8_t shell_verify_password(const char *input_pass, const char *stored_pass);
#endif
// ==================== 新增结束 ====================
// ==================== 新增:用户管理内部函数实现 ====================
#if SHELL_USERS_ENABLE == 1
/**
* @brief 分配新的用户节点
* @return 分配的用户节点指针,失败返回NULL
*/
static shell_user_t* shell_user_alloc(void)
{
shell_user_t *user = (shell_user_t*)malloc(sizeof(shell_user_t));
if (user) {
memset(user, 0, sizeof(shell_user_t));
}
return user;
}

/**
* @brief 释放用户节点
* @param user 要释放的用户节点
*/
static void shell_user_free(shell_user_t *user)
{
if (user) {
free(user);
}
}

/**
* @brief 将权限级别转换为权限掩码
* @param level 权限级别
* @return 权限掩码
*/
static uint32_t shell_permission_level_to_mask(shell_permission_level_t level)
{
switch (level) {
case SHELL_PERMISSION_USER:
return SHELL_PERM_MASK_USER;
case SHELL_PERMISSION_ADMIN:
return SHELL_PERM_MASK_ADMIN;
case SHELL_PERMISSION_ROOT:
return SHELL_PERM_MASK_ROOT;
case SHELL_PERMISSION_GUEST:
return SHELL_PERM_MASK_GUEST;
default:
return 0;
}
}

/**
* @brief 更新提示符,显示当前用户名
*/
static void shell_prompt_update(shell_context_t *ctx)
{
if (!ctx) return;

if (ctx->current_user) {
// 已登录,显示 [用户名@主机]$
snprintf(ctx->prompt, sizeof(ctx->prompt), "[%s@shell]$ ",
ctx->current_user->username);
} else if (ctx->login_state == LOGIN_STATE_WAITING_PASSWORD) {
// 等待输入密码,显示 Password:
strcpy(ctx->prompt, "Password: ");
} else {
// 未登录,显示 login:
strcpy(ctx->prompt, "login: ");
}
}

/**
* @brief 简单的密码验证(实际应用中应使用哈希比较)
* @param input_pass 输入的密码
* @param stored_pass 存储的密码
* @return 1表示验证通过,0表示失败
*/
static uint8_t shell_verify_password(const char *input_pass, const char *stored_pass)
{
// TODO: 实际应用中应使用安全的密码哈希比较,如bcrypt、scrypt等
// 这里仅作演示,直接比较字符串
return (strcmp(input_pass, stored_pass) == 0) ? 1 : 0;
}

/**
* @brief 处理登录序列(用户名/密码输入)
* @param ctx Shell上下文
* @param input 用户输入
* @return SHELL_OK表示登录处理完成,SHELL_ERR表示需要继续
*/
static shell_status_t shell_handle_login_sequence(shell_context_t *ctx, const char *input)
{
if (!ctx || !input) {
return SHELL_ERR;
}

switch (ctx->login_state) {
case LOGIN_STATE_LOGGED_OUT:
// 未登录状态,等待输入用户名
if (strlen(input) > 0) {
// 保存用户名
strncpy(ctx->login_username, input, sizeof(ctx->login_username) - 1);
ctx->login_username[sizeof(ctx->login_username) - 1] = '\0';

// 查找用户
shell_user_t *user = shell_user_find(ctx, ctx->login_username);
if (!user) {
shell_print(ctx, "\r\nUser not found\r\n");
ctx->login_attempts++;
if (ctx->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
shell_print(ctx, "Too many login attempts\r\n");
// 可以在这里添加延时防止暴力破解
}
return SHELL_OK;
}

if (user->is_locked) {
shell_print(ctx, "\r\nUser account is locked\r\n");
return SHELL_OK;
}

// 切换到等待密码状态
ctx->login_state = LOGIN_STATE_WAITING_PASSWORD;
ctx->login_start_time = 0; // 实际应用中应获取系统时间
shell_prompt_update(ctx);

}
break;

case LOGIN_STATE_WAITING_PASSWORD:
// 等待密码状态,验证密码
{
shell_user_t *user = shell_user_find(ctx, ctx->login_username);
if (!user) {
// 用户不存在,返回登录状态
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
shell_prompt_update(ctx);
return SHELL_OK;
}

// 验证密码
if (shell_verify_password(input, user->password)) {
// 登录成功
ctx->current_user = user;
user->is_logged_in = 1;
user->login_attempts = 0;
ctx->login_state = LOGIN_STATE_LOGGED_IN;

// 更新提示符
shell_prompt_update(ctx);

// 显示欢迎信息
shell_printf(ctx, "\r\nWelcome, %s!\r\n", user->username);
shell_printf(ctx, "Permission level: %d\r\n", user->permission_level);

} else {
// 密码错误
user->login_attempts++;
ctx->login_attempts++;

shell_print(ctx, "\r\nInvalid password\r\n");

if (user->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
// 锁定用户
user->is_locked = 1;
shell_print(ctx, "User account locked due to too many failed attempts\r\n");
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
} else {
// 继续等待密码
return SHELL_OK; // 保持等待密码状态,不显示提示符
}

// 返回登录状态
ctx->login_state = LOGIN_STATE_LOGGED_OUT;
shell_prompt_update(ctx);
}
}
break;

default:
break;
}

return SHELL_OK;
}

/**
* @brief 初始化默认用户(管理员和访客)
* @param ctx Shell上下文
* @return SHELL_OK表示成功
*/
shell_status_t shell_init_default_users(shell_context_t *ctx)
{
if (!ctx) {
return SHELL_ERR;
}

// 添加管理员用户(密码:admin)
shell_user_add(ctx, "admin", "admin", SHELL_PERMISSION_ADMIN);

// 添加普通用户(密码:user)
shell_user_add(ctx, "user", "user", SHELL_PERMISSION_USER);

// 添加访客用户(密码:guest,无密码)
shell_user_add(ctx, "guest", "", SHELL_PERMISSION_GUEST);

// 添加超级用户(密码:root)
shell_user_add(ctx, "root", "root", SHELL_PERMISSION_ROOT);

return SHELL_OK;
}

/**
* @brief 列出所有用户(需要管理员权限)
* @param ctx Shell上下文
*/
void shell_list_users(shell_context_t *ctx)
{
if (!ctx) {
return;
}

// 检查权限(只有管理员和root可以查看用户列表)
if (!ctx->current_user ||
(ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN)) {
shell_print(ctx, "Permission denied\r\n");
return;
}

shell_print(ctx, "\r\n=== User List ===\r\n");
shell_printf(ctx, "%-20s %-10s %-8s %-8s\r\n",
"Username", "Level", "Locked", "Logged In");
shell_print(ctx, "------------------------------------------------\r\n");

shell_user_t *user = ctx->user_list;
while (user) {
const char *level_str;
switch (user->permission_level) {
case SHELL_PERMISSION_ROOT: level_str = "root"; break;
case SHELL_PERMISSION_ADMIN: level_str = "admin"; break;
case SHELL_PERMISSION_USER: level_str = "user"; break;
case SHELL_PERMISSION_GUEST: level_str = "guest"; break;
default: level_str = "none"; break;
}

shell_printf(ctx, "%-20s %-10s %-8s %-8s\r\n",
user->username,
level_str,
user->is_locked ? "Yes" : "No",
user->is_logged_in ? "Yes" : "No");

user = user->next;
}

shell_print(ctx, "\r\n");
}

// ==================== 新增:用户管理API实现 ====================
/**
* @brief 添加新用户
* @param ctx Shell上下文
* @param username 用户名
* @param password 密码
* @param level 权限级别
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_add(shell_context_t *ctx,
const char *username,
const char *password,
shell_permission_level_t level)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 检查用户是否已存在
if (shell_user_find(ctx, username)) {
return SHELL_ERR_CMD_EXISTS; // 用户已存在
}

// 分配新用户节点
shell_user_t *new_user = shell_user_alloc();
if (!new_user) {
return SHELL_ERR_MEMORY;
}

// 填充用户信息
strncpy(new_user->username, username, sizeof(new_user->username) - 1);
new_user->username[sizeof(new_user->username) - 1] = '\0';

if (password) {
strncpy(new_user->password, password, sizeof(new_user->password) - 1);
new_user->password[sizeof(new_user->password) - 1] = '\0';
}

new_user->permission_level = level;
new_user->permission_mask = shell_permission_level_to_mask(level);
new_user->is_locked = 0;
new_user->login_attempts = 0;
new_user->last_login_time = 0;
new_user->is_logged_in = 0;

// 添加到用户链表头部
new_user->next = ctx->user_list;
ctx->user_list = new_user;

return SHELL_OK;
}

/**
* @brief 删除用户
* @param ctx Shell上下文
* @param username 要删除的用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_remove(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 不能删除当前登录用户
if (ctx->current_user && strcmp(ctx->current_user->username, username) == 0) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *prev = NULL;
shell_user_t *curr = ctx->user_list;

while (curr) {
if (strcmp(curr->username, username) == 0) {
if (prev) {
prev->next = curr->next;
} else {
ctx->user_list = curr->next;
}
shell_user_free(curr);
return SHELL_OK;
}
prev = curr;
curr = curr->next;
}

return SHELL_ERR_USER_NOT_FOUND;
}

/**
* @brief 修改用户密码
* @param ctx Shell上下文
* @param username 用户名
* @param old_password 旧密码
* @param new_password 新密码
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_change_password(shell_context_t *ctx,
const char *username,
const char *old_password,
const char *new_password)
{
if (!ctx || !username || !new_password) {
return SHELL_ERR;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

// 验证旧密码(如果是修改自己的密码)
if (ctx->current_user && strcmp(ctx->current_user->username, username) == 0) {
if (!shell_verify_password(old_password, user->password)) {
return SHELL_ERR_INVALID_PASSWORD;
}
} else {
// 修改其他用户密码需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}
}

// 设置新密码
strncpy(user->password, new_password, sizeof(user->password) - 1);
user->password[sizeof(user->password) - 1] = '\0';

return SHELL_OK;
}

/**
* @brief 设置用户权限级别
* @param ctx Shell上下文
* @param username 用户名
* @param level 新的权限级别
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_set_permission(shell_context_t *ctx,
const char *username,
shell_permission_level_t level)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->permission_level = level;
user->permission_mask = shell_permission_level_to_mask(level);

return SHELL_OK;
}

/**
* @brief 锁定用户账户
* @param ctx Shell上下文
* @param username 用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_lock(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->is_locked = 1;
return SHELL_OK;
}

/**
* @brief 解锁用户账户
* @param ctx Shell上下文
* @param username 用户名
* @return SHELL_OK表示成功
*/
shell_status_t shell_user_unlock(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return SHELL_ERR;
}

// 需要管理员权限
if (!ctx->current_user ||
ctx->current_user->permission_level < SHELL_PERMISSION_ADMIN) {
return SHELL_ERR_PERMISSION_DENIED;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

user->is_locked = 0;
user->login_attempts = 0;
return SHELL_OK;
}

/**
* @brief 查找用户
* @param ctx Shell上下文
* @param username 用户名
* @return 用户指针,未找到返回NULL
*/
shell_user_t* shell_user_find(shell_context_t *ctx, const char *username)
{
if (!ctx || !username) {
return NULL;
}

shell_user_t *user = ctx->user_list;
while (user) {
if (strcmp(user->username, username) == 0) {
return user;
}
user = user->next;
}

return NULL;
}

/**
* @brief 用户登录
* @param ctx Shell上下文
* @param username 用户名
* @param password 密码
* @return SHELL_OK表示成功
*/
shell_status_t shell_login(shell_context_t *ctx,
const char *username,
const char *password)
{
if (!ctx || !username || !password) {
return SHELL_ERR;
}

shell_user_t *user = shell_user_find(ctx, username);
if (!user) {
return SHELL_ERR_USER_NOT_FOUND;
}

if (user->is_locked) {
return SHELL_ERR_USER_LOCKED;
}

if (!shell_verify_password(password, user->password)) {
user->login_attempts++;
if (user->login_attempts >= SHELL_MAX_LOGIN_ATTEMPTS) {
user->is_locked = 1;
}
return SHELL_ERR_INVALID_PASSWORD;
}

// 登录成功
ctx->current_user = user;
user->is_logged_in = 1;
user->login_attempts = 0;
ctx->login_state = LOGIN_STATE_LOGGED_IN;

// 更新提示符
shell_prompt_update(ctx);

return SHELL_OK;
}

/**
* @brief 用户登出
* @param ctx Shell上下文
* @return SHELL_OK表示成功
*/
shell_status_t shell_logout(shell_context_t *ctx)
{
if (!ctx) {
return SHELL_ERR;
}

if (ctx->current_user) {
ctx->current_user->is_logged_in = 0;
ctx->current_user = NULL;
}

ctx->login_state = LOGIN_STATE_LOGGED_OUT;
ctx->login_username[0] = '\0';
ctx->login_attempts = 0;

// 更新提示符
shell_prompt_update(ctx);

return SHELL_OK;
}

/**
* @brief 检查是否已登录
* @param ctx Shell上下文
* @return 1表示已登录,0表示未登录
*/
uint8_t shell_is_logged_in(shell_context_t *ctx)
{
return (ctx && ctx->current_user) ? 1 : 0;
}

/**
* @brief 获取当前用户权限级别
* @param ctx Shell上下文
* @return 权限级别,未登录返回SHELL_PERMISSION_NONE
*/
shell_permission_level_t shell_get_current_permission(shell_context_t *ctx)
{
if (!ctx || !ctx->current_user) {
return SHELL_PERMISSION_NONE;
}

return ctx->current_user->permission_level;
}

/**
* @brief 检查用户是否有权限执行命令
* @param ctx Shell上下文
* @param cmd 命令指针
* @return 1表示有权限,0表示无权限
*/
uint8_t shell_check_command_permission(shell_context_t *ctx, shell_command_t *cmd)
{
if (!ctx || !cmd) {
return 0;
}

// 如果不需要登录,则所有命令都可执行
if (!ctx->require_login) {
return 1;
}

// 未登录状态只能执行登录相关命令
if (!ctx->current_user) {
// 允许登录和帮助命令
if (strcmp(cmd->name, "login") == 0 ||
strcmp(cmd->name, "help") == 0) {
return 1;
}
return 0;
}

// 检查命令权限掩码
if (cmd->permission_mask == 0) {
// 权限掩码为0表示所有用户都可执行
return 1;
}

// 检查当前用户权限掩码是否包含命令所需的权限
return (ctx->current_user->permission_mask & cmd->permission_mask) ? 1 : 0;
}

#endif
// ==================== 新增结束 ====================

最后就是命令示例编写:

#include "lsy_shell_core.h"

// 静态命令处理函数示例
static shell_status_t cmd_reboot(int argc, char **argv) {
(void)argc;
(void)argv;
shell_print(&g_lsy_shell, "Rebooting...\r\n");
// 直接调用库函数
NVIC_SystemReset();
return SHELL_OK;
}

static shell_status_t cmd_version(int argc, char **argv) {
(void)argc;
(void)argv;
shell_printf(&g_lsy_shell, "\r\n=== Little Dynamic Shell ===\r\n");
shell_printf(&g_lsy_shell, "Shell Version: %s\r\n",LSY_SHELL_VERSION_STR);
shell_printf(&g_lsy_shell, "Build Date: %s %s\r\n", __DATE__, __TIME__);
return SHELL_OK;
}

static shell_status_t cmd_analysis(int argc, char **argv) {
int i;
shell_printf(&g_lsy_shell, "CMD Name: %s\r\n", argv[0]);
for(i=1;i<argc;i++)
{
shell_printf(&g_lsy_shell, "Para%d: %s\r\n", i, argv[i]);
}
return SHELL_OK;
}

// 静态命令表
shell_command_t static_commands[] = {
{"cmdtest", "Test cmd parameter", cmd_analysis,NULL, NULL, 1},
{"reboot", "Reboot the system", cmd_reboot, NULL, NULL, 1},
{"version", "Show version information", cmd_version, NULL, NULL, 1}
};

// 获取静态命令表
shell_command_t* get_static_commands(size_t *count) {
*count = sizeof(static_commands) / sizeof(static_commands[0]);
return static_commands;
}

动态命令:


#include <stdlib.h>
#include "main.h"
#include "lsy_shell_core.h"

// 示例命令处理函数
static shell_status_t cmd_led_control(int argc, char **argv)
{
uint32_t pinstate = 1;

if (argc != 3) {
shell_print(&g_lsy_shell, "Usage: led <r|g|b> <on|off>\r\n");
return SHELL_ERR_PARAM;
}

if(!strcmp(argv[2], "on"))
{
pinstate = 0;
}else if(!strcmp(argv[2],"off"))
{
pinstate = 1;
}else
{
shell_print(&g_lsy_shell,"cmd para2 ERROR!\n");
return SHELL_ERR_PARAM;
}

if(!strcmp(argv[1], "r"))
{
GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN,pinstate);
}else if(!strcmp(argv[1],"g"))
{
GPIO_PinWrite(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN,pinstate);
}else if(!strcmp(argv[1],"b"))
{
GPIO_PinWrite(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN,pinstate);
}else
{
shell_print(&g_lsy_shell,"cmd para1 ERROR!\n");
return SHELL_ERR_PARAM;
}

shell_printf(&g_lsy_shell, "led %s\r\n",pinstate ? "off":"on");

return SHELL_OK;
}

// 调用下面函数注册动态注册简单命令
shell_register_command(shell_ctx, "led",
"Control LED: led <on|off>",
cmd_led_control, NULL);


用户调用接口:

#include "lsy_shell_core.h"

// 全局Shell上下文
shell_context_t g_lsy_shell;

extern void register_example_commands(shell_context_t *shell_ctx);
extern void register_batch_commands(shell_context_t *shell_ctx);

int lsy_shell_init(shell_io_ops_t * io_ops)
{
// 初始化Shell
shell_init(&g_lsy_shell, io_ops, SHELL_PROMPT);

// 注册静态命令表
size_t static_cmd_count;
shell_command_t *static_cmds = get_static_commands(&static_cmd_count);
shell_register_static_table(&g_lsy_shell, static_cmds, static_cmd_count);

// 注册内存控制命令
memory_view_init(&g_lsy_shell);

// 注册示例命令
register_example_commands(&g_lsy_shell);

return 0;
}

int lsy_shell_input(uint8_t ch)
{
shell_process_char(&g_lsy_shell, ch);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//
void shell_usart_init(void)
{
#if UART_SHELL != 4
serial_manager_status_t status = kStatus_SerialManager_Error;

g_write_handle = (serial_write_handle_t)&g_write_handle_buff[0];
status = SerialManager_OpenWriteHandle(g_serialHandle, g_write_handle);
assert(kStatus_SerialManager_Success == status);

g_read_handle = (serial_read_handle_t)&g_read_handle_buff[0];
status = SerialManager_OpenReadHandle(g_serialHandle, g_read_handle);
assert(kStatus_SerialManager_Success == status);
#endif

#ifdef UART_SHELL
#if UART_SHELL == 1
userShellInit(); //LETTER_SHELL
#elif UART_SHELL == 2
shell_init(); //NR_MICRO_SHELL
#elif UART_SHELL == 3
// 配置IO操作
shell_io_ops_t io_ops = {
.send = USART_PutStr,
};

lsy_shell_init(&io_ops); //LSY_SHELL

#elif UART_SHELL == 4
//初始化shell
SHELL_Init((shell_handle_t)s_shellHandle, (serial_handle_t)g_serialHandle, "nxp:>");

SHELL_RegisterCommand(s_shellHandle,SHELL_COMMAND(test)); //注册新的shell函数
SHELL_RegisterCommand(s_shellHandle,SHELL_COMMAND(led)); //注册新的shell函数

#endif
#endif
/* 启动非阻塞式读取接收数据 */


}

void shell_usart_loop(void)
{
#if UART_SHELL == 4
SHELL_Task(s_shellHandle);
#else
//阻塞式读取接收数据
serial_manager_status_t status = SerialManager_ReadBlocking(g_read_handle, uart_recv_buff, 1);
if(kStatus_Success == status)
{
if(((g_shell_uart.rx.write_i+1)&0x1ff) != g_shell_uart.rx.read_i)
{
g_shell_uart.rx.buff[g_shell_uart.rx.write_i++] = uart_recv_buff[0] & 0xff;
g_shell_uart.rx.write_i &= 0x1ff;//256Byte
}
}

//=============================================================================================
if(g_shell_uart.rx.read_i != g_shell_uart.rx.write_i)
{
#ifdef UART_SHELL
#if UART_SHELL == 1
shellHandler(&shell, g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]); //letter shell
#elif UART_SHELL == 2
shell(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);
#elif UART_SHELL == 3
lsy_shell_input(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);
#else
USART_PutChar(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);
#endif
#endif
g_shell_uart.rx.read_i &= 0x1ff; //256Byte
}

if(g_shell_uart.tx_cpl == 0)
{
uart_get_data_send();
}
#endif
}

最终实现了一个功能完善的嵌入式命令行外壳(Shell)系统,提供了动态命令管理、终端控制、历史记录、用户权限管理等核心功能。系统采用模块化设计,可灵活配置,适用于嵌入式设备、物联网终端、调试系统等场景。


2.3、Shell核心功能总结

2.3.1. 命令管理模块

静态命令

  • 编译时确定的命令表
  • 节省内存,执行效率高
  • 适用于系统基础命令

动态命令

  • 运行时动态注册/注销
  • 链表结构存储
  • 支持热插拔式命令管理

内置命令

  • help - 显示帮助信息
  • list - 列出所有命令
  • echo <on|off> - 控制输入回显
  • history [clear] - 历史记录管理

2.3.2. 终端控制模块

按键识别

  • 上下左右箭头:光标移动
  • Home/End:行首/行尾跳转
  • Backspace/Del:字符删除
  • ESC序列:完整终端控制

行编辑功能

  • 光标位置移动
  • 字符插入/删除
  • 行内编辑
  • 自动换行处理

2.3.3. 历史记录模块

存储管理

  • 环形缓冲区设计
  • 自动去重(连续重复命令)
  • 内存紧凑存储

浏览功能

  • 上箭头:上一条历史
  • 下箭头:下一条历史
  • 命令快速复用

管理功能

  • history:显示历史列表
  • history clear:清空历史

2.3.4. 用户权限管理模块

用户系统

text

权限级别:
├── 超级用户(root) - 最高权限
├── 管理员(admin) - 管理权限
├── 普通用户(user) - 基本权限
└── 访客(guest) - 受限权限

用户管理命令

  • login - 用户登录
  • logout - 用户登出
  • passwd - 修改密码
  • users - 查看用户列表(管理员)
  • useradd - 添加用户(管理员)
  • userdel - 删除用户(管理员)
  • userlock - 锁定用户(管理员)
  • userunlock - 解锁用户(管理员)

安全特性

  • 密码不回显
  • 登录尝试次数限制
  • 账户自动锁定
  • 权限掩码控制
  • 命令级权限检查

三、任务功能展示

下面是运行效果:

image.png

image.png

image.png

四、总结

本次活动通过与AI的多轮对话完成了任务目标,实现了一个基于串口的shell项目代码工程。总体来说还是很顺利的,核心代码都是AI给出,然后通过调试和与AI的提问进行优化和解决出现的所有问题。

最后感谢电子森林与得捷电子联合推出的Funpack系列活动,给了我们动手实验的机会。学习了更多的技能。


附件下载
NXP.FRDM-MCXA346_BSP.25.12.00.pack
keil安装包
NXP.MCXA346_DFP.25.12.00.pack
keil安装包
mcxa346_shell.zip
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号