当前位置: 首页 > news >正文

从0开始的操作系统手搓教程43——实现一个简单的shell

目录

添加 read 系统调用,获取键盘输入 :sys_read

putchar和clear

上班:实现一个简单的shell

测试上电


我们下面来实现一个简单的shell

添加 read 系统调用,获取键盘输入 :sys_read

/* Read count bytes from the file pointed to by file descriptor fd into buf,* return the number of bytes read on success, return -1 if end of file is* reached*/
int32_t sys_read(int32_t fd, void *buf, uint32_t count)
{KERNEL_ASSERT(buf);int32_t ret = -1;uint32_t global_fd = 0;if (fd < 0 || fd == stdout_no || fd == stderr_no){ccos_printk("sys_read: fd error\n");}else if (fd == stdin_no){char *buffer = buf;uint32_t bytes_read = 0;while (bytes_read < count){*buffer = ioq_getchar(&keyboard_ringbuffer);bytes_read++;buffer++;}ret = (bytes_read == 0 ? -1 : (int32_t)bytes_read);}else{global_fd = fd_local2global(fd);ret = file_read(&file_table[global_fd], buf, count);}return ret;
}

我们终于跟老朋友见面了。我们修订一下:sys_read,现在实现了读取文件的功能。它首先检查传入的 buf 指针是否有效。如果文件描述符 fd 无效(例如小于0或者是标准输出、标准错误),则会打印错误信息。如果文件描述符是标准输入(stdin_no),函数会从键盘输入的缓冲区 keyboard_ringbuffer 中读取字符,将其存入 buf 中,直到读取指定的字节数或达到文件末尾。函数会返回成功读取的字节数,如果没有读取到任何数据,返回 -1。如果文件描述符不是标准输入,函数会根据 fd 获取对应的文件,并调用 file_read 函数来执行实际的读取操作,并返回成功读取的字节数。如果文件读取失败,返回 -1

int32_t read(int32_t fd, void *buf, uint32_t count)
{return _syscall3(SYS_READ, fd, buf, count);
}

putchar和clear

这个把我们之前做的工作编程系统调用即可

/* Outputs a character */
void putchar(char char_asci) {_syscall1(SYS_PUTCHAR, char_asci);
}
/* Clears the screen */
void clear(void) {_syscall0(SYS_CLEAR);
}
​
void sys_putchar(char char_asci)
{console__ccos_putchar(char_asci);
}
​
​
/* Initialize the system call table */
void syscall_init(void) {verbose_ccputs("syscall_init start\n"); // Logging the start of syscall initialization/* Set the system call table entries for various system call numbers */syscall_table[SYS_GETPID] = sys_getpid; // Get process IDsyscall_table[SYS_WRITE] = sys_write;   // Write to consolesyscall_table[SYS_MALLOC] = sys_malloc; // Memory allocationsyscall_table[SYS_FREE] = sys_free;     // Free allocated memorysyscall_table[SYS_FORK] = sys_fork;     // Fork a new processsyscall_table[SYS_READ] = sys_read;syscall_table[SYS_PUTCHAR] = sys_putchar;syscall_table[SYS_CLEAR] = clean_screen;verbose_ccputs("syscall_init done\n"); // Logging the completion of syscall// initialization
}

上班:实现一个简单的shell

#include "include/user/ccshell/ccshell.h"
#include "include/defines.h"
#include "include/filesystem/file.h"
#include "include/library/string.h"
#include "include/library/types.h"
#include "include/syscall/syscall.h"
#include "include/user/stdio/stdio.h"
#include "include/filesystem/filesystem_settings.h"
#include "include/user/library/user_assertion.h"
#define CMD_LEN MAX_PATH_LEN
#define MAX_ARG_NR (16)
​
/* Stores the input command */
static char cmd_line[CMD_LEN] = {0};
​
/* Used to record the current directory; it is updated every time the cd command* is executed */
char cwd_cache[MAX_PATH_LEN] = {0};
​
/* Outputs the shell prompt */
void print_prompt(void)
{printf("[" HOST_NAME "@localhost %s]$ ", cwd_cache);
}
​
/* Reads up to 'count' bytes from the keyboard buffer into 'buf' */
static void readline(char *buf, int32_t count)
{user_assert(buf && count > 0);char *pos = buf;
​while (read(stdin_no, pos, 1) != -1 &&(pos - buf) < count){ // Read until enter key is foundswitch (*pos){/* If enter or newline is found, treat it as the end of the command*/case '\n':case '\r':*pos = 0; // Add null terminator to cmd_lineputchar('\n');return;
​case '\b':if (cmd_line[0] != '\b'){          // Prevent deleting non-inputted data--pos; // Move back to the previous character in the bufferputchar('\b');}break;
​/* For other characters, output normally */default:putchar(*pos);pos++;}}printf("readline: can't find enter_key in the cmd_line, max num of char is ""128\n");
}

先说说readline:这段代码实现了一个从键盘缓冲区读取用户输入的功能。函数readline的作用是从输入流中读取字符,直到遇到回车键(\n\r)为止,或者读取达到指定的字节数限制。读取的内容会存储到buf中。具体步骤如下:

  1. 函数首先检查传入的缓冲区指针buf是否有效,并确认count大于0。

  2. while循环会持续读取一个字符(通过read(stdin_no, pos, 1)),直到读取到回车键或达到指定的字符数量(count)。读取的字符会存储在buf中。

  3. 当遇到回车符(\n\r)时,表示用户输入完成,此时将当前位置字符设置为'\0',并输出换行符,表示命令输入结束。

  4. 如果遇到退格符(\b),程序会检查输入内容是否为空。如果不为空,指针会退回一个字符,删除命令行中的最后一个字符,并输出退格符。此功能允许用户删除输入的字符。

  5. 其他字符直接输出并追加到pos指向的位置,继续读取下一个字符。

  6. 如果没有在指定字符数内读取到回车键,则会输出错误提示,表明命令行输入超出了最大字符限制。

这个函数的设计使得用户可以在命令行中输入命令,且支持基本的退格功能,直到按下回车键为止。

ccshell是我们的核心:

void ccshell(void)
{cwd_cache[0] = '/';while (1){print_prompt();k_memset(cmd_line, 0, CMD_LEN);readline(cmd_line, CMD_LEN);if (cmd_line[0] == 0){continue;}}user_panic("Man!: you should not be here!!!");
}

这段代码实现了一个简单的命令行shell功能。函数ccshell定义了一个无限循环,其中每次循环都会显示提示符,等待用户输入命令。命令输入通过readline函数完成,读取用户输入并存储到cmd_line中。每次读取命令之前,cmd_line会被清空,确保新命令不会受到旧命令的影响。如果用户没有输入命令,程序会跳过本次循环。当用户输入命令时,如果命令不为空,程序会继续执行。虽然代码没有明确的退出机制,但如果程序异常执行到user_panic("Man!: you should not be here!!!"),说明发生了错误。

测试上电

#include "include/device/console_tty.h"
#include "include/kernel/init.h"
#include "include/library/kernel_assert.h"
#include "include/thread/thread.h"
#include "include/user/stdio/stdio.h"
#include "include/memory/memory.h"
#include "include/library/ccos_print.h"
#include "include/filesystem/filesystem.h"
#include "include/library/string.h"
#include "include/filesystem/dir.h"
#include "include/syscall/syscall.h"
#include "include/user/ccshell/ccshell.h"
void init(void);
​
int main(void)
{init_all();while(1);
}
​
// init process here
void init(void)
{uint32_t ret_pid = fork();if (ret_pid){while(1);}else{ccshell();}while (1);
}
​

注意多敲几下键盘,因为输出非常多。

下一篇

从0开始的操作系统手搓教程44——实现更好的shell-CSDN博客文章浏览阅读766次,点赞14次,收藏9次。在 Linux 系统中,快捷键如“Ctrl+u”和“Ctrl+l”是由操作系统提供的标准功能,但它们的实现方式并不是直接由键盘驱动程序(keyboard.c)来处理的。如果在键盘驱动程序中加入过多的逻辑处理,会导致系统的中断处理变得非常复杂,效率降低,进而影响整个系统的响应速度。的数据类型(从16位改为32位),因为一旦改动数据类型,后续代码可能会受到影响,造成所谓的“雪崩效应”,即需要改动很多地方的代码和解释。时,输入缓冲区中的字符会被清除,屏幕会被清空,然后打印命令提示符,再显示用户已输入的命令。 https://blog.csdn.net/charlie114514191/article/details/146144528

相关文章:

从0开始的操作系统手搓教程43——实现一个简单的shell

目录 添加 read 系统调用&#xff0c;获取键盘输入 :sys_read putchar和clear 上班&#xff1a;实现一个简单的shell 测试上电 我们下面来实现一个简单的shell 添加 read 系统调用&#xff0c;获取键盘输入 :sys_read /* Read count bytes from the file pointed to by fi…...

‌Visual Studio Code(VS Code)支持的编程语言

‌JavaScript‌&#xff1a;VS Code 原生支持 JavaScript&#xff0c;提供语法高亮、代码折叠、自动补全等功能。推荐使用ESLint和Prettier进行代码格式化和错误检查‌。 ‌TypeScript‌&#xff1a;作为 JavaScript 的超集&#xff0c;TypeScript 在 VS Code 中也得到原生支持…...

探索AI对冲基金:开源自动化交易系统的革新之路

在量化交易领域,人工智能技术的应用正悄然改变传统对冲基金的运作模式。GitHub上的开源项目ai-hedge-fund为开发者和金融从业者提供了一个独特的实践平台。该项目通过多智能体系统架构,整合市场数据分析、量化策略生成、风险管理和投资组合优化等核心功能,实现了从数据采集到…...

C语言每日一练——day_3(快速上手C语言)

引言 针对初学者&#xff0c;每日练习几个题&#xff0c;快速上手C语言。第三天。&#xff08;会连续更新&#xff09; 采用在线OJ的形式 什么是在线OJ&#xff1f; 在线判题系统&#xff08;英语&#xff1a;Online Judge&#xff0c;缩写OJ&#xff09;是一种在编程竞赛中用…...

vue3中接收props的两种写法

在 Vue 3 中&#xff0c;接收 props 有两种主要的写法&#xff0c;分别是运行时声明和基于类型的声明。下面为你详细介绍这两种写法。 1. 运行时声明 运行时声明是 Vue 2 中就已经存在的方式&#xff0c;在 Vue 3 中依然可以使用。这种方式通过在组件中使用 defineProps 宏来…...

Django下防御Race Condition

目录 漏洞原因 环境搭建 复现 A.无锁无事务时的竞争攻击 B.无锁有事务时的竞争攻击 防御 A.悲观锁加事务防御 B.乐观锁加事务防御 总结 漏洞原因 Race Condition 发生在多个执行实体&#xff08;如线程、进程&#xff09;同时访问共享资源时&#xff0c;由于执行顺序…...

Vue 项目中,.env文件怎么用?

在 Vue 项目中&#xff0c;.env 文件用于存储环境变量&#xff0c;不同的环境&#xff08;如开发环境、测试环境、生产环境&#xff09;可以使用不同的 .env 文件来管理对应的配置信息。以下是关于 Vue 项目中 .env 文件的详细使用方法&#xff1a; 1. 项目创建 确保你已经使…...

LeetCode hot 100—爬楼梯

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例…...

【js逆向】

地址&#xff1a;aHR0cHM6Ly93d3cud2VpYm90b3AuY24vMi4wLw f12进入 debugger&#xff0c;过debugger 查看预览数据 全局搜索 请求网址中的 api.weibotop.cn 在下方疑似找到了加密和解密的函数 断点调试 控制台输出 那个n就是 常见的 cryptoJs库 const cryptoJs require(cry…...

论文阅读-秦汉时期北方边疆组织的空间互动模式与直道的定位(中国)

论文英文题目&#xff1a;A spatial interaction model of Qin-Han Dynasty organisation on the northern frontier and the location of the Zhidao highway (China) 发表于&#xff1a;journal of archaeological science&#xff0c;影响因子&#xff1a;3.030 论文主要是…...

DirectX12(D3D12)基础教程四 入门指南

本章主要讲了些D3D12概念和理论&#xff0c;对第一、二章相关概念的补充和纠正&#xff0c;要的理解D3D12概念和理论基础&#xff0c;结合代码加深理解。 命令队列和命令列表 为了实现渲染工作的重用和多线程缩放&#xff0c; 在 D3D12 中&#xff0c;做了三个重要方面不同于 …...

C语言:确定进制

题目&#xff1a; 6942对于十进制来说是错误的&#xff0c;但是对于13进制来说是正确的。即, 6(13) 9(13) 42(13)&#xff0c; 而 42(13)4131213054(10)。 任务是写一段程序&#xff0c;读入三个整数p、q和 r&#xff0c;然后确定一个进制 B(2<B<40) 使得 p q r。 如果…...

如何在 Windows 10 启用卓越性能模式及不同电源计划对比

在使用 powercfg -duplicatescheme 命令启用 “卓越性能模式”&#xff08;即 Ultimate Performance 模式&#xff09;之前&#xff0c;有几个前提条件需要注意&#xff1a; 前提条件&#xff1a; 系统版本要求&#xff1a;卓越性能模式 仅在 Windows 10 专业版 或更高版本&a…...

Unity Android出包

Unity Android出包 1.Android Studio版本 不能高于Unity的版本 2.so库 这个库需要自己拷贝到Android工程当中 3.JDK版本太老 编译可以正常&#xff0c;但无法运行 File->ProjectStructure->SDK Location->Gradle Setting->Gradle JDK->X:/Android Stuido/jre …...

Day04 模拟原生开发app过程 Androidstudio+逍遥模拟器

1、用Androidstudio打开已经写好了的music项目 2、逍遥模拟器打开apk后缀文件 3、在源文件搜索关键字 以后的测试中做资产收集...

2025人工智能AI新突破:PINN内嵌物理神经网络火了

最近在淘金的时候发现基于物理信息的神经网络&#xff08;简称PINN&#xff09;也是个研究热点&#xff0c;遂研读了几篇经典论文&#xff0c;深觉这也是个好发论文的方向&#xff0c;所以火速整理了一些个人认为很值得一读的PINN论文和同学们分享。 为了方面同学们更好地理解…...

通义万相 2.1 携手蓝耘云平台:开启影视广告创意新纪元

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【计算机网络】深入解析 HTTP 请求中的 header 类型:Cookie 的概念、特点和应用场景:登录和用户认证

网络原理— HTTP 请求“报头”(header) Cookie 是什么 HTTP报头中的Cookie&#xff0c;用大白话来说&#xff0c;就像你去餐厅吃饭时拿到的一张会员卡&#xff1a; 初次访问 (清除该网站的所有 Cookie 后重新访问该网站&#xff0c;效果相同)&#xff1a; 当你第一次访问一个网…...

LeetCode 解题思路 11(Hot 100)

解题思路&#xff1a; 若相等&#xff1a; 直接返回 true。若当前元素大于目标值&#xff1a; 由于列递增&#xff0c;当前列下方所有元素均大于目标值&#xff0c;故排除该列&#xff08;向左移动&#xff09;。若当前元素小于目标值&#xff1a; 由于行递增&#xff0c;当前…...

警惕AI神话破灭:深度解析大模型缺陷与禁用场景指南

摘要 当前AI大模型虽展现强大能力&#xff0c;但其本质缺陷可能引发系统性风险。本文从认知鸿沟、数据困境、伦理雷区、技术瓶颈四大维度剖析大模型局限性&#xff0c;揭示医疗诊断、法律决策等8类禁用场景&#xff0c;提出可信AI建设框架与用户防护策略。通过理论分析与实操案…...

文件系统调用(上) ─── linux第17课

目录 linux 中man 2和man 3的区别 文件内容介绍 C语言文件接口 示例: 输出信息到显示器&#xff0c;你有哪些方法 总结: 系统文件I/O 文件类的系统调用接口介绍 示例 open 函数具体使用哪个,和具体应用场景相关&#xff0c; write read close lseek ,类比C文件相关接…...

go 标准库包学习笔记

本博文包含了go的math&#xff0c;net/http&#xff0c;fmt,io,csv&#xff0c;time.Time,strconv,strings,sync.Pool的学习,笔记多是其实战如何用&#xff0c;而非简单的函数式的讲解&#xff0c;可谓是收藏佳作&#xff0c;不时翻翻。 文章目录 1、math2、net/http3、fmt4、…...

Unity摄像机跟随物体

功能描述 实现摄像机跟随物体&#xff0c;并使物体始终保持在画面中心位置。 实现步骤 创建脚本&#xff1a;在Unity中创建一个新的C#脚本&#xff0c;命名为CameraFollow。 代码如下&#xff1a; using UnityEngine;public class CameraFollow : MonoBehaviour {public Tran…...

线程管理操作

1.创建两个线程&#xff0c;&#xff0c;分支线程1拷贝文件的前一部分&#xff0c;分支线程2拷贝文件的后一部分 #include <head.h>#define SRC_FILE "./1.txt" #define DST_FILE "./2.txt" #define BUFFER_SIZE 4096struct copy_args {long start;l…...

VSCode 2025最新前端开发必备插件推荐汇总(提效指南)

&#x1f31f;前言: 如果你是一名前端开发工程师&#xff0c;合适的开发工具能大大提高工作效率。Visual Studio Code (VSCode) 凭借其轻量级、高扩展性的特点&#xff0c;已成为众多前端开发者在win系电脑的首选IDE。 名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。—…...

docker不停机部署

背景 最近做大疆项目时&#xff0c;后台更新部署时&#xff0c;机场和无人机就会掉线。设备自动重连注册时间比较长&#xff0c;应用长时间不可用。所以需要灰色发布服务。docker-compose的swarm模式可解决此问题。 服务构建脚本Dockerfile # 使用官方Java基础镜像&#xff…...

鸿蒙应用开发—数据持久化之SQLite

文章目录 SQLite简介创建数据库添加数据查询数据更新数据删除数据升级数据库使用事务参考 SQLite简介 SQLite是一个轻量级关系数据库&#xff0c;占用资源很少&#xff0c;只有几百KB的大小&#xff0c;无需服务器支撑&#xff0c;是一个零配置、事务性的SQL数据库引擎。 相对…...

JSON对象处理工具类

目录 1. 工具类的功能设计 2. 工具类的实现 依赖配置 工具类代码 3. 工具类的使用示例 示例1&#xff1a;美化JSON打印 示例2&#xff1a;从JSON中提取数据 示例3&#xff1a;修改JSON数据 示例4&#xff1a;合并JSON对象 4. 总结 在现代软件开发中&#xff0c;JSON&…...

通义万相 2.1 + 蓝耘算力,AI 视频生成的梦幻组合

在这个科技日新月异的时代&#xff0c;人工智能不断刷新着我们对世界的认知。一次偶然的机会&#xff0c;我借助北京蓝耘科技股份有限公司提供的算力支持&#xff0c;踏上了使用通义万相 2.1 进行 AI 视频生成的奇妙之旅。 目录 1.1初遇蓝耘科技&#xff1a; 1.2通义万相 2.1…...

汽车一键启动按钮更换注意事项

汽车一键启动开关更换教程 一键启动开关是现代汽车中常见的便捷配置&#xff0c;但随着时间的推移&#xff0c;这个部件可能会出现失灵的情况。当一键启动开关发生故障时&#xff0c;许多车主选择自行更换。以下是整理的一键启动开关更换教程&#xff1a; 更换前的准备 选择匹…...