add user
This commit is contained in:
parent
be6dd22181
commit
01ec2b3896
82
Makefile
82
Makefile
|
@ -1,7 +1,7 @@
|
|||
# Compile xv6 for porting on k210
|
||||
|
||||
K=kernel
|
||||
U=user
|
||||
U=xv6-user
|
||||
T=target
|
||||
|
||||
OBJS = \
|
||||
|
@ -94,6 +94,82 @@ run-k210: k210
|
|||
@sudo chmod 777 $(k210-serialport)
|
||||
python3 ./tools/kflash.py -p $(k210-serialport) -b 1500000 -t $(k210)
|
||||
|
||||
|
||||
$U/initcode: $U/initcode.S
|
||||
$(CC) $(CFLAGS) -march=rv64g -nostdinc -I. -Ikernel -c $U/initcode.S -o $U/initcode.o
|
||||
$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o $U/initcode.out $U/initcode.o
|
||||
$(OBJCOPY) -S -O binary $U/initcode.out $U/initcode
|
||||
$(OBJDUMP) -S $U/initcode.o > $U/initcode.asm
|
||||
|
||||
tags: $(OBJS) _init
|
||||
@etags *.S *.c
|
||||
|
||||
ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o
|
||||
|
||||
_%: %.o $(ULIB)
|
||||
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $@ $^
|
||||
$(OBJDUMP) -S $@ > $*.asm
|
||||
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
|
||||
|
||||
$U/usys.S : $U/usys.pl
|
||||
@perl $U/usys.pl > $U/usys.S
|
||||
|
||||
$U/usys.o : $U/usys.S
|
||||
$(CC) $(CFLAGS) -c -o $U/usys.o $U/usys.S
|
||||
|
||||
$U/_forktest: $U/forktest.o $(ULIB)
|
||||
# forktest has less library code linked in - needs to be small
|
||||
# in order to be able to max out the proc table.
|
||||
$(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $U/_forktest $U/forktest.o $U/ulib.o $U/usys.o
|
||||
$(OBJDUMP) -S $U/_forktest > $U/forktest.asm
|
||||
|
||||
mkfs/mkfs: mkfs/mkfs.c $K/fs.h $K/param.h
|
||||
@gcc -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c
|
||||
|
||||
# Prevent deletion of intermediate files, e.g. cat.o, after first build, so
|
||||
# that disk image changes after first build are persistent until clean. More
|
||||
# details:
|
||||
# http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
|
||||
.PRECIOUS: %.o
|
||||
|
||||
UPROGS=\
|
||||
$U/_cat\
|
||||
$U/_echo\
|
||||
$U/_forktest\
|
||||
$U/_grep\
|
||||
$U/_init\
|
||||
$U/_kill\
|
||||
$U/_ln\
|
||||
$U/_ls\
|
||||
$U/_mkdir\
|
||||
$U/_rm\
|
||||
$U/_sh\
|
||||
$U/_stressfs\
|
||||
$U/_usertests\
|
||||
$U/_grind\
|
||||
$U/_wc\
|
||||
$U/_zombie\
|
||||
|
||||
UEXTRA = $U/xargstest.sh
|
||||
|
||||
fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)
|
||||
@mkfs/mkfs fs.img README $(UEXTRA) $(UPROGS)
|
||||
|
||||
-include kernel/*.d user/*.d
|
||||
|
||||
SDCARD ?= /dev/sdb
|
||||
|
||||
sdcard: fs.img
|
||||
@echo "flashing into sd card..."
|
||||
@sudo dd if=/dev/zero of=$(SDCARD) bs=1M count=50
|
||||
@sudo dd if=fs.img of=$(SDCARD)
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
rm -f $K/*.o $K/*.d
|
||||
rm -rf $T/*
|
||||
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
||||
*/*.o */*.d */*.asm */*.sym \
|
||||
$U/initcode $U/initcode.out $K/kernel fs.img \
|
||||
mkfs/mkfs .gdbinit \
|
||||
$U/usys.S \
|
||||
$(UPROGS)
|
|
@ -0,0 +1,45 @@
|
|||
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
|
||||
Version 6 (v6). xv6 loosely follows the structure and style of v6,
|
||||
but is implemented for a modern RISC-V multiprocessor using ANSI C.
|
||||
|
||||
ACKNOWLEDGMENTS
|
||||
|
||||
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
|
||||
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
|
||||
2000)). See also https://pdos.csail.mit.edu/6.828/, which
|
||||
provides pointers to on-line resources for v6.
|
||||
|
||||
The following people have made contributions: Russ Cox (context switching,
|
||||
locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
|
||||
Clements.
|
||||
|
||||
We are also grateful for the bug reports and patches contributed by
|
||||
Silas Boyd-Wickizer, Anton Burtsev, Dan Cross, Cody Cutler, Mike CAT,
|
||||
Tej Chajed, Asami Doi, eyalz800, , Nelson Elhage, Saar Ettinger, Alice
|
||||
Ferrazzi, Nathaniel Filardo, Peter Froehlich, Yakir Goaron,Shivam
|
||||
Handa, Bryan Henry, jaichenhengjie, Jim Huang, Alexander Kapshuk,
|
||||
Anders Kaseorg, kehao95, Wolfgang Keller, Jonathan Kimmitt, Eddie
|
||||
Kohler, Austin Liew, Imbar Marinescu, Yandong Mao, Matan Shabtay,
|
||||
Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
|
||||
Greg Price, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
|
||||
Shigemitsu, Takahiro, Cam Tenny, tyfkda, Rafael Ubal, Warren Toomey,
|
||||
Stephen Tu, Pablo Ventura, Xi Wang, Keiichi Watanabe, Nicolas
|
||||
Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, and Zou Chang
|
||||
Wei.
|
||||
|
||||
The code in the files that constitute xv6 is
|
||||
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
|
||||
|
||||
ERROR REPORTS
|
||||
|
||||
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
||||
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
|
||||
operating system for MIT's 6.S081, so we are more interested in
|
||||
simplifications and clarifications than new features.
|
||||
|
||||
BUILDING AND RUNNING XV6
|
||||
|
||||
You will need a RISC-V "newlib" tool chain from
|
||||
https://github.com/riscv/riscv-gnu-toolchain, and qemu compiled for
|
||||
riscv64-softmmu. Once they are installed, and in your shell
|
||||
search path, you can run "make qemu".
|
|
@ -46,7 +46,7 @@ main(unsigned long hartid, unsigned long dtb_pa)
|
|||
__sync_synchronize();
|
||||
started = 1;
|
||||
|
||||
scheduler();
|
||||
// scheduler();
|
||||
|
||||
} else
|
||||
{
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define stat xv6_stat // avoid clash with host struct stat
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/param.h"
|
||||
|
||||
#ifndef static_assert
|
||||
#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0)
|
||||
#endif
|
||||
|
||||
#define NINODES 200
|
||||
|
||||
// Disk layout:
|
||||
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
|
||||
|
||||
int nbitmap = FSSIZE/(BSIZE*8) + 1;
|
||||
int ninodeblocks = NINODES / IPB + 1;
|
||||
int nlog = LOGSIZE;
|
||||
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
|
||||
int nblocks; // Number of data blocks
|
||||
|
||||
int fsfd;
|
||||
struct superblock sb;
|
||||
char zeroes[BSIZE];
|
||||
uint freeinode = 1;
|
||||
uint freeblock;
|
||||
|
||||
|
||||
void balloc(int);
|
||||
void wsect(uint, void*);
|
||||
void winode(uint, struct dinode*);
|
||||
void rinode(uint inum, struct dinode *ip);
|
||||
void rsect(uint sec, void *buf);
|
||||
uint ialloc(ushort type);
|
||||
void iappend(uint inum, void *p, int n);
|
||||
|
||||
// convert to intel byte order
|
||||
ushort
|
||||
xshort(ushort x)
|
||||
{
|
||||
ushort y;
|
||||
uchar *a = (uchar*)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint
|
||||
xint(uint x)
|
||||
{
|
||||
uint y;
|
||||
uchar *a = (uchar*)&y;
|
||||
a[0] = x;
|
||||
a[1] = x >> 8;
|
||||
a[2] = x >> 16;
|
||||
a[3] = x >> 24;
|
||||
return y;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, cc, fd;
|
||||
uint rootino, inum, off;
|
||||
struct dirent de;
|
||||
char buf[BSIZE];
|
||||
struct dinode din;
|
||||
|
||||
|
||||
static_assert(sizeof(int) == 4, "Integers must be 4 bytes!");
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(stderr, "Usage: mkfs fs.img files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert((BSIZE % sizeof(struct dinode)) == 0);
|
||||
assert((BSIZE % sizeof(struct dirent)) == 0);
|
||||
|
||||
fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||
if(fsfd < 0){
|
||||
perror(argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 1 fs block = 1 disk sector
|
||||
nmeta = 2 + nlog + ninodeblocks + nbitmap;
|
||||
nblocks = FSSIZE - nmeta;
|
||||
|
||||
sb.magic = FSMAGIC;
|
||||
sb.size = xint(FSSIZE);
|
||||
sb.nblocks = xint(nblocks);
|
||||
sb.ninodes = xint(NINODES);
|
||||
sb.nlog = xint(nlog);
|
||||
sb.logstart = xint(2);
|
||||
sb.inodestart = xint(2+nlog);
|
||||
sb.bmapstart = xint(2+nlog+ninodeblocks);
|
||||
|
||||
printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
|
||||
nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
|
||||
|
||||
freeblock = nmeta; // the first free block that we can allocate
|
||||
|
||||
for(i = 0; i < FSSIZE; i++)
|
||||
wsect(i, zeroes);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memmove(buf, &sb, sizeof(sb));
|
||||
wsect(1, buf);
|
||||
|
||||
rootino = ialloc(T_DIR);
|
||||
assert(rootino == ROOTINO);
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, ".");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(rootino);
|
||||
strcpy(de.name, "..");
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
for(i = 2; i < argc; i++){
|
||||
// get rid of "user/"
|
||||
char *shortname;
|
||||
if(strncmp(argv[i], "xv6-user/", 9) == 0)
|
||||
shortname = argv[i] + 9;
|
||||
else
|
||||
shortname = argv[i];
|
||||
|
||||
assert(index(shortname, '/') == 0);
|
||||
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
perror(argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Skip leading _ in name when writing to file system.
|
||||
// The binaries are named _rm, _cat, etc. to keep the
|
||||
// build operating system from trying to execute them
|
||||
// in place of system binaries like rm and cat.
|
||||
if(shortname[0] == '_')
|
||||
shortname += 1;
|
||||
|
||||
inum = ialloc(T_FILE);
|
||||
|
||||
bzero(&de, sizeof(de));
|
||||
de.inum = xshort(inum);
|
||||
strncpy(de.name, shortname, DIRSIZ);
|
||||
iappend(rootino, &de, sizeof(de));
|
||||
|
||||
while((cc = read(fd, buf, sizeof(buf))) > 0)
|
||||
iappend(inum, buf, cc);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// fix size of root inode dir
|
||||
rinode(rootino, &din);
|
||||
off = xint(din.size);
|
||||
off = ((off/BSIZE) + 1) * BSIZE;
|
||||
din.size = xint(off);
|
||||
winode(rootino, &din);
|
||||
|
||||
balloc(freeblock);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
wsect(uint sec, void *buf)
|
||||
{
|
||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
|
||||
perror("lseek");
|
||||
exit(1);
|
||||
}
|
||||
if(write(fsfd, buf, BSIZE) != BSIZE){
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
winode(uint inum, struct dinode *ip)
|
||||
{
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
||||
*dip = *ip;
|
||||
wsect(bn, buf);
|
||||
}
|
||||
|
||||
void
|
||||
rinode(uint inum, struct dinode *ip)
|
||||
{
|
||||
char buf[BSIZE];
|
||||
uint bn;
|
||||
struct dinode *dip;
|
||||
|
||||
bn = IBLOCK(inum, sb);
|
||||
rsect(bn, buf);
|
||||
dip = ((struct dinode*)buf) + (inum % IPB);
|
||||
*ip = *dip;
|
||||
}
|
||||
|
||||
void
|
||||
rsect(uint sec, void *buf)
|
||||
{
|
||||
if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE){
|
||||
perror("lseek");
|
||||
exit(1);
|
||||
}
|
||||
if(read(fsfd, buf, BSIZE) != BSIZE){
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint
|
||||
ialloc(ushort type)
|
||||
{
|
||||
uint inum = freeinode++;
|
||||
struct dinode din;
|
||||
|
||||
bzero(&din, sizeof(din));
|
||||
din.type = xshort(type);
|
||||
din.nlink = xshort(1);
|
||||
din.size = xint(0);
|
||||
winode(inum, &din);
|
||||
return inum;
|
||||
}
|
||||
|
||||
void
|
||||
balloc(int used)
|
||||
{
|
||||
uchar buf[BSIZE];
|
||||
int i;
|
||||
|
||||
printf("balloc: first %d blocks have been allocated\n", used);
|
||||
assert(used < BSIZE*8);
|
||||
bzero(buf, BSIZE);
|
||||
for(i = 0; i < used; i++){
|
||||
buf[i/8] = buf[i/8] | (0x1 << (i%8));
|
||||
}
|
||||
printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
|
||||
wsect(sb.bmapstart, buf);
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
void
|
||||
iappend(uint inum, void *xp, int n)
|
||||
{
|
||||
char *p = (char*)xp;
|
||||
uint fbn, off, n1;
|
||||
struct dinode din;
|
||||
char buf[BSIZE];
|
||||
uint indirect[NINDIRECT];
|
||||
uint x;
|
||||
|
||||
rinode(inum, &din);
|
||||
off = xint(din.size);
|
||||
// printf("append inum %d at off %d sz %d\n", inum, off, n);
|
||||
while(n > 0){
|
||||
fbn = off / BSIZE;
|
||||
assert(fbn < MAXFILE);
|
||||
if(fbn < NDIRECT){
|
||||
if(xint(din.addrs[fbn]) == 0){
|
||||
din.addrs[fbn] = xint(freeblock++);
|
||||
}
|
||||
x = xint(din.addrs[fbn]);
|
||||
} else {
|
||||
if(xint(din.addrs[NDIRECT]) == 0){
|
||||
din.addrs[NDIRECT] = xint(freeblock++);
|
||||
}
|
||||
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
||||
if(indirect[fbn - NDIRECT] == 0){
|
||||
indirect[fbn - NDIRECT] = xint(freeblock++);
|
||||
wsect(xint(din.addrs[NDIRECT]), (char*)indirect);
|
||||
}
|
||||
x = xint(indirect[fbn-NDIRECT]);
|
||||
}
|
||||
n1 = min(n, (fbn + 1) * BSIZE - off);
|
||||
rsect(x, buf);
|
||||
bcopy(p, buf + off - (fbn * BSIZE), n1);
|
||||
wsect(x, buf);
|
||||
n -= n1;
|
||||
off += n1;
|
||||
p += n1;
|
||||
}
|
||||
din.size = xint(off);
|
||||
winode(inum, &din);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
char buf[512];
|
||||
|
||||
void
|
||||
cat(int fd)
|
||||
{
|
||||
int n;
|
||||
|
||||
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
if (write(1, buf, n) != n) {
|
||||
fprintf(2, "cat: write error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(n < 0){
|
||||
fprintf(2, "cat: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
|
||||
if(argc <= 1){
|
||||
cat(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
cat(fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
write(1, argv[i], strlen(argv[i]));
|
||||
if(i + 1 < argc){
|
||||
write(1, " ", 1);
|
||||
} else {
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// Test that fork fails gracefully.
|
||||
// Tiny executable so that the limit can be filling the proc table.
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
#define N 1000
|
||||
|
||||
void
|
||||
print(const char *s)
|
||||
{
|
||||
write(1, s, strlen(s));
|
||||
}
|
||||
|
||||
void
|
||||
forktest(void)
|
||||
{
|
||||
int n, pid;
|
||||
|
||||
print("fork test\n");
|
||||
|
||||
for(n=0; n<N; n++){
|
||||
pid = fork();
|
||||
if(pid < 0)
|
||||
break;
|
||||
if(pid == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(n == N){
|
||||
print("fork claimed to work N times!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(; n > 0; n--){
|
||||
if(wait(0) < 0){
|
||||
print("wait stopped early\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(wait(0) != -1){
|
||||
print("wait got too many\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print("fork test OK\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
forktest();
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Simple grep. Only supports ^ . * $ operators.
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
char buf[1024];
|
||||
int match(char*, char*);
|
||||
|
||||
void
|
||||
grep(char *pattern, int fd)
|
||||
{
|
||||
int n, m;
|
||||
char *p, *q;
|
||||
|
||||
m = 0;
|
||||
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
|
||||
m += n;
|
||||
buf[m] = '\0';
|
||||
p = buf;
|
||||
while((q = strchr(p, '\n')) != 0){
|
||||
*q = 0;
|
||||
if(match(pattern, p)){
|
||||
*q = '\n';
|
||||
write(1, p, q+1 - p);
|
||||
}
|
||||
p = q+1;
|
||||
}
|
||||
if(m > 0){
|
||||
m -= p - buf;
|
||||
memmove(buf, p, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
char *pattern;
|
||||
|
||||
if(argc <= 1){
|
||||
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
pattern = argv[1];
|
||||
|
||||
if(argc <= 2){
|
||||
grep(pattern, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 2; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
printf("grep: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
grep(pattern, fd);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Regexp matcher from Kernighan & Pike,
|
||||
// The Practice of Programming, Chapter 9.
|
||||
|
||||
int matchhere(char*, char*);
|
||||
int matchstar(int, char*, char*);
|
||||
|
||||
int
|
||||
match(char *re, char *text)
|
||||
{
|
||||
if(re[0] == '^')
|
||||
return matchhere(re+1, text);
|
||||
do{ // must look at empty string
|
||||
if(matchhere(re, text))
|
||||
return 1;
|
||||
}while(*text++ != '\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// matchhere: search for re at beginning of text
|
||||
int matchhere(char *re, char *text)
|
||||
{
|
||||
if(re[0] == '\0')
|
||||
return 1;
|
||||
if(re[1] == '*')
|
||||
return matchstar(re[0], re+2, text);
|
||||
if(re[0] == '$' && re[1] == '\0')
|
||||
return *text == '\0';
|
||||
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
|
||||
return matchhere(re+1, text+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// matchstar: search for c*re at beginning of text
|
||||
int matchstar(int c, char *re, char *text)
|
||||
{
|
||||
do{ // a * matches zero or more instances
|
||||
if(matchhere(re, text))
|
||||
return 1;
|
||||
}while(*text!='\0' && (*text++==c || c=='.'));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
//
|
||||
// run random system calls in parallel forever.
|
||||
//
|
||||
|
||||
#include "kernel/param.h"
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "kernel/syscall.h"
|
||||
#include "kernel/memlayout.h"
|
||||
#include "kernel/riscv.h"
|
||||
|
||||
// from FreeBSD.
|
||||
int
|
||||
do_rand(unsigned long *ctx)
|
||||
{
|
||||
/*
|
||||
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||
* without overflowing 31 bits:
|
||||
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||
* From "Random number generators: good ones are hard to find",
|
||||
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||
* October 1988, p. 1195.
|
||||
*/
|
||||
long hi, lo, x;
|
||||
|
||||
/* Transform to [1, 0x7ffffffe] range. */
|
||||
x = (*ctx % 0x7ffffffe) + 1;
|
||||
hi = x / 127773;
|
||||
lo = x % 127773;
|
||||
x = 16807 * lo - 2836 * hi;
|
||||
if (x < 0)
|
||||
x += 0x7fffffff;
|
||||
/* Transform to [0, 0x7ffffffd] range. */
|
||||
x--;
|
||||
*ctx = x;
|
||||
return (x);
|
||||
}
|
||||
|
||||
unsigned long rand_next = 1;
|
||||
|
||||
int
|
||||
rand(void)
|
||||
{
|
||||
return (do_rand(&rand_next));
|
||||
}
|
||||
|
||||
void
|
||||
go(int which_child)
|
||||
{
|
||||
int fd = -1;
|
||||
static char buf[999];
|
||||
char *break0 = sbrk(0);
|
||||
uint64 iters = 0;
|
||||
|
||||
mkdir("grindir");
|
||||
if(chdir("grindir") != 0){
|
||||
printf("chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
chdir("/");
|
||||
|
||||
while(1){
|
||||
iters++;
|
||||
if((iters % 500) == 0)
|
||||
write(1, which_child?"B":"A", 1);
|
||||
int what = rand() % 23;
|
||||
if(what == 1){
|
||||
close(open("grindir/../a", O_CREATE|O_RDWR));
|
||||
} else if(what == 2){
|
||||
close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
|
||||
} else if(what == 3){
|
||||
unlink("grindir/../a");
|
||||
} else if(what == 4){
|
||||
if(chdir("grindir") != 0){
|
||||
printf("chdir grindir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
unlink("../b");
|
||||
chdir("/");
|
||||
} else if(what == 5){
|
||||
close(fd);
|
||||
fd = open("/grindir/../a", O_CREATE|O_RDWR);
|
||||
} else if(what == 6){
|
||||
close(fd);
|
||||
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
|
||||
} else if(what == 7){
|
||||
write(fd, buf, sizeof(buf));
|
||||
} else if(what == 8){
|
||||
read(fd, buf, sizeof(buf));
|
||||
} else if(what == 9){
|
||||
mkdir("grindir/../a");
|
||||
close(open("a/../a/./a", O_CREATE|O_RDWR));
|
||||
unlink("a/a");
|
||||
} else if(what == 10){
|
||||
mkdir("/../b");
|
||||
close(open("grindir/../b/b", O_CREATE|O_RDWR));
|
||||
unlink("b/b");
|
||||
} else if(what == 11){
|
||||
unlink("b");
|
||||
link("../grindir/./../a", "../b");
|
||||
} else if(what == 12){
|
||||
unlink("../grindir/../a");
|
||||
link(".././b", "/grindir/../a");
|
||||
} else if(what == 13){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 14){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
fork();
|
||||
fork();
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 15){
|
||||
sbrk(6011);
|
||||
} else if(what == 16){
|
||||
if(sbrk(0) > break0)
|
||||
sbrk(-(sbrk(0) - break0));
|
||||
} else if(what == 17){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
close(open("a", O_CREATE|O_RDWR));
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(chdir("../grindir/..") != 0){
|
||||
printf("chdir failed\n");
|
||||
exit(1);
|
||||
}
|
||||
kill(pid);
|
||||
wait(0);
|
||||
} else if(what == 18){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
kill(getpid());
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 19){
|
||||
int fds[2];
|
||||
if(pipe(fds) < 0){
|
||||
printf("grind: pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
fork();
|
||||
fork();
|
||||
if(write(fds[1], "x", 1) != 1)
|
||||
printf("grind: pipe write failed\n");
|
||||
char c;
|
||||
if(read(fds[0], &c, 1) != 1)
|
||||
printf("grind: pipe read failed\n");
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
wait(0);
|
||||
} else if(what == 20){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
unlink("a");
|
||||
mkdir("a");
|
||||
chdir("a");
|
||||
unlink("../a");
|
||||
fd = open("x", O_CREATE|O_RDWR);
|
||||
unlink("x");
|
||||
exit(0);
|
||||
} else if(pid < 0){
|
||||
printf("fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
wait(0);
|
||||
} else if(what == 21){
|
||||
unlink("c");
|
||||
// should always succeed. check that there are free i-nodes,
|
||||
// file descriptors, blocks.
|
||||
int fd1 = open("c", O_CREATE|O_RDWR);
|
||||
if(fd1 < 0){
|
||||
printf("create c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(write(fd1, "x", 1) != 1){
|
||||
printf("write c failed\n");
|
||||
exit(1);
|
||||
}
|
||||
struct stat st;
|
||||
if(fstat(fd1, &st) != 0){
|
||||
printf("fstat failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(st.size != 1){
|
||||
printf("fstat reports wrong size %d\n", (int)st.size);
|
||||
exit(1);
|
||||
}
|
||||
if(st.ino > 200){
|
||||
printf("fstat reports crazy i-number %d\n", st.ino);
|
||||
exit(1);
|
||||
}
|
||||
close(fd1);
|
||||
unlink("c");
|
||||
} else if(what == 22){
|
||||
// echo hi | cat
|
||||
int aa[2], bb[2];
|
||||
if(pipe(aa) < 0){
|
||||
fprintf(2, "pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pipe(bb) < 0){
|
||||
fprintf(2, "pipe failed\n");
|
||||
exit(1);
|
||||
}
|
||||
int pid1 = fork();
|
||||
if(pid1 == 0){
|
||||
close(bb[0]);
|
||||
close(bb[1]);
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if(dup(aa[1]) != 1){
|
||||
fprintf(2, "dup failed\n");
|
||||
exit(1);
|
||||
}
|
||||
close(aa[1]);
|
||||
char *args[3] = { "echo", "hi", 0 };
|
||||
exec("grindir/../echo", args);
|
||||
fprintf(2, "echo: not found\n");
|
||||
exit(2);
|
||||
} else if(pid1 < 0){
|
||||
fprintf(2, "fork failed\n");
|
||||
exit(3);
|
||||
}
|
||||
int pid2 = fork();
|
||||
if(pid2 == 0){
|
||||
close(aa[1]);
|
||||
close(bb[0]);
|
||||
close(0);
|
||||
if(dup(aa[0]) != 0){
|
||||
fprintf(2, "dup failed\n");
|
||||
exit(4);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(1);
|
||||
if(dup(bb[1]) != 1){
|
||||
fprintf(2, "dup failed\n");
|
||||
exit(5);
|
||||
}
|
||||
close(bb[1]);
|
||||
char *args[2] = { "cat", 0 };
|
||||
exec("/cat", args);
|
||||
fprintf(2, "cat: not found\n");
|
||||
exit(6);
|
||||
} else if(pid2 < 0){
|
||||
fprintf(2, "fork failed\n");
|
||||
exit(7);
|
||||
}
|
||||
close(aa[0]);
|
||||
close(aa[1]);
|
||||
close(bb[1]);
|
||||
char buf[3] = { 0, 0, 0 };
|
||||
read(bb[0], buf+0, 1);
|
||||
read(bb[0], buf+1, 1);
|
||||
close(bb[0]);
|
||||
int st1, st2;
|
||||
wait(&st1);
|
||||
wait(&st2);
|
||||
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi") != 0){
|
||||
printf("exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
iter()
|
||||
{
|
||||
unlink("a");
|
||||
unlink("b");
|
||||
|
||||
int pid1 = fork();
|
||||
if(pid1 < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid1 == 0){
|
||||
rand_next = 31;
|
||||
go(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int pid2 = fork();
|
||||
if(pid2 < 0){
|
||||
printf("grind: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid2 == 0){
|
||||
rand_next = 7177;
|
||||
go(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int st1 = -1;
|
||||
wait(&st1);
|
||||
if(st1 != 0){
|
||||
kill(pid1);
|
||||
kill(pid2);
|
||||
}
|
||||
int st2 = -1;
|
||||
wait(&st2);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
while(1){
|
||||
int pid = fork();
|
||||
if(pid == 0){
|
||||
iter();
|
||||
exit(0);
|
||||
}
|
||||
if(pid > 0){
|
||||
wait(0);
|
||||
}
|
||||
sleep(20);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// init: The initial user-level program
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/spinlock.h"
|
||||
#include "kernel/sleeplock.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/file.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
char *argv[] = { "sh", 0 };
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int pid, wpid;
|
||||
|
||||
if(open("console", O_RDWR) < 0){
|
||||
mknod("console", CONSOLE, 0);
|
||||
open("console", O_RDWR);
|
||||
}
|
||||
dup(0); // stdout
|
||||
dup(0); // stderr
|
||||
|
||||
for(;;){
|
||||
printf("init: starting sh\n");
|
||||
pid = fork();
|
||||
if(pid < 0){
|
||||
printf("init: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid == 0){
|
||||
exec("sh", argv);
|
||||
printf("init: exec sh failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(;;){
|
||||
// this call to wait() returns if the shell exits,
|
||||
// or if a parentless process exits.
|
||||
wpid = wait((int *) 0);
|
||||
if(wpid == pid){
|
||||
// the shell exited; restart it.
|
||||
break;
|
||||
} else if(wpid < 0){
|
||||
printf("init: wait returned an error\n");
|
||||
exit(1);
|
||||
} else {
|
||||
// it was a parentless process; do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
# Initial process that execs /init.
|
||||
# This code runs in user space.
|
||||
|
||||
#include "syscall.h"
|
||||
|
||||
# exec(init, argv)
|
||||
.globl start
|
||||
start:
|
||||
la a0, init
|
||||
la a1, argv
|
||||
li a7, SYS_exec
|
||||
ecall
|
||||
|
||||
# for(;;) exit();
|
||||
exit:
|
||||
li a7, SYS_exit
|
||||
ecall
|
||||
jal exit
|
||||
|
||||
# char init[] = "/init\0";
|
||||
init:
|
||||
.string "/init\0"
|
||||
|
||||
# char *argv[] = { init, 0 };
|
||||
.p2align 2
|
||||
argv:
|
||||
.long init
|
||||
.long 0
|
|
@ -0,0 +1,17 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "usage: kill pid...\n");
|
||||
exit(1);
|
||||
}
|
||||
for(i=1; i<argc; i++)
|
||||
kill(atoi(argv[i]));
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if(argc != 3){
|
||||
fprintf(2, "Usage: ln old new\n");
|
||||
exit(1);
|
||||
}
|
||||
if(link(argv[1], argv[2]) < 0)
|
||||
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/fs.h"
|
||||
|
||||
char*
|
||||
fmtname(char *path)
|
||||
{
|
||||
static char buf[DIRSIZ+1];
|
||||
char *p;
|
||||
|
||||
// Find first character after last slash.
|
||||
for(p=path+strlen(path); p >= path && *p != '/'; p--)
|
||||
;
|
||||
p++;
|
||||
|
||||
// Return blank-padded name.
|
||||
if(strlen(p) >= DIRSIZ)
|
||||
return p;
|
||||
memmove(buf, p, strlen(p));
|
||||
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
ls(char *path)
|
||||
{
|
||||
char buf[512], *p;
|
||||
int fd;
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
|
||||
if((fd = open(path, 0)) < 0){
|
||||
fprintf(2, "ls: cannot open %s\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fstat(fd, &st) < 0){
|
||||
fprintf(2, "ls: cannot stat %s\n", path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(st.type){
|
||||
case T_FILE:
|
||||
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
|
||||
break;
|
||||
|
||||
case T_DIR:
|
||||
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
|
||||
printf("ls: path too long\n");
|
||||
break;
|
||||
}
|
||||
strcpy(buf, path);
|
||||
p = buf+strlen(buf);
|
||||
*p++ = '/';
|
||||
while(read(fd, &de, sizeof(de)) == sizeof(de)){
|
||||
if(de.inum == 0)
|
||||
continue;
|
||||
memmove(p, de.name, DIRSIZ);
|
||||
p[DIRSIZ] = 0;
|
||||
if(stat(buf, &st) < 0){
|
||||
printf("ls: cannot stat %s\n", buf);
|
||||
continue;
|
||||
}
|
||||
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
ls(".");
|
||||
exit(0);
|
||||
}
|
||||
for(i=1; i<argc; i++)
|
||||
ls(argv[i]);
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "Usage: mkdir files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if(mkdir(argv[i]) < 0){
|
||||
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static char digits[] = "0123456789ABCDEF";
|
||||
|
||||
static void
|
||||
putc(int fd, char c)
|
||||
{
|
||||
write(fd, &c, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
printint(int fd, int xx, int base, int sgn)
|
||||
{
|
||||
char buf[16];
|
||||
int i, neg;
|
||||
uint x;
|
||||
|
||||
neg = 0;
|
||||
if(sgn && xx < 0){
|
||||
neg = 1;
|
||||
x = -xx;
|
||||
} else {
|
||||
x = xx;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do{
|
||||
buf[i++] = digits[x % base];
|
||||
}while((x /= base) != 0);
|
||||
if(neg)
|
||||
buf[i++] = '-';
|
||||
|
||||
while(--i >= 0)
|
||||
putc(fd, buf[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
printptr(int fd, uint64 x) {
|
||||
int i;
|
||||
putc(fd, '0');
|
||||
putc(fd, 'x');
|
||||
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||
putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||
}
|
||||
|
||||
// Print to the given fd. Only understands %d, %x, %p, %s.
|
||||
void
|
||||
vprintf(int fd, const char *fmt, va_list ap)
|
||||
{
|
||||
char *s;
|
||||
int c, i, state;
|
||||
|
||||
state = 0;
|
||||
for(i = 0; fmt[i]; i++){
|
||||
c = fmt[i] & 0xff;
|
||||
if(state == 0){
|
||||
if(c == '%'){
|
||||
state = '%';
|
||||
} else {
|
||||
putc(fd, c);
|
||||
}
|
||||
} else if(state == '%'){
|
||||
if(c == 'd'){
|
||||
printint(fd, va_arg(ap, int), 10, 1);
|
||||
} else if(c == 'l') {
|
||||
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||
} else if(c == 'x') {
|
||||
printint(fd, va_arg(ap, int), 16, 0);
|
||||
} else if(c == 'p') {
|
||||
printptr(fd, va_arg(ap, uint64));
|
||||
} else if(c == 's'){
|
||||
s = va_arg(ap, char*);
|
||||
if(s == 0)
|
||||
s = "(null)";
|
||||
while(*s != 0){
|
||||
putc(fd, *s);
|
||||
s++;
|
||||
}
|
||||
} else if(c == 'c'){
|
||||
putc(fd, va_arg(ap, uint));
|
||||
} else if(c == '%'){
|
||||
putc(fd, c);
|
||||
} else {
|
||||
// Unknown % sequence. Print it to draw attention.
|
||||
putc(fd, '%');
|
||||
putc(fd, c);
|
||||
}
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fprintf(int fd, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fd, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(1, fmt, ap);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(2, "Usage: rm files...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if(unlink(argv[i]) < 0){
|
||||
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,493 @@
|
|||
// Shell.
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
// Parsed command representation
|
||||
#define EXEC 1
|
||||
#define REDIR 2
|
||||
#define PIPE 3
|
||||
#define LIST 4
|
||||
#define BACK 5
|
||||
|
||||
#define MAXARGS 10
|
||||
|
||||
struct cmd {
|
||||
int type;
|
||||
};
|
||||
|
||||
struct execcmd {
|
||||
int type;
|
||||
char *argv[MAXARGS];
|
||||
char *eargv[MAXARGS];
|
||||
};
|
||||
|
||||
struct redircmd {
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
char *file;
|
||||
char *efile;
|
||||
int mode;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct pipecmd {
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
};
|
||||
|
||||
struct listcmd {
|
||||
int type;
|
||||
struct cmd *left;
|
||||
struct cmd *right;
|
||||
};
|
||||
|
||||
struct backcmd {
|
||||
int type;
|
||||
struct cmd *cmd;
|
||||
};
|
||||
|
||||
int fork1(void); // Fork but panics on failure.
|
||||
void panic(char*);
|
||||
struct cmd *parsecmd(char*);
|
||||
|
||||
// Execute cmd. Never returns.
|
||||
void
|
||||
runcmd(struct cmd *cmd)
|
||||
{
|
||||
int p[2];
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
|
||||
if(cmd == 0)
|
||||
exit(1);
|
||||
|
||||
switch(cmd->type){
|
||||
default:
|
||||
panic("runcmd");
|
||||
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd*)cmd;
|
||||
if(ecmd->argv[0] == 0)
|
||||
exit(1);
|
||||
exec(ecmd->argv[0], ecmd->argv);
|
||||
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
|
||||
break;
|
||||
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd*)cmd;
|
||||
close(rcmd->fd);
|
||||
if(open(rcmd->file, rcmd->mode) < 0){
|
||||
fprintf(2, "open %s failed\n", rcmd->file);
|
||||
exit(1);
|
||||
}
|
||||
runcmd(rcmd->cmd);
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
lcmd = (struct listcmd*)cmd;
|
||||
if(fork1() == 0)
|
||||
runcmd(lcmd->left);
|
||||
wait(0);
|
||||
runcmd(lcmd->right);
|
||||
break;
|
||||
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd*)cmd;
|
||||
if(pipe(p) < 0)
|
||||
panic("pipe");
|
||||
if(fork1() == 0){
|
||||
close(1);
|
||||
dup(p[1]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->left);
|
||||
}
|
||||
if(fork1() == 0){
|
||||
close(0);
|
||||
dup(p[0]);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
runcmd(pcmd->right);
|
||||
}
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
wait(0);
|
||||
wait(0);
|
||||
break;
|
||||
|
||||
case BACK:
|
||||
bcmd = (struct backcmd*)cmd;
|
||||
if(fork1() == 0)
|
||||
runcmd(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
getcmd(char *buf, int nbuf)
|
||||
{
|
||||
fprintf(2, "$ ");
|
||||
memset(buf, 0, nbuf);
|
||||
gets(buf, nbuf);
|
||||
if(buf[0] == 0) // EOF
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
static char buf[100];
|
||||
int fd;
|
||||
|
||||
// Ensure that three file descriptors are open.
|
||||
while((fd = open("console", O_RDWR)) >= 0){
|
||||
if(fd >= 3){
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read and run input commands.
|
||||
while(getcmd(buf, sizeof(buf)) >= 0){
|
||||
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
|
||||
// Chdir must be called by the parent, not the child.
|
||||
buf[strlen(buf)-1] = 0; // chop \n
|
||||
if(chdir(buf+3) < 0)
|
||||
fprintf(2, "cannot cd %s\n", buf+3);
|
||||
continue;
|
||||
}
|
||||
if(fork1() == 0)
|
||||
runcmd(parsecmd(buf));
|
||||
wait(0);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
panic(char *s)
|
||||
{
|
||||
fprintf(2, "%s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
fork1(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1)
|
||||
panic("fork");
|
||||
return pid;
|
||||
}
|
||||
|
||||
//PAGEBREAK!
|
||||
// Constructors
|
||||
|
||||
struct cmd*
|
||||
execcmd(void)
|
||||
{
|
||||
struct execcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = EXEC;
|
||||
return (struct cmd*)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
|
||||
{
|
||||
struct redircmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = REDIR;
|
||||
cmd->cmd = subcmd;
|
||||
cmd->file = file;
|
||||
cmd->efile = efile;
|
||||
cmd->mode = mode;
|
||||
cmd->fd = fd;
|
||||
return (struct cmd*)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
pipecmd(struct cmd *left, struct cmd *right)
|
||||
{
|
||||
struct pipecmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = PIPE;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd*)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
listcmd(struct cmd *left, struct cmd *right)
|
||||
{
|
||||
struct listcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = LIST;
|
||||
cmd->left = left;
|
||||
cmd->right = right;
|
||||
return (struct cmd*)cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
backcmd(struct cmd *subcmd)
|
||||
{
|
||||
struct backcmd *cmd;
|
||||
|
||||
cmd = malloc(sizeof(*cmd));
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->type = BACK;
|
||||
cmd->cmd = subcmd;
|
||||
return (struct cmd*)cmd;
|
||||
}
|
||||
//PAGEBREAK!
|
||||
// Parsing
|
||||
|
||||
char whitespace[] = " \t\r\n\v";
|
||||
char symbols[] = "<|>&;()";
|
||||
|
||||
int
|
||||
gettoken(char **ps, char *es, char **q, char **eq)
|
||||
{
|
||||
char *s;
|
||||
int ret;
|
||||
|
||||
s = *ps;
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
if(q)
|
||||
*q = s;
|
||||
ret = *s;
|
||||
switch(*s){
|
||||
case 0:
|
||||
break;
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case '&':
|
||||
case '<':
|
||||
s++;
|
||||
break;
|
||||
case '>':
|
||||
s++;
|
||||
if(*s == '>'){
|
||||
ret = '+';
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = 'a';
|
||||
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
if(eq)
|
||||
*eq = s;
|
||||
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
peek(char **ps, char *es, char *toks)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = *ps;
|
||||
while(s < es && strchr(whitespace, *s))
|
||||
s++;
|
||||
*ps = s;
|
||||
return *s && strchr(toks, *s);
|
||||
}
|
||||
|
||||
struct cmd *parseline(char**, char*);
|
||||
struct cmd *parsepipe(char**, char*);
|
||||
struct cmd *parseexec(char**, char*);
|
||||
struct cmd *nulterminate(struct cmd*);
|
||||
|
||||
struct cmd*
|
||||
parsecmd(char *s)
|
||||
{
|
||||
char *es;
|
||||
struct cmd *cmd;
|
||||
|
||||
es = s + strlen(s);
|
||||
cmd = parseline(&s, es);
|
||||
peek(&s, es, "");
|
||||
if(s != es){
|
||||
fprintf(2, "leftovers: %s\n", s);
|
||||
panic("syntax");
|
||||
}
|
||||
nulterminate(cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseline(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
cmd = parsepipe(ps, es);
|
||||
while(peek(ps, es, "&")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = backcmd(cmd);
|
||||
}
|
||||
if(peek(ps, es, ";")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = listcmd(cmd, parseline(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parsepipe(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
cmd = parseexec(ps, es);
|
||||
if(peek(ps, es, "|")){
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = pipecmd(cmd, parsepipe(ps, es));
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseredirs(struct cmd *cmd, char **ps, char *es)
|
||||
{
|
||||
int tok;
|
||||
char *q, *eq;
|
||||
|
||||
while(peek(ps, es, "<>")){
|
||||
tok = gettoken(ps, es, 0, 0);
|
||||
if(gettoken(ps, es, &q, &eq) != 'a')
|
||||
panic("missing file for redirection");
|
||||
switch(tok){
|
||||
case '<':
|
||||
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
||||
break;
|
||||
case '>':
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
|
||||
break;
|
||||
case '+': // >>
|
||||
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseblock(char **ps, char *es)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
if(!peek(ps, es, "("))
|
||||
panic("parseblock");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseline(ps, es);
|
||||
if(!peek(ps, es, ")"))
|
||||
panic("syntax - missing )");
|
||||
gettoken(ps, es, 0, 0);
|
||||
cmd = parseredirs(cmd, ps, es);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct cmd*
|
||||
parseexec(char **ps, char *es)
|
||||
{
|
||||
char *q, *eq;
|
||||
int tok, argc;
|
||||
struct execcmd *cmd;
|
||||
struct cmd *ret;
|
||||
|
||||
if(peek(ps, es, "("))
|
||||
return parseblock(ps, es);
|
||||
|
||||
ret = execcmd();
|
||||
cmd = (struct execcmd*)ret;
|
||||
|
||||
argc = 0;
|
||||
ret = parseredirs(ret, ps, es);
|
||||
while(!peek(ps, es, "|)&;")){
|
||||
if((tok=gettoken(ps, es, &q, &eq)) == 0)
|
||||
break;
|
||||
if(tok != 'a')
|
||||
panic("syntax");
|
||||
cmd->argv[argc] = q;
|
||||
cmd->eargv[argc] = eq;
|
||||
argc++;
|
||||
if(argc >= MAXARGS)
|
||||
panic("too many args");
|
||||
ret = parseredirs(ret, ps, es);
|
||||
}
|
||||
cmd->argv[argc] = 0;
|
||||
cmd->eargv[argc] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NUL-terminate all the counted strings.
|
||||
struct cmd*
|
||||
nulterminate(struct cmd *cmd)
|
||||
{
|
||||
int i;
|
||||
struct backcmd *bcmd;
|
||||
struct execcmd *ecmd;
|
||||
struct listcmd *lcmd;
|
||||
struct pipecmd *pcmd;
|
||||
struct redircmd *rcmd;
|
||||
|
||||
if(cmd == 0)
|
||||
return 0;
|
||||
|
||||
switch(cmd->type){
|
||||
case EXEC:
|
||||
ecmd = (struct execcmd*)cmd;
|
||||
for(i=0; ecmd->argv[i]; i++)
|
||||
*ecmd->eargv[i] = 0;
|
||||
break;
|
||||
|
||||
case REDIR:
|
||||
rcmd = (struct redircmd*)cmd;
|
||||
nulterminate(rcmd->cmd);
|
||||
*rcmd->efile = 0;
|
||||
break;
|
||||
|
||||
case PIPE:
|
||||
pcmd = (struct pipecmd*)cmd;
|
||||
nulterminate(pcmd->left);
|
||||
nulterminate(pcmd->right);
|
||||
break;
|
||||
|
||||
case LIST:
|
||||
lcmd = (struct listcmd*)cmd;
|
||||
nulterminate(lcmd->left);
|
||||
nulterminate(lcmd->right);
|
||||
break;
|
||||
|
||||
case BACK:
|
||||
bcmd = (struct backcmd*)cmd;
|
||||
nulterminate(bcmd->cmd);
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Demonstrate that moving the "acquire" in iderw after the loop that
|
||||
// appends to the idequeue results in a race.
|
||||
|
||||
// For this to work, you should also add a spin within iderw's
|
||||
// idequeue traversal loop. Adding the following demonstrated a panic
|
||||
// after about 5 runs of stressfs in QEMU on a 2.1GHz CPU:
|
||||
// for (i = 0; i < 40000; i++)
|
||||
// asm volatile("");
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
char path[] = "stressfs0";
|
||||
char data[512];
|
||||
|
||||
printf("stressfs starting\n");
|
||||
memset(data, 'a', sizeof(data));
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
if(fork() > 0)
|
||||
break;
|
||||
|
||||
printf("write %d\n", i);
|
||||
|
||||
path[8] += i;
|
||||
fd = open(path, O_CREATE | O_RDWR);
|
||||
for(i = 0; i < 20; i++)
|
||||
// printf(fd, "%d\n", i);
|
||||
write(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
|
||||
printf("read\n");
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
for (i = 0; i < 20; i++)
|
||||
read(fd, data, sizeof(data));
|
||||
close(fd);
|
||||
|
||||
wait(0);
|
||||
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
char*
|
||||
strcpy(char *s, const char *t)
|
||||
{
|
||||
char *os;
|
||||
|
||||
os = s;
|
||||
while((*s++ = *t++) != 0)
|
||||
;
|
||||
return os;
|
||||
}
|
||||
|
||||
int
|
||||
strcmp(const char *p, const char *q)
|
||||
{
|
||||
while(*p && *p == *q)
|
||||
p++, q++;
|
||||
return (uchar)*p - (uchar)*q;
|
||||
}
|
||||
|
||||
uint
|
||||
strlen(const char *s)
|
||||
{
|
||||
int n;
|
||||
|
||||
for(n = 0; s[n]; n++)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
void*
|
||||
memset(void *dst, int c, uint n)
|
||||
{
|
||||
char *cdst = (char *) dst;
|
||||
int i;
|
||||
for(i = 0; i < n; i++){
|
||||
cdst[i] = c;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char*
|
||||
strchr(const char *s, char c)
|
||||
{
|
||||
for(; *s; s++)
|
||||
if(*s == c)
|
||||
return (char*)s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
gets(char *buf, int max)
|
||||
{
|
||||
int i, cc;
|
||||
char c;
|
||||
|
||||
for(i=0; i+1 < max; ){
|
||||
cc = read(0, &c, 1);
|
||||
if(cc < 1)
|
||||
break;
|
||||
buf[i++] = c;
|
||||
if(c == '\n' || c == '\r')
|
||||
break;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
stat(const char *n, struct stat *st)
|
||||
{
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
fd = open(n, O_RDONLY);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
r = fstat(fd, st);
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
atoi(const char *s)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
while('0' <= *s && *s <= '9')
|
||||
n = n*10 + *s++ - '0';
|
||||
return n;
|
||||
}
|
||||
|
||||
void*
|
||||
memmove(void *vdst, const void *vsrc, int n)
|
||||
{
|
||||
char *dst;
|
||||
const char *src;
|
||||
|
||||
dst = vdst;
|
||||
src = vsrc;
|
||||
if (src > dst) {
|
||||
while(n-- > 0)
|
||||
*dst++ = *src++;
|
||||
} else {
|
||||
dst += n;
|
||||
src += n;
|
||||
while(n-- > 0)
|
||||
*--dst = *--src;
|
||||
}
|
||||
return vdst;
|
||||
}
|
||||
|
||||
int
|
||||
memcmp(const void *s1, const void *s2, uint n)
|
||||
{
|
||||
const char *p1 = s1, *p2 = s2;
|
||||
while (n-- > 0) {
|
||||
if (*p1 != *p2) {
|
||||
return *p1 - *p2;
|
||||
}
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
memcpy(void *dst, const void *src, uint n)
|
||||
{
|
||||
return memmove(dst, src, n);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
#include "kernel/param.h"
|
||||
|
||||
// Memory allocator by Kernighan and Ritchie,
|
||||
// The C programming Language, 2nd ed. Section 8.7.
|
||||
|
||||
typedef long Align;
|
||||
|
||||
union header {
|
||||
struct {
|
||||
union header *ptr;
|
||||
uint size;
|
||||
} s;
|
||||
Align x;
|
||||
};
|
||||
|
||||
typedef union header Header;
|
||||
|
||||
static Header base;
|
||||
static Header *freep;
|
||||
|
||||
void
|
||||
free(void *ap)
|
||||
{
|
||||
Header *bp, *p;
|
||||
|
||||
bp = (Header*)ap - 1;
|
||||
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
||||
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
||||
break;
|
||||
if(bp + bp->s.size == p->s.ptr){
|
||||
bp->s.size += p->s.ptr->s.size;
|
||||
bp->s.ptr = p->s.ptr->s.ptr;
|
||||
} else
|
||||
bp->s.ptr = p->s.ptr;
|
||||
if(p + p->s.size == bp){
|
||||
p->s.size += bp->s.size;
|
||||
p->s.ptr = bp->s.ptr;
|
||||
} else
|
||||
p->s.ptr = bp;
|
||||
freep = p;
|
||||
}
|
||||
|
||||
static Header*
|
||||
morecore(uint nu)
|
||||
{
|
||||
char *p;
|
||||
Header *hp;
|
||||
|
||||
if(nu < 4096)
|
||||
nu = 4096;
|
||||
p = sbrk(nu * sizeof(Header));
|
||||
if(p == (char*)-1)
|
||||
return 0;
|
||||
hp = (Header*)p;
|
||||
hp->s.size = nu;
|
||||
free((void*)(hp + 1));
|
||||
return freep;
|
||||
}
|
||||
|
||||
void*
|
||||
malloc(uint nbytes)
|
||||
{
|
||||
Header *p, *prevp;
|
||||
uint nunits;
|
||||
|
||||
nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
|
||||
if((prevp = freep) == 0){
|
||||
base.s.ptr = freep = prevp = &base;
|
||||
base.s.size = 0;
|
||||
}
|
||||
for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
|
||||
if(p->s.size >= nunits){
|
||||
if(p->s.size == nunits)
|
||||
prevp->s.ptr = p->s.ptr;
|
||||
else {
|
||||
p->s.size -= nunits;
|
||||
p += p->s.size;
|
||||
p->s.size = nunits;
|
||||
}
|
||||
freep = prevp;
|
||||
return (void*)(p + 1);
|
||||
}
|
||||
if(p == freep)
|
||||
if((p = morecore(nunits)) == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
struct stat;
|
||||
struct rtcdate;
|
||||
|
||||
// system calls
|
||||
int fork(void);
|
||||
int exit(int) __attribute__((noreturn));
|
||||
int wait(int*);
|
||||
int pipe(int*);
|
||||
int write(int, const void*, int);
|
||||
int read(int, void*, int);
|
||||
int close(int);
|
||||
int kill(int);
|
||||
int exec(char*, char**);
|
||||
int open(const char*, int);
|
||||
int mknod(const char*, short, short);
|
||||
int unlink(const char*);
|
||||
int fstat(int fd, struct stat*);
|
||||
int link(const char*, const char*);
|
||||
int mkdir(const char*);
|
||||
int chdir(const char*);
|
||||
int dup(int);
|
||||
int getpid(void);
|
||||
char* sbrk(int);
|
||||
int sleep(int);
|
||||
int uptime(void);
|
||||
|
||||
// ulib.c
|
||||
int stat(const char*, struct stat*);
|
||||
char* strcpy(char*, const char*);
|
||||
void *memmove(void*, const void*, int);
|
||||
char* strchr(const char*, char c);
|
||||
int strcmp(const char*, const char*);
|
||||
void fprintf(int, const char*, ...);
|
||||
void printf(const char*, ...);
|
||||
char* gets(char*, int max);
|
||||
uint strlen(const char*);
|
||||
void* memset(void*, int, uint);
|
||||
void* malloc(uint);
|
||||
void free(void*);
|
||||
int atoi(const char*);
|
||||
int memcmp(const void *, const void *, uint);
|
||||
void *memcpy(void *, const void *, uint);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# Generate usys.S, the stubs for syscalls.
|
||||
|
||||
print "# generated by usys.pl - do not edit\n";
|
||||
|
||||
print "#include \"kernel/syscall.h\"\n";
|
||||
|
||||
sub entry {
|
||||
my $name = shift;
|
||||
print ".global $name\n";
|
||||
print "${name}:\n";
|
||||
print " li a7, SYS_${name}\n";
|
||||
print " ecall\n";
|
||||
print " ret\n";
|
||||
}
|
||||
|
||||
entry("fork");
|
||||
entry("exit");
|
||||
entry("wait");
|
||||
entry("pipe");
|
||||
entry("read");
|
||||
entry("write");
|
||||
entry("close");
|
||||
entry("kill");
|
||||
entry("exec");
|
||||
entry("open");
|
||||
entry("mknod");
|
||||
entry("unlink");
|
||||
entry("fstat");
|
||||
entry("link");
|
||||
entry("mkdir");
|
||||
entry("chdir");
|
||||
entry("dup");
|
||||
entry("getpid");
|
||||
entry("sbrk");
|
||||
entry("sleep");
|
||||
entry("uptime");
|
|
@ -0,0 +1,54 @@
|
|||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
char buf[512];
|
||||
|
||||
void
|
||||
wc(int fd, char *name)
|
||||
{
|
||||
int i, n;
|
||||
int l, w, c, inword;
|
||||
|
||||
l = w = c = 0;
|
||||
inword = 0;
|
||||
while((n = read(fd, buf, sizeof(buf))) > 0){
|
||||
for(i=0; i<n; i++){
|
||||
c++;
|
||||
if(buf[i] == '\n')
|
||||
l++;
|
||||
if(strchr(" \r\t\n\v", buf[i]))
|
||||
inword = 0;
|
||||
else if(!inword){
|
||||
w++;
|
||||
inword = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(n < 0){
|
||||
printf("wc: read error\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("%d %d %d %s\n", l, w, c, name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd, i;
|
||||
|
||||
if(argc <= 1){
|
||||
wc(0, "");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
printf("wc: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
wc(fd, argv[i]);
|
||||
close(fd);
|
||||
}
|
||||
exit(0);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
mkdir a
|
||||
echo hello > a/b
|
||||
mkdir c
|
||||
echo hello > c/b
|
||||
echo hello > b
|
||||
find . b | xargs grep hello
|
|
@ -0,0 +1,14 @@
|
|||
// Create a zombie process that
|
||||
// must be reparented at exit.
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "xv6-user/user.h"
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
if(fork() > 0)
|
||||
sleep(5); // Let child exit before parent.
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue