Skip to content

Commit d3b44f4

Browse files
author
Margo
committed
Add exercises for Tuesday 11/8 (baby shell)
1 parent ffe9c28 commit d3b44f4

File tree

3 files changed

+305
-0
lines changed

3 files changed

+305
-0
lines changed

kernel4/kernel.c

+9
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ void exception(x86_64_registers* reg) {
203203
snprintf(name, sizeof(name), "Process %d", current->p_pid);
204204
else
205205
strcpy(name, "Kernel");
206+
if (reg->reg_err & PFERR_USER) {
207+
uintptr_t p = page_alloc_unused();
208+
// Check if it's on the stack
209+
if (virtual_memory_map(current->p_pagetable,
210+
(addr & ~(PAGESIZE - 1)), p, PAGESIZE,
211+
PTE_P | PTE_U | PTE_W, NULL) !=0)
212+
panic("Adding page failed");
213+
break;
214+
}
206215

207216
error_printf(CPOS(23, 0), 0xC000,
208217
"%s page fault for %p (%s %s, rip=%p)!\n",

shell2x/GNUmakefile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
all: babysh
2+
O ?= -O2
3+
4+
include ../common/rules.mk
5+
6+
%.o: %.c $(BUILDSTAMP)
7+
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCFLAGS) $(O) -o $@ -c $<
8+
9+
babysh: babysh.o
10+
$(CC) $(CFLAGS) $(O) -o $@ $^ -lm
11+
12+
clean:
13+
rm -f babysh *.o
14+
rm -rf $(DEPSDIR) *.dSYM
15+
16+
.PHONY: all clean

shell2x/babysh.c

+280
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
/*
2+
* sh - shell
3+
*
4+
* Usage:
5+
* sh
6+
* sh -c command
7+
*
8+
* This is a stripped down version of the shell we use in CS161. The goal of
9+
* today's exercise is to provide practice using the key system calls you'll
10+
* need to use in Assignment 5.
11+
*/
12+
13+
#include <sys/types.h>
14+
#include <sys/wait.h>
15+
#include <assert.h>
16+
#include <unistd.h>
17+
#include <stdlib.h>
18+
#include <stdio.h>
19+
#include <string.h>
20+
#include <limits.h>
21+
#include <errno.h>
22+
#include <err.h>
23+
24+
/*
25+
* We are going to limit both the number of arguments that we might pass to a
26+
* shell command and the total length of those arguments. On most UNIX systems,
27+
* there is no NARG_MAX. The structure below including a #define brackeded by
28+
* #ifndef and #endif is how we define things, if we want to define them only if
29+
* they are not already defined in system include files.
30+
*/
31+
#ifndef NARG_MAX
32+
#define NARG_MAX 1024
33+
#endif
34+
35+
#ifndef ARG_MAX
36+
#define CMDLINE_MAX 4096
37+
#elif ARG_MAX > 4096
38+
#define CMDLINE_MAX 4096
39+
#else
40+
#define CMDLINE_MAX ARG_MAX
41+
#endif
42+
43+
static int dowait(pid_t pid);
44+
45+
/*
46+
* runcommand --
47+
* This routine is where you need to use fork and exec to run commands.
48+
*/
49+
static int
50+
run_cmd(int argc, char *argv[]) {
51+
(void)argc;
52+
(void)argv;
53+
/*
54+
* TODO
55+
* If you get here, then you are dealing with a command that
56+
* will be implemented by executing a program. You will need
57+
* to do a fork/exec here and then wait for the child.
58+
*/
59+
60+
/*
61+
* TODO
62+
* The parent should wait for its child and then return the exit
63+
* status of the process it created. Note that there is a function
64+
* you have to fill in called "dowait." Call it here in the parent
65+
* process.
66+
*/
67+
return (0);
68+
}
69+
70+
/*
71+
* dowait -- this is a routine you need to write so that a parent can
72+
* wait for its child to complete. The pid parameter is the pid of the
73+
* child for whom this process wishes to wait.
74+
*/
75+
static int
76+
dowait(pid_t pid)
77+
{
78+
(void)pid;
79+
/*
80+
* TODO
81+
* Make a process wait on a particular pid, and give proper
82+
* error messages and/or warnings on failure. Return exit
83+
* status.
84+
* NOTE: Read the man page to decide what, if any, flags you want
85+
* to user here.
86+
*/
87+
return (0);
88+
}
89+
90+
/*
91+
* chdir
92+
* This is just an interface to the chdir system call. This shell has
93+
* no notion of current working directory (you'll get to implement this
94+
* for assignment 5), so you need full pathnames here.
95+
* YOU DO NOT NEED TO CHANGE THIS
96+
*/
97+
static int
98+
cmd_chdir(int argc, char *argv[])
99+
{
100+
if (argc == 2) {
101+
if (chdir(argv[1]) != 0) {
102+
warn("chdir");
103+
return (1);
104+
}
105+
return (0);
106+
}
107+
printf("Usage: chdir dir\n");
108+
return (1);
109+
}
110+
111+
/*
112+
* cmd_exit: This is the function we use to exit the shell.
113+
* YOU DO NOT NEED TO CHANGE THIS.
114+
*/
115+
static int
116+
cmd_exit(int argc, char *argv[])
117+
{
118+
int stat;
119+
120+
stat = 0;
121+
if (argc == 2) {
122+
stat = atoi(argv[1]);
123+
} else if (argc > 1) {
124+
printf("Usage: exit [status]\n");
125+
return (1);
126+
}
127+
exit(stat);
128+
129+
/*
130+
* You never get here, but if you don't put this here,
131+
* the compiler will complain.
132+
*/
133+
return (0);
134+
}
135+
136+
/*
137+
* This is a command dispatch table for a few of the builtin functions. Each
138+
* of them takes an argc and argv.
139+
*
140+
* Feel free to add some builtins here if you want.
141+
*/
142+
static struct {
143+
const char *name;
144+
int (*func)(int, char **);
145+
} builtins[] = {
146+
{ "cd", cmd_chdir },
147+
{ "chdir", cmd_chdir },
148+
{ "exit", cmd_exit },
149+
{ NULL, NULL }
150+
};
151+
152+
/*
153+
* docommand --
154+
* We use the C library strtok to break a command line into a set of tokens.
155+
* If the command line is blank, then we simply return. Once we have the set
156+
* of tokens, we check check to see if the command is a builtin -- if so, we
157+
* run it. If not, we assume that it is a program that we need to fork/exec.
158+
* YOU DO NOT HAVE TO CHANGE THIS.
159+
*/
160+
static int
161+
docommand(char *buf)
162+
{
163+
char *args[NARG_MAX + 1];
164+
int nargs, i;
165+
char *s;
166+
int bg;
167+
168+
bg = 0;
169+
nargs = 0;
170+
171+
for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) {
172+
if (nargs >= NARG_MAX) {
173+
printf("%s: Too many arguments "
174+
"(exceeds system limit)\n", args[0]);
175+
return (1);
176+
}
177+
args[nargs++] = s;
178+
}
179+
args[nargs] = NULL;
180+
181+
/* Check for empty line. */
182+
if (nargs == 0) {
183+
return (0);
184+
}
185+
186+
/* Check for builtin command. */
187+
for (i = 0; builtins[i].name; i++) {
188+
if (strcmp(builtins[i].name, args[0]) == 0) {
189+
return (builtins[i].func(nargs, args));
190+
}
191+
}
192+
193+
/* Not a builtin; run it */
194+
return run_cmd(nargs, args);
195+
}
196+
197+
/*
198+
* getcmd --
199+
* Reads valid characters from the console, filling the buffer.
200+
* Backspace deletes a character, by moving the position backwards.
201+
* A newline or carriage return breaks the loop, which terminates
202+
* the string and returns.
203+
*
204+
* If there is an invalid character or a backspace when there is nothing
205+
* in the buffer, outputs an alert (bell).
206+
* YOU DO NOT HAVE TO CHANGE THIS.
207+
*/
208+
static void
209+
getcmd(char *buf, size_t len)
210+
{
211+
size_t pos;
212+
int ch, done;
213+
214+
pos = 0;
215+
done = 0;
216+
217+
/*
218+
* In the absence of a <ctype.h>, assume input is 7-bit ASCII.
219+
*/
220+
221+
while (!done) {
222+
ch = getchar();
223+
if ((ch == '\b' || ch == 127) && pos > 0) {
224+
pos--;
225+
} else if (ch == '\r' || ch == '\n') {
226+
done = 1;
227+
} else if (ch >= 32 && ch < 127 && pos < len-1) {
228+
buf[pos++] = ch;
229+
}
230+
}
231+
buf[pos] = 0;
232+
}
233+
234+
/*
235+
* interactive --
236+
* Runs the interactive shell. This is your basic infinite loop that
237+
* grabs commands and executes them (printing the exit status if it's not
238+
* success.)
239+
* YOU DO NOT HAVE TO CHANGE THIS.
240+
*/
241+
static void
242+
interactive(void)
243+
{
244+
char buf[CMDLINE_MAX];
245+
246+
while (1) {
247+
printf("BabyShell: ");
248+
getcmd(buf, sizeof(buf));
249+
/*
250+
* We don't do anything with the error status
251+
* in interactive mode.
252+
*/
253+
(void)docommand(buf);
254+
}
255+
}
256+
257+
258+
/*
259+
* main --
260+
* If there are no arguments, run interactively, otherwise, run a program
261+
* from within the shell, but immediately exit.
262+
* YOU DO NOT HAVE TO CHANGE THIS.
263+
*/
264+
int
265+
main(int argc, char *argv[])
266+
{
267+
/*
268+
* Allow argc to be 0 in case we're running on a broken kernel,
269+
* or one that doesn't set argv when starting the first shell.
270+
*/
271+
if (argc == 0 || argc == 1) {
272+
interactive();
273+
} else if (argc == 3 && !strcmp(argv[1], "-c")) {
274+
return (docommand(argv[2]));
275+
} else {
276+
errx(1, "Usage: sh [-c command]");
277+
}
278+
279+
return (0);
280+
}

0 commit comments

Comments
 (0)