目录
job3/myecho.c
job3/mycat.c
知识点:
job3/mycp.c
job3/mysys.c
实现函数mysys,用于执行一个系统命令,要求如下
job3/sh1.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
结果展示:
题目:
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
结果:
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;
}
实现函数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;
}
展示:
该程序读取用户输入的命令,调用函数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
展示: