1
0
Fork 0
cl-sites/w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/html/Extended3Bash.html
2025-01-28 10:11:14 +01:00

650 lines
No EOL
39 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>3.9. Extended Example: Bash-lite: A Simple Command-line Shell &mdash; Computer Systems Fundamentals</title>
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
<style>
.underline { text-decoration: underline; }
</style>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true
},
"HTML-CSS": {
scale: "80"
}
});
</script>
<link rel="shortcut icon" href="_static/favicon.ico"/>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
<link rel="next" title="1. Networked Concurrency" href="SocketsOverview.html" />
<link rel="prev" title="8. Semaphores" href="IPCSems.html" />
</head><body>
<nav class="navbar navbar-expand-md navbar-dark navbar-custom fixed-top">
<a class="navbar-brand py-0" href="index.html"><img src="_static/CSF-Logo-Square-Text.png" alt="OpenCSF Logo" height="40em" class="py-1 px-2 mb-0 align-center rounded-lg bg-white" /></a>
<!-- Show a navbar toggler on mobile -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#defaultNavbars" aria-controls="defaultNavbars" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="defaultNavbars">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle jmu-gold rounded" href="Extended3Bash.html#" id="navbarDropdownChapters" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Contents</a>
<div class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="navbarDropdownChapters">
<a class="dropdown-item" tabindex="-1" href="Extended3Bash.html#"><b>Chapter 1</b></a>
<a class="dropdown-item" href="IntroConcSysOverview.html">&nbsp;&nbsp;&nbsp;1.1. Introduction to Concurrent Systems</a>
<a class="dropdown-item" href="SysAndModels.html">&nbsp;&nbsp;&nbsp;1.2. Systems and Models</a>
<a class="dropdown-item" href="Themes.html">&nbsp;&nbsp;&nbsp;1.3. Themes and Guiding Principles</a>
<a class="dropdown-item" href="Architectures.html">&nbsp;&nbsp;&nbsp;1.4. System Architectures</a>
<a class="dropdown-item" href="StateModels.html">&nbsp;&nbsp;&nbsp;1.5. State Models in UML</a>
<a class="dropdown-item" href="SequenceModels.html">&nbsp;&nbsp;&nbsp;1.6. Sequence Models in UML</a>
<a class="dropdown-item" href="StateModelImplementation.html">&nbsp;&nbsp;&nbsp;1.7. Extended Example: State Model Implementation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 2</b></a>
<a class="dropdown-item" href="ProcessesOverview.html">&nbsp;&nbsp;&nbsp;2.1. Processes and OS Basics</a>
<a class="dropdown-item" href="Multiprogramming.html">&nbsp;&nbsp;&nbsp;2.2. Processes and Multiprogramming</a>
<a class="dropdown-item" href="KernelMechanics.html">&nbsp;&nbsp;&nbsp;2.3. Kernel Mechanics</a>
<a class="dropdown-item" href="Syscall.html">&nbsp;&nbsp;&nbsp;2.4. System Call Interface</a>
<a class="dropdown-item" href="ProcessCycle.html">&nbsp;&nbsp;&nbsp;2.5. Process Life Cycle</a>
<a class="dropdown-item" href="UnixFile.html">&nbsp;&nbsp;&nbsp;2.6. The UNIX File Abstraction</a>
<a class="dropdown-item" href="EventsSignals.html">&nbsp;&nbsp;&nbsp;2.7. Events and Signals</a>
<a class="dropdown-item" href="Extended2Processes.html">&nbsp;&nbsp;&nbsp;2.8. Extended Example: Listing Files with Processes</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 3</b></a>
<a class="dropdown-item" href="IPCOverview.html">&nbsp;&nbsp;&nbsp;3.1. Concurrency with IPC</a>
<a class="dropdown-item" href="IPCModels.html">&nbsp;&nbsp;&nbsp;3.2. IPC Models</a>
<a class="dropdown-item" href="Pipes.html">&nbsp;&nbsp;&nbsp;3.3. Pipes and FIFOs</a>
<a class="dropdown-item" href="MMap.html">&nbsp;&nbsp;&nbsp;3.4. Shared Memory With Memory-mapped Files</a>
<a class="dropdown-item" href="POSIXvSysV.html">&nbsp;&nbsp;&nbsp;3.5. POSIX vs. System V IPC</a>
<a class="dropdown-item" href="MQueues.html">&nbsp;&nbsp;&nbsp;3.6. Message Passing With Message Queues</a>
<a class="dropdown-item" href="ShMem.html">&nbsp;&nbsp;&nbsp;3.7. Shared Memory</a>
<a class="dropdown-item" href="IPCSems.html">&nbsp;&nbsp;&nbsp;3.8. Semaphores</a>
<a class="dropdown-item" href="Extended3Bash.html">&nbsp;&nbsp;&nbsp;3.9. Extended Example: Bash-lite: A Simple Command-line Shell</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 4</b></a>
<a class="dropdown-item" href="SocketsOverview.html">&nbsp;&nbsp;&nbsp;4.1. Networked Concurrency</a>
<a class="dropdown-item" href="FiveLayer.html">&nbsp;&nbsp;&nbsp;4.2. The TCP/IP Internet Model</a>
<a class="dropdown-item" href="NetApps.html">&nbsp;&nbsp;&nbsp;4.3. Network Applications and Protocols</a>
<a class="dropdown-item" href="Sockets.html">&nbsp;&nbsp;&nbsp;4.4. The Socket Interface</a>
<a class="dropdown-item" href="TCPSockets.html">&nbsp;&nbsp;&nbsp;4.5. TCP Socket Programming: HTTP</a>
<a class="dropdown-item" href="UDPSockets.html">&nbsp;&nbsp;&nbsp;4.6. UDP Socket Programming: DNS</a>
<a class="dropdown-item" href="AppBroadcast.html">&nbsp;&nbsp;&nbsp;4.7. Application-Layer Broadcasting: DHCP</a>
<a class="dropdown-item" href="Extended4CGI.html">&nbsp;&nbsp;&nbsp;4.8. Extended Example: CGI Web Server</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 5</b></a>
<a class="dropdown-item" href="InternetOverview.html">&nbsp;&nbsp;&nbsp;5.1. The Internet and Connectivity</a>
<a class="dropdown-item" href="AppLayer.html">&nbsp;&nbsp;&nbsp;5.2. Application Layer: Overlay Networks</a>
<a class="dropdown-item" href="TransLayer.html">&nbsp;&nbsp;&nbsp;5.3. Transport Layer</a>
<a class="dropdown-item" href="NetSec.html">&nbsp;&nbsp;&nbsp;5.4. Network Security Fundamentals</a>
<a class="dropdown-item" href="NetLayer.html">&nbsp;&nbsp;&nbsp;5.5. Network Layer: IP</a>
<a class="dropdown-item" href="LinkLayer.html">&nbsp;&nbsp;&nbsp;5.6. Link Layer</a>
<a class="dropdown-item" href="Wireless.html">&nbsp;&nbsp;&nbsp;5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
<a class="dropdown-item" href="Extended5DNS.html">&nbsp;&nbsp;&nbsp;5.8. Extended Example: DNS client</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 6</b></a>
<a class="dropdown-item" href="ThreadsOverview.html">&nbsp;&nbsp;&nbsp;6.1. Concurrency with Multithreading</a>
<a class="dropdown-item" href="ProcVThreads.html">&nbsp;&nbsp;&nbsp;6.2. Processes vs. Threads</a>
<a class="dropdown-item" href="RaceConditions.html">&nbsp;&nbsp;&nbsp;6.3. Race Conditions and Critical Sections</a>
<a class="dropdown-item" href="POSIXThreads.html">&nbsp;&nbsp;&nbsp;6.4. POSIX Thread Library</a>
<a class="dropdown-item" href="ThreadArgs.html">&nbsp;&nbsp;&nbsp;6.5. Thread Arguments and Return Values</a>
<a class="dropdown-item" href="ImplicitThreads.html">&nbsp;&nbsp;&nbsp;6.6. Implicit Threading and Language-based Threads</a>
<a class="dropdown-item" href="Extended6Input.html">&nbsp;&nbsp;&nbsp;6.7. Extended Example: Keyboard Input Listener</a>
<a class="dropdown-item" href="Extended6Primes.html">&nbsp;&nbsp;&nbsp;6.8. Extended Example: Concurrent Prime Number Search</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 7</b></a>
<a class="dropdown-item" href="SynchOverview.html">&nbsp;&nbsp;&nbsp;7.1. Synchronization Primitives</a>
<a class="dropdown-item" href="CritSect.html">&nbsp;&nbsp;&nbsp;7.2. Critical Sections and Peterson's Solution</a>
<a class="dropdown-item" href="Locks.html">&nbsp;&nbsp;&nbsp;7.3. Locks</a>
<a class="dropdown-item" href="Semaphores.html">&nbsp;&nbsp;&nbsp;7.4. Semaphores</a>
<a class="dropdown-item" href="Barriers.html">&nbsp;&nbsp;&nbsp;7.5. Barriers</a>
<a class="dropdown-item" href="Condvars.html">&nbsp;&nbsp;&nbsp;7.6. Condition Variables</a>
<a class="dropdown-item" href="Deadlock.html">&nbsp;&nbsp;&nbsp;7.7. Deadlock</a>
<a class="dropdown-item" href="Extended7Events.html">&nbsp;&nbsp;&nbsp;7.8. Extended Example: Event Log File</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 8</b></a>
<a class="dropdown-item" href="SynchProblemsOverview.html">&nbsp;&nbsp;&nbsp;8.1. Synchronization Patterns and Problems</a>
<a class="dropdown-item" href="SynchDesign.html">&nbsp;&nbsp;&nbsp;8.2. Basic Synchronization Design Patterns</a>
<a class="dropdown-item" href="ProdCons.html">&nbsp;&nbsp;&nbsp;8.3. Producer-Consumer Problem</a>
<a class="dropdown-item" href="ReadWrite.html">&nbsp;&nbsp;&nbsp;8.4. Readers-Writers Problem</a>
<a class="dropdown-item" href="DiningPhil.html">&nbsp;&nbsp;&nbsp;8.5. Dining Philosophers Problem and Deadlock</a>
<a class="dropdown-item" href="CigSmokers.html">&nbsp;&nbsp;&nbsp;8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
<a class="dropdown-item" href="Extended8ModExp.html">&nbsp;&nbsp;&nbsp;8.7. Extended Example: Parallel Modular Exponentiation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 9</b></a>
<a class="dropdown-item" href="ParallelDistributedOverview.html">&nbsp;&nbsp;&nbsp;9.1. Parallel and Distributed Systems</a>
<a class="dropdown-item" href="ParVConc.html">&nbsp;&nbsp;&nbsp;9.2. Parallelism vs. Concurrency</a>
<a class="dropdown-item" href="ParallelDesign.html">&nbsp;&nbsp;&nbsp;9.3. Parallel Design Patterns</a>
<a class="dropdown-item" href="Scaling.html">&nbsp;&nbsp;&nbsp;9.4. Limits of Parallelism and Scaling</a>
<a class="dropdown-item" href="DistTiming.html">&nbsp;&nbsp;&nbsp;9.5. Timing in Distributed Environments</a>
<a class="dropdown-item" href="DistDataStorage.html">&nbsp;&nbsp;&nbsp;9.6. Reliable Data Storage and Location</a>
<a class="dropdown-item" href="DistConsensus.html">&nbsp;&nbsp;&nbsp;9.7. Consensus in Distributed Systems</a>
<a class="dropdown-item" href="Extended9Blockchain.html">&nbsp;&nbsp;&nbsp;9.8. Extended Example: Blockchain Proof-of-Work</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Appendix A</b></a>
<a class="dropdown-item" href="CLangOverview.html">&nbsp;&nbsp;&nbsp;A.1. C Language Reintroduction</a>
<a class="dropdown-item" href="Debugging.html">&nbsp;&nbsp;&nbsp;A.2. Documentation and Debugging</a>
<a class="dropdown-item" href="BasicTypes.html">&nbsp;&nbsp;&nbsp;A.3. Basic Types and Pointers</a>
<a class="dropdown-item" href="Arrays.html">&nbsp;&nbsp;&nbsp;A.4. Arrays, Structs, Enums, and Type Definitions</a>
<a class="dropdown-item" href="Functions.html">&nbsp;&nbsp;&nbsp;A.5. Functions and Scope</a>
<a class="dropdown-item" href="Pointers.html">&nbsp;&nbsp;&nbsp;A.6. Pointers and Dynamic Allocation</a>
<a class="dropdown-item" href="Strings.html">&nbsp;&nbsp;&nbsp;A.7. Strings</a>
<a class="dropdown-item" href="FunctionPointers.html">&nbsp;&nbsp;&nbsp;A.8. Function Pointers</a>
<a class="dropdown-item" href="Files.html">&nbsp;&nbsp;&nbsp;A.9. Files</a>
</div>
</li>
</ul>
</div>
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
<li class="nav-item"><a class="nav-link jmu-gold" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/source/Extended3Bash.rst"
target="_blank" rel="nofollow">Show Source</a></li>
</ul>
</nav>
<div class="container center">
«&#160;&#160;<a id="prevmod" href="IPCSems.html">3.8. Semaphores</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod" href="SocketsOverview.html">4.1. Networked Concurrency</a>&#160;&#160;»
</div>
<br />
<script type="text/javascript" src="_static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="_static/js/jquery-1.11.4-ui.min.js"></script>
<script type="text/javascript" src="_static/js/forge-0.7.0.min.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/jquery.transit.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/raphael.js"></script>
<script type="text/javascript" src="../../../JSAV/build/JSAV-min.js"></script>
<script type="text/javascript" src="_static/js/config.js"></script>
<script type="text/javascript" src="../../../lib/odsaUtils-min.js"></script>
<script type="text/javascript" src="../../../lib/odsaMOD-min.js"></script>
<script type="text/javascript" src="_static/js/d3-4.13.0.min.js"></script>
<script type="text/javascript" src="_static/js/d3-selection-multi.v1.min.js"></script>
<script type="text/javascript" src="../../../lib/dataStructures.js"></script>
<div class="container">
<script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "Extended3Bash";ODSA.SETTINGS.MODULE_LONG_NAME = "Extended Example: Bash-lite: A Simple Command-line Shell";ODSA.SETTINGS.MODULE_CHAPTER = "Concurrency with IPC"; ODSA.SETTINGS.BUILD_DATE = "2021-06-01 15:31:50"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="extended-example-bash-lite-a-simple-command-line-shell">
<h1>3.9. Extended Example: Bash-lite: A Simple Command-line Shell<a class="headerlink" href="Extended3Bash.html#extended-example-bash-lite-a-simple-command-line-shell" title="Permalink to this headline"></a></h1>
<p>This Extended Example creates a minimal shell similar to the bash shell used in Linux and macOS.
When this program runs, it will read a line of text at a time from the user. This line will be used
as a command line, running in a separate process. The user can enter <code class="docutils literal notranslate"><span class="pre">quit</span></code> or <code class="docutils literal notranslate"><span class="pre">logout</span></code> to exit.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#include</span> <span class="cpf">&lt;assert.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;stdbool.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp"></span>
<span class="cm">/* Set the maximum allowable length for a command line */</span>
<span class="cp">#define MAX_LINE_LENGTH 1024</span>
<span class="cm">/* Allow spaces, tabs, newline, and carriage return to match</span>
<span class="cm"> whitespace between tokens */</span>
<span class="cp">#define WHITESPACE &quot; \t\n\r&quot;</span>
<span class="kt">void</span> <span class="nf">run_child_process</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">);</span>
<span class="kt">char</span> <span class="o">**</span><span class="nf">tokenize_arguments</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="p">);</span>
<span class="kt">char</span> <span class="o">**</span><span class="nf">get_out_name</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="p">);</span>
<span class="kt">int</span>
<span class="nf">main</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">MAX_LINE_LENGTH</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
<span class="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_LINE_LENGTH</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
<span class="cm">/* Main loop: iterate until user enters &quot;quit&quot; or &quot;logout&quot; */</span>
<span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Display a minimal prompt and read the command line */</span>
<span class="n">printf</span> <span class="p">(</span><span class="s">&quot;$ &quot;</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">fgets</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">MAX_LINE_LENGTH</span><span class="p">,</span> <span class="n">stdin</span><span class="p">))</span>
<span class="k">break</span><span class="p">;</span>
<span class="cm">/* Get the command for this line without any arguments */</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">command</span> <span class="o">=</span> <span class="n">strtok</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">WHITESPACE</span><span class="p">);</span>
<span class="cm">/* Check for reserved keywords to quit the shell */</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">strncmp</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&quot;quit&quot;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="n">strncmp</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&quot;logout&quot;</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">break</span><span class="p">;</span>
<span class="cm">/* Get the array of arguments and determine the output file</span>
<span class="cm"> to use (if the line ends with &quot;&gt; output&quot; redirection). */</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">output</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">**</span><span class="n">arg_list</span> <span class="o">=</span> <span class="n">tokenize_arguments</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">output</span><span class="p">);</span>
<span class="cm">/* Security precaution: This is a simple shell that should</span>
<span class="cm"> not be used for running commands in root. */</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">strncmp</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&quot;sudo&quot;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="n">strncmp</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="s">&quot;su&quot;</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">printf</span> <span class="p">(</span><span class="s">&quot;*WARNING* This implementation does not &quot;</span>
<span class="s">&quot;support super-user commands</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
<span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* If something went wrong, skip this line */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">arg_list</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">perror</span> <span class="p">(</span><span class="s">&quot;-bash-lite: syntax error</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
<span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* Copy the command name as the first argument */</span>
<span class="n">arg_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">command</span><span class="p">;</span>
<span class="cm">/* Create the child process and execute the command in it */</span>
<span class="kt">pid_t</span> <span class="n">child_pid</span> <span class="o">=</span> <span class="n">fork</span> <span class="p">();</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">child_pid</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">child_pid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">run_child_process</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">arg_list</span><span class="p">,</span> <span class="n">output</span><span class="p">);</span>
<span class="cm">/* Parent waits for the child, then frees up allocated memory</span>
<span class="cm"> for the argument list and moves on to the next line */</span>
<span class="n">wait</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="n">free</span> <span class="p">(</span><span class="n">arg_list</span><span class="p">);</span>
<span class="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_LINE_LENGTH</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">EXIT_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* Runs a command in an already created child process. The command</span>
<span class="cm"> string should already be copied as the first argument in the</span>
<span class="cm"> list. If the user typed an output redirection (&quot;&gt; out&quot; or</span>
<span class="cm"> &quot;&gt;out&quot;), then output_file is the name of the file to create.</span>
<span class="cm"> Otherwise, output_file is NULL. Should never return. */</span>
<span class="kt">void</span>
<span class="nf">run_child_process</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">command</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">arg_list</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">output_file</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">out_fd</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="cm">/* If there is a specified output file, open it and redirect</span>
<span class="cm"> STDOUT to write to this file */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">output_file</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">out_fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="n">output_file</span><span class="p">,</span> <span class="n">O_RDWR</span> <span class="o">|</span> <span class="n">O_CREAT</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">out_fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;-bash-lite: failed to open file %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">output_file</span><span class="p">);</span>
<span class="n">exit</span> <span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/* Make the file readable and redirect STDOUT */</span>
<span class="n">fchmod</span> <span class="p">(</span><span class="n">out_fd</span><span class="p">,</span> <span class="mo">0644</span><span class="p">);</span>
<span class="n">dup2</span> <span class="p">(</span><span class="n">out_fd</span><span class="p">,</span> <span class="n">STDOUT_FILENO</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/* Use execvp, because we are not doing a PATH lookup and the</span>
<span class="cm"> arguments are in a dynamically allocated array */</span>
<span class="n">execvp</span> <span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">arg_list</span><span class="p">);</span>
<span class="cm">/* Should never reach here. Print an error message, free up</span>
<span class="cm"> resources, and exit. */</span>
<span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;-bash-lite: %s: command not found</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">command</span><span class="p">);</span>
<span class="n">free</span> <span class="p">(</span><span class="n">arg_list</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">out_fd</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">close</span> <span class="p">(</span><span class="n">out_fd</span><span class="p">);</span>
<span class="n">exit</span> <span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/* Given a command line (buffer), create the list of arguments to</span>
<span class="cm"> use for the child process. If the command line ends in an output</span>
<span class="cm"> redirection, update the output_file pointer to point to the name</span>
<span class="cm"> of the file to use. */</span>
<span class="kt">char</span> <span class="o">**</span>
<span class="nf">tokenize_arguments</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">output_file</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">buffer</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">output_file</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">token</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="cm">/* Allocate an initial array for 10 arguments; this can grow</span>
<span class="cm"> later if needed */</span>
<span class="kt">size_t</span> <span class="n">arg_list_capacity</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">**</span><span class="n">arguments</span> <span class="o">=</span> <span class="n">calloc</span> <span class="p">(</span><span class="n">arg_list_capacity</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">));</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">arguments</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cm">/* Leave the first space blank for the command name */</span>
<span class="kt">size_t</span> <span class="n">arg_list_length</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span> <span class="p">(</span><span class="n">token</span> <span class="o">=</span> <span class="n">strtok</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">WHITESPACE</span><span class="p">))</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* If token starts with &gt;, it is an output redirection. The</span>
<span class="cm"> rest of the line must be the file name. Need to pass both</span>
<span class="cm"> the rest of the token and the buffer, as there might not</span>
<span class="cm"> be a space before the file name. */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;&gt;&#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">get_out_name</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">token</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">output_file</span><span class="p">,</span> <span class="n">arguments</span><span class="p">);</span>
<span class="cm">/* If current argument array is full, double its capacity */</span>
<span class="k">if</span> <span class="p">((</span><span class="n">arg_list_length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="n">arg_list_capacity</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">arg_list_capacity</span> <span class="o">*=</span> <span class="mi">2</span><span class="p">;</span>
<span class="n">arguments</span> <span class="o">=</span> <span class="n">realloc</span> <span class="p">(</span><span class="n">arguments</span><span class="p">,</span> <span class="n">arg_list_capacity</span> <span class="o">*</span> <span class="k">sizeof</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">));</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">arguments</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/* Add the token to the end of the argument list */</span>
<span class="n">arguments</span><span class="p">[</span><span class="n">arg_list_length</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">token</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">arguments</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* Determine the output file from either the token that begins with</span>
<span class="cm"> the &#39;&gt;&#39; character (but that character was removed) or from the</span>
<span class="cm"> next token on the command line. Note that all tokens after the</span>
<span class="cm"> output file name will be ignored. */</span>
<span class="kt">char</span> <span class="o">**</span>
<span class="nf">get_out_name</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">token</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">output_file</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* If token is not an empty string, it contains the output file</span>
<span class="cm"> name */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">strlen</span> <span class="p">(</span><span class="n">token</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="o">*</span><span class="n">output_file</span> <span class="o">=</span> <span class="n">token</span><span class="p">;</span>
<span class="k">return</span> <span class="n">arguments</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* Token is empty, so there was a space after the &#39;&gt;&#39; symbol.</span>
<span class="cm"> There should be one token left that is the file name. */</span>
<span class="n">token</span> <span class="o">=</span> <span class="n">strtok</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">WHITESPACE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">token</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* This is an error, no file name was passed */</span>
<span class="n">free</span> <span class="p">(</span><span class="n">arguments</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* The last token is the file name, so return it and the argument </span>
<span class="cm"> list */</span>
<span class="o">*</span><span class="n">output_file</span> <span class="o">=</span> <span class="n">token</span><span class="p">;</span>
<span class="k">return</span> <span class="n">arguments</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
</div>
</div>
<div class="container">
<div class="mt-4 container center">
«&#160;&#160;<a id="prevmod1" href="IPCSems.html">3.8. Semaphores</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod1" href="SocketsOverview.html">4.1. Networked Concurrency</a>&#160;&#160;»
</div>
</div>
<br />
<div class="row jmu-dark-purple-bg">
<div class="col-md-12">
<center>
<a id="contact_us" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="mailto:webmaster@opencsf.org" role="button">Contact Us</a>
<a id="license" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/lib/license.html" target="_blank">License</a>
</center>
</div>
</div>
<script src="_static/js/popper.js-1.14.7-min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="_static/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>