还剩35页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
实验
1.
1、
1.2LinuxUbuntu的__、创建新的虚拟机VMWare实验
1.3Shell编程
1.实验目的与内容通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息如“WelcometoLinux”并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息
2.程序源代码清单#includestdio.h#includesys/wait.hint__in{printfHelloLinux\n;intpid;intstate;intpfd
[2];pipepfd;iffork==0{printfInthegrepprogress\n;dup2pfd
[0]0;closepfd
[0];closepfd
[1];execlpgrepgrepsh0;perrorexelpgreperror;}esleiffork==0{printfInthepsprogress\n;dup2pfd
[1]1;closepfd
[0];closepfd
[1];execlppsps-ef0;perrorexeclpps-ef;}closepfd
[1];closepfd
[0];waitstate;waitstate;}实验
2.3内核模块实验步骤:
1.编写内核模块文件中主要包含init_clock,exit_clock,read_clock三个函数其中init_clock,exit_clock负责将模块从系统中加载或卸载,以及增加或删除模块在/proc中的入口read_clock负责产生/proc/clock被读时的动作
2.编译内核模块__kefile文件#__kefileunder
2.
6.25ifneq$KERNELRELEASE#kbuildsyntax.dependencyrelationshsipoffilesandtargetmodulesarelistedhere.o__-m:=proc_clock.oelsePWD:=$shellpwdKVER=$shelluname-rKDIR:=/lib/modules/$KVER/buildall:$__KE-C$KDIRM=$PWDmodulesclean:rm-rf.*.cmd*.o*.mod.c*.ko.tmp_versions*.symvers*.orderendif编译完成之后生成proc_clock.ko模块文件
3.内核模块源代码clock.c#includelinux/kernel.h#includelinux/module.h#includelinux/proc_fs.h#includelinux/string.h#includelinux/v__lloc.h#includea__/uac__ss.h#defineMODULE#defineMODULE_VERSION
1.0#defineMODULE_NAMEclockstructproc_dir_entry*my_clock;intread_clockchar*pagechar**startoff_toffintcountint*eofvoid*data{intlen;structtimevalxtime;do_gettimeofdayxtime;len=sprintfpage%d%d\nxtime.tv_secxtime.tv_usec;printkclock:read_func\n;returnlen;}structproc_dir_entry*clock_proc_file;intinit_clockvoid{clock_proc_file=create_proc_read_entryclock0NULLread_clockNULL;return0;}voidexit_clockvoid{remove_proc_entryclockclock_proc_file;}module_initinit_clockmodule_exitexit_clockMODULE_LI__NSEGPL;
4.编译内核模块#__ke
5.加载内核模块在系统root用户下运行用户态模块命令装载内核模块#in__odproc_clock.ko
6.测试在终端中输入以下命令#cat/proc/clock
7.卸载内核模块在系统root用户下运行用户态模块命令卸载内核模块#rmmodproc_clock.ko实验
2.4系统调用实验步骤:
1.添加新调用的源代码在./linux-
2.
6.
33.7/arch/x86/kernel/sys_i____
32.c中添加相应的调用代码a__linkageintsys_xwlcallstructtimeval*tv{structtimevalktv;do_gettimeofdayktv;copy_to_usertvktvsizeofktv;printkKERN_ALERTPID%ldcalledsys_xwlcall./nlongcurrent-pid;return0;}
2.连接系统调用a、修改./linux-
2.
6.
33.7/arch/x86/include/a__/unistd_
32.h,在系统调用列表后面相应位置添加一行,这样在用户空间做系统调用时就不需要知道系统调用号了,如果在用户空间指明了调用号,就可以省略这一步,实际上我就没写#define__NR_xwlcall338新增加的调用号位338b、修改./linux-
2.
6.
33.7/arch/x86/kernel/syscall_table_
32.S在ENTRYsys_call_table清单最后添加一行,这步至关重要,338就是这里来的.longsys_xwlcall
3.重建新的Linux内核先__好编译内核必要的软件包#sudoapt-getinstallbuild-essentialkernel-packagelibncurses5-dev__当前内核的配置文件#cp/boot/config-`uname-r`./.config保存配置文件#sudo__kemenuconfig使用debian的的内核编译方法,要简单很多#sudo__ke-kpkg-initrd--initrd--append-to-version=xwlcallkernel_i__gekernel-headers运行以下deb包,__内核镜像和模块linux-i__ge-
2.
6.
33.7xwlcall_
2.
6.
33.7xwlcall-
10.
00.Custom_i___.deb运行以下deb包,__内核头文件linux-headers-
2.
6.
33.7xwlcall_
2.
6.
33.7xwlcall-
10.
00.Custom_i___.deb运行以下命令,使内核启动时能调用模块,比如硬件驱动#sudoupdate-initramfs-c-k
2.
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、代码(源代码清单)#includestdio.h#includestring.h#includestdlib.h#defineBUFFERSIZE256//最简单的shell,只是简单的执行命令调用,没有任何的其他功能int__in{charbuf[BUFFERSIZE]*cmd*argv
[100];charinchar;intnsvbuflength;intresult;buflength=0;for;;{printf=;//处理过长的命令;inchar=getchar;//读取命令whileinchar!=\nbuflengthBUFFERSIZE{buf[buflength++]=inchar;inchar=getchar;}ifbuflengthBUFFERSIZE{printfCom__ndtoolongpleaseenteragain!\n;buflength=0;continue;}elsebuf[buflength]=\0;//解析命令行,分成一个个的标记//char*strtokchar*schar*delim//分解字符串为一组字符串s为要分解的字符串,delim为分隔符字符串cmd=strtokbuf\t\n;ifcmd{ifstrcmpcmdexit==0exit0;n=0;argv[n++]=cmd;whileargv[n++]=strtokNULL\t\n;iffork==0{execvpcmdargv;fprintfstderrsxh:%s:com__ndnotfound.\nbuf;//如果子进程顺利执行,这段话是不会执行的exit1;}waitsv;buflength=0;}}}实验内容2编写一个带有重定向和管道功能的Shell
1.设计思路通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束这三个系统调用可以很好地创建多进程另一方面,编写的Shell要实现管道功能,需要用pipe()创建管道使子进程进行通信
2.源代码清单#includestdio.h#includestdlib.h#includestring.h#includefcntl.h#defineBUFFERSIZE256//具有输入输出重定向的功能和管道功能int__in{charbuf
[256]*buf2*cmd*cmd2*argv
[64]*argv2
[64]*infile*outfile;charinchar;intnsvbuflengthfd
[2];for;;{buflength=0;printf=;inchar=getchar;whileinchar!=\nbuflengthBUFFERSIZE{buf[buflength++]=inchar;inchar=getchar;}ifbuflengthBUFFERSIZE{fprintfstderrCom__ndtoolongpleaseenteragain!\n;buflength=0;continue;}elsebuf[buflength]=\0;//检查是否具有管道操作符//strstr在字符串中查找指定字符串的第一次出现,buf2指向管道符号前端的命令buf2=strstrbuf|;ifbuf2*buf2++=\0;else{//否则查看是否具有重定向的操作符infile=strstrbuf;outfile=strstrbuf;ifinfile{*infile=\0;infile=strtokinfile+1\t\n;}ifoutfile{*outfile=\0;outfile=strtokoutfile+1\t\n;}}//解析命令行,分成一个个的标记cmd=strtokbuf\t\n;//执行管道命令ifbuf2{ifstrcmpcmdexit==0exit0;if!cmd{fprintfstderrCom__ndtokenerror.\n;exit1;}n=0;//管道后端的命令argv[n++]=cmd;whileargv[n++]=strtokNULL\t\n;//管道前端的命令cmd2=strtokbuf2\t\n;if!cmd2{fprintfstderrCom__ndtokenerror.\n;exit1;}n=0;argv2[n++]=cmd2;whileargv2[n++]=strtokNULL\t\n;pipefd;iffork==0{dup2fd
[0]0;//dup2__文件句柄,将fd
[0]__到描述符0closefd
[0];closefd
[1];execvpcmd2argv2;fprintfstderr**badcom__nd\n;exit1;}elseiffork==0{dup2fd
[1]1;closefd
[0];closefd
[1];execvpcmdargv;fprintfstderr**badcom__nd\n;exit1;}closefd
[0];closefd
[1];waitsv;waitsv;buflength=0;}//如果没有管道命令如果有重定向就执行重定向操作,如果没有重定向就当作普通shell命令执行else{ifcmd{ifstrcmpcmdexit==0exit0;n=0;argv[n++]=cmd;whileargv[n++]=strtokNULL\t\n;iffork==0{intfd0=-1fd1=-1;ifinfilefd0=openinfileO_RDONLY;ifoutfilefd1=openoutfileO_CREAT|O_WRONLY0666;iffd0!=-1dup2fd00;//dup2__文件句柄,将fd0__到描述符0iffd1!=-1dup2fd11;//dup2__文件句柄,将fd1__到描述符1closefd0;closefd1;execvpcmdargv;fprintfstderr**Badcom__nd\n;exit1;}waitsv;buflength=0;}}}//for}实验
4.1观察实验存储管理实验
1.实验步骤
1、__GDB
2、编写观测程序
3、按照指令手册进行观察操作
2.观测程序源代码#includestdio.h#includestdlib.hcharstr
[50]=HelloLinux.;int__in{intnum=10;whilenum--{printf%s\nstr;}}//__c-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的输出重定向,输入到f
1.___里面
4、实验步骤编写daemon.c代码如下#includestdio.h#includestdlib.hint__inintar__char*argv[]{intip;p=fork;ifp0{exit0;}elseifp==0{fori=0;i100;i++{sleep100;systempsf
1.___;}}else{perrorCreatenewpro__ss!;}return1;}}编译程序#__c-odaemondaemon.c执行程序#./daemon实验
7.1代码分析文件系统管理实验
1.实验目的了解与文件管理有关的Linux内核模块的代码结构
2.实验结果(源代码分析)A.创建文件模块分析5780/*creatsystemcall*/5781Creat5782{5783resister*ip;5784externuchar;57855786ip=nameiuchar1;5787ifip==NULL{5788ifu.u_error57__return;5790ip=__knodeu.u_arg
[1]07777~ISVTX;5791ifip==NULL5792return;5793open1ipFWRITE2;5794}else5795open1ipFWRITE1;5796}第5786“namei”7518将一路径名变换成一个“inode”指针“uchar”是一个过程的名字,它从用户程序数据区一个字符一个字符地取得文件路径名5787一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在5788对于出错的各种条件,请见UMP的CREATII5790“__knode”7455调用“ialloc”创建一内存“inode”,然后对其赋初值,并使其进入适当的目录注意,显式地清除了“粘住”位ISVTXB.删除文件rm模块分析3510unlink3511{3512resister*ip*pp;3513externuchar;35143515pp=nameiuchar2;3516ifpp==NULL3517return;3518prelepp;3519ip=isetpp-devu.u_dent.u_ino;3520ifip==NULL3521panic*unlink–iset*;3522ifip-i_mode%IFMT==IFDIR!suser3523gotoout;3524u.u_offset
[1]=-DIRSIZ+2;3525u.ubase=u.u_dent;3526u.ucount=DIRSIZE+2;3527u.u_dent.u_ino=0;3528writeipp;3529ip-i_nlink--;3530ip-i_flag=!IUPD;35313532out:3533iputpp;3534iputip;3535}新文件作为永久文件自动进入文件目录关闭文件不会自动地造成文件被删除当内存“inode”项中的“i_nlink”字段值为0并且相应文件未被打开时,将删除该文件在创建文件时,该字段由“__knode”赋初值为1系统调用“link”5941可将其值加1,系统调用“unlink”3529则可将其值减1创建临时“工作文件”的程序应当在其终止前执行“unlink”系统调用将这些文件删除注意,“unlink”系统调用本身并没有删除文件当引用计数i_count被减为0时
7350、7362,才删除该文件为了减少在程序或系统崩溃时遗留下来的临时文件所带来的问题,程序员应当遵守下列约定1在打开临时文件后立即对其执行“unlink”操作2应在“tmp”目录下创建临时文件在文件名中包括进程标识数就可构成一惟一文件名C.读写模块分析5711Read5712{5713rdwrFREAD;5714}5720Write5721{5722rdwrFWRITE;5723}5731rdwrmode5732{5733resister*fpm;57345735m=mode;5736fp=setfu.u_arg[R0];5737iffp==NILL5738return;5739iffp-f_flagm==0{5740u.u_error=EBADF;5741return;5742}5743u.u_base=u.u_arg
[0];5744u.u_count=u.u_arg
[1];5745u.u_seg___=0;5746iffp-f_flagFPIPE{5747ifm==FREAD5748readpfp;else5749writepfp;5750}else{5751u.u_offset
[1]=fp-f_offset
[1];5752u.u_offset
[0]=fp-f_offset
[0];5753ifm==FREAD5754readifp-f_inode;else5755writeifp-f_inode;5756dpaddfp-f_offsetu.u_arg
[1]–u.u_count;5757}5758u.u_ar0[R0]=u.u_arg
[1]–u.u_count;5759}“read”系统调用的基本工作过程为……readfbn;/*用户程序*/{发生陷入}2693trap{#3系统调用}5711read;5713rdwrFREAD;用户进程执行系统调用激活运行在核心态的“trap”“trap”识别#3系统调用,然后通过“trapl”调用例程“read”,它又调用“rdwr”“rdwr”包含了很多“read”和“write”操作共用的代码它调用“getf”6619将用户进程提供的文件标识变换成“file”数组中一项的地址注意,该系统调用的第1个参数是以不同于另外2个参数的方式传送的将“u.u_seg___”设置为0,这表示此操作的目的地址在用户地址空间中在以一个inode指针参数调用“readi”后,将要求传送的字符数减去剩余未传输字符数在u.u_count中,加至文件位移量中6221readi6239lbn=lshiftu.u_offset-9;6248on=u.u_offset[i]0777;6241n=min512–onu.u_count;6250dn=ip-i_dev;6258bp=breaddnbn;6260iomovebponnB_READ;6261brelsebp;“readi”将文件位移量分解成两部分一个逻辑块号“lbn”,以及一个块内索引“on”将要传输的字符数是下而两个值中的较小者“u.u_count”和块内尚余字符数在这种情况下以后还必须读其他块,此处没有进一步对此说明,还应考虑尚余留在文件中的字符数对这种情况也未进一步说明“dn”是存储在“inode”中的设备编号,“bn”是在该设备磁盘上的实际块号,这是由“b__p”6415用“lbn”计算得到的对“bread”的调用找到所要求的磁盘块,若需要,则将其从磁盘__到内存中“iomove”6364将适当数量的字符传送至目的区,然后执行计数操作“read”和“write”执行的操作有很多相似之处,两者共享很多代码系统调用“read”5711和“write”5720,然后立即调用“rdwr”,它执行下列操作5736将用户程序文件标识变换成指向相应文件表项的指针5739检查所要求的操作读或写是否与文件打开时的读/写方式符合5743用各参数在“u”中设置几个标准单元5746从此开始对“管道”文件进行特殊处理5755按读、写要求分别调用“readi”或“writei”5756更新文件位移量,使其增加实际传送的字符数,同时也将实际传送的字符数返回。