目录
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 <stdio.h>
int main(int argc,char *argv[])
{
int i;
for(i=1;i<argc;i++)
printf("%s ",argv[i]);
printf("\n");
return 0;
}
在一个终端中使用 gcc
编译器来编译程序并生成自定义目标文件
gcc -o myecho myecho.c
结果展示:
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 <sys/stat.h>
#include <fcntl.h>
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 <unistd.h>
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 <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
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/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 <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
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 <stdio.h> 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
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/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<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/wait.h> #include<linux/string.h> #include<string.h> 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
展示: