《linux操作系统课程设计ls的编写含源码.doc》由会员分享,可在线阅读,更多相关《linux操作系统课程设计ls的编写含源码.doc(35页珍藏版)》请在三一办公上搜索。
1、西安郵電大學操作系统课程设计报 告 书院系名称:计算机学院学生姓名:专业名称:软件工程班 级:班学号:时间:2015 年4月 13 日 至 2015 年 4月 24 日 1 实验目的操作系统是控制和管理计算机硬件和软件资源的虚拟机,其中的文件系统是对软件和设备进行管理的系统,文件系统是操作系统中非常重要的一个模块,它的实现占用了操作系统源码的最大编码量,其好坏也直接影响着用户对操作系统的感受程度。通过对操作系统课程设计的实践,进一步加深对文件系统的认识和理解,并在此基础上培养学生的工程应用能力。实验分别从用户态和内核态两个层次实践文件系统的部分功能。2 实验任务2.1 ls实现在linux下编
2、程实现带参数的shell命令 ls,ls命令必须支持如下功能。1.基本要求(1) 支持 -l 参数;(2) 输出结果按字典排序;(3) 列出“.”文件,支持-a参数,在没有-a时候不显示隐藏文件;(4) 显示记录总数。2.高级要求(1) 支持对给定的目录进行操作,如 ls /tmp;(2) 输出结果分栏排序,每栏的宽度由这一栏最长的文件名决定,显示的栏数还受终端显示器的宽度影响,每一列尽可能的等宽;(3) 正确显示文件特殊属性suid、sgid和sticky,参见联机帮助确保程序能处理各种情况;(4) 支持标准的ls支持选项-R,它的功能是递归地列出目录中所有的文件包含子目录中的文件;(5)
3、支持标准的ls支持选项-u,它会显示出文件的最后访问时间,如果用了-u而不用-l,会有什么结果?;(6) 当关掉一个文件的读权限,就不能打开这个文件来读。如果从一个终端登录,打开一个文件,保持文件的打开状态,然后从另外的终端登录,去掉文件的读权限,这时有什么事情会发生?编写一个程序,先用open()打开一个文件,用read()读一些内容,调用sleep()等待20s以后,再读一些内容,从另外的终端,再等待的20s内去掉文件的读权限,这样会有什么结果?。2.2编写内核模块显示目录或文件的信息。(1) 使用内核模块编程;(2) 调试Linux操作系统原理与应用第8章文件系统P215 的例子;(3)
4、 练习给内核模块传入参数,参考关于带参数的模块编程 (4) 给内核模块传入参数path,其中path为绝对路径;1) 当path为目录时,显示目录对应的dentrey结构中的相关信息(可打印的信息);2) 当path为文件时,显示文件对应的indoe结构中的相关信息(可打印的信息);3) 当路径错误时,有错误提示信息。3 开发环境 设备名称设备类型配置类型参数LenovoG480 PC机硬件配置RAM 4G 软件配置Ubuntu 32位 4 测试环境设备名称设备类型配置类型参数LenovoG480 PC机硬件配置RAM 4G 软件配置Ubuntu 32位 5 总体设计5.1功能组织图ls 功能
5、图:运行命令Ls-aLsLs-lLs-la添加 /temp(指定目录)输出所有文件属性输出隐藏文件输出文件属性按字典顺序排序文件权限:运行命令chmod修改权限读文件,ls显示权限信息内核模块:super_blocks:运行命令加载模块加锁遍历系统中的超级块打印文件设备号打印文件系统名打印索引结点号统计索引结点计数卸载模块path:运行命令路径错误Path=文件Path=目录显示目录信息显示错误信息显示文件信息5.2原理linux文件系统:linux下有普通文件、目录文件、链接文件、设备文件、管道文件这几种类型。但链接文件、设备文件、管道文件都可以当做普通文件看待,那实际也就只要区分普通文件和
6、目录文件这两种了。而目录文件的内容就是它所包含所有文件和子目录的一个列表,所以只要打开目录文件并读取对应目录块里的那个列表数据,就可以得到些目录下所有文件和子目录的名称了。其实这个流程简单,就是:打开目录-读取内容-显示文件名称-关闭打开的目录。Linux系统中会有很多目录。每个目录中又会有很多文件。如果要列出一个非当前目录的内容或者是一个特定文件的信息,则需要在参数中给出目录名或文件名。如:ls/tmp/列出/tmp目录中各文件的文件名lsdocs/列出docs目录中各文件的属性ls*.c/列出当前目录下与*.c匹配的文件,即当前目录下所有以.c为后缀的经常用到的命令行选项ls-l在前面已经
7、提到过,-l就是输出文件详细的信息ls-a列出的内容包含以“.“开头的文件,即所谓有隐藏文件Linux的文件访问权限:Linux是一个安全的操作系统,说他安全,最重要的一个原因是对用户访问权限的控制。在shell下我们可以通过命令ls-l filename 来查看一文件的属性。其中第一项文件属性总共由10位构成,第一位是文件类型,剩下9位都是表示文件的访问权限,每3个一组,第一组:文件所有者对该文件的操作权限,第二组表示与文件所有者同组的用户对该文件的操作权限,第三组表示其他用户对该文件的操作权限,权限由三种字母组成:r:可读w:可写x:可执行。编写内核模块 写内核模块,打印super_blo
8、ck结构中一些域的值。(课本上的例子)遍历系统中的超级块:list_head结构类型的字段名称为s_list。list_entry宏通过指向list_head节点的地址来得到外部超级块的首地址。获取系统中个超级块的地址,获得某个子进程的地址,打印文件系统所在的主设备号和次设备号和文件系统名。遍历打印每个超级块中的所有索引节点号,打印索引结点。 内核模块传入参数path,其中path为绝对路径path=路径时,显示如下信息:目录项标志、哈希表、短目录名、目录项长度、目录项名、目录项计数器的引用path=文件时,显示如下信息:文件索引节点的数量、文件类型和权限、用户ID、用户组ID、指定文件系统的
9、读写访问标志、文件大小、索引节点的状态、硬链接数、引用记数、文件的块、版本号、以位为单位的块大小6 详细设计6.1 模块一ls1.功能(1)ls支持 -l 参数;(2)输出结果按字典排序;(3)列出“.”文件,支持-a参数,在没有-a时候不显示隐藏文件;(4)显示记录总数。(5)支持对给定的目录进行操作,如 ls /tmp;(6)输出结果分栏排序,每栏的宽度由这一栏最长的文件名决定,显示的栏数还受终端显示器的宽度影响,每一列尽可能的等宽;(7)修改文件权限 2.算法/流程图ls算法描述:用parameter20保存命令行参数的值,用pathPATH_MAX+1保存文件的路径名;程序运行时,先将
10、命令参数保存下来,并给flag_parameter赋相应的值,再判断文件路径是否存在,不存在则代表当前目录,将./赋值给path,若存在,则根据文件路径判断是文件还是目录,若是文件,就根据flag_parameter和path调用Output_parameter()函数,输出该文件的属性;若是目录,就将正确的目录名保存到path;最后根据flag_parameter和path调用Output_dir()函数,列出目录下所有文件的属性。流程图:main()函数:开始parameter20保存命令行参数的值给flag_parameter赋相应的值判断是否有文件路径否给path赋值为./是文件路径名
11、保存在path中判断文件路径是否存在否是判断文件路径是目录否是调用Output_dir(flag_parameter,path);判断文件路径是文件否 是调用Output_parameter(flag_parameter, path);结 束Output_file_attribute():开始给str赋值”-”判断文件的类型,给str0赋值对应的字母判断用户的权限,给str13赋值判断组的权限,给str46赋值判断其他用户的权限,给str79赋值输出str 10的内容输出文件的各种属性文件个数加一结束Output_parameter():开始文件个数加一从路径中解析出文件名Lstat解析链接文
12、件否是flag_parameter= PARAMETER_N调用Output()Name0=.是是 否否flag_parameter= PARAMETER_A调用Output()是否flag_parameter= PARAMETER_L调用Output_file_attribute()Name0=. 是是否否flag_parameter= PARAMETER_A_L调用Output_file_attribute()是否结束Output():开始本行剩余长度文件名长度否是换行,给剩余长度赋最大值打印文件名文件个数加一结束3.运行结果4.模块使用的主要函数、数据类型和宏(1)主要函数说明1)函数一
13、Output_file_attribute原型:Output_file_attribute(struct stat buf, char * name)功能:根据文件名输出文件的各种属性参数:buf,name返回值:void2)函数二Output原型:Output(char * name)功能:将文件名分栏排序参数: name返回值:void3)函数三Output_parameter原型: Output_parameter(int flag, char * pathname)功能:根据命令行参数和完整路径名按要求显示目标文件参数:flag,pathname返回值:void4)函数四Output_
14、dir原型: Output_dir(int flag_parameter, char * path)功能:根据命令行参数和目录路径名将目录下的文件按要求显示出来参数:flag_parameter,path返回值:void(2)数据类型1)数据类型1名称:num类型:int含义:保存命令参数行-的个数2)数据类型2名称:pathPATH_MAX+1类型:char含义:保存文件路径名3)数据类型3名称:parameter20类型:char含义:保存命令行参数4)数据类型4名称:flag_parameter类型:int含义:记录命令行参数的种类5)数据类型5名称:buf类型:struct stat含
15、义:保存文件信息(3)宏1名称:#define PARAMETER_N 0 含义:命令行无参数宏2名称:#define PARAMETER_A 1含义:命令行参数只有-a宏3名称:#define PARAMETER_L 2含义:命令行参数只有-l宏4名称:#define PARAMETER_A_L 3含义:命令行参数有-a和-l宏5名称:#define MAXROWLEN 80含义:一行显示的最多字符数,用于分栏排序6.2 模块二read1.功能打开文件,修改文件权限后读取文件内容2.算法/流程图算法:定义一个空指针buf用来存放动态申请内存空间的地址,定义一个整型变量file用来存放文件描述
16、符;用open()函数已只读的方式打开指定的文件,返回的文件描述符赋给file;若文件打开成功,就休眠20秒,在这20秒期间,通过chmod 命令改变文件的读写权限;然后根据file的值来读取文件中的字符,存放在buf,再输出buf,若读取失败就退出。流程图:开始定义buf,file变量buf = malloc(30);file=open (read.txt,O_RDONLY);file=-1是否休眠20s,chmod修改文件权限(read(file,buf,30) = -1是否输出buf的内容结束3.运行结果4.模块使用的主要函数、数据类型和宏(1)主要函数说明1)函数一main原型:voi
17、d main()功能:打开文件参数:无返回值:无(2)数据类型1)数据类型1名称:buf类型:void *含义:定义一个空指针,用来指向动态申请的内存地址2)数据类型2名称:file类型:int含义:用来存放打开文件的文件描述符(3)宏:无6.3 模块三super_block1.功能通过加载内核的方式,打印出超级块super_blocks数据结构中文件系统所在的主设备号和次设备号以及文件系统名2.算法/流程图开始加载模块加锁遍历系统中的超级块打印文件设备号打印文件系统名打印索引结点号索引结点计数卸载模块结束3.运行结果4.模块使用的主要函数、数据类型和宏(1)主要函数说明1)函数一原型: st
18、atic int _init my_init(void)功能:模块加载参数:无返回值:int2)函数二原型:static void _exit my_exit(void)功能:模块卸载参数:void返回值:void(2)数据类型1)数据类型1名称:sb类型:struct super_block *含义:定义一个超级块2)数据类型2名称:pos类型:struct list_head *含义:定义一个链表3)数据类型3名称:linode类型:struct list_head *含义:定义一个链表4)数据类型4名称:pinode类型:struct inode *含义:定义一个索引结点5)数据类型5名
19、称:count类型:int含义:存储总数(3)宏一名称:#define SUPER_BLOCKS_ADDRESS 0xc1778bc0含义:超级块的变量地址宏二名称:#define SB_LOCK_ADDRESS0xc1932aa0含义: sb_lock超级块对应的自旋锁6.4 模块四path1.功能给内核模块传入参数path,其中path为绝对路径;1) 当path为目录时,显示目录对应的dentrey结构中的相关信息(可打印的信息);2) 当path为文件时,显示文件对应的indoe结构中的相关信息(可打印的信息);3) 当路径错误时,有错误提示信息。2.算法/流程图开始加载模块调用ope
20、n()卸载模块结束开始open()函数:打开文件是文件 否调用file_put()打印文件信息是调用dir()打印目录信息关 闭 文 件结束3.运行结果4.模块使用的主要函数、数据类型和宏(1)主要函数说明1)函数一原型:static int file_put(void)功能:打印文件信息参数:void返回值:int2)函数二原型:static int dir(void)功能:打印目录信息参数:void返回值:int3)函数三原型:static int open(char *path)功能:打开文件参数:char *path返回值:int4)函数四原型:static int param_ini
21、t(void)功能:加载模块参数:void返回值:int5)函数五原型:static void param_exit(void)功能:模块卸载参数:void返回值:void(2)数据类型1)数据类型1名称:file类型:struct file *含义:定义一个文件2)数据类型2名称:inode类型:struct inode *含义:定义一个索引结点3)数据类型3名称:dent类型:struct dentry *含义:4)数据类型4名称:path_file类型:static char *含义:定义一个字符串存放输入文件名(3)宏:无7 测试方法与测试结果7.1测试方法 编号 输入用例 期望结果
22、1 ./ls按字典排序,输出当前目录下的所有文件名(不含隐藏文件) 2 ./ls -l ls.c显示 ls.c文件的详细信息 3 ./ls -a ./python显示上级目录下python目录的所有文件名,含有隐藏文件。 4 ./ls -l .显示当前目录下的非隐藏文件详细信息按字典排序 5 ./ls -al ./shell显示上层文件夹下所有文件文件的详细信息 6 ./ls abc 显示ERROR:当前文件夹下没有该文件7.2测试结果 1. ./ls 2. ./ls l ls.c3. ./ls a ./python4. ./ls l ./pyhon5. ./ls al ./shell6. .
23、/ls abc8 调试情况,设计技巧及体会在设计过程中,在编写多个命令参数时遇到了困难,由于在程序整个过程中都需要根据命令参数打印记录文件,因此设定了一个数组用来存储命令行参数,考虑到全局参数不安全,因此选择使用函数的形参来传递。,通过这次课程设计,不仅使我对ls命令有了更深一层的认识,还认识到了系统提供的命令实现的途径和方法。之前总是使用系统命令,如今自己编程实现了一些命令,每次使用系统提供的命令和调用自己编写的命令感觉大不相同。对同时对内核模块的编程也更加熟悉了。在做设计时先要理清思路,设计好功能模块之间的关系,再一步一步编码实现。9 参考资料 1 DANIEL P.BOVET&MARCO
24、 CESATI. 深入理解LINUX内核M. 陈莉君,张琼声,张宏伟,译.第三版. 北京:中国电力出版社,2007:825-831.2Documentation/x86/boot.txt 4 Richard Blum. 汇编语言程序设计M. 马朝晖 译. 北京:机械工业出版社,2006.5 http:/elinux.org/images/d/d2/Tools-and-technique-for-reducing-bootup-time.pdf10 源程序清单Ls.c#include #include #include #include #include #include #include #i
25、nclude #include #include #include #define PARAMETER_N 0 / 无参数#define PARAMETER_A 1 / -a: 显示所有文件#define PARAMETER_L 2 / -l:一行显示一个文件的详细信息#define PARAMETER_A_L 3 /-a-l或-la或-al显示所有文件的详细信息#define MAXROWLEN 80 / 一行显示的最多字符数int cnt = 0;/显示文件的总个数int leave_len = MAXROWLEN; / 一行剩余长度,用于输出对齐int maxlen; / 存放某目录下最
26、长文件名的长度void Output_file_attribute(struct stat buf, char * name); /打印文件属性void Output(char * name);/只输出文件名,命令没有-l选项,文件名时要保持上下文对齐void Output_parameter(int flag, char * pathname); /根据命令行参数和文件路径名显示目标文件void Output_dir(int flag_parameter, char * path); /显示目录下的文件int main(int argc, char * argv)int i, j, k, n
27、um;char pathPATH_MAX+1; /文件路径名char parameter20; / 保存命令行参数-a-lint flag_parameter = PARAMETER_N; / 用来记录参数种类struct stat buf;j = 0;num = 0;for (i = 1 ; i argc; i+)if (argvi0 = -)for(k = 1; k strlen(argvi); k+)parameterj = argvik; / 获取-后面的参数保存到数组parameter中j+;num+; / 保存的个数/记录参数,最后为选项数组的末尾元素赋0。for(i = 0; i
28、 j; i+)if(parameteri = a)flag_parameter = PARAMETER_A;i+;if(parameteri = l)/记录-al情况flag_parameter = PARAMETER_A_L;elsei-;continue;else if (parameteri = l)flag_parameter = PARAMETER_L;i+;if(parameteri = a)/记录-la情况flag_parameter = PARAMETER_A_L;continue;elseprintf(ls:参数输入错误-%cn, parameteri);exit(1);pa
29、rameterj = 0;/判断是否是当前目录,若是,则给path赋值为./if (num + 1) = argc)strcpy(path, ./);/ ./当前目录path2 = 0;Output_dir(flag_parameter, path);printf(nTotal:%dn,cnt);return 0;i=1;do/如果不是目标文件名或目录,解析下一个命令行参数if (argvi0 = -)/跳过-a-l参数i+;continue;elsestrcpy(path, argvi);/如果目标文件或目录不存在,报错并退出程序if ( stat(path, &buf) = -1 )pri
30、ntf(目标文件不存在);if ( S_ISDIR(buf.st_mode) ) / argvi是一个目录/ 如果目录的最后一个字符不是/,就加上/if ( path strlen(argvi)-1 != /)path strlen(argvi) = /;path strlen(argvi)+1 = 0;elsepath strlen(argvi) = 0;Output_dir(flag_parameter,path);i+;else /argvi是一个文件Output_parameter(flag_parameter, path);i+; while (i pw_name); /打印文件拥有
31、者printf( %-8s, grp-gr_name); /打印文件所属用户组printf(%6ld,(long)buf.st_size); / 打印文件的大小strcpy(buf_time,ctime(&buf.st_mtime);buf_timestrlen(buf_time) - 1 = 0; / 去掉换行符printf( %s,buf_time);/ 打印文件的时间信息cnt+;/在没有使用-l选项时,打印一个文件名,打印时上下行之间进行对齐void Output(char *name)int i, len;/如果本行不足以打印一个文件名则换行if (leave_len maxlen)
32、printf(n);leave_len = MAXROWLEN;len = strlen(name);len = maxlen - len;printf(%-s, name);for (i = 0; i len; i+)printf( );cnt+;printf( );leave_len -= (maxlen + 2);/ 根据命令行参数和完整路径名显示目标文件void Output_parameter(int flag_parameter, char * pathname)int i, j;struct stat buf;char nameNAME_MAX + 1;/从路径中解析出文件名fo
33、r (i = 0, j = 0; i strlen(pathname); i+)if (pathnamei = /)j = 0;continue;namej+ = pathnamei;namej = 0;/用lstat解析链接文件if ( lstat(pathname, &buf) = -1 ) /lstat返回的是符号链接文件文件本身的状态信息printf(errorn);switch (flag_parameter)case PARAMETER_N: / 没有-l和-a选项if (name0 != .)/不输出隐藏文件Output(name);break;case PARAMETER_A:
34、 / -a:显示包括隐藏文件在内的所有文件Output(name);break;case PARAMETER_L: / -l:每个文件单独占一行,显示文件的详细属性信息if (name0 != .)Output_file_attribute(buf, name);printf( %-sn, name);break;case PARAMETER_A_L: / 同时有-a和-l选项的情况,输出所有文件详细信息Output_file_attribute(buf, name);printf( %-sn, name);break;default:break;/*为显示目录下的文件做准备*/void Ou
35、tput_dir(int flag_parameter, char *path)DIR *dir;struct dirent *ptr;int count = 0;char filenames256PATH_MAX + 1,tempPATH_MAX + 1;/ 获取该目录下文件总数和最长的文件名dir = opendir(path);if (dir = NULL)printf(目录打开失败n);while (ptr = readdir(dir) != NULL)if (maxlen d_name)maxlen = strlen(ptr-d_name);count+;closedir(dir);if(count 256)printf(errorn);int i, j, len = strlen(path);/ 获取该目录下所有的文件名