我电操作系统上机实验题目(1\2)整理记录
最近课少了,实验多了。趁今天下午的机会把操作系统的上机题也解决一下,顺便整理下相关的知识点。
老师还蛮奇葩的,非要搞什么中英文教学。
下面是实验一的内容:
题目的大概意思就是,让我们写一个shell脚本,模拟Linux中的cp命令,也就是拷贝文件的命令,需要进行错误检查(参数检查,程序逻辑,函数返回值判断等),然后又说明了只考虑文件,不考虑目录(简单了点-.-),并且最后用strace命令查看所编写程序执行过程中调用的系统调用。
先看一下,实验一中涉及到的两个命令的基本用法:
cp命令:(摘自菜鸟教程)
strace命令:
按照strace官网的描述, strace是一个可用于诊断、调试和教学的Linux用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。不难理解,该命令它能够打开应用进程的这个黑盒,通过系统调用的线索,告诉你进程大概在干嘛。
两个比较常用的用法:
1、strace [your commend](在要执行的命令前直接加strace,追踪你的命令的执行过程)
2、strace -p [your commend's pid](跟踪已经在执行的进程,并且不打断。先查看pid:pidof)
实验过程:
根据资料的查询,这里是可以利用两种系统调用来实现cp的功能:
(1)read&write
(2)fread&fwrite
这里采用的是read/write的系统调用:
首先不po代码:(我已经记不得debug了多少次了),先上报错。
报错一:
第一个报错很**,头文件.h忘记加了。
报错二:
warning是隐式声明与内建函数'printf'不兼容,就是缺少‘printf’的库函数头文件<stdio.h>加上。
报错三:
expected declaration or statement,以前码代码的时候经常看见,大部分的原因就是花括号少了或者多了不匹配,这里也是同样的问题。
下面就编译成功了。
在当前目录下创建一个test文件,文件内容'test success!‘。
跑一下看看:./my_cp test /tmp
结果在/tmp目录下发现并没产生任何文件。(喝口wusu冷静一下)
再回头看看源文件,发现缺少关闭文件的代码块(但这不该是上边问题的根源哈),还是先加上了。
在跑一下,无果。
用strace跟踪一下看看:strace ./my_cp test /tmp
红色标注的部分提示Bad file descriptor,google了下相关报错,其中有篇文章这样解释:
Open默认的打开方式是只读,进行写操作时,是不允许的。
但是我的程序并不是对打开文件进行写操作啊??半信半疑的将open的参数改为了O_WRONLY
再重编译,运行,还是一样的结果。
再用strace跟踪看看:
刚才一直认为是写操作出现了问题,然后忽略了上面的报错,open的返回值为-1,说明文件open就失败了,但我命令的/tmp是目录啊!!原来如此,自己给自己设坑了。在一开始还窃喜避开目录的讨论,但是在这里又不自觉地用了目录作为目标地址,很捞。
修改命令 ./my_cp test /temp/test2
复制成功。
再测试下命令输入不符合格式:
代码部分:
实验二:
大致要求就是,自己实现一个shell,然后着重的说明了添加history的特性和相关注意事项。
能力有限,代码也是参考的一个博主的。虽然有点出入,但是大同小异。
编译的时候遇到一个问题:
函数未声明,重写了下这个函数,得以解决。
测试结果:
Ctrl C查看历史命令(history) || Ctrl Z 停止
代码
```
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <wait.h>
#include <string.h>
#include <signal.h>
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
#define BUFFERSIZE 11
typedef struct{
int number;
char com[MAX_LINE];
}command;
command buffer[BUFFERSIZE];
int buffer_pointer;
int setup(char inputBuffer[], char *args[],int *background);
void print(){
int i;
fflush(stdout);
write(STDOUT_FILENO,"\n",1);
for(i = (buffer_pointer - 1) % BUFFERSIZE;\
i != (buffer_pointer % BUFFERSIZE) && buffer[i].number;\
i = (i - 1 + BUFFERSIZE) % BUFFERSIZE ){
printf("%d\t%s",buffer[i].number,buffer[i].com);
fflush(stdout);
}
}
void handle_SIGINT(){
print();
signal(SIGINT, SIG_IGN);
return;
}
int setup(char inputBuffer[], char *args[],int *background){
int length, /* # of characters in the command line */
i, /* loop index for accessing inputBuffer array */
start, /* index where beginning of next command parameter is */
ct; /* index of where to place the next parameter into args[] */
pid_t pid;
ct = 0;
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
start = -1;
if(length == 0)
exit(0);
if(length < 0){
args[0] = NULL;
return 0;
}
if(inputBuffer[0] == 'r' && (inputBuffer[1] == ' ' || inputBuffer[1] == '\n')){
if(inputBuffer[1] == '\n'){
write(STDOUT_FILENO,buffer[(buffer_pointer - 1) % BUFFERSIZE].com,\
strlen(buffer[(buffer_pointer - 1) % BUFFERSIZE].com));
strcpy(inputBuffer,buffer[(buffer_pointer - 1) % BUFFERSIZE].com);
length = strlen(inputBuffer);
}
else{
int j;
if(!buffer_pointer) return 0;
for(j = (buffer_pointer - 1) % BUFFERSIZE;\
j != (buffer_pointer % BUFFERSIZE) && (buffer[j].com[0] != inputBuffer[2]) \
&& buffer[j].number;\
j = (j - 1 + BUFFERSIZE) % BUFFERSIZE );
if(j == (buffer_pointer % BUFFERSIZE) || buffer[j].number == 0){
char NF[15] = "Not found\n";
write(STDOUT_FILENO,NF,strlen(NF));
return 0;
}
else{
write(STDOUT_FILENO,buffer[j].com,strlen(buffer[j].com));
strcpy(inputBuffer,buffer[j].com);
length = strlen(inputBuffer);
}
}
}
if(inputBuffer[0] != '\n'){
buffer[(buffer_pointer % BUFFERSIZE)].number = buffer_pointer + 1;
strcpy(buffer[(buffer_pointer % BUFFERSIZE)].com,inputBuffer);
buffer_pointer++;
}
for (i = 0;i < length;i++) {
switch (inputBuffer[i]){
case ' ' :
case '\t' : /* argument separators */
if(start != -1){
args[ct] = &inputBuffer[start]; /* set up pointer */
ct++;
}
inputBuffer[i] = '\0'; /* add a null char; make a C string */
start = -1;
break;
case '\n': /* should be the final char examined */
if (start != -1){
args[ct] = &inputBuffer[start];
ct++;
}
inputBuffer[i] = '\0';
args[ct] = NULL; /* no more arguments to this command */
break;
default : /* some other character */
if (start == -1)
start = i;
if (inputBuffer[i] == '&'){
*background = 1;
inputBuffer[i] = '\0';
}
}
}
args[ct] = NULL; /* just in case the input line was > 80 */
return 1;
}
int main(void){
buffer_pointer = 0;
memset(buffer, 0, sizeof(buffer));
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2 + 1]; /* command line (of 80) has max of 40 arguments */
pid_t pid;
char com[20] = "osh> ";
while (1){ /* Program terminates normally inside setup */
background = 0;
memset(inputBuffer,0,MAX_LINE);
write(STDOUT_FILENO,com,strlen(com));
setup(inputBuffer,args,&background); /* get next command */
struct sigaction handler;
handler.sa_handler = handle_SIGINT;
sigaction(SIGINT,&handler,NULL);
/* the steps are:
(1) fork a child process using fork()
(2) the child process will invoke execvp()
(3) if background == 0, the parent will wait,
otherwise returns to the setup() function. */
pid = fork();
if(pid < 0){
fprintf(stderr,"Fork Failed");
exit(-1);
}
else if(pid == 0){execvp(args[0],args);exit(0);}
else if(!background) wait(NULL);
}
return 0;
}
```