操作系统Linux课程实验报告.docx

上传人:b****2 文档编号:19081337 上传时间:2023-04-24 格式:DOCX 页数:34 大小:1.77MB
下载 相关 举报
操作系统Linux课程实验报告.docx_第1页
第1页 / 共34页
操作系统Linux课程实验报告.docx_第2页
第2页 / 共34页
操作系统Linux课程实验报告.docx_第3页
第3页 / 共34页
操作系统Linux课程实验报告.docx_第4页
第4页 / 共34页
操作系统Linux课程实验报告.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

操作系统Linux课程实验报告.docx

《操作系统Linux课程实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统Linux课程实验报告.docx(34页珍藏版)》请在冰豆网上搜索。

操作系统Linux课程实验报告.docx

操作系统Linux课程实验报告

实验1.1、1.2LinuxUbuntu的安装、创建新的虚拟机VMWare

 

实验1.3Shell编程

1.实验目的与容

通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧。

编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,如“WelcometoLinux”,并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。

2.程序源代码清单

#include

#include

intmain(){

printf("HelloLinux\n");

intpid;

intstate;

intpfd[2];

pipe(pfd);

if(fork()==0){

printf("Inthegrepprogress\n");

dup2(pfd[0],0);

close(pfd[0]);

close(pfd[1]);

execlp("grep","grep","sh",0);

perror("exelpgreperror");

}

esleif(fork()==0){

printf("Inthepsprogress\n");

dup2(pfd[1],1);

close(pfd[0]);

close(pfd[1]);

execlp("ps","ps","-ef",0);

perror("execlpps-ef");

}

close(pfd[1]);

close(pfd[0]);

wait(&state);

wait(&state);

}

实验2.3核模块

实验步骤:

(1).编写核模块

文件中主要包含init_clock(),exit_clock(),read_clock()三个函数。

其中init_clock(),exit_clock()负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口。

read_clock()负责产生/proc/clock被读时的动作。

(2).编译核模块Makefile文件

#Makefileunder2.6.25

ifneq($(KERNELRELEASE),)

#kbuildsyntax.dependencyrelationshsipoffilesandtargetmodulesarelistedhere.

obj-m:

=proc_clock.o

else

PWD:

=$(shellpwd)

KVER?

=$(shelluname-r)

KDIR:

=/lib/modules/$(KVER)/build

all:

$(MAKE)-C$(KDIR)M=$(PWD)modules

clean:

rm-rf.*.cmd*.o*.mod.c*.ko.tmp_versions*.symvers*.order

endif

编译完成之后生成proc_clock.ko模块文件。

(3).核模块源代码clock.c

#include

#include

#include

#include

#include

#include

#defineMODULE

#defineMODULE_VERSION"1.0"

#defineMODULE_NAME"clock"

structproc_dir_entry*my_clock;

intread_clock(char*page,char**start,off_toff,intcount,int*eof,

void*data){

intlen;

structtimevalxtime;

do_gettimeofday(&xtime);

len=sprintf(page,"%d%d\n",xtime.tv_sec,xtime.tv_usec);

printk("clock:

read_func()\n");

returnlen;

}

structproc_dir_entry*clock_proc_file;

intinit_clock(void)

{

clock_proc_file=create_proc_read_entry("clock",0,NULL,read_clock,NULL);

return0;

}

voidexit_clock(void)

{

remove_proc_entry("clock",clock_proc_file);

}

module_init(init_clock)

module_exit(exit_clock)

MODULE_LICENSE("GPL");

(4).编译核模块

#make

(5).加载核模块

在系统root用户下运行用户态模块命令装载核模块

#insmodproc_clock.ko

(6).测试

在终端中输入以下命令:

#cat/proc/clock

(7).卸载核模块

在系统root用户下运行用户态模块命令卸载核模块

#rmmodproc_clock.ko

实验2.4系统调用

实验步骤:

(1).添加新调用的源代码

在./linux-2.6.33.7/arch/x86/kernel/sys_i386_32.c中添加相应的调用代码

asmlinkageintsys_xwlcall(structtimeval*tv)

{

structtimevalktv;

do_gettimeofday(&ktv);

copy_to_user(tv,&ktv,sizeof(ktv));

printk(KERN_ALERT"PID%ldcalledsys_xwlcall()./n",(long)current->pid);

return0;

}

(2).连接系统调用

a、修改./linux-2.6.33.7/arch/x86/include/asm/unistd_32.h,

在系统调用列表后面相应位置添加一行,这样在用户空间做系统调用时就不需要知道系统调用号了,如果在用户空间指明了调用号,就可以省略这一步,实际上我就没写:

#define__NR_xwlcall338

新增加的调用号位338

b、修改./linux-2.6.33.7/arch/x86/kernel/syscall_table_32.S

在ENTRY(sys_call_table)清单最后添加一行,这步至关重要,338就是这里来的:

.longsys_xwlcall

(3).重建新的Linux核

先安装好编译核必要的软件包:

#sudoapt-getinstallbuild-essentialkernel-packagelibncurses5-dev

复制当前核的配置文件

#cp/boot/config-`uname-r`./.config

保存配置文件

#sudomakemenuconfig

使用debian的的核编译方法,要简单很多

#sudomake-kpkg-initrd--initrd--append-to-version=xwlcall

kernel_imagekernel-headers

运行以下deb包,安装核镜像和模块:

linux-image-2.6.33.7xwlcall_2.6.33.7xwlcall-10.00.Custom_i386.deb

运行以下deb包,安装核头文件:

linux-headers-2.6.33.7xwlcall_2.6.33.7xwlcall-10.00.Custom_i386.deb

运行以下命令,使核启动时能调用模块,比如硬件驱动:

#sudoupdate-initramfs-c-k2.6.33.7xwlcall

此次编译的核采用ubuntu默认配置文件,通用性非常好,可以拷贝到大部分x86机器上安装。

安装后系统自动会修改grub启动选单。

4.重建引导信息

a、安装deb包就自动重建引导信息了,无须另行处理。

b、如果仍然不放心,可以运行

#update-grub

5.重新引导从新的核进入

6.修改系统调用表

7.测试

实验3.3Shell编程实验(进程管理实验)

1、实验目的

通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得多进程程序的编程经验。

2、实验容1

设计一个简单的shell解释程序,能实现基本的bsh功能。

3、实验原理

将每一条命令分子段压入argv栈。

然后再子进程中调用execvp()来实现该命令的功能。

4、代码(源代码清单)

#include

#include

#include

#defineBUFFERSIZE256

//最简单的shell,只是简单的执行命令调用,没有任何的其他功能

intmain()

{

charbuf[BUFFERSIZE],*cmd,*argv[100];

charinchar;

intn,sv,buflength;

intresult;

buflength=0;

for(;;){

printf("=>");

//处理过长的命令;

inchar=getchar();//读取命令

while(inchar!

='\n'&&buflength

buf[buflength++]=inchar;

inchar=getchar();

}

if(buflength>BUFFERSIZE){

printf("Commandtoolong,pleaseenteragain!

\n");

buflength=0;

continue;

}

else

buf[buflength]='\0';

//解析命令行,分成一个个的标记

//char*strtok(char*s,char*delim)

//分解字符串为一组字符串。

s为要分解的字符串,delim为分隔符字符串。

cmd=strtok(buf,"\t\n");

if(cmd){

if(strcmp(cmd,"exit")==0)exit(0);

n=0;

argv[n++]=cmd;

while(argv[n++]=strtok(NULL,"\t\n"));

if(fork()==0){

execvp(cmd,argv);

fprintf(stderr,"sxh:

%s:

commandnotfound.\n",buf);//如果子进程顺利执行,这段话是不会执行的

exit

(1);

}

wait(&sv);

buflength=0;

}

}

}

实验容2

编写一个带有重定向和管道功能的Shell

1.设计思路

通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束。

这三个系统调用可以很好地创建多进程。

另一方面,编写的Shell要实现管道功能,需要用pipe()创建管道使子进程进行通信。

2.源代码清单

#include

#include

#include

#include

#defineBUFFERSIZE256

//具有输入输出重定向的功能和管道功能

int

main()

{

charbuf[256],*buf2,*cmd,*cmd2,*argv[64],*argv2[64],*infile,*outfile;

charinchar;

intn,sv,buflength,fd[2];

for(;;){

buflength=0;

printf("=>");

inchar=getchar();

while(inchar!

='\n'&&buflength

buf[buflength++]=inchar;

inchar=getchar();

}

if(buflength>BUFFERSIZE){

fprintf(stderr,"Commandtoolong,pleaseenteragain!

\n");

buflength=0;

continue;

}

else

buf[buflength]='\0';

//检查是否具有管道操作符

//strstr()在字符串中查找指定字符串的第一次出现,buf2指向管道符号前端的命令

buf2=strstr(buf,"|");

if(buf2)

*buf2++='\0';

else{

//否则查看是否具有重定向的操作符

infile=strstr(buf,"<");

outfile=strstr(buf,">");

if(infile){

*infile='\0';

infile=strtok(infile+1,"\t\n");

}

if(outfile){

*outfile='\0';

outfile=strtok(outfile+1,"\t\n");

}

}

//解析命令行,分成一个个的标记

cmd=strtok(buf,"\t\n");

//执行管道命令

if(buf2){

if(strcmp(cmd,"exit")==0)exit(0);

if(!

cmd){

fprintf(stderr,"Commandtokenerror.\n");

exit

(1);

}

n=0;

//管道后端的命令

argv[n++]=cmd;

while(argv[n++]=strtok(NULL,"\t\n"));

//管道前端的命令

cmd2=strtok(buf2,"\t\n");

if(!

cmd2){

fprintf(stderr,"Commandtokenerror.\n");

exit

(1);

}

n=0;

argv2[n++]=cmd2;

while(argv2[n++]=strtok(NULL,"\t\n"));

pipe(fd);

if(fork()==0){

dup2(fd[0],0);//dup2复制文件句柄,将fd[0]复制到描述符0。

close(fd[0]);close(fd[1]);

execvp(cmd2,argv2);

fprintf(stderr,"**badcommand\n");exit

(1);

}elseif(fork()==0){

dup2(fd[1],1);

close(fd[0]);close(fd[1]);

execvp(cmd,argv);

fprintf(stderr,"**badcommand\n");exit

(1);

}

close(fd[0]);

close(fd[1]);

wait(&sv);

wait(&sv);

buflength=0;

}

//如果没有管道命令,如果有重定向就执行重定向操作,如果没有重定向就当作普通shell命令执行

else{

if(cmd){

if(strcmp(cmd,"exit")==0)exit(0);

n=0;

argv[n++]=cmd;

while(argv[n++]=strtok(NULL,"\t\n"));

if(fork()==0){

intfd0=-1,fd1=-1;

if(infile)fd0=open(infile,O_RDONLY);

if(outfile)fd1=open(outfile,O_CREAT|O_WRONLY,0666);

if(fd0!

=-1)dup2(fd0,0);//dup2复制文件句柄,将fd0复制到描述符0。

if(fd1!

=-1)dup2(fd1,1);//dup2复制文件句柄,将fd1复制到描述符1。

close(fd0);

close(fd1);

execvp(cmd,argv);

fprintf(stderr,"**Badcommand\n");

exit

(1);

}

wait(&sv);

buflength=0;

}

}

}//for

}

实验4.1观察实验(存储管理实验)

1.实验步骤

(1)、安装GDB

(2)、编写观测程序

(3)、按照指令手册进行观察操作

2.观测程序源代码

#include

#include

charstr[50]="HelloLinux.";

intmain()

{

intnum=10;

while(num--){

printf("%s\n",str);

}

}

//gcc-g-otestingtesting.c

3.实验结果及分析

(1).Gdb程序观察一个程序文件的容和结构

结果截图:

(2).GDB观察程序存映象的容和结构

(3).在Linux下,用free和vmstat命令观察存使用情况

(4).在Linux下,查看/proc与存管理相关的文件,并解释显示结果

实验5.1观察实验(进程通信)

在Linux下,用ipcs()命令观察进程通信情况,了解Linux基本通信机制

实验结果(截图):

实验6.3IO系统编程实验

1、实验目的

编写一个daemon进程,该进程定时执行ps命令,然后将该命令的输出写至文件F1尾部。

通过此实验,掌握LinuxI/O系统相关容。

2、实验容

编写一个daemon进程,该进程定时执行ps命令,然后将该命令的输出写至文件F1尾部。

3、实验原理

在这个程序中,首先fork一个子程序,然后,关闭父进程,这样,新生成的子进程被交给init进程接管,并在后台执行。

新生成的子进程里,使用system系统调用,将ps的输出重定向,输入到f1.txt里面。

4、实验步骤

编写daemon.c

代码如下:

#include

#include

intmain(intargc,char*argv[])

{

inti,p;

p=fork();

if(p>0){

exit(0);

}

elseif(p==0){

for(i=0;i<100;i++){

sleep(100);

system("ps>f1.txt");

}

}

else{

perror("Createnewprocess!

");

}

return1;

}

}

编译程序

#gcc-odaemondaemon.c

执行程序

#./daemon

实验7.1代码分析(文件系统管理实验)

1.实验目的

了解与文件管理有关的Linux核模块的代码结构。

2.实验结果(源代码分析)

A.创建文件模块分析

5780/*creatsystemcall*/

5781Creat()

5782{

5783resister*ip;

5784externuchar;

5785

5786ip=namei(&uchar,1);

5787if(ip==NULL){

5788if(u.u_error)

5789return;

5790ip=maknode(u.u_arg[1]&07777&(~ISVTX));

5791if(ip==NULL)

5792return;

5793open1(ip,FWRITE,2);

5794}else

5795open1(ip,FWRITE,1);

5796}

第5786:

“namei”(7518)将一路径名变换成一个“inode”指针。

“uchar”是一个过程的

名字,它从用户程序数据区一个字符一个字符地取得文件路径名。

5787:

一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在。

5788:

对于出错的各种条件,请见UMP的CREAT(II)。

5790:

“maknode”(7455)调用“ialloc”创建一存“inode”,然后对其赋初值,并使

其进入适当的目录。

注意,显式地清除了“粘住”位(ISVTX)。

B.删除文件rm模块分析

3510unlink()

3511{

3512resister*ip,*pp;

3513externuchar;

3514

3515pp=namei(&uchar,2);

3516if(pp==NULL)

3517return;

3518prele(pp);

3519ip=iset(pp->dev,u.u_dent.u_ino);

3520if(ip==NULL)

3521panic(*unlink–iset*);

3522if((ip->i_mode%IFMT)==IFDIR&&!

suser())

3523gotoout;

3524u.u_offset[1]=-DIRSIZ+2;

3525u.ubase=&u.u_dent;

3526u.ucount=DIRSIZE+2;

3527u.u_dent.u_ino=0;

3528writei(pp);

3529ip->i_nlink--;

3530ip->i_flag=!

IUPD;

3531

3532out:

3533iput(pp);

3534iput(ip);

3535}

新文件作为永久文件自动进入文件目录。

关闭文件

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1