操作系统实践 job3

目录

job3/myecho.c

job3/mycat.c

知识点:

job3/mycp.c

job3/mysys.c

实现函数mysys,用于执行一个系统命令,要求如下

job3/sh1.c


job3/myecho.c

题目:

  • myecho.c的功能与系统echo程序相同

  • 接受命令行参数,并将参数打印出来,例子如下:

    $ ./myecho x
    x
    $ ./myecho a b c
    a b c

思路:

  • C程序的main函数原型,argc:命令行参数的个数,argv:命令行参数数组

    int main(int argc, char *argv[]);
  • 因此从第二行开始输出指令中的字符串就行

#include 
int main(int argc,char *argv[])
{
        int i;
        for(i=1;i

在一个终端中使用 gcc 编译器来编译程序并生成自定义目标文件

gcc -o myecho myecho.c

结果展示:

操作系统实践 job3_第1张图片


job3/mycat.c

题目:

  • mycp.c的功能与系统cp程序相同

  • 将源文件复制到目标文件,例子如下:

  • 要求使用系统调用open/read/write/close实现

    $ cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...
    $ ./mycp /etc/passwd passwd.bak 
    $ cat passwd.bak
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin

知识点:

文件操作:https://www.linuxmooc.com/courses/io/

用到的几个函数:

#include 
#include 
int open(const char *pathname, int flags);//打开
int creat(const char *pathname, mode_t mode);//创建
int open(const char *pathname, int flags, mode_t mode);
int close(int fd);//关闭
#include 
int read(int fd, void *buf, size_t count);//读取
int write(int fd, void *buf, size_t count);//写入
off_t lseek(int fd, off_t offset, int whence);//定位

思路:

  • 打开文件,文件名就是输入指令的第二个字符串,进行健壮性检查。

  • 每次读取128字节数据并实时输出在屏幕上,STDOUT_FILENO是终端的描述符,直到文件末尾。也可以只读取1字节,更不容易溢出,就是效率可能没那么高。

#include 
#include 
#include 
#include 
#include 
#include 
void panic(char*message)
{
        perror(message);
        exit(EXIT_FAILURE);
}
int main(int argc,char *argv[])
{
        //open file
        int fp=open(argv[128],O_RDONLY);
        if(fp<0)
                panic("open");
        //read file
        char s[1];
        int flag;
        while((flag=read(fp,&s,1))>0){
                //write file
                write(STDOUT_FILENO,s,1);
        }
        close(fp);
        return 0;
}

在一个终端中使用 gcc 编译器来编译程序并生成自定义目标文件

gcc -o mycat mycat.c

结果:

操作系统实践 job3_第2张图片


job3/mycp.c

  • mycp.c的功能与系统cp程序相同

  • 将源文件复制到目标文件,例子如下:

  • 要求使用系统调用open/read/write/close实现

    $ cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...
    $ ./mycp /etc/passwd passwd.bak 
    $ cat passwd.bak
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...

思路和job2类似

#include 
#include 
#include 
#include 
#include 
#include 
void panic(char*message)
{
        perror(message);
        exit(EXIT_FAILURE);
}
int main(int argc,char *argv[])
{
        //open file
        int fout=open(argv[1],O_RDONLY);
        if(fout<0)
                panic("open");
        //read file
    mode_t mode=0777;
    int fin=open(argv[2],O_RDWR|O_APPEND|O_CREAT,mode);
        char s[10];
        int flag;
        while((flag=read(fout,&s,1))>0){
                //write file
                write(fin,s,1);
        }
        close(fout);
    close(fin);
        return 0;
}

job3/mysys.c

实现函数mysys,用于执行一个系统命令,要求如下

  • mysys的功能与系统函数system相同,要求用进程管理相关系统调用自己实现一遍

  • 使用fork/exec/wait系统调用实现mysys

  • 不能通过调用系统函数system实现mysys

  • 测试程序

    #include 
    ​
    void mysys(char *command)
    {
        实现该函数,该函数执行一条命令,并等待该命令执行结束
    }
    ​
    int main()
    {
        printf("--------------------------------------------------\n");
        mysys("echo HELLO WORLD");
        printf("--------------------------------------------------\n");
        mysys("ls /");
        printf("--------------------------------------------------\n");
        return 0;
    }
  • 测试程序的输出结果

    --------------------------------------------------
    HELLO WORLD
    --------------------------------------------------
    bin    core  home        lib     mnt   root  snap  tmp  vmlinuz
    boot   dev   initrd.img      lost+found  opt   run   srv   usr  vmlinuz.old
    cdrom  etc   initrd.img.old  media   proc  sbin  sys   var
    --------------------------------------------------

在mysys函数中创建一个子进程,调用execl函数实现sh命令,并等待子进程结束。

execl函数:

int execl(const char *path, const char *arg, ...);

最后一个参数必须是NULL

第一个参数path指定被装入程序的路径。

这里需要使用的是sh指令,/bin/sh是指令路径,sh -c command是命令。

#include 
#include 
#include 
#include 
#include 
void mysys(char *command)
{
    pid_t pid;
    if(command==NULL){
        printf("Error: wrong command!");
        exit(0);
    }
    pid=fork();
    if(pid==0)
    {
        error=execl("/bin/sh","sh","-c",command,NULL);
        if(error<0)perror("execl");
    }
    wait(NULL);
}
​
int main()
{
    printf("--------------------------------------------------\n");
    mysys("echo HELLO WORLD");
    printf("--------------------------------------------------\n");
    mysys("ls /");
    printf("--------------------------------------------------\n");
    return 0;
}

展示:

操作系统实践 job3_第3张图片


job3/sh1.c

  • 该程序读取用户输入的命令,调用函数mysys(上一个作业)执行用户的命令,示例如下

    # 编译sh1.c
    $ cc -o sh1 sh1.c
    ​
    # 执行sh1
    $ ./sh 
    ​
    # sh1打印提示符>,同时读取用户输入的命令echo,并执行输出结果
    > echo a b c
    a b c
    ​
    # sh1打印提示符>,同时读取用户输入的命令cat,并执行输出结果
    > cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
  • 实现内置命令cd、pwd、exit

  • 首先在'>'后输入命令,当输入回车时触发功能函数。这里需要处理一下字符串,在回车处截断。

  • 添加exit,cd 的功能这里调用了exit(),chdir(),getcwd()函数。

    • chdir()同cd

      函数原型:int chdir(const char *path);

      功 能:更改当前工作目录。

      参 数:Path 目标目录,可以是绝对目录或相对目录。

      返回值:成功返回0 ,失败返回-1

    • getcwd()

      函数原型:char *getcwd( char *buffer, int maxlen );

      功 能:获取当前工作目录

      参数说明:getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数maxlen为buffer的空间大小。

      返 回 值:成功则返回当前工作目录,失败返回 FALSE

    • exit()

      结束当前进程/当前程序

    #include
    #include
    #include
    #include
    #include
    #include
    extern void mysys(char *command);
    ​
    int main()
    {
        while(1)
        {
            char command[100]={0};
            char c;
            printf(">");
            //read from screen
            int i=0;
            do{
                c=getchar();
                command[i]=c;
                i++;
            }while(c!='\n');
            command[i-1]='\0';
    //exit功能
            if(!strcmp(command,"exit"))exit(0);
    //pwd功能
            else if(!strcmp(command,"pwd"))
            {
                char *path=getcwd(NULL,0);
                printf("Current directory:%s\n",path);
                free(path);
            }
    //cd功能
            else if(command[0]=='c'&&command[1]=='d')
            {
                char cd[100]={0};
                strcpy(cd,command+3);
                int error=chdir(cd);
                if(error<0)perror("cd");
                else{
                    char *path=getcwd(NULL,0);
                    printf("Current directory:%s\n",path);
                    free(path);
                }
            }
    //其他功能
            else mysys(command);
        }
    }
  • 要想调用mysys.c,首先得将其主函数注释掉。需要进行重定位,mysys作为外部符号需要用extern引用,并进行静态库链接。

将静态库中包含的目标模块先生成可重定位目标文件:
cc -c mysys.c
cc -c sh1.c
打包编译:
cc -o sh sh1.o mysys.o

展示:

操作系统实践 job3_第4张图片

你可能感兴趣的:(#,操作系统,linux)