Files
rust-based-os-comp2022/chapter7/2cmdargs-and-redirection.html
2022-06-30 04:46:48 +00:00

704 lines
96 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html class="no-js" lang="zh_CN">
<head><meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="索引" href="../genindex.html" /><link rel="search" title="搜索" href="../search.html" /><link rel="next" title="chapter7练习" href="3exercise.html" /><link rel="prev" title="管道" href="1pipe.html" />
<meta name="generator" content="sphinx-4.1.2, furo 2021.08.31"/>
<title>命令行参数与标准 I/O 重定向 - Open-Source-OS-Training-Camp-2022 文档</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo.css?digest=c7c65a82b42f6b978e58466c1e9ef2509836d916" />
<link rel="stylesheet" type="text/css" href="../_static/tabs.css" />
<link rel="stylesheet" type="text/css" href="../_static/styles/furo-extensions.css?digest=16fb25fabf47304eee183a5e9af80b1ba98259b1" />
<link rel="stylesheet" type="text/css" href="../_static/my_style.css" />
<style>
body {
--color-code-background: #f8f8f8;
--color-code-foreground: black;
}
body[data-theme="dark"] {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
}
</style></head>
<body>
<script>
document.body.dataset.theme = localStorage.getItem("theme") || "auto";
</script>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-toc" viewBox="0 0 24 24">
<title>Contents</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" />
<line x1="4" y1="6" x2="20" y2="6" />
<line x1="10" y1="12" x2="20" y2="12" />
<line x1="6" y1="18" x2="20" y2="18" />
</svg>
</symbol>
<symbol id="svg-menu" viewBox="0 0 24 24">
<title>Menu</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</symbol>
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
<title>Expand</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24">
<title>Light mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24">
<title>Dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</symbol>
<symbol id="svg-sun-half" viewBox="0 0 24 24">
<title>Auto light/dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<circle cx="12" cy="12" r="9" />
<path d="M13 12h5" />
<path d="M13 15h4" />
<path d="M13 18h1" />
<path d="M13 9h4" />
<path d="M13 6h1" />
</svg>
</symbol>
</svg>
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
<label class="overlay sidebar-overlay" for="__navigation">
<div class="visually-hidden">Hide navigation sidebar</div>
</label>
<label class="overlay toc-overlay" for="__toc">
<div class="visually-hidden">Hide table of contents sidebar</div>
</label>
<div class="page">
<header class="mobile-header">
<div class="header-left">
<label class="nav-overlay-icon" for="__navigation">
<div class="visually-hidden">Toggle site navigation sidebar</div>
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
</label>
</div>
<div class="header-center">
<a href="../index.html"><div class="brand">Open-Source-OS-Training-Camp-2022 文档</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-header-icon" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
</header>
<aside class="sidebar-drawer">
<div class="sidebar-container">
<div class="sidebar-sticky"><a class="sidebar-brand" href="../index.html">
<span class="sidebar-brand-text">Open-Source-OS-Training-Camp-2022 文档</span>
</a><form class="sidebar-search-container" method="get" action="../search.html" role="search">
<input class="sidebar-search" placeholder=搜索 name="q" aria-label="搜索">
<input type="hidden" name="check_keywords" value="yes">
<input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
<p class="caption" role="heading"><span class="caption-text">正文</span></p>
<ul class="current">
<li class="toctree-l1 has-children"><a class="reference internal" href="../0setup-devel-env.html">第零章:实验环境配置</a><input class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" role="switch" type="checkbox"/><label for="toctree-checkbox-1"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter1/index.html">第一章:应用程序与基本执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" role="switch" type="checkbox"/><label for="toctree-checkbox-2"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter1/0intro.html">引言</a></li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/1app-ee-platform.html">应用程序执行环境与平台支持</a><input class="toctree-checkbox" id="toctree-checkbox-3" name="toctree-checkbox-3" role="switch" type="checkbox"/><label for="toctree-checkbox-3"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/2remove-std.html">移除标准库依赖</a><input class="toctree-checkbox" id="toctree-checkbox-4" name="toctree-checkbox-4" role="switch" type="checkbox"/><label for="toctree-checkbox-4"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/3mini-rt-usrland.html">构建用户态执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-5" name="toctree-checkbox-5" role="switch" type="checkbox"/><label for="toctree-checkbox-5"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter1/4mini-rt-baremetal.html">构建裸机执行环境</a><input class="toctree-checkbox" id="toctree-checkbox-6" name="toctree-checkbox-6" role="switch" type="checkbox"/><label for="toctree-checkbox-6"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a><input class="toctree-checkbox" id="toctree-checkbox-7" name="toctree-checkbox-7" role="switch" type="checkbox"/><label for="toctree-checkbox-7"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter2/0intro.html">引言</a></li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/2application.html">实现应用程序</a><input class="toctree-checkbox" id="toctree-checkbox-8" name="toctree-checkbox-8" role="switch" type="checkbox"/><label for="toctree-checkbox-8"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/3batch-system.html">实现批处理操作系统</a><input class="toctree-checkbox" id="toctree-checkbox-9" name="toctree-checkbox-9" role="switch" type="checkbox"/><label for="toctree-checkbox-9"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../chapter2/4trap-handling.html">实现特权级的切换</a><input class="toctree-checkbox" id="toctree-checkbox-10" name="toctree-checkbox-10" role="switch" type="checkbox"/><label for="toctree-checkbox-10"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a><input class="toctree-checkbox" id="toctree-checkbox-11" name="toctree-checkbox-11" role="switch" type="checkbox"/><label for="toctree-checkbox-11"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/1multi-loader.html">多道程序放置与加载</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/2task-switching.html">任务切换</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/3multiprogramming.html">管理多道程序</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/4time-sharing-system.html">分时多任务系统</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter3/5exercise.html">chapter3练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter4/index.html">第四章:地址空间</a><input class="toctree-checkbox" id="toctree-checkbox-12" name="toctree-checkbox-12" role="switch" type="checkbox"/><label for="toctree-checkbox-12"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/3sv39-implementation-1.html">实现 SV39 多级页表机制(上)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/4sv39-implementation-2.html">实现 SV39 多级页表机制(下)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/5kernel-app-spaces.html">内核与应用的地址空间</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/6multitasking-based-on-as.html">基于地址空间的分时多任务</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter4/7exercise.html">chapter4练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter5/index.html">第五章:进程及进程管理</a><input class="toctree-checkbox" id="toctree-checkbox-13" name="toctree-checkbox-13" role="switch" type="checkbox"/><label for="toctree-checkbox-13"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter5/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter5/1process.html">与进程有关的重要系统调用</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter5/2core-data-structures.html">进程管理的核心数据结构</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter5/3implement-process-mechanism.html">进程管理机制的设计实现</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter5/4exercise.html">chapter5练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter6/index.html">第六章文件系统与I/O重定向</a><input class="toctree-checkbox" id="toctree-checkbox-14" name="toctree-checkbox-14" role="switch" type="checkbox"/><label for="toctree-checkbox-14"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/1file-descriptor.html">文件与文件描述符</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/1fs-interface.html">文件系统接口</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/2fs-implementation-1.html">简易文件系统 easy-fs (上)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/2fs-implementation-2.html">简易文件系统 easy-fs (下)</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/3using-easy-fs-in-kernel.html">在内核中使用 easy-fs</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter6/4exercise.html">chapter6练习</a></li>
</ul>
</li>
<li class="toctree-l1 current has-children"><a class="reference internal" href="index.html">第七章:进程间通信</a><input checked="" class="toctree-checkbox" id="toctree-checkbox-15" name="toctree-checkbox-15" role="switch" type="checkbox"/><label for="toctree-checkbox-15"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="1pipe.html">管道</a></li>
<li class="toctree-l2 current current-page"><a class="current reference internal" href="#">命令行参数与标准 I/O 重定向</a></li>
<li class="toctree-l2"><a class="reference internal" href="3exercise.html">chapter7练习</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../chapter8/index.html">第八章:并发</a><input class="toctree-checkbox" id="toctree-checkbox-16" name="toctree-checkbox-16" role="switch" type="checkbox"/><label for="toctree-checkbox-16"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/0intro.html">引言</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/1thread-kernel.html">内核态的线程管理</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/2lock.html">锁机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/3semaphore.html">信号量机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/4condition-variable.html">条件变量机制</a></li>
<li class="toctree-l2"><a class="reference internal" href="../chapter8/5exercise.html">chapter8 练习</a></li>
</ul>
</li>
</ul>
<p class="caption" role="heading"><span class="caption-text">附录</span></p>
<ul>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-a/index.html">附录 ARust 系统编程资料</a><input class="toctree-checkbox" id="toctree-checkbox-17" name="toctree-checkbox-17" role="switch" type="checkbox"/><label for="toctree-checkbox-17"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-b/index.html">附录 B常见工具的使用方法</a><input class="toctree-checkbox" id="toctree-checkbox-18" name="toctree-checkbox-18" role="switch" type="checkbox"/><label for="toctree-checkbox-18"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../appendix-c/index.html">附录 C深入机器模式RustSBI</a><input class="toctree-checkbox" id="toctree-checkbox-19" name="toctree-checkbox-19" role="switch" type="checkbox"/><label for="toctree-checkbox-19"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../appendix-d/index.html">附录 DRISC-V相关信息</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">开发注记</span></p>
<ul>
<li class="toctree-l1 has-children"><a class="reference internal" href="../setup-sphinx.html">修改和构建本项目</a><input class="toctree-checkbox" id="toctree-checkbox-20" name="toctree-checkbox-20" role="switch" type="checkbox"/><label for="toctree-checkbox-20"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../rest-example.html">reStructuredText 基本语法</a><input class="toctree-checkbox" id="toctree-checkbox-21" name="toctree-checkbox-21" role="switch" type="checkbox"/><label for="toctree-checkbox-21"><div class="visually-hidden">Toggle child pages in navigation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul class="simple">
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
</aside>
<div class="main">
<div class="content">
<article role="main">
<div class="content-icon-container">
<div class="theme-toggle-container theme-toggle-content">
<button class="theme-toggle">
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-content-icon" for="__toc">
<div class="visually-hidden">Toggle table of contents sidebar</div>
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
</label>
</div>
<div class="section" id="i-o">
<h1>命令行参数与标准 I/O 重定向<a class="headerlink" href="#i-o" title="永久链接至标题"></a></h1>
<div class="section" id="id1">
<h2>命令行参数<a class="headerlink" href="#id1" title="永久链接至标题"></a></h2>
<p>使用 C 语言开发 Linux 应用时,可以使用标准库提供的 <code class="docutils literal notranslate"><span class="pre">argc/argv</span></code> 来获取命令行参数我们希望在我们自己的内核和shell程序上支持这个功能。为了支持命令行参数 <code class="docutils literal notranslate"><span class="pre">sys_exec</span></code> 的系统调用接口需要发生变化:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/syscall.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_exec</span><span class="p">(</span><span class="n">path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">args</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span>-&gt; <span class="kt">isize</span><span class="p">;</span><span class="w"></span>
</pre></div>
</div>
<p>可以看到,它的参数多出了一个 <code class="docutils literal notranslate"><span class="pre">args</span></code> 数组,数组中的每个元素都是命令行参数字符串的起始地址。实际传递给内核的实际上是这个数组的起始地址:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/syscall.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_exec</span><span class="p">(</span><span class="n">path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">args</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">syscall</span><span class="p">(</span><span class="n">SYSCALL_EXEC</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">path</span><span class="p">.</span><span class="n">as_ptr</span><span class="p">()</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">args</span><span class="p">.</span><span class="n">as_ptr</span><span class="p">()</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">])</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// user/src/lib.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">exec</span><span class="p">(</span><span class="n">path</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">args</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"> </span><span class="n">sys_exec</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<div class="section" id="shell">
<h3>shell程序的命令行参数分割<a class="headerlink" href="#shell" title="永久链接至标题"></a></h3>
<p>回忆一下在shell程序 <code class="docutils literal notranslate"><span class="pre">user_shell</span></code> 中,一旦接收到一个回车,我们就会将当前行的内容 <code class="docutils literal notranslate"><span class="pre">line</span></code> 作为一个名字并试图去执行同名的应用。但是现在 <code class="docutils literal notranslate"><span class="pre">line</span></code> 还可能包含一些命令行参数,只有最开头的一个才是要执行的应用名。因此我们要做的第一件事情就是将 <code class="docutils literal notranslate"><span class="pre">line</span></code> 用空格分割:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/bin/ch6b_user_shell.rs</span>
<span class="kd">let</span><span class="w"> </span><span class="n">args</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">line</span><span class="p">.</span><span class="n">as_str</span><span class="p">().</span><span class="n">split</span><span class="p">(</span><span class="sc">' '</span><span class="p">).</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">args_copy</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args</span><span class="w"></span>
<span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">arg</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">string</span><span class="p">.</span><span class="n">push_str</span><span class="p">(</span><span class="n">arg</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">string</span><span class="w"></span>
<span class="p">})</span><span class="w"></span>
<span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
<span class="n">args_copy</span><span class="w"></span>
<span class="p">.</span><span class="n">iter_mut</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">for_each</span><span class="p">(</span><span class="o">|</span><span class="n">string</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">string</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="sc">'\0'</span><span class="p">);</span><span class="w"></span>
<span class="p">});</span><span class="w"></span>
</pre></div>
</div>
<p>经过分割, <code class="docutils literal notranslate"><span class="pre">args</span></code> 中的 <code class="docutils literal notranslate"><span class="pre">&amp;str</span></code> 都是 <code class="docutils literal notranslate"><span class="pre">line</span></code> 中的一段子区间,它们的结尾并没有包含 <code class="docutils literal notranslate"><span class="pre">\0</span></code> ,因为 <code class="docutils literal notranslate"><span class="pre">line</span></code> 是我们输入得到的,中间本来就没有 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 。由于在向内核传入字符串的时候,我们只能传入字符串的起始地址,因此我们必须保证其结尾为 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 。从而我们用 <code class="docutils literal notranslate"><span class="pre">args_copy</span></code><code class="docutils literal notranslate"><span class="pre">args</span></code> 中的字符串拷贝一份到堆上并在末尾手动加入 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 。这样就可以安心的将 <code class="docutils literal notranslate"><span class="pre">args_copy</span></code> 中的字符串传入内核了。我们用 <code class="docutils literal notranslate"><span class="pre">args_addr</span></code> 来收集这些字符串的起始地址:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/bin/ch6b_user_shell.rs</span>
<span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">args_addr</span>: <span class="nb">Vec</span><span class="o">&lt;*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_copy</span><span class="w"></span>
<span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">arg</span><span class="o">|</span><span class="w"> </span><span class="n">arg</span><span class="p">.</span><span class="n">as_ptr</span><span class="p">())</span><span class="w"></span>
<span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
<span class="n">args_addr</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="mi">0</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
<p>向量 <code class="docutils literal notranslate"><span class="pre">args_addr</span></code> 中的每个元素都代表一个命令行参数字符串的起始地址。为了让内核能够获取到命令行参数的个数,我们在 <code class="docutils literal notranslate"><span class="pre">args_addr</span></code> 的末尾放入一个 0 ,这样内核看到它时就能知道命令行参数已经获取完毕了。</p>
<p><code class="docutils literal notranslate"><span class="pre">fork</span></code> 出来的子进程中,我们调用 <code class="docutils literal notranslate"><span class="pre">exec</span></code> 传入命令行参数。</p>
</div>
<div class="section" id="sys-exec">
<h3>sys_exec 将命令行参数压入用户栈<a class="headerlink" href="#sys-exec" title="永久链接至标题"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">sys_exec</span></code> 中,首先需要将应用传进来的命令行参数取出来:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/syscall/process.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_exec</span><span class="p">(</span><span class="n">path</span>: <span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">args</span>: <span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_user_token</span><span class="p">();</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">translated_str</span><span class="p">(</span><span class="n">token</span><span class="p">,</span><span class="w"> </span><span class="n">path</span><span class="p">);</span><span class="w"></span>
<span class="hll"><span class="linenos"> 6</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">args_vec</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos"> 7</span><span class="w"> </span><span class="k">loop</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos"> 8</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">arg_str_ptr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="n">translated_ref</span><span class="p">(</span><span class="n">token</span><span class="p">,</span><span class="w"> </span><span class="n">args</span><span class="p">);</span><span class="w"></span>
</span><span class="hll"><span class="linenos"> 9</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">arg_str_ptr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">10</span><span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">11</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="hll"><span class="linenos">12</span><span class="w"> </span><span class="n">args_vec</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">translated_str</span><span class="p">(</span><span class="n">token</span><span class="p">,</span><span class="w"> </span><span class="n">arg_str_ptr</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">));</span><span class="w"></span>
</span><span class="hll"><span class="linenos">13</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">args</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="hll"><span class="linenos">14</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="linenos">15</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">app_inode</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">open_file</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">as_str</span><span class="p">(),</span><span class="w"> </span><span class="n">OpenFlags</span>::<span class="n">RDONLY</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">all_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">app_inode</span><span class="p">.</span><span class="n">read_all</span><span class="p">();</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_task</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="linenos">18</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">argc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_vec</span><span class="p">.</span><span class="n">len</span><span class="p">();</span><span class="w"></span>
<span class="hll"><span class="linenos">19</span><span class="w"> </span><span class="n">task</span><span class="p">.</span><span class="n">exec</span><span class="p">(</span><span class="n">all_data</span><span class="p">.</span><span class="n">as_slice</span><span class="p">(),</span><span class="w"> </span><span class="n">args_vec</span><span class="p">);</span><span class="w"></span>
</span><span class="linenos">20</span><span class="w"> </span><span class="c1">// return argc because cx.x[10] will be covered with it later</span>
<span class="linenos">21</span><span class="w"> </span><span class="n">argc</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">isize</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">25</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>每次我们都可以从一个起始地址通过 <code class="docutils literal notranslate"><span class="pre">translated_str</span></code> 拿到一个字符串,直到 <code class="docutils literal notranslate"><span class="pre">args</span></code> 为 0 就说明没有更多命令行参数了。在第 19 行调用 <code class="docutils literal notranslate"><span class="pre">TaskControlBlock::exec</span></code> 的时候,我们需要将获取到的 <code class="docutils literal notranslate"><span class="pre">args_vec</span></code> 传入进去并将里面的字符串压入到用户栈上。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// os/src/task/task.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="k">impl</span><span class="w"> </span><span class="n">TaskControlBlock</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 4</span><span class="w"> </span><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">exec</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">elf_data</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="kt">u8</span><span class="p">],</span><span class="w"> </span><span class="n">args</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="c1">// memory_set with elf program headers/trampoline/trap context/user stack</span>
<span class="linenos"> 6</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">memory_set</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"> </span><span class="n">entry_point</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MemorySet</span>::<span class="n">from_elf</span><span class="p">(</span><span class="n">elf_data</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">VirtAddr</span>::<span class="n">from</span><span class="p">(</span><span class="n">TRAP_CONTEXT</span><span class="p">).</span><span class="n">into</span><span class="p">())</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="p">.</span><span class="n">unwrap</span><span class="p">()</span><span class="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="p">.</span><span class="n">ppn</span><span class="p">();</span><span class="w"></span>
<span class="hll"><span class="linenos">11</span><span class="w"> </span><span class="c1">// push arguments on user stack</span>
</span><span class="hll"><span class="linenos">12</span><span class="w"> </span><span class="n">user_sp</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">core</span>::<span class="n">mem</span>::<span class="n">size_of</span>::<span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos">13</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">argv_base</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_sp</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">14</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">argv</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="o">..=</span><span class="n">args</span><span class="p">.</span><span class="n">len</span><span class="p">())</span><span class="w"></span>
</span><span class="hll"><span class="linenos">15</span><span class="w"> </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">arg</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">16</span><span class="w"> </span><span class="n">translated_refmut</span><span class="p">(</span><span class="w"></span>
</span><span class="hll"><span class="linenos">17</span><span class="w"> </span><span class="n">memory_set</span><span class="p">.</span><span class="n">token</span><span class="p">(),</span><span class="w"></span>
</span><span class="hll"><span class="linenos">18</span><span class="w"> </span><span class="p">(</span><span class="n">argv_base</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">arg</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">core</span>::<span class="n">mem</span>::<span class="n">size_of</span>::<span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">())</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="kt">usize</span><span class="w"></span>
</span><span class="hll"><span class="linenos">19</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
</span><span class="hll"><span class="linenos">20</span><span class="w"> </span><span class="p">})</span><span class="w"></span>
</span><span class="hll"><span class="linenos">21</span><span class="w"> </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos">22</span><span class="w"> </span><span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="n">args</span><span class="p">.</span><span class="n">len</span><span class="p">()]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">23</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">args</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">24</span><span class="w"> </span><span class="n">user_sp</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">args</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">25</span><span class="w"> </span><span class="o">*</span><span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_sp</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">26</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">user_sp</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">27</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">args</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">as_bytes</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">28</span><span class="w"> </span><span class="o">*</span><span class="n">translated_refmut</span><span class="p">(</span><span class="n">memory_set</span><span class="p">.</span><span class="n">token</span><span class="p">(),</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="kt">u8</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="n">c</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">29</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">30</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="hll"><span class="linenos">31</span><span class="w"> </span><span class="o">*</span><span class="n">translated_refmut</span><span class="p">(</span><span class="n">memory_set</span><span class="p">.</span><span class="n">token</span><span class="p">(),</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="kt">u8</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
</span><span class="hll"><span class="linenos">32</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="hll"><span class="linenos">33</span><span class="w"> </span><span class="c1">// make the user_sp aligned to 8B</span>
</span><span class="hll"><span class="linenos">34</span><span class="w"> </span><span class="n">user_sp</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">user_sp</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">core</span>::<span class="n">mem</span>::<span class="n">size_of</span>::<span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">();</span><span class="w"></span>
</span><span class="linenos">35</span>
<span class="linenos">36</span><span class="w"> </span><span class="c1">// **** access current TCB exclusively</span>
<span class="linenos">37</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">inner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">inner_exclusive_access</span><span class="p">();</span><span class="w"></span>
<span class="linenos">38</span><span class="w"> </span><span class="c1">// substitute memory_set</span>
<span class="linenos">39</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">memory_set</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">memory_set</span><span class="p">;</span><span class="w"></span>
<span class="linenos">40</span><span class="w"> </span><span class="c1">// update trap_cx ppn</span>
<span class="linenos">41</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">trap_cx_ppn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">trap_cx_ppn</span><span class="p">;</span><span class="w"></span>
<span class="linenos">42</span><span class="w"> </span><span class="c1">// initialize trap_cx</span>
<span class="linenos">43</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">trap_cx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">TrapContext</span>::<span class="n">app_init_context</span><span class="p">(</span><span class="w"></span>
<span class="linenos">44</span><span class="w"> </span><span class="n">entry_point</span><span class="p">,</span><span class="w"></span>
<span class="hll"><span class="linenos">45</span><span class="w"> </span><span class="n">user_sp</span><span class="p">,</span><span class="w"></span>
</span><span class="linenos">46</span><span class="w"> </span><span class="n">KERNEL_SPACE</span><span class="p">.</span><span class="n">exclusive_access</span><span class="p">().</span><span class="n">token</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">47</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">kernel_stack</span><span class="p">.</span><span class="n">get_top</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">48</span><span class="w"> </span><span class="n">trap_handler</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"></span>
<span class="linenos">49</span><span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="hll"><span class="linenos">50</span><span class="w"> </span><span class="n">trap_cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args</span><span class="p">.</span><span class="n">len</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos">51</span><span class="w"> </span><span class="n">trap_cx</span><span class="p">.</span><span class="n">x</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">argv_base</span><span class="p">;</span><span class="w"></span>
</span><span class="linenos">52</span><span class="w"> </span><span class="o">*</span><span class="n">inner</span><span class="p">.</span><span class="n">get_trap_cx</span><span class="p">()</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">trap_cx</span><span class="p">;</span><span class="w"></span>
<span class="linenos">53</span><span class="w"> </span><span class="c1">// **** release current PCB</span>
<span class="linenos">54</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">55</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>第 11-34 行所做的主要工作是将命令行参数以某种格式压入用户栈。具体的格式可以参考下图(比如应用传入了两个命令行参数 <code class="docutils literal notranslate"><span class="pre">aa</span></code><code class="docutils literal notranslate"><span class="pre">bb</span></code> </p>
<img alt="../_images/user-stack-cmdargs.png" class="align-center" src="../_images/user-stack-cmdargs.png"/>
<ul class="simple">
<li><p>首先需要在用户栈上分配一个字符串指针数组,也就是蓝色区域。数组中的每个元素都指向一个用户栈更低处的命令行参数字符串的起始地址。在第 12~24 行可以看到,最开始我们只是分配空间,具体的值要等到字符串被放到用户栈上之后才能确定更新。</p></li>
<li><p>第 23~32 行,我们逐个将传入的 <code class="docutils literal notranslate"><span class="pre">args</span></code> 中的字符串压入到用户栈中,对应于图中的橙色区域。为了实现方便,我们在用户栈上预留空间之后逐字节进行复制。注意 <code class="docutils literal notranslate"><span class="pre">args</span></code> 中的字符串是通过 <code class="docutils literal notranslate"><span class="pre">translated_str</span></code> 从应用地址空间取出的,它的末尾不包含 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 。为了应用能知道每个字符串的长度,我们需要手动在末尾加入 <code class="docutils literal notranslate"><span class="pre">\0</span></code></p></li>
<li><p>第 34 行将 <code class="docutils literal notranslate"><span class="pre">user_sp</span></code> 以 8 字节对齐,在 Qemu 平台上其实可以忽略这一步。</p></li>
</ul>
<p>我们还需要对应修改 Trap 上下文。首先是第 45 行,我们的 <code class="docutils literal notranslate"><span class="pre">user_sp</span></code> 相比之前已经发生了变化,它上面已经压入了命令行参数。同时,我们还需要修改 Trap 上下文中的 <code class="docutils literal notranslate"><span class="pre">a0/a1</span></code> 寄存器,让 <code class="docutils literal notranslate"><span class="pre">a0</span></code> 表示命令行参数的个数,而 <code class="docutils literal notranslate"><span class="pre">a1</span></code> 则表示图中 <code class="docutils literal notranslate"><span class="pre">argv_base</span></code> 即蓝色区域的起始地址。这两个参数在第一次进入对应应用的用户态的时候会被接收并用于还原命令行参数。</p>
</div>
<div class="section" id="id2">
<h3>用户库从用户栈上还原命令行参数<a class="headerlink" href="#id2" title="永久链接至标题"></a></h3>
<p>在应用第一次进入用户态的时候,我们放在 Trap 上下文 a0/a1 两个寄存器中的内容可以被用户库中的入口函数以参数的形式接收:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// user/src/lib.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="linenos"> 4</span><span class="cp">#[link_section = </span><span class="s">".text.entry"</span><span class="cp">]</span><span class="w"></span>
<span class="linenos"> 5</span><span class="k">pub</span><span class="w"> </span><span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="k">fn</span> <span class="nf">_start</span><span class="p">(</span><span class="n">argc</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">argv</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 6</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// 初始化堆分配器</span>
<span class="linenos"> 7</span><span class="w"> </span><span class="n">HEAP</span><span class="p">.</span><span class="n">lock</span><span class="p">()</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">HEAP_SPACE</span><span class="p">.</span><span class="n">as_ptr</span><span class="p">()</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">USER_HEAP_SIZE</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="hll"><span class="linenos">10</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">v</span>: <span class="nb">Vec</span><span class="o">&lt;&amp;'</span><span class="nb">static</span><span class="w"> </span><span class="kt">str</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos">11</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="n">argc</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">12</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">str_start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">13</span><span class="w"> </span><span class="p">((</span><span class="n">argv</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">core</span>::<span class="n">mem</span>::<span class="n">size_of</span>::<span class="o">&lt;</span><span class="kt">usize</span><span class="o">&gt;</span><span class="p">())</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">usize</span><span class="p">).</span><span class="n">read_volatile</span><span class="p">()</span><span class="w"></span>
</span><span class="hll"><span class="linenos">14</span><span class="w"> </span><span class="p">};</span><span class="w"></span>
</span><span class="hll"><span class="linenos">15</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="k">usize</span><span class="o">..</span><span class="p">).</span><span class="n">find</span><span class="p">(</span><span class="o">|</span><span class="n">i</span><span class="o">|</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">16</span><span class="w"> </span><span class="p">((</span><span class="n">str_start</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">*</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">).</span><span class="n">read_volatile</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
</span><span class="hll"><span class="linenos">17</span><span class="w"> </span><span class="p">}).</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
</span><span class="hll"><span class="linenos">18</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="w"></span>
</span><span class="hll"><span class="linenos">19</span><span class="w"> </span><span class="n">core</span>::<span class="kt">str</span>::<span class="n">from_utf8</span><span class="p">(</span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
</span><span class="hll"><span class="linenos">20</span><span class="w"> </span><span class="n">core</span>::<span class="n">slice</span>::<span class="n">from_raw_parts</span><span class="p">(</span><span class="n">str_start</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="kt">u8</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">)</span><span class="w"></span>
</span><span class="hll"><span class="linenos">21</span><span class="w"> </span><span class="p">}).</span><span class="n">unwrap</span><span class="p">()</span><span class="w"></span>
</span><span class="hll"><span class="linenos">22</span><span class="w"> </span><span class="p">);</span><span class="w"></span>
</span><span class="hll"><span class="linenos">23</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
</span><span class="hll"><span class="linenos">24</span><span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">as_slice</span><span class="p">()));</span><span class="w"></span>
</span><span class="linenos">25</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>可以看到,在入口 <code class="docutils literal notranslate"><span class="pre">_start</span></code> 中我们就接收到了命令行参数个数 <code class="docutils literal notranslate"><span class="pre">argc</span></code> 和字符串数组的起始地址 <code class="docutils literal notranslate"><span class="pre">argv</span></code> 。但是这个起始地址不太好用,我们希望能够将其转化为编写应用的时候看到的 <code class="docutils literal notranslate"><span class="pre">&amp;[&amp;str]</span></code> 的形式。转化的主体在第 10~23 行,就是分别取出 <code class="docutils literal notranslate"><span class="pre">argc</span></code> 个字符串的起始地址(基于字符串数组的 base 地址 <code class="docutils literal notranslate"><span class="pre">argv</span></code> ),从它向后找到第一个 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 就可以得到一个完整的 <code class="docutils literal notranslate"><span class="pre">&amp;str</span></code> 格式的命令行参数字符串并加入到向量 <code class="docutils literal notranslate"><span class="pre">v</span></code> 中。最后通过 <code class="docutils literal notranslate"><span class="pre">v.as_slice</span></code> 就得到了我们在 <code class="docutils literal notranslate"><span class="pre">main</span></code> 主函数中看到的 <code class="docutils literal notranslate"><span class="pre">&amp;[&amp;str]</span></code></p>
<p>有了命令行参数支持,我们就可以编写命令行工具 <code class="docutils literal notranslate"><span class="pre">ch6b_cat</span></code> 来输出指定文件的内容了。读者可以自行参阅其实现。</p>
</div>
</div>
<div class="section" id="id3">
<h2>标准输入输出重定向<a class="headerlink" href="#id3" title="永久链接至标题"></a></h2>
<p>为了增强 shell 程序使用文件系统时的灵活性,我们需要新增标准输入输出重定向功能。</p>
<p>重定向功能对于应用来说是透明的。在应用中除非明确指出了数据要从指定的文件输入或者输出到指定的文件,否则数据默认都是输入自进程文件描述表位置 0 处的标准输入,并输出到进程文件描述符表位置 1 处的标准输出。</p>
<p>为了对应用进程的文件描述符表进行某种替换,引入一个新的系统调用 <code class="docutils literal notranslate"><span class="pre">sys_dup</span></code> </p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/syscall.rs</span>
<span class="sd">/// 功能:将进程中一个已经打开的文件复制一份并分配到一个新的文件描述符中。</span>
<span class="sd">/// 参数fd 表示进程中一个已经打开的文件的文件描述符。</span>
<span class="sd">/// 返回值:如果出现了错误则返回 -1否则能够访问已打开文件的新文件描述符。</span>
<span class="sd">/// 可能的错误原因是:传入的 fd 并不对应一个合法的已打开文件。</span>
<span class="sd">/// syscall ID24</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_dup</span><span class="p">(</span><span class="n">fd</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">isize</span><span class="p">;</span><span class="w"></span>
</pre></div>
</div>
<p>这个系统调用的实现非常简单:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/syscall/fs.rs</span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">sys_dup</span><span class="p">(</span><span class="n">fd</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">isize</span> <span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">current_task</span><span class="p">().</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">inner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">task</span><span class="p">.</span><span class="n">acquire_inner_lock</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">fd</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">fd_table</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">fd_table</span><span class="p">[</span><span class="n">fd</span><span class="p">].</span><span class="n">is_none</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">new_fd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">alloc_fd</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">fd_table</span><span class="p">[</span><span class="n">new_fd</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">Arc</span>::<span class="n">clone</span><span class="p">(</span><span class="n">inner</span><span class="p">.</span><span class="n">fd_table</span><span class="p">[</span><span class="n">fd</span><span class="p">].</span><span class="n">as_ref</span><span class="p">().</span><span class="n">unwrap</span><span class="p">()));</span><span class="w"></span>
<span class="w"> </span><span class="n">new_fd</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">isize</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">sys_dup</span></code> 函数中,首先检查传入 <code class="docutils literal notranslate"><span class="pre">fd</span></code> 的合法性。然后在文件描述符表中分配一个新的文件描述符,并保存 <code class="docutils literal notranslate"><span class="pre">fd</span></code> 指向的已打开文件的一份拷贝即可。</p>
<p>在shell程序 <code class="docutils literal notranslate"><span class="pre">user_shell</span></code> 分割命令行参数的时候,我们要检查是否存在通过 <code class="docutils literal notranslate"><span class="pre">&lt;</span></code><code class="docutils literal notranslate"><span class="pre">&gt;</span></code> 进行输入输出重定向的情况,如果存在的话则需要将它们从命令行参数中移除,并记录匹配到的输入文件名或输出文件名到字符串 <code class="docutils literal notranslate"><span class="pre">input</span></code><code class="docutils literal notranslate"><span class="pre">output</span></code> 中。注意为了实现方便我们这里假设输入shell程序的命令一定合法<code class="docutils literal notranslate"><span class="pre">&lt;</span></code><code class="docutils literal notranslate"><span class="pre">&gt;</span></code> 最多只会出现一次,且后面总是会有一个参数作为重定向到的文件。</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// user/src/bin/ch6b_user_shell.rs</span>
<span class="c1">// redirect input</span>
<span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">input</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">((</span><span class="n">idx</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_copy</span><span class="w"></span>
<span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">enumerate</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">arg</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">arg</span><span class="p">.</span><span class="n">as_str</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"&lt;</span><span class="se">\0</span><span class="s">"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">input</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_copy</span><span class="p">[</span><span class="n">idx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">].</span><span class="n">clone</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">args_copy</span><span class="p">.</span><span class="n">drain</span><span class="p">(</span><span class="n">idx</span><span class="o">..=</span><span class="n">idx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// redirect output</span>
<span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">((</span><span class="n">idx</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_copy</span><span class="w"></span>
<span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">enumerate</span><span class="p">()</span><span class="w"></span>
<span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">arg</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">arg</span><span class="p">.</span><span class="n">as_str</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">"&gt;</span><span class="se">\0</span><span class="s">"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">args_copy</span><span class="p">[</span><span class="n">idx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">].</span><span class="n">clone</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">args_copy</span><span class="p">.</span><span class="n">drain</span><span class="p">(</span><span class="n">idx</span><span class="o">..=</span><span class="n">idx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>打开文件和替换的过程则发生在 <code class="docutils literal notranslate"><span class="pre">fork</span></code> 之后的子进程分支中:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="c1">// user/src/bin/user_shell.rs</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span><span class="kd">let</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fork</span><span class="p">();</span><span class="w"></span>
<span class="linenos"> 4</span><span class="k">if</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 5</span><span class="w"> </span><span class="c1">// input redirection</span>
<span class="linenos"> 6</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">input</span><span class="p">.</span><span class="n">is_empty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 7</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">input_fd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">open</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">as_str</span><span class="p">(),</span><span class="w"> </span><span class="n">OpenFlags</span>::<span class="n">RDONLY</span><span class="p">);</span><span class="w"></span>
<span class="linenos"> 8</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">input_fd</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos"> 9</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Error when opening file {}"</span><span class="p">,</span><span class="w"> </span><span class="n">input</span><span class="p">);</span><span class="w"></span>
<span class="linenos">10</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
<span class="linenos">11</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">12</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">input_fd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">input_fd</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">;</span><span class="w"></span>
<span class="linenos">13</span><span class="w"> </span><span class="n">close</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"></span>
<span class="linenos">14</span><span class="w"> </span><span class="fm">assert_eq!</span><span class="p">(</span><span class="n">dup</span><span class="p">(</span><span class="n">input_fd</span><span class="p">),</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span><span class="w"></span>
<span class="linenos">15</span><span class="w"> </span><span class="n">close</span><span class="p">(</span><span class="n">input_fd</span><span class="p">);</span><span class="w"></span>
<span class="linenos">16</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">17</span><span class="w"> </span><span class="c1">// output redirection</span>
<span class="linenos">18</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">!</span><span class="n">output</span><span class="p">.</span><span class="n">is_empty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">19</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">output_fd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">open</span><span class="p">(</span><span class="w"></span>
<span class="linenos">20</span><span class="w"> </span><span class="n">output</span><span class="p">.</span><span class="n">as_str</span><span class="p">(),</span><span class="w"></span>
<span class="linenos">21</span><span class="w"> </span><span class="n">OpenFlags</span>::<span class="n">CREATE</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">OpenFlags</span>::<span class="n">WRONLY</span><span class="w"></span>
<span class="linenos">22</span><span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="linenos">23</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">output_fd</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">24</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Error when opening file {}"</span><span class="p">,</span><span class="w"> </span><span class="n">output</span><span class="p">);</span><span class="w"></span>
<span class="linenos">25</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
<span class="linenos">26</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">27</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">output_fd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">output_fd</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">;</span><span class="w"></span>
<span class="linenos">28</span><span class="w"> </span><span class="n">close</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="linenos">29</span><span class="w"> </span><span class="fm">assert_eq!</span><span class="p">(</span><span class="n">dup</span><span class="p">(</span><span class="n">output_fd</span><span class="p">),</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="linenos">30</span><span class="w"> </span><span class="n">close</span><span class="p">(</span><span class="n">output_fd</span><span class="p">);</span><span class="w"></span>
<span class="linenos">31</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">32</span><span class="w"> </span><span class="c1">// child process</span>
<span class="linenos">33</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">exec</span><span class="p">(</span><span class="n">args_copy</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">as_str</span><span class="p">(),</span><span class="w"> </span><span class="n">args_addr</span><span class="p">.</span><span class="n">as_slice</span><span class="p">())</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">34</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Error when executing!"</span><span class="p">);</span><span class="w"></span>
<span class="linenos">35</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
<span class="linenos">36</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="linenos">37</span><span class="w"> </span><span class="fm">unreachable!</span><span class="p">();</span><span class="w"></span>
<span class="linenos">38</span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="linenos">39</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">exit_code</span>: <span class="kt">i32</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="linenos">40</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">exit_pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">waitpid</span><span class="p">(</span><span class="n">pid</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">exit_code</span><span class="p">);</span><span class="w"></span>
<span class="linenos">41</span><span class="w"> </span><span class="fm">assert_eq!</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span><span class="w"> </span><span class="n">exit_pid</span><span class="p">);</span><span class="w"></span>
<span class="linenos">42</span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Shell: Process {} exited with code {}"</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">,</span><span class="w"> </span><span class="n">exit_code</span><span class="p">);</span><span class="w"></span>
<span class="linenos">43</span><span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<ul class="simple">
<li><p>输入重定向发生在第 6~16 行。我们尝试打开输入文件 <code class="docutils literal notranslate"><span class="pre">input</span></code><code class="docutils literal notranslate"><span class="pre">input_fd</span></code> 中。之后,首先通过 <code class="docutils literal notranslate"><span class="pre">close</span></code> 关闭标准输入所在的文件描述符 0 。之后通过 <code class="docutils literal notranslate"><span class="pre">dup</span></code> 来分配一个新的文件描述符来访问 <code class="docutils literal notranslate"><span class="pre">input_fd</span></code> 对应的输入文件。这里用到了文件描述符分配的重要性质:即必定分配可用描述符中编号最小的一个。由于我们刚刚关闭了描述符 0 ,那么在 <code class="docutils literal notranslate"><span class="pre">dup</span></code> 的时候一定会将它分配出去,于是现在应用进程的文件描述符 0 就对应到输入文件了。最后,因为应用进程的后续执行不会用到输入文件原来的描述符 <code class="docutils literal notranslate"><span class="pre">input_fd</span></code> ,所以就将其关掉。</p></li>
<li><p>输出重定向则发生在 18~31 行。它的原理和输入重定向几乎完全一致,只是通过 <code class="docutils literal notranslate"><span class="pre">open</span></code> 打开文件的标志不太相同</p></li>
</ul>
</div>
</div>
</article>
<footer>
<div class="related-pages">
<a class="next-page" href="3exercise.html">
<div class="page-info">
<div class="context">
<span>Next</span>
</div>
<div class="title">chapter7练习</div>
</div>
<svg><use href="#svg-arrow-right"></use></svg>
</a>
<a class="prev-page" href="1pipe.html">
<svg><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>Previous</span>
</div>
<div class="title">管道</div>
</div>
</a>
</div>
<div class="related-information">
Copyright &#169; OS2022Summer
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a>
and
<a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
<a href="https://github.com/pradyunsg/furo">Furo theme</a>.
|
<a class="muted-link" href="../_sources/chapter7/2cmdargs-and-redirection.rst.txt"
rel="nofollow">
显示源代码
</a>
</div>
</footer>
</div>
<aside class="toc-drawer">
<div class="toc-sticky toc-scroll">
<div class="toc-title-container">
<span class="toc-title">
目录
</span>
</div>
<div class="toc-tree-container">
<div class="toc-tree">
<ul>
<li><a class="reference internal" href="#">命令行参数与标准 I/O 重定向</a><ul>
<li><a class="reference internal" href="#id1">命令行参数</a><ul>
<li><a class="reference internal" href="#shell">shell程序的命令行参数分割</a></li>
<li><a class="reference internal" href="#sys-exec">sys_exec 将命令行参数压入用户栈</a></li>
<li><a class="reference internal" href="#id2">用户库从用户栈上还原命令行参数</a></li>
</ul>
</li>
<li><a class="reference internal" href="#id3">标准输入输出重定向</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</aside>
</div>
</div><script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/scripts/main.js"></script>
<script kind="utterances">
var commentsRunWhenDOMLoaded = cb => {
if (document.readyState != 'loading') {
cb()
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', cb)
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState == 'complete') cb()
})
}
}
var addUtterances = () => {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://utteranc.es/client.js";
script.async = "async";
script.setAttribute("repo", "LearningOS/rust-based-os-comp2022");
script.setAttribute("issue-term", "pathname");
script.setAttribute("theme", "github-light");
script.setAttribute("label", "comments");
script.setAttribute("crossorigin", "anonymous");
sections = document.querySelectorAll("div.section");
if (sections !== null) {
section = sections[sections.length-1];
section.appendChild(script);
}
}
commentsRunWhenDOMLoaded(addUtterances);
</script>
<script src="../_static/translations.js"></script>
</body>
</html>