MIT6.s081_Lab1 util: Unix utilities

MIT6.s081 Lab1:Unix utilities

lab1比较简单,内容较多,但是都是实现一些简单的命令,其中primes这个很有趣,还是花了点时间。

代码

1. sleep

user/sleep.c中添加如下代码:

int main(int argc, char** argv) {
    if (argc <= 1) {
        fprintf(2,"usage: sleep n second...\n");
        exit(1);
    }
    
    sleep(atoi(argv[1]));
    exit(0);
}

2. pingpong

user/pingpong.c中添加如下代码:

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

int main(int argc, char** argv) {
    int p[2];
    pipe(p);
    char buffer[5];
    if (fork() != 0) {
        int status;
        write(p[1], "ping\n", 5);
        close(p[1]);
        wait(&status);
        
        read(p[0], buffer, 5);
        close(p[0]);
        fprintf(1, "%d: received %s",getpid(), buffer);
    } else {
        read(p[0], buffer, 5);
        close(p[0]);
        fprintf(1, "%d: received %s",getpid(), buffer);
        write(p[1], "pong\n", 5);
        close(p[1]);
        exit(0);
    }
    exit(0);
}

3. primes

这个属于难度较大的编程,重点需要理解这个,图片放在下面了

流程

下面注释后补的,可能没有那么深刻,代码如下:

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

int main(int argc, char** argv) {
    //开了35,2的数组,0为读,1为写
    int p[35][2];
    int pipe_num = 0;
    //只开了第一个管道,因为第一个进程只需要向第一个管道写
    pipe(p[pipe_num++]);
    int child = -1;
    if((child = fork()) != 0) {
        //关闭第一个读端
        close(p[0][0]);
        //向第一个管道写入,从2写到36
        for (int i = 2; i < 36; ++i) {
            write(p[0][1], &i, sizeof(int));
        }
        //全部写完后,关闭写端
        close(p[0][1]);
        wait(&child);
    }else {
        //因为前面pipe(p[pipe_num++]);,此时pipe_num已经变成了1
        int cur_pn = pipe_num - 1;
        //关闭0,1
        close(p[cur_pn][1]);
        //通往子进程的管道
        int next_pn = pipe_num;
        int *num = 0;
        //当读到第一个数据的时候退出循环,打印
        while(!read(p[cur_pn][0], num, sizeof(int)));
        fprintf(1, "prime %d\n", *num);
        
        
        int cur = *num;
        while(read(p[cur_pn][0], num, sizeof(int)) != 0) {
            //下面是关键,先从管道读取数据,如果读取的数无法当前子进程保留的数, 就送到下一个管道,第一次会生成一个子进程接收,使用pipe_num控制生成个数
            if (*num % cur != 0) {
                //保证每个进程只会生成一个子进程
                if (pipe_num - 1 == cur_pn){
                    pipe(p[pipe_num++]);
                    child = fork();
                } 
                write(p[next_pn][1], num, sizeof(int));
                //更新子进程维护的数据,curpn是读取数据的管道,nextpn是写给子进程的管道
                //每个子进程只有无法整除才会送到下一个,因此在第一次生成子进程的时候打印即可
                if(child == 0) {
                    cur_pn = pipe_num - 1;
                    next_pn = pipe_num;
                    close(p[cur_pn][1]);
                    read(p[cur_pn][0], num, sizeof(int));
                    cur = *num;
                    fprintf(1, "prime %d\n", cur);
                }
            }
        }
        //关闭管道
        close(p[cur_pn][0]);
        close(p[next_pn][1]);
        close(p[next_pn][0]);
        wait(&child);
    }
    exit(0);
}

4. find

主要是需要知道两个结构体,statdirent,以及递归查询子目录的方法。删除了部分检测代码。

void find(char* path, char* name) {
    int fd;
    char buf[512], *p;
    struct stat st;
    struct dirent de;
    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;
        }
        if(st.type == T_FILE) {
            if(0 == strcmp(de.name, name))
                printf("%s\n", buf);
            continue;
        }
        if(st.type == T_DIR && 0 != strcmp(".", de.name) && 0 != strcmp("..", de.name)) {
            find(buf, name);
        }
    }
    close(fd);
}
int main(int argc, char** argv) {
    if (argc < 3) {
        fprintf(2, "usage: find dir ...");
        exit(0);
    }
    find(argv[1], argv[2]);
    exit(0);
}

5. xargs

重点是\的处理,然后是exec的使用,难度不大,代码如下:

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

int main(int args, char** argv) {
    char c, buf[512];
    char* p = buf;
    char* argv_exc[32];
    argv_exc[0] = argv[1];
    for (int i = 1; i < args - 1; i++) {
        argv_exc[i] = argv[i+1];
    }
    
    while(read(0, &c, 1) > 0) {
        if(c == '\\') {
            if(read(0, &c, 1) > 0) {
                if(c == 'n') {
                    c = '\n';
                } else {
                    *p++ = '\\';
                }
            }
        }
        if(c == '\n') {
            *p++ = '\0';
            argv_exc[args - 1] = buf;
            argv_exc[args] = 0;
            int child = fork();
            if (child == 0) {
                exec(argv[1], argv_exc);
                exit(1);
            } else {
                p = buf;
                wait(&child);
            }
        } else {
           *p++ = c;
        }  
    }
    exit(0);
}
posted @ 2025-07-11 18:51  BuerH  阅读(16)  评论(0)    收藏  举报