Lab 1: Summary of Unix utilities

This experiment mainly learned some commonly used system calls.

Lab 1: Unix utilities

Boot xv6 (easy)

git clone, switch branches, qemu. Just proceed as required.

$ git clone git://g.csail.mit.edu/xv6-labs-2020
$ cd xv6-labs-2020
$ git checkout util
$ makeqemu

sleep (easy)

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc,char *argv[])
{
    if(argc < 2)
    {
        fprintf(2,"please enter a number!");
        exit(1);
    }else{

        int n = atoi(argv[1]);
        sleep(n);
        exit(0);
    }

}

Add sleep to the build target in the Makefile.

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\
$U/_sleep\ . # here !!!

pingpong (easy)

For pipe problems, use fork() to copy this process to create a child process, and then use pipes to communicate with each other.

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc,char *argv[])
{
    int pp2c[2],pp2p[2];
    pipe(pp2c);
    pipe(pp2p);
    int n = fork();
    if(n != 0 ){
        write(pp2c[1],"a",1);
        char buff;
        read(pp2p[0], & amp;buff,1);
        printf("%d: received pong\
",n);
    }else{
        char buff;
        read(pp2c[0], & amp;buff,1);
        printf("%d: received ping\
",n);
        write(pp2p[1], & amp;buff,1);
        
    }
    exit(0);

}

primes (moderate) / (hard)

Observe the picture below to understand, and use fork to implement the function of prime number sieve.

// primes.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"



void sieve(int pleft[2]){<!-- -->

    int p ;
    read(pleft[0] , & amp;p,sizeof(p));
    if(p == -1){<!-- -->

        exit(0);
    }
    printf("prime %d\
", p);
    int pright[2];
    pipe(pright);
    if(fork() == 0){<!-- -->
        // child process
        close(pright[1]);
        close(pleft[0]);
        sieve(pright);
    }else{<!-- -->
        close(pright[0]);
        int buff;
        while(read(pleft[0] , & amp;buff,sizeof(buff)) & amp; & amp; buff != -1){<!-- -->
            if(buff %p != 0 ){<!-- -->
                write(pright[1] , & amp;buff,sizeof(buff));
            }
        }
        buff = -1;
        write(pright[1] , & amp;buff,sizeof(buff));
        wait(0);
        exit(0);
    }
}

int main(int argc,char* argv[]){<!-- -->

    int inputpipe[2];
    pipe(inputpipe);

    if(fork() == 0){<!-- -->
        // child process
        close(inputpipe[1]);
        sieve(inputpipe);
        exit(0);

    }else{<!-- -->
        close(inputpipe[0]);
   
        int i;
        for( i = 2 ; i <=35;i + + ){<!-- -->
            write(inputpipe[1] , & amp;i,sizeof(i) );
            
        }
        i =-1;
        write(inputpipe[1] , & amp;i,sizeof(i) );
        
    }
    wait(0);
    exit(0);
}

find (moderate)

Based on the transformation of ls.c

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"


void find(char *path,char *target)
{<!-- -->
  char buf[512], *p;
  int fd;
  struct dirent de;
  struct stat st;

  if((fd = open(path, 0)) < 0){<!-- -->
    fprintf(2, "ls: cannot open %s\
", path);
    return;
  }

  if(fstat(fd, & amp;st) < 0){<!-- -->
    fprintf(2, "ls: cannot stat %s\
", path);
    close(fd);
    return;
  }

  switch(st.type){<!-- -->
  case T_FILE:
    if(strcmp(path + strlen(path) - strlen(target) ,target) == 0)
      printf("%s\
", path);
    break;

  case T_DIR:
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){<!-- -->
      printf("find: path too long\
");
      break;
    }
    strcpy(buf, path);
    p = buf + strlen(buf);
    *p + + = '/';
    while(read(fd, & amp;de, sizeof(de)) == sizeof(de)){<!-- -->
      if(de.inum == 0|| strcmp(de.name, ".")==0 || strcmp(de.name, ".." )==0 )
        continue;
      memmove(p, de.name, DIRSIZ);//It will be overwritten every time it loops
      p[DIRSIZ] = 0;
      if(stat(buf, & amp;st) < 0){<!-- -->
        printf("find: cannot stat %s\
", buf);
        continue;
      }
      // printf(buf);
      // printf("\
");
    find(buf, target); // Recursive search
\t\t
    }
    break;
  }
  close(fd);
}

int main(int argc, char *argv[])
{<!-- -->
  
if(argc < 3){<!-- -->
exit(0);
}
char target[512];
target[0] = '/'; // Add / at the beginning of the file name to be searched for
strcpy(target + 1, argv[2]);
find(argv[1], target);
exit(0);
}

xargs (moderate)

Introduction to xargs

Overall idea:

  • Save the parameters passed in by the xargs command to an array of pointers, with each pointer pointing to a parameter;
  • Parse the input parameters. If ‘ ‘ or \
    is encountered, save the parameters to the pointer array. Use exec to run each time a line is read.
  • The last line is judged and run separately, in case the last line does not have a newline character
// xargs.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"


void run(char *program, char ** args)
{<!-- -->
    if(fork() == 0 ){<!-- -->
        exec(program,args);
        exit(0);
    }
    return ;
}
int main(int argc,char* argv[]){<!-- -->

    char buf[2048]; // Memory pool used when reading
char *p = buf, *last_p = buf; // End and start pointers of the current parameter
char *argsbuf[128]; //All parameter list, string pointer array, including parameters passed in by argv and parameters read in by stdin
char **args = argsbuf; // Point to the first parameter in argsbuf read from stdin
    for(int i=1;i<argc;i + + ) {<!-- -->
//Add the parameters provided by argv to the final parameter list
*args = argv[i];
args + + ;
}

    char **pa = args;

    while(read(0,p,1) != 0 ){<!-- -->
        if(*p == ' ' || *p == '\
'){<!-- -->
            *p = '\0';
            *(pa + + ) = last_p;
            last_p = p + 1;
            
            if(*p == '\
'){<!-- -->
    
                
                *pa = 0;
                run(argv[1],argsbuf);
                pa = args;
            }
        }
        p + + ;

    }

    if(pa != args) {<!-- --> // If the last line is not a blank line
//Finish the last parameter

      
*p = '\0';
*(pa + + ) = last_p;
// End the last line
*pa = 0; // Use null at the end of the parameter list to identify the end of the list
//Execute the last line of instructions
run(argv[1], argsbuf);
}
    while(wait(0) != -1) {<!-- -->};

    exit(0);
}