资源预览内容
第1页 / 共428页
第2页 / 共428页
第3页 / 共428页
第4页 / 共428页
第5页 / 共428页
第6页 / 共428页
第7页 / 共428页
第8页 / 共428页
第9页 / 共428页
第10页 / 共428页
亲,该文档总共428页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Linux操作系统操作系统吴翔虎吴翔虎1第一章第一章 Linux概述概述 Linux是是一一套套免免费费使使用用和和自自由由传传播播的的类类Unix操操作作系系统统,它它主主要要用用于于基基于于Intel x86系系列列CPU的的计计算算机机上上。其其目目的的是是建建立立不不受受任任何何商商品品化化软软件件的的版版权权制制约约的的、全全世世界界都能自由使用的都能自由使用的Unix兼容产品。兼容产品。 Linux最最早早由由一一位位名名叫叫Linus Torvalds的的计计算算机机爱爱好好者者开开发发,他他的的目目的的是是设设计计一一个个代代替替Minix的的操操作作系系统统,这这个个操操作作系系统统可可用用于于386、486或或奔奔腾腾处处理理器器的的个个人人计计算算机上,并且具有机上,并且具有Unix操作系统的全部功能。操作系统的全部功能。2Linux概貌概貌 Linux以它的高效性和灵活性著称。它能够在个人计算机上实现全部的Unix特性,具有多任务、多用户的能力。Linux可在GNU(“不是UNIX”工程的缩写)公共许可权限下免费获得,是一个符合POSIX标准的操作系统。Linux操作系统软件包不仅包括完整的Linux操作系统,而且还包括了文本编辑器、高级语言编译器等应用软件。它还包括带有多个窗口管理器的X-Windows图形用户界面,如同我们使用Windows NT一样,允许我们使用窗口、图标和菜单对系统进行操作。3Linux概貌概貌 Linux之所以受到广大计算机爱好者的喜爱,主要原因有两个,一是它属于自由软件,用户不用支付任何费用就可以获得它和它的源代码,并且可以根据自己的需要对它进行必要的修改和无约束地继续传播。另一个原因是,它具有Unix的全部功能,任何使用Unix操作系统或想要学习Unix操作系统的人都可以从Linux中获益。4Linux的主要特点的主要特点开放性:指系统遵循世界标准规范,特别是遵循开放系统互连(OSI)国际标准。 多用户:是指系统资源可以被不同用户使用,每个用户对自己的资源(例如:文件、设备)有特定的权限,互不影响。多任务:它是指计算机同时执行多个程序,而且各个程序的运行互相独立。良好的用户界面 :Linux向用户提供了两种界面:用户界面和系统调用。Linux还为用户提供了图形用户界面。它利用鼠标、菜单、窗口、滚动条等设施,给用户呈现一个直观、易操作、交互性强的友好的图形化界面。5Linux的主要特点的主要特点设备独立性:是指操作系统把所有外部设备统一当作成文件来看待,只要安装它们的驱动程序,任何用户都可以象使用文件一样,操纵、使用这些设备,而不必知道它们的具体存在形式。Linux是具有设备独立性的操作系统,它的内核具有高度适应能力 提供了丰富的网络功能:完善的内置网络是Linux一大特点。 可靠的安全系统:Linux采取了许多安全技术措施,包括对读、写控制、带保护的子系统、审计跟踪、核心授权等,这为网络多用户环境中的用户提供了必要的安全保障。良好的可移植性:是指将操作系统从一个平台转移到另一个平台使它仍然能按其自身的方式运行的能力。Linux是一种可移植的操作系统,能够在从微型计算机到大型计算机的任何环境中和任何平台上运行。 6Linux的组成的组成LINUX的内核:内核是系统的核心,是运行程序和管理像磁盘和打印机等硬件设备的核心程序。LINUX SHELL: Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。LINUX文件系统: Linux文件系统是文件存放在磁盘等存储设备上的组织方法。Linux能支持多种目前浒的文件系统,如EXT2、EXT3、FAT、VFAT、ISO9660、NFS、SMB等。LINUX应用系统:标准的Linux系统都有一整套称为应用程序的程序集,包括文本编辑器、编程语言、X Window、办公套件、Internet工具、数据库等。7Linux的主要版本的主要版本1.红旗红旗Linux 2.冲浪冲浪Linux 3.中软中软Linux 4. Red Hat Linux 5.Mandrake Linux 6. TurboLinux8Linux的系统结构9Linux文件系统10文件系统的特点层次结构文件数据的一致对待建立、删除文件的能力文件的动态增长文件数据的保护把外围设备(如终端及磁盘等)作为文件看待11处理环境1、程序与进程程序与进程程序是一个可执行文件,进程是一个执行中的程序的实例;2、子进程与父进程子进程与父进程 一个进程可通过系统调用fork创建一个新进程,称创建的进程为子进程,而创建它的进程称为父进程。3、系统调用的执行shell命令解释程序命令解释程序 shell允许三种类型的命令:可执行文件;包含一系列shell命令的可执行文件;一个内部shell命令。12Linux操作系统的服务通过允许进程的创建、终止、挂起及通信来控制进程的执行 对进程在CPU上的执行进行公平调度对正在执行的进程分配主存为实现用户数据的有效存储和检索而分配二级存储允许进程对IO设备进行有控制的存取13Linux对硬件的要求1、用户进程的执行状态:用户进程的执行状态:用户态和核心态2、中断与异常中断与异常中断:允许IO外设或系统时钟异步终端CPU例外:指的是有一个进程引起的非期望事件,如:非法存储寻找,执行特权指令等3、存储管理存储管理核心永远驻留在主存中编译程序产生的是虚地址,核心与机器硬件一起协作,建立虚地址到物理地址的转换14第二章第二章 Shell及常用命令及常用命令 shellshell是一种命令解释器,它提供了用是一种命令解释器,它提供了用户和操作系统之间的交互接口。户和操作系统之间的交互接口。shellshell是面是面向命令行的,而向命令行的,而X Window 则是图形界面。则是图形界面。你在命令行输入命令,你在命令行输入命令,shellshell进行解释,然进行解释,然后送往操作系统执行。后送往操作系统执行。shellshell可以执行可以执行Linux 的系统内部命令,也可以执行应用程的系统内部命令,也可以执行应用程序。你还可以利用外壳编程,执行复杂的序。你还可以利用外壳编程,执行复杂的命令程序。命令程序。shellshell也可以说是一种程序设计也可以说是一种程序设计语言。语言。15Shell的类型的类型 Linux 提供几种提供几种shellshell程序以供选择。程序以供选择。常用的有常用的有Bourne shellshell( b s h )、C shellshell( c s h )和和Korn shellshell( k s h )。各个。各个shellshell都都能提供基本的功能,又有其各自的特点。能提供基本的功能,又有其各自的特点。Bourne shellshell是由是由Steven Bourne 编写的,编写的,是是UNIX 的缺省的缺省shellshell。Bourne shellshell编程编程能力很强。但它不能处理命令的用户交互能力很强。但它不能处理命令的用户交互特征。特征。bash 是是Bourne 外壳的增强版。外壳的增强版。16Shell的类型的类型C shellshell是由加利福尼亚大学伯克利分校的是由加利福尼亚大学伯克利分校的Bill Joy编写的。编写的。它能提供它能提供Bourne shellshell所不能处理的用户交互特征,如命所不能处理的用户交互特征,如命令补全、命令别名、历史命令替换等。很多人认为,令补全、命令别名、历史命令替换等。很多人认为, C shellshell的编程能力不如的编程能力不如Bourne shell shell ,但它的语法和,但它的语法和C语语言类似,所以言类似,所以C程序员将发现程序员将发现C shellshell很顺手。很顺手。tcsh 是是C shellshell的增强版本和的增强版本和C shellshell完全兼容。完全兼容。K o r n shellshell是由是由Dave Korn 编写的。编写的。Korn shellshell融合了融合了C shellshell和和Bourne shellshell的优点,并和的优点,并和Bourne shellshell完全完全兼容。兼容。Korn shellshell的效率很高,其命令交互界面和编程交的效率很高,其命令交互界面和编程交互界面都很不错。互界面都很不错。Public Domain Korn shellshell( p d k s h )是是Korn shellshell的增强版。的增强版。17bash shell bash 是大多数是大多数L i n u x系统的缺省外壳。它系统的缺省外壳。它克服了克服了Bourne 外壳的缺点,又和外壳的缺点,又和Bourne 外壳完外壳完全兼容。全兼容。ba s h有以下的特点:有以下的特点:补全命令行。当你在补全命令行。当你在bash 命令提示符下输入命令命令提示符下输入命令或程序名时,你不必输全命令或程序名,按或程序名时,你不必输全命令或程序名,按Tab 键,键,b a s h将自动补全命令或程序名。将自动补全命令或程序名。通配符。在通配符。在b a s h下可以使用通配符下可以使用通配符* 和?。和?。*可可以替代多个字符,而?则替代一个字符。以替代多个字符,而?则替代一个字符。18bash shell历史命令。历史命令。bash 能自动跟踪你每次输入的命令,能自动跟踪你每次输入的命令,并把输入的命令保存在历史列表缓冲区。缓冲区并把输入的命令保存在历史列表缓冲区。缓冲区的大小由的大小由HISTSIZE 变量控制。当你每次登录后,变量控制。当你每次登录后,home 目录下的目录下的.bash_history 文件将初始化你的文件将初始化你的历史列表缓冲区。你也能通过历史列表缓冲区。你也能通过history 和和fc 命令执命令执行、编辑历史命令。行、编辑历史命令。别名。在别名。在b a s h下,可用下,可用alias 和和unalias 命令给命命令给命令或可执行程序起别名和清除别名。这样你可以令或可执行程序起别名和清除别名。这样你可以用自己习惯的方式输入命令。用自己习惯的方式输入命令。19bash shell输入输入/ /输出重定向。输入重定向用于改变命输出重定向。输入重定向用于改变命令的输入,输出重定向用于改变命令的输令的输入,输出重定向用于改变命令的输出。输出重定向更为常用,它经常用于将出。输出重定向更为常用,它经常用于将命令的结果输入到文件中,而不是屏幕上。命令的结果输入到文件中,而不是屏幕上。输入重定向的命令是输入重定向的命令是。管道。管道用于将一系列的命令连接起来。管道。管道用于将一系列的命令连接起来。也就是把前面的命令的输出作为后面的命也就是把前面的命令的输出作为后面的命令的输入。管道的命令是令的输入。管道的命令是|。20bash shell提示符。提示符。bash 有两级提示符。第一级提示符就是你登录外有两级提示符。第一级提示符就是你登录外壳时见到的,缺省为壳时见到的,缺省为$。你可以通过重新给。你可以通过重新给p s 1变量赋值变量赋值来改变第一级提示符。当来改变第一级提示符。当b a s h需要进一步提示以便补全需要进一步提示以便补全命令时,会显示第二级提示符。第二级提示符缺省为命令时,会显示第二级提示符。第二级提示符缺省为,你可以通过重新给你可以通过重新给p s 2变量赋值来改变第二级提示符。一变量赋值来改变第二级提示符。一些特殊意义的字符也可以加入提示符赋值中。些特殊意义的字符也可以加入提示符赋值中。作业控制。作业控制是指在一个作业执行过程中,控制执作业控制。作业控制是指在一个作业执行过程中,控制执行的状态。你可以挂起一个正在执行的进程,并在以后恢行的状态。你可以挂起一个正在执行的进程,并在以后恢复该进程的执行。按下复该进程的执行。按下Ctrl+Z 挂起正在执行的进程,用挂起正在执行的进程,用b g命令使进程恢复在后台执行,用命令使进程恢复在后台执行,用f g命令使进程恢复在前命令使进程恢复在前台执行。台执行。21登陆和退出登陆和退出 Linux 启动后,给出启动后,给出login 命令,等待用户登录。命令,等待用户登录。 Login: Password: 如果是正确的用户名和密码,那么你就会进入如果是正确的用户名和密码,那么你就会进入Linux 的的shellshell, shellshell给出命令提示符,等待你给出命令提示符,等待你输入命令(不要随意以输入命令(不要随意以r o o t身份登录,以避免对身份登录,以避免对系统造成意外的破坏)。系统造成意外的破坏)。 使用使用l o g o u t命令退出外壳。命令退出外壳。22更改账号密码更改账号密码语法:语法: p a s s w dOld password: New password: Retype new password: 23联机帮助联机帮助语法:语法: man 命令命令例如例如: man ls24远程登录远程登录语法:语法:rlogin 主机名主机名-1 用户名用户名例如:例如:rlogin doc 远程登录到工作站远程登录到工作站doc 中。中。rlogin doc -l user 使用使用user 帐号登录到工作站帐号登录到工作站doc 中。中。语法:语法:telnet 主机名或主机名或telnet IP地址地址例如:例如:telnet doctelnet 140.109.20.25125文件或目录处理文件或目录处理列出文件或目录下的文件名。列出文件或目录下的文件名。语法:语法: ls -atFlgR namename :文件名或目录名。文件名或目录名。例如:例如:ls 列出目前目录下的文件名。列出目前目录下的文件名。ls -a 列出包括以开始的隐藏文件的所有文件名。列出包括以开始的隐藏文件的所有文件名。ls -t 依照文件最后修改时间的顺序列出文件名。依照文件最后修改时间的顺序列出文件名。26文件或目录处理文件或目录处理ls -F 列出当前目录下的文件名及其类型。以列出当前目录下的文件名及其类型。以/ 结尾结尾 表示为目录名,以表示为目录名,以* 结尾表示为可执行文件,结尾表示为可执行文件, 以以 结尾表示为符号连接。结尾表示为符号连接。ls -l 列出目录下所有文件的权限、所有者、文件大列出目录下所有文件的权限、所有者、文件大 小、修改时间及名称。小、修改时间及名称。ls -lg 同上,并显示出文件的所有者工作组名。同上,并显示出文件的所有者工作组名。ls -R 显示出目录下以及其所有子目录的文件名。显示出目录下以及其所有子目录的文件名。27改变工作目录改变工作目录语法:语法:cd namen a m e:目录名、路径或目录缩写。目录名、路径或目录缩写。例如例如:cd 改变目录位置至用户登录时的工作目录。改变目录位置至用户登录时的工作目录。cd dir1 改变目录位置至改变目录位置至d i r 1目录下。目录下。28改变工作目录改变工作目录cd user 改变目录位置至用户的工作目录。改变目录位置至用户的工作目录。cd . 改变目录位置至当前目录的父目录。改变目录位置至当前目录的父目录。cd ./user 改变目录位置至相对路径改变目录位置至相对路径user 的目录下。的目录下。cd /./. 改变目录位置至绝对路径的目录位置下。改变目录位置至绝对路径的目录位置下。cd 改变目录位置至用户登录时的工作目录。改变目录位置至用户登录时的工作目录。29复制文件复制文件语法语法: cp -r 源地址目的地址源地址目的地址例如:例如:cp file1 file2 将文件将文件file1 复制成复制成f i l e 2。cp file1 dir1 将文件将文件file1 复制到目录复制到目录dir1 下,文件名下,文件名 仍为仍为f i l e 1。30复制文件复制文件cp /tmp/file1 . 将目录将目录/tmp 下的文件下的文件file1 复制到当前复制到当前 目录下,文件名仍为目录下,文件名仍为f i l e 1。cp /tmp/file1 file2 将目录将目录/tmp 下的文件下的文件file1 复制到复制到 当前目录下,文件名为当前目录下,文件名为f i l e 2。cp -r dir1 dir2 复制整个目录。复制整个目录。31移动或更改文件、目录名称移动或更改文件、目录名称语法:语法: mv 源地址目的地址源地址目的地址例如:例如:mv file1 file2 将文件将文件f i l e 1更名为更名为f i l e 2。mv file1 dir1 将文件将文件f i l e 1移到目录移到目录dir1 下,文件名下,文件名 仍为仍为f i l e 1。mv dir1 dir2 将目录将目录dir1 更改为目录更改为目录d i r 2。32建立新目录建立新目录语法:语法: mkdir 目录名目录名例如:例如:mkdir dir1 建立一新目录建立一新目录d i r 1。33删除目录删除目录语法:语法: rmdir 目录名或目录名或rm 目录名目录名例如:例如:rmdir dir1 删除目录删除目录d i r 1,但,但dir1 下必须没有文件下必须没有文件 存在,否则无法删除。存在,否则无法删除。rm -r dir1 删除目录删除目录d i r 1及其子目录下所有文件。及其子目录下所有文件。34删除文件删除文件语法:语法: rm 文件名文件名例如:例如:rm file1 删除文件名为删除文件名为file1 的文件。的文件。rm file? 删除文件名中有五个字符且前四个字符为删除文件名中有五个字符且前四个字符为 file 的所有文件。的所有文件。rm f* 删除文件名中以删除文件名中以f 为字首的所有文件。为字首的所有文件。35列出当前目录列出当前目录语法:语法: p w d36查看文件内容查看文件内容语法:语法: cat 文件名文件名例如:例如:cat file1 以连续显示方式,查看文件名以连续显示方式,查看文件名file1 的内的内容。容。37分页查看文件内容分页查看文件内容语法:语法: more 文件名或文件名或cat 文件名文件名| more例如:例如:more file1 以分页方式查看文件名以分页方式查看文件名file1 的内容。的内容。cat file1 | more 以分页方式查看文件名以分页方式查看文件名file1 的内的内容。容。38查看目录所占磁盘容量查看目录所占磁盘容量语法语法: du -s 目录目录例如例如:du dir1 显示目录显示目录dir1 的总容量及其子目录的容量的总容量及其子目录的容量(以以KB 为单位为单位)。du -s dir1 显示目录显示目录dir1 的总容量。的总容量。39文件传输文件传输1. 拷贝文件或目录至远程工作站拷贝文件或目录至远程工作站语法:语法: rcp -r 源地址主机名源地址主机名:目的地址目的地址例如:例如:rcp file1 doc:/home/user 将文件将文件f i l e 1拷贝到工作站拷贝到工作站doc 路径路径/home/user 下。下。rcp -r dir1 doc:/home/user 将目录将目录d i r 1拷贝到工作拷贝到工作站站doc 路径路径/home/user 下。下。40文件传输文件传输2. 自远程工作站,拷贝文件或目录自远程工作站,拷贝文件或目录语法:语法: rcp -r 主机名主机名:源地址目的地址源地址目的地址例如:例如:rcp doc:/home/user/file1 file2 将工作站将工作站d o c路径路径/home/user 下的文件下的文件filefile 1,拷贝到当前工作站的拷贝到当前工作站的目录下,文件名为目录下,文件名为filefile 2。rcp -r doc:/home/user/dir1 . 将工作站将工作站doc 路径路径/home/user 下的目录下的目录d i r 1,拷贝到当前工作站的拷贝到当前工作站的目目录下,目录名仍为录下,目录名仍为d i r 1。41文件传输文件传输3. 本地工作站与远程工作站之间的文件传输本地工作站与远程工作站之间的文件传输必须拥有远程工作站的帐号及密码,才可进行传输工作。必须拥有远程工作站的帐号及密码,才可进行传输工作。语法:语法: ftp 主机名或主机名或ftp ip地址地址例如:例如:ftp doc 与远程工作站与远程工作站doc 之间进行文件传输。之间进行文件传输。Name (doc:user-name): Password (doc:user-password): ftp help 列出列出ftp 文件传输时可使用的命令。文件传输时可使用的命令。ftp !ls 列出本地工作站当前目录下的所有文件名。列出本地工作站当前目录下的所有文件名。ftp !pwd 列出本地工作站当前所在的目录位置。列出本地工作站当前所在的目录位置。ftp ls 列出远程工作站当前目录下的所有文件名。列出远程工作站当前目录下的所有文件名。42文件传输文件传输ftp dir 列出远程工作站当前目录下的所有文件名。列出远程工作站当前目录下的所有文件名。ftp dir . |more 分页列出远程工作站当前目录下的所有文件分页列出远程工作站当前目录下的所有文件 名。名。ftp pwd 列出远程工作站当前所在的目录位置。列出远程工作站当前所在的目录位置。ftp cd dir1 更改远程工作站的工作目录位置至更改远程工作站的工作目录位置至dir1 之下。之下。ftp get file1 将远程工作站的文件将远程工作站的文件f i l e 1拷贝到本地工作站拷贝到本地工作站 中。中。ftp put file2 将本地工作站的文件将本地工作站的文件f i l e 2拷贝到远程工作站拷贝到远程工作站 中。中。ftp mget *.c 将远程工作站中扩展文件名为将远程工作站中扩展文件名为c 的所有文件拷的所有文件拷 贝到本地工作站中。贝到本地工作站中。43文件传输文件传输ftp mput *.txt 将本地工作站中扩展文件名为将本地工作站中扩展文件名为txt 的所有文的所有文件件 拷贝到远程工作站中。拷贝到远程工作站中。ftp prompt 切换交互式指令切换交互式指令(使用使用mput/mget 时不是每个文时不是每个文 件皆询问件皆询问y e s / n o )。ftp quit 结束结束ftp 工作。工作。ftp bye 结束结束ftp 工作。工作。注意从注意从PC与工作站间的文件传输也可透过在与工作站间的文件传输也可透过在PC端的端的FTP指指令进行文件传输,指令用法与上述指令大致相同。令进行文件传输,指令用法与上述指令大致相同。44文件权限设定文件权限设定1. 改变文件或目录的读、写、执行权限改变文件或目录的读、写、执行权限语法:语法:chmod -R mode namen a m e :文件名或目录名。文件名或目录名。mode: 3个个8位数字或位数字或r w x的组合。的组合。 r- r e a d (读读),w - w r i t e (写写) x - e x e c u t e (执行执行) u - u s e r (当前用户当前用户),g - g r o u p(组)组) o - o t h e r(其他用户)。其他用户)。45文件权限设定文件权限设定chmod 755 dir1 对于目录对于目录d i r 1,设定成任何使用者设定成任何使用者皆有读取及执行的权利,但只有所有者可做修改。皆有读取及执行的权利,但只有所有者可做修改。chmod 700 file1 对于文件对于文件f i l e 1,设定只有所有者设定只有所有者可以读、写和执行的权利。可以读、写和执行的权利。chmod u+x file2 对于文件对于文件f i l e 2,增加当前用户可增加当前用户可以执行的权利。以执行的权利。chmod g+x file3 对于文件对于文件f i l e 3,增加工作组使用增加工作组使用者可执行的权利。者可执行的权利。chmod o-r file4 对于文件对于文件f i l e 4,删除其他使用者删除其他使用者可读取的权利。可读取的权利。46文件权限设定文件权限设定2改变文件或目录的所有权改变文件或目录的所有权语法:语法:chown -R 用户名用户名 namen a m e:文件名或目录名。文件名或目录名。例如:例如:chown user file1 将文件将文件file1 改为用户改为用户user 所有。所有。chown -R user dir1 将目录将目录d i r 1及其子目录下面的及其子目录下面的所有文件改为用户所有文件改为用户user 所有。所有。47检查自己所属的工作组检查自己所属的工作组语法:语法:g r o u p s48改变文件或目录工作组所有权改变文件或目录工作组所有权语法:语法:chgrp -R 工作组名工作组名 name n a m e:文件名或目录名文件名或目录名例如:例如:chgrp vlsi file1 将文件将文件file1 的工作组所有权改为的工作组所有权改为vlsi 工作组所有。工作组所有。chgrp -R image dir1 将目录将目录d i r 1及其子目录下面的及其子目录下面的所有文件,改为所有文件,改为image 工作组所有。工作组所有。49改变文件或目录最后修改时间改变文件或目录最后修改时间语法:语法:touch namen a m e:文件名或目录名。文件名或目录名。50文件的链接文件的链接同一文件,可拥有一个以上的名称,也就是把一个同一文件,可拥有一个以上的名称,也就是把一个文件进行链接。文件进行链接。语法:语法:ln 老文件名老文件名 新文件名新文件名例如:例如:ln file1 file2 将文件将文件f i l e 2链接至文件链接至文件f i l e 1。51文件中字符串查寻文件中字符串查寻语法:语法:grep string file例如:例如:grep abc file1 寻找文件寻找文件f i l e 1中包含字符串中包含字符串abc 所所在行的文本内容。在行的文本内容。52寻找文件或命令的路径寻找文件或命令的路径语法:语法:whereis command 显示命令的路径。显示命令的路径。语法:语法:which command 显示命令的路径,及使用者显示命令的路径,及使用者 所定义的别名。所定义的别名。语法:语法:whatis command 显示命令功能的摘要。显示命令功能的摘要。语法:语法:find search-path -name filename -print 搜寻搜寻 指定路径下某文件的路径。指定路径下某文件的路径。例如:例如:find / -name file1 -print 自根目录下寻找文件自根目录下寻找文件file1 的的路径。路径。53比较文件或目录的内容比较文件或目录的内容语法:语法:d i ff -r name1 name2name1 name2:可同时为文件名或目录名。可同时为文件名或目录名。例如:例如:d i ff file1 file2 比较文件比较文件file1 与与file2 内各行的不同内各行的不同之处。之处。d i ff -r dir1 dir2 比较目录比较目录dir1 与与dir2 内各文件的不内各文件的不同之处。同之处。54文件打印输出文件打印输出用户可用用户可用 set 命令命令来设定打印机名。来设定打印机名。例如:例如:set -a PRINTER=sp 设定自设定自sp 打印机打印资料。打印机打印资料。语法:语法:lpr -P打印机名打印机名 文件名文件名例如:例如:lpr file1 或或lpr -Psp file1 自自s p打印机打印文件打印机打印文件f i l e 1。55文件打印输出文件打印输出语法:语法:enscript -P打印机名打印机名 文件名文件名例如:例如:enscript file3 或或enscript -Psp file3 自自s p打印机打印打印机打印文件文件f i l e 3。56打印机控制命令打印机控制命令1检查打印机状态、打印作业顺序号和用户名检查打印机状态、打印作业顺序号和用户名语法:语法:lpq -P 打印机名打印机名例如:例如:lpq 或或lpq -Psp 检查检查sp 打印机的状态。打印机的状态。57打印机控制命令打印机控制命令2. . 删除打印机内的打印作业删除打印机内的打印作业( 用户仅可删除自己的用户仅可删除自己的 打印作业打印作业)语法:语法:lprm -P打印机名打印机名 用户名或作业编号用户名或作业编号例如:例如:lprm user或或lprm -Psp user 删除删除s p打印机中用户打印机中用户user 的打印作业,此时用户名必须为的打印作业,此时用户名必须为u s e r。lprm -Psp 456 删除删除sp 打印机上编号为打印机上编号为456 的打印作的打印作业。业。58进程控制命令进程控制命令1查看系统中的进程查看系统中的进程语法:语法:ps -aux例如例如:p s或或ps -x 查看系统中,属于自己的进程。查看系统中,属于自己的进程。ps -au 查看系统中,所有用户的进程。查看系统中,所有用户的进程。ps -aux 查看系统中,包含系统内部的及所有用户的查看系统中,包含系统内部的及所有用户的进程。进程。59进程控制命令进程控制命令2. 结束或终止进程结束或终止进程语法:语法:kill -9 PIDP I D:利用利用ps 命令所查出的进程号。命令所查出的进程号。例如例如:kill 456或或kill -9 456 终止进程号为终止进程号为456 的进程。的进程。60进程控制命令进程控制命令3. 在后台执行进程的方式在后台执行进程的方式语法:命令语法:命令&例如例如:cc file1.c & 将编译将编译file1.c 文件的工作置于后台行。文件的工作置于后台行。61进程控制命令进程控制命令语法:按下语法:按下C o n t r o l + Z键,暂停正在执行的进键,暂停正在执行的进 程。键入程。键入b g命令,将暂停的进程置于后台继命令,将暂停的进程置于后台继 续执行。续执行。例如例如:cc file2.c ZS t o p p e db g62进程控制命令进程控制命令4. 查看正在后台中执行的进程查看正在后台中执行的进程语法:语法:j o b s63进程控制命令进程控制命令5. 结束或终止后台中的进程结束或终止后台中的进程语法:语法:kill %nn:利用利用j o b s命令查看出的后台作业号命令查看出的后台作业号例如:例如:kill % 终止在后台中的第一个进程。终止在后台中的第一个进程。kill %2 终止在后台中的第二个进程。终止在后台中的第二个进程。64shell变量变量1. 查看外壳变量的设定值查看外壳变量的设定值语法:语法:set 查看所有外壳变量的设定值。查看所有外壳变量的设定值。语法:语法:echo $变量名显示指定的外壳变量的设定变量名显示指定的外壳变量的设定值。值。65shell变量变量2. 设定外壳变量设定外壳变量语法:语法:set var = value例如例如:set term=vt100 设定外壳变量设定外壳变量t e r m为为VT100 型终型终端。端。66shell变量变量3. 删除外壳变量删除外壳变量语法:语法:unset var例如例如:unset PRINTER 删除外壳变量删除外壳变量PRINTER 的设定的设定值。值。67环境变量环境变量1. 查看环境变量的设定值查看环境变量的设定值语法:语法:s e t 查看所有环境变量的设定值。查看所有环境变量的设定值。语法:语法:echo $NAME 显示指定的环境变量显示指定的环境变量N A M E 的设定值。的设定值。例如例如:echo $PRINTER 显示环境变量显示环境变量PRINTER 的设定的设定值。值。68环境变量环境变量2. 设定环境变量设定环境变量语法:语法:set a NAME=word例如例如:set -a PRINTER=sp 设定环境变量设定环境变量PRINTER 为为sp。69环境变量环境变量3. 删除环境变量删除环境变量语法:语法:unset NAME例如例如:unset PRINTER 删除环境变量删除环境变量P R I N T E R的设定的设定值。值。70别名别名1. 查看所定义的命令的别名查看所定义的命令的别名语法:语法: a l i a s 查看自己目前定义的所有命令,及查看自己目前定义的所有命令,及 所对应的别名。所对应的别名。语法:语法: alias name 查看指定的查看指定的name 命令的别名。命令的别名。例如例如:alias dir 查看别名查看别名dir 所定义的命令。所定义的命令。ls -atl71别名别名2. 定义命令的别名定义命令的别名语法:语法: alias namecommand line例如例如:alias dir ls -l 将命令将命令ls - l 定义别名为定义别名为d i r。72别名别名3. 删除所定义的别名删除所定义的别名语法:语法: unalias name例如:例如:unalias dir 删除别名删除别名dir 的定义。的定义。unalias * 删除所有别名的设定。删除所有别名的设定。73历史命令历史命令1. 设定命令记录表的长度设定命令记录表的长度语法:语法: set history = n例如例如:set history = 40 设定命令记录表的长度为设定命令记录表的长度为40 (可记录可记录执行过的前面执行过的前面40 个命令个命令)。74历史命令历史命令2. 查看命令记录表的内容查看命令记录表的内容语法:语法: h i s t o r y75历史命令历史命令3. 使用命令记录表使用命令记录表语法:语法: ! 重复执行前一个命令。重复执行前一个命令。语法:语法: ! n76文件压缩文件压缩1. 压缩文件压缩文件语法:语法:compress 文件名文件名 压缩文件压缩文件语法:语法:compressdir 目录名目录名 压缩目录压缩目录2. 解压缩文件解压缩文件语法:语法:uncompress 文件名文件名 解压缩文件解压缩文件语法:语法:uncompressdir 目录名目录名 解压缩目录解压缩目录77重定向重定向1. 标准输入的控制标准输入的控制语法:命令语法:命令 文件将文件做为命令的输入。文件将文件做为命令的输入。例如:例如:mail -s “mail test” wesongzhouhotmail.com 文件将命令的执行结果送至指定的文文件将命令的执行结果送至指定的文 件中。件中。例如例如:ls -l list 将执行将执行“ls -l” 命令的结果写入文件命令的结果写入文件list 中。中。79重定向重定向语法:命令语法:命令! 文件将命令的执行结果送至指定的文文件将命令的执行结果送至指定的文 件中,若文件已经存在,则覆盖。件中,若文件已经存在,则覆盖。例如:例如:ls -lg ! list 将执行将执行“ls - lg” 命令的结果覆盖写入命令的结果覆盖写入文文件件list 中。中。80重定向重定向语法:命令语法:命令& 文件将命令执行时屏幕上所产生的文件将命令执行时屏幕上所产生的 任何信息写入指定的文件中。任何信息写入指定的文件中。例如:例如:cc file1.c & error 将编译将编译file1.c 文件时所产生的任文件时所产生的任何信息写入文件何信息写入文件error 中。中。81重定向重定向语法:命令语法:命令 文件将命令执行的结果附加到指定的文件文件将命令执行的结果附加到指定的文件 中。中。例如例如:ls - lag list 将执行将执行“ls - lag” 命令的结果附加到文件命令的结果附加到文件list 中。中。语法:命令语法:命令& 文件将命令执行时屏幕上所产生的任何信息文件将命令执行时屏幕上所产生的任何信息 附加到指定的文件中。附加到指定的文件中。例如例如:cc file2.c & error 将编译将编译file2.c 文件时屏幕所产生的任何文件时屏幕所产生的任何信息附加到文件信息附加到文件error 中。中。82管道命令管道命令语法:命令语法:命令1 | 命令命令2 将命令将命令1的执行结果送到命令的执行结果送到命令 2,做为命令,做为命令2的输入。的输入。例如:例如:ls -Rl | more 以分页方式列出当前目录及其子目录下以分页方式列出当前目录及其子目录下 所有文件的名称。所有文件的名称。cat file1 | more 以分页方式列出文件以分页方式列出文件file1 的内容。的内容。83重定向和管道命令重定向和管道命令psps | sort | more | sort | morepsps | sort | more output1.txt | sort | more output1.txtkill kill 1 1234 output1.txt 2&11 1234 output1.txt 2&1kill kill 1 1234 /dev/null 2&11 1234 /dev/null 2&184第三章第三章 shell程序设计程序设计交互式程序。交互式程序。 顺序地敲入一系列命令,让顺序地敲入一系列命令,让shellshell交互地执行它们。交互地执行它们。脚本程序(脚本程序(shell scriptshell script) 编写编写shellshell脚本文件,并执行。脚本文件,并执行。85交互式程序交互式程序$ for file in *$ for file in * do do if if grepgrep l POSIX $filel POSIX $file then then more $file more $file fifi done done86关于通配符关于通配符*可以替代多个字符,而?则替代一个字符。可以替代多个字符,而?则替代一个字符。setset匹配方括号中任何一个单个的字符。如:匹配方括号中任何一个单个的字符。如:lsls l l YyYy* * 列出当前目录下所有以列出当前目录下所有以y y和和Y Y开头的文开头的文件。件。匹配花括号中的任何一个字符串。如:匹配花括号中的任何一个字符串。如:lsls my_fingermy_finger toestoes 列出列出my_fingersmy_fingers和和my_toesmy_toes两两个文件。个文件。87脚本程序脚本程序#!/bin/#!/bin/shsh# # first.shfirst.sh# This file looks through all the files # This file looks through all the files in the currentin the current# directory for the string POSIX, and # directory for the string POSIX, and then displays thosethen displays those# files to the standard output.# files to the standard output.88脚本程序脚本程序For file in *For file in *dodo if if grepgrep q POSIX $fileq POSIX $file then then more $file more $file fifiDoneDoneexit 0exit 089运行脚本程序运行脚本程序chmod +x first.sh 给所有用户添加执行权限给所有用户添加执行权限./first.sh90shell程序设计的语法程序设计的语法变量:字符串、数字、环境和参数变量:字符串、数字、环境和参数条件:条件:shell中的布尔值中的布尔值程序控制:程序控制:if、elif、for、while、until、case等等命令表命令表函数函数内建在内建在shell中的命令中的命令获取某个命令的执行结果获取某个命令的执行结果即时文档(即时文档(here文档)文档)91变量变量 在在shellshell里,使用变量之前不需要事先对它做里,使用变量之前不需要事先对它做出声明。变量是在第一次用到的时候被创建的。出声明。变量是在第一次用到的时候被创建的。在默认情况下,所有变量的值被认为是字符串。在默认情况下,所有变量的值被认为是字符串。需要用工具程序将需要用工具程序将“数值数值”型字符串转换为正确型字符串转换为正确的数值并操作。的数值并操作。shellshell的变量名是大小写敏感的。的变量名是大小写敏感的。在变量名前加上一个在变量名前加上一个“$ $”字符可以获得变量的内字符可以获得变量的内容。容。92变量变量 $ salutation=Hello$ salutation=Hello $ echo $salutation $ echo $salutation Hello Hello $ salutation=“Yes Dear” $ salutation=“Yes Dear” $ echo $salutation $ echo $salutation Yes Dear Yes Dear $ salutation=7+5 $ salutation=7+5 $ echo $salutation $ echo $salutation 7+5 7+593引号的用法引号的用法 一般情况下,参数之间是用空白字符分隔的,一般情况下,参数之间是用空白字符分隔的,如一个空格、制表符或换行符等。如想在一个参如一个空格、制表符或换行符等。如想在一个参数里包含一个或多个这样的空白字符,就需要给数里包含一个或多个这样的空白字符,就需要给参数加上引号。带有参数加上引号。带有“$ $”字符的变量表达式放在字符的变量表达式放在双引号里,表达式会替换为它的值。如放在单引双引号里,表达式会替换为它的值。如放在单引号里,则不替换。在号里,则不替换。在“$ $”字符前面加一个字符前面加一个“ ”字符取消它的特殊意义。字符取消它的特殊意义。94引号的用法引号的用法#!/bin/#!/bin/shshmyvarmyvar= =“Hi thereHi there”echo $echo $myvarmyvarecho echo “$ $myvarmyvar”echo echo $ $myvarmyvarecho $echo $myvarmyvar95引号的用法引号的用法echo Enter some textecho Enter some textread read myvarmyvarecho echo $ $myvarmyvar now equals $ now equals $myvarmyvarexit 0exit 096引号的用法引号的用法程序输出结果如下:程序输出结果如下:Hi thereHi thereHi thereHi there$ $myvarmyvar$ $myvarmyvarEnter some textEnter some textHello WorldHello World$ $myvarmyvar mow equals Hello World mow equals Hello World97环境变量环境变量 环境变量是环境变量是shellshell预先初始化的一些变量,环预先初始化的一些变量,环境变量可被子进程继承。环境变量通常使用大写境变量可被子进程继承。环境变量通常使用大写字母作名字。具体有哪些环境变量取决于个人配字母作名字。具体有哪些环境变量取决于个人配置。置。 $HOME $HOME 当前用户的登陆子目录当前用户的登陆子目录 $PATH $PATH 以冒号分隔的用来搜索命令的子目录清单以冒号分隔的用来搜索命令的子目录清单 $PS1 $PS1 命令行提示符命令行提示符 $PS2 $PS2 辅助提示符,用来提示后续输入辅助提示符,用来提示后续输入98环境变量环境变量 $IFS $IFS 输入区的分隔符。输入区的分隔符。shellshell读取输入数据时读取输入数据时会将一组字符视为单词之间的分隔字符,他们通会将一组字符视为单词之间的分隔字符,他们通常是空格、制表符和换行符常是空格、制表符和换行符 $0 shell$0 shell脚本程序的名字脚本程序的名字 $# $# 传递到脚本程序的参数个数传递到脚本程序的参数个数 $ $ 该该shellshell脚本程序的进程脚本程序的进程IDID99参数变量参数变量 shellshell脚本程序在调用时还带有参数,会产生脚本程序在调用时还带有参数,会产生参数变量。参数变量。 $1,$2,$1,$2, 脚本程序的第一个参数、第二个参脚本程序的第一个参数、第二个参数、数、 $* $* 全体参数组成的清单,各参数之间用环全体参数组成的清单,各参数之间用环境变量境变量IFSIFS中的第一个字符分隔开中的第一个字符分隔开 $ $ 全体参数组成的清单,不使用全体参数组成的清单,不使用IFS分隔符分隔符100$*$*与与$ $ 的区别的区别$ IFS=$ IFS=$ set $ set foofoo bar bam bar bam$ echo $ echo “$”foofoo bar bam bar bam$ echo $ echo “$*$*”foobarbamfoobarbam$ unset IFS$ unset IFS$ $ echo “$*”echo “$*”foofoo bar bam bar bam101参数和环境变量的例子参数和环境变量的例子#!/bin/#!/bin/shshsalutation=salutation=“hellohello”echo $salutationecho $salutationecho echo “The program $0 is now runningThe program $0 is now running”echo echo “The second parameter was $2The second parameter was $2”echo echo “The first parameter was $1The first parameter was $1”echo echo “The parameter list was $*The parameter list was $*”echo echo “The userThe users home directory is $HOMEs home directory is $HOME”102参数和环境变量的例子参数和环境变量的例子echo echo “Please enter a new greetingPlease enter a new greeting”read salutationread salutationecho $salutationecho $salutationecho echo “The script is now completeThe script is now complete”exit 0exit 0103参数和环境变量的例子输出参数和环境变量的例子输出$ ./try_variables $ ./try_variables foofoo bar bar bazbazHelloHelloThe program ./try_variables is now runningThe program ./try_variables is now runningThe second parameter was barThe second parameter was barThe first parameter was The first parameter was foofooThe parameter list was The parameter list was foofoo bar bar bazbazThe userThe users home directory is /home/s home directory is /home/rickrickPlease enter a new greetingPlease enter a new greetingSireSireSireSireThe script is now completeThe script is now complete$ $104条件测试条件测试 shellshell的条件测试命令可以对命令的退出码、的条件测试命令可以对命令的退出码、字符串比较、算术比较、文件属性进行测试。字符串比较、算术比较、文件属性进行测试。shellshell的条件测试命令(布尔判断命令)有的条件测试命令(布尔判断命令)有testtest和和。 例如,检查一个文件是否存在代码如下:例如,检查一个文件是否存在代码如下: if test if test f f fred.cfred.c then then fifi105条件测试条件测试 或者或者: : if -f if -f fred.cfred.c then then fi fi106条件测试条件测试-字符串比较字符串比较string1 = string2 string1 = string2 如果两个字符串相同则结果如果两个字符串相同则结果 为真为真string1 != string2 string1 != string2 如果两个字符串不同则结果如果两个字符串不同则结果 为真为真-n string -n string 如果字符串不是空则结果为如果字符串不是空则结果为 真真-z string -z string 如果字符串是空则结果为真如果字符串是空则结果为真107条件测试条件测试-算术比较算术比较expression1 expression1 eqeq expression2 expression2 如果两个表达式相如果两个表达式相等则结果为真等则结果为真expression1 expression1 nene expression2 expression2 如果两个表达式不如果两个表达式不等则结果为真等则结果为真expression1 expression1 gtgt expression2 expression2 如果前一个表达式如果前一个表达式大于后一个表达式则结果为真大于后一个表达式则结果为真expression1 expression1 gege expression2 expression2 如果前一个表达式如果前一个表达式大于或等于后一个表达式大于或等于后一个表达式则结果为真则结果为真108条件测试条件测试-算术比较算术比较expression1 expression1 ltlt expression2 expression2 如果前一个表达式如果前一个表达式小于后一个表达式小于后一个表达式则结果为真则结果为真expression1 le expression2 expression1 le expression2 如果前一个表达式如果前一个表达式小于或等于后一个表达式小于或等于后一个表达式则结果为真则结果为真!expression1 !expression1 如果表达式为假则结果为真,如果表达式为假则结果为真, 表达表达式结果为真则结果为假式结果为真则结果为假109条件测试条件测试-文件测试文件测试-d file -d file 如果文件是一个子目录则结果为真如果文件是一个子目录则结果为真-e file -e file 如果文件存在则结果为真如果文件存在则结果为真-f file -f file 如果文件是一个普通文件则结果为真如果文件是一个普通文件则结果为真-g file -g file 如果文件的如果文件的set-group-idset-group-id位被设置则结果位被设置则结果 为真为真110条件测试条件测试-文件测试文件测试-r file -r file 如果文件可读则结果为真如果文件可读则结果为真-s file -s file 如果文件长度不为如果文件长度不为0 0则结果为真则结果为真-u file -u file 如果文件的如果文件的set-user-idset-user-id位位被设置被设置则结果则结果 为真为真-w file -w file 如果文件可写则结果为真如果文件可写则结果为真-x file -x file 如果文件可执行则结果为真如果文件可执行则结果为真111控制结构控制结构-if语句语句if if conditionthenthen statementselseelse statementsfifi112控制结构控制结构-if语句例子语句例子#!/bin/shecho “Is it morning? Please answer yes or no”read timeofdayif $timeofday = “yes” ; then echo “Good morning”113控制结构控制结构-if语句例子语句例子else echo “Good afternoon”fiexit 0如果直接输入回车键会怎样?如果直接输入回车键会怎样?114控制结构控制结构-elif语句语句#!/bin/#!/bin/shshecho “Is it morning? Please answer yes or echo “Is it morning? Please answer yes or no” no”read read timeofdaytimeofdayif “$if “$timeofdaytimeofday” = “yes” ; then” = “yes” ; then echo “Good morning” echo “Good morning”115控制结构控制结构-elif语句语句elifelif “$ “$timeofdaytimeofday” = “no” ; then” = “no” ; then echo “Good afternoon” echo “Good afternoon”elseelse echo “Sorry, $ echo “Sorry, $timeofdaytimeofday not recognized . not recognized . Enter yes or no”Enter yes or no” exit 1 exit 1fifiexit 0exit 0116控制结构控制结构-for语句语句for for variable in in valuesdodo statementsdonedone117控制结构控制结构-for语句语句例子:forfor foo inin bar fud 43dodo echo $foodonedoneexitexit 0118控制结构控制结构-for语句语句结果:结果:barbarfudfud4343119控制结构控制结构-for语句语句例子:#!/bin/shforfor file inin $(ls f*.sh)dodo lpr $filedonedoneexitexit 0120控制结构控制结构-while语句语句whilewhile conditiondodo statementsdonedone121控制结构控制结构-while语句语句例子:口令字检查程序例子:口令字检查程序#!/bin/#!/bin/shshecho echo “enter passwordenter password”read read trythistrythiswhile while “$ $trythistrythis” != != “secretsecret” ;do ;do echo echo “Sorry, try againSorry, try again” read read trythistrythisdonedoneexit 0exit 0122控制结构控制结构-while语句语句例子:命令执行特定的次数例子:命令执行特定的次数#!/bin/#!/bin/shshfoofoo=1=1while “$while “$foofoo” le 20 ;” le 20 ;dodo echo “we go again” echo “we go again” foofoo=$($foo+1)=$($foo+1)donedoneexit 0exit 0123控制结构控制结构-until语句语句untiluntil conditiondodo statementsdonedone124控制结构控制结构-until语句语句例子:报警程序例子:报警程序#!/bin/#!/bin/shshuntil who | grep until who | grep “$1$1” /dev/null /dev/nulldodo sleep 60 sleep 60donedoneecho echo e e aaecho echo “* $1 has just logged in * $1 has just logged in *”exit 0exit 0125控制结构控制结构-case语句语句casecase variable inin pattern | pattern ) statements; pattern | pattern ) statements;esacesac126控制结构控制结构-case语句语句例子:例子:#!/bin/#!/bin/shshecho echo “Is it morning? Please answer yes or noIs it morning? Please answer yes or no”read read timeofdaytimeofdaycase case “$ $timeofdaytimeofday” yes) echo yes) echo “Good MorningGood Morning”; no ) echo no ) echo “Good AfternoonGood Afternoon”; y ) y ) echo “Good Morning”;echo “Good Morning”; n ) echo “Good Afternoon”; n ) echo “Good Afternoon”; * ) echo “Sorry, answer not recognized”; * ) echo “Sorry, answer not recognized”;esacesacexit 0exit 0127控制结构控制结构-case语句语句例子:例子:#!/bin/#!/bin/shshecho echo “Is it morning? Please answer yes or noIs it morning? Please answer yes or no”read read timeofdaytimeofdaycase case “$ $timeofdaytimeofday” yes | y | Yes | YES) echo yes | y | Yes | YES) echo “Good MorningGood Morning”; n* | N* ) echo n* | N* ) echo “Good AfternoonGood Afternoon”; * ) echo “Sorry, answer not recognized”; * ) echo “Sorry, answer not recognized”;esacesacexit 0exit 0128控制结构控制结构-case语句语句例子:例子:#!/bin/#!/bin/shshecho echo “Is it morning? Please answer yes or noIs it morning? Please answer yes or no”read read timeofdaytimeofdaycase case “$ $timeofdaytimeofday” yes | y | Yes | YES) yes | y | Yes | YES) echo echo “Good MorningGood Morning” echo echo “Up bright and early this morningUp bright and early this morning” ; ;129控制结构控制结构-case语句语句 nNnN ) ) echo echo “Good AfternoonGood Afternoon” ; ; * ) * ) echo “Sorry, answer not recognized” echo “Sorry, answer not recognized” echo “Please answer yes or no” echo “Please answer yes or no” exit 1 exit 1 ; ;esacesacexit 0exit 0130AND命令表命令表 ANDAND命令表结构允许我们按这样的方式执行一命令表结构允许我们按这样的方式执行一连串命令:只有前面的所有命令都执行成功的情连串命令:只有前面的所有命令都执行成功的情况下才执行后一条命令。况下才执行后一条命令。 语法:语法:statement1 & statement2 & statement1 & statement2 & statement3 & statement3 & 131AND命令表命令表 例子:例子: #!/bin/#!/bin/shsh touch file_one touch file_one rm f file_two rm f file_two 132AND命令表命令表 if -f file_one & echo “hello” & if -f file_one & echo “hello” & -f file_two & echo “there” -f file_two & echo “there” then then echo “in if” echo “in if” else else echo “in else” echo “in else” fi fi exit o exit o133OR命令表命令表 OROR命令表允许我们持续执行一系列命令直到命令表允许我们持续执行一系列命令直到有一条成功为止,其后的命令将不再被执行。有一条成功为止,其后的命令将不再被执行。 语法:语法:statement1 | statement2 | statement1 | statement2 | statement3 | statement3 | 134OR命令表命令表 例子:例子: #!/bin/#!/bin/shsh rm f file_one rm f file_one if -f file_one | echo “hello” | echo if -f file_one | echo “hello” | echo “there” “there” then then echo “in if” echo “in if”135OR命令表命令表 elseelse echo “in else” echo “in else” fi fi exit 0 exit 0136语句块语句块 在只允许使用单个语句的地方使用多条语句,在只允许使用单个语句的地方使用多条语句,可以把它们括在花括号可以把它们括在花括号里来构造一个语句块。里来构造一个语句块。137语句块语句块 例子:例子: get_confirm & get_confirm & grep grep v v “$ $cacatnumcacatnum” $tracks_file $tracks_file $temp_file$temp_file cat $temp_file $tracks_file cat $temp_file $tracks_file echo echo add_record_tracks add_record_tracks 138函数函数语法:语法:function_name()function_name() statements statements 139函数函数例子:例子:#!/bin/#!/bin/shshfoofoo()() echo echo “Function Function foofoo is executing is executing” echo echo “script startingscript starting”foofooecho echo “script endedscript ended”exit 0exit 0140函数函数-局部变量局部变量#!/bin/#!/bin/shshsample_text=“sample_text=“globlegloble varablevarable”foofoo()() local sample_text=“local variable” local sample_text=“local variable” echo “Function echo “Function foofoo is executing” is executing” echo $sample_text echo $sample_text 141函数函数-局部变量局部变量echo “script starting”echo “script starting”echo $sample_textecho $sample_textfoofooecho “script ended”echo “script ended”echo $sample_textecho $sample_textexit 0exit 0142命令命令-break breakbreak命令用于从命令用于从forfor、whilewhile或或untiluntil循环里中途退出循环里中途退出例子:例子:#!/bin/#!/bin/shshrmrm rfrf fredfred* *echo fred1echo fred1echo fred2echo fred2mkdirmkdir fred3 fred3echo fred4echo fred4143命令命令-breakfor file in for file in fredfred* *dodo if -d if -d “$file$file” ; then ; then break; break;fifidonedoneecho first directory starting echo first directory starting fredfred was $file was $filermrm rfrf fredfred* *exit 0exit 0144命令命令-continue continuecontinue命令使命令使forfor、whilewhile或或untiluntil循环跳到下一个循环跳到下一个循环继续执行,循环变量取循环清单里的下一个值。循环继续执行,循环变量取循环清单里的下一个值。 例子:例子: #!/bin/#!/bin/shsh rmrm rfrf fredfred* * echo fred1 echo fred1 echo fred2 echo fred2 mkdirmkdir fred3 fred3 echo fred4 echo fred4145命令命令-continue for file in for file in fredfred* * do do if -d “$file” ; then if -d “$file” ; then echo “skipping directory $file” echo “skipping directory $file” continue; continue; fifi done done rmrm rfrf fredfred* * exit 0 exit 0146命令命令-: 冒号命令是一个空命令。偶尔会被用来简化冒号命令是一个空命令。偶尔会被用来简化逻辑条件,相当于逻辑条件,相当于truetrue的一个假名。的一个假名。147命令命令-: 例子:例子: #!/bin/#!/bin/shsh rmrm f f fredfred if -f if -f fredfred ; then ; then : : else else echo file echo file fredfred did not exist did not exist fifi exit 0 exit 0148命令命令- . 在一般情况下,在一般情况下,shellshell在执行外部命令和脚本在执行外部命令和脚本程序的时候,会创建一个新的环境(子程序的时候,会创建一个新的环境(子shellshell)。)。子环境执行完毕后被丢弃,只有退出码返回给上子环境执行完毕后被丢弃,只有退出码返回给上一级一级shellshell。 . .命令和外部命令命令和外部命令sourcesource在当前在当前shellshell中执行脚本中的命令,这样脚本中命令对环中执行脚本中的命令,这样脚本中命令对环境变量的修改可以保存下来。境变量的修改可以保存下来。149命令命令- . 脚本脚本classic_setclassic_set为老开发工具设置环境为老开发工具设置环境 #!/bin/#!/bin/shsh version=classic version=classic PATH=/ PATH=/usr/local/old_bin:/usr/bin:/binusr/local/old_bin:/usr/bin:/bin PS1= PS1=“classicclassic” 脚本脚本latest_setlatest_set为新开发工具设置环境为新开发工具设置环境 #!/bin/#!/bin/shsh version=latest version=latest PATH=/ PATH=/usr/local/new_bin:/usr/bin:/binusr/local/new_bin:/usr/bin:/bin PS1= PS1=“latestlatest”150命令命令- . 执行结果执行结果$ . ./classic_set$ . ./classic_setclassic echo $versionclassic echo $versionclassicclassicclassic. ./latest_setclassic. ./latest_setlatest echo $versionlatest echo $versionlatestlatestlatestlatest151命令命令- eval evaleval命令对参数进行求值操作。例子:命令对参数进行求值操作。例子:foofoo=10=10x=x=foofooy=y=$ $x$xecho $yecho $y输出是输出是$ $foofoo152命令命令- evalfoofoo=10=10x=x=foofooevaleval y= y=$ $x$xecho $yecho $y输出是输出是1010153命令命令- exec execexec命令被用来以另一个不同程序替换掉当命令被用来以另一个不同程序替换掉当前的前的shellshell。例子:例子: exec wall exec wall “Thank you for all the fishThank you for all the fish” 这个命令会用这个命令会用wallwall替换掉当前的替换掉当前的shellshell,脚本脚本中后面的程序就不会执行了。中后面的程序就不会执行了。154命令命令- exit n exit nexit n命令使脚本程序以退出码命令使脚本程序以退出码n n结束运行。结束运行。 0 0 脚本执行成功脚本执行成功 1-125 1-125 脚本程序用出错码脚本程序用出错码 126 126 文件是不可执行的文件是不可执行的 127 127 命令未找到命令未找到 128128以上以上 引发一个出错信号引发一个出错信号155命令命令- export exportexport命令用于创建环境变量,并被子命令用于创建环境变量,并被子shellshell继承。继承。 语法:语法:export name=wordexport name=word 脚本脚本export2:export2: #!/bin/ #!/bin/shsh echo echo “$ $foofoo” echo echo “$bar$bar”156命令命令- export 脚本脚本export1:export1: #!/bin/ #!/bin/shsh foofoo= =“This is This is foofoo” export bar= export bar=“This is barThis is bar” export2 export2 脚本脚本export1export1运行结果:运行结果:This is barThis is bar157命令命令- expr exprexpr命令把它的参数当作一个算术表达式进行求值。命令把它的参数当作一个算术表达式进行求值。 例子:例子:x=x=exprexpr $x + 1 $x + 1 注意:注意: 为反引号,为反引号,+ +号两边需要空格号两边需要空格 比较新的用法是比较新的用法是$($()158命令命令- exprexpr1 | expr2 expr1 | expr2 如果如果expr1expr1非零则等于非零则等于expr1expr1,否则等否则等 于于expr2expr2expr1 & expr2 expr1 & expr2 如果两个表达式都是零则等于零,否如果两个表达式都是零则等于零,否 则等于则等于expr1expr1expr1 = expr2 expr1 = expr2 相等相等expr1 expr2 expr1 expr2 大于大于expr1 = expr2 expr1 = expr2 大于等于大于等于expr1 expr2 expr1 expr2 小于小于expr1 = expr2 expr1 = expr2 小于等于小于等于159命令命令- exprexpr1 != expr2 expr1 != expr2 不等于不等于expr1 + expr2 expr1 + expr2 加法加法expr1 - expr2 expr1 - expr2 减法减法expr1 * expr2 expr1 * expr2 乘法乘法expr1 / expr2 expr1 / expr2 整数除法整数除法expr1 % expr2 expr1 % expr2 求整数除法的余数求整数除法的余数160命令命令- set setset命令的作用是为命令的作用是为shellshell设定参数变量。设定参数变量。 例子:在例子:在shellshell脚本里使用当前月份的名字脚本里使用当前月份的名字 #!/bin/#!/bin/shsh echo the date is $(date) echo the date is $(date) set $(date) set $(date) echo the month is $2 echo the month is $2 exit 0 exit 0161命令命令- shift shiftshift命令使所有参数变量向前移动一个位置,命令使所有参数变量向前移动一个位置,$2$2成为成为$1$1,$3$3成为成为$2,$2,。在扫描脚本程序参数时,。在扫描脚本程序参数时,对第对第1010个和以后参数需用个和以后参数需用shiftshift处理。处理。162命令命令- shift 例子:例子: #!/bin/#!/bin/shsh while while “$1$1” != != “” ; do ; do echo echo “$1$1” shift shift done done exit 0 exit 0163命令的执行命令的执行 我们希望执行一条命令并将命令的输出放到我们希望执行一条命令并将命令的输出放到一个变量里。注意:是命令的输出而不是返回值。一个变量里。注意:是命令的输出而不是返回值。 语法:语法:$(command)$(command)164命令的执行命令的执行 例子:例子: #!/bin/#!/bin/shsh echo The current directory is $PWD echo The current directory is $PWD echo The current users are $(who) echo The current users are $(who) exit 0 exit 0165命令的执行命令的执行-算术扩展算术扩展 完成简单的算术计算。完成简单的算术计算。 语法:语法:$(expr1)$(expr1)166命令的执行命令的执行-算术扩展算术扩展 例子:例子: #!/bin/#!/bin/shsh x=0 x=0 while while “$x$x” - -nene 10 ; do 10 ; do echo $x echo $x x=$($x + 1) x=$($x + 1) done done exit 0 exit 0167命令的执行命令的执行-参数扩展参数扩展 语法:语法:$variable$variable 例子:处理例子:处理1_tmp1_tmp和和2_tmp2_tmp文件(不能正常执行的情况)文件(不能正常执行的情况) #!/bin/#!/bin/shsh for i in 1 2 for i in 1 2 do do grepgrep POSIX $ POSIX $i_tmpi_tmp done done exit 0 exit 0168命令的执行命令的执行-参数扩展参数扩展 语法:语法:$variable$variable 例子:处理例子:处理1_tmp1_tmp和和2_tmp2_tmp文件(正常执行的情况)文件(正常执行的情况) #!/bin/#!/bin/shsh for i in 1 2 for i in 1 2 do do grepgrep POSIX $ POSIX $i_tmpi_tmp done done exit 0 exit 0169第四章第四章 Linux文件系统文件系统 传统传统UNIXUNIX的文件系统为的文件系统为s5s5文件系统,文件系统,linuxlinux的的文件系统为文件系统为ext2ext2或或ext3ext3文件系统。文件系统。ext3ext3文件系统文件系统与与ext2ext2文件系统的不同之处在于文件系统的不同之处在于ext3ext3文件系统使文件系统使用了一个特殊的索引节点(用了一个特殊的索引节点(inodeinode)作为日志文件,)作为日志文件,除此之外,除此之外,ext3ext3与与ext2ext2在格式上兼容。在格式上兼容。170第四章第四章 Linux文件系统文件系统 s5s5文件系统磁盘布局如下:文件系统磁盘布局如下:引导块引导块超级块超级块索引节点表索引节点表数据块数据块数据块数据块数据块数据块ext2ext2文件系统磁盘布局如下(块大小为文件系统磁盘布局如下(块大小为1k1k) :引导块引导块超级块超级块组描述符表组描述符表组内块位视图组内块位视图数据块数据块组内索引节点位视图组内索引节点位视图组内磁盘布局组内磁盘布局索引节点表索引节点表171ext2文件系统文件系统ext2ext2文件系统的块大小是一样的(文件系统的块大小是一样的(10241024字节或字节或40964096字节)字节)超级块的大小为超级块的大小为10241024字节,单独占据一块字节,单独占据一块组描述符表占据一个完整块(组描述符表占据一个完整块(10241024字节或字节或40964096字节)字节)块位视图占据一个完整块(块位视图占据一个完整块(10241024字节或字节或40964096字节)字节)索引节点位视图占据一个完整块(索引节点位视图占据一个完整块(10241024字节或字节或40964096字节)字节)172ext2文件系统文件系统每组包含的块数是一样的每组包含的块数是一样的每组包含的索引节点数是一样的每组包含的索引节点数是一样的块号从块号从0 0开始计数,为全局性的开始计数,为全局性的索引节点号从索引节点号从1 1开始,为全局性的开始,为全局性的根目录的索引节点号为根目录的索引节点号为2 2173ext2文件系统文件系统-超级块超级块Magic numberMagic number(0xef530xef53)inodesinodes 计数计数 blocks blocks 计数计数 保留的保留的 blocks blocks 计数计数 空闲的空闲的 blocks blocks 计数计数 空闲的空闲的 inodesinodes 计数计数 174ext2文件系统文件系统-超级块超级块第一个数据第一个数据 block block block block 的大小的大小 每每 block group block group 的的 block block 数量数量每每 block group block group 的的 inodeinode 数量数量 日志文件的日志文件的 inodeinode 号数号数 日志文件的设备号日志文件的设备号 175ext2文件系统文件系统-组描述符表组描述符表structstruct ext3_group_desc ext3_group_desc _u32 _u32 bg_block_bitmapbg_block_bitmap; /* block ; /* block 指针指向指针指向 block bitmap block bitmap */*/_u32 _u32 bg_inode_bitmapbg_inode_bitmap; /* block ; /* block 指针指向指针指向 inodeinode bitmap bitmap */*/_u32 _u32 bg_inode_tablebg_inode_table; /* block ; /* block 指针指向指针指向 inodesinodes table table */*/_u16 _u16 bg_free_blocks_countbg_free_blocks_count; /* ; /* 空闲的空闲的 blocks blocks 计数计数 * */ /_u16 _u16 bg_free_inodes_countbg_free_inodes_count; /* ; /* 空闲的空闲的 inodesinodes 计数计数 * */ /_u16 _u16 bg_used_dirs_countbg_used_dirs_count; /* ; /* 目录计数目录计数 * */ /_u16 _u16 bg_padbg_pad; /* ; /* 可以忽略可以忽略 * */ /_u32 bg_reserved3; /* _u32 bg_reserved3; /* 可以忽略可以忽略 * */ /;176ext2文件系统文件系统-索引节点索引节点structstruct ext3_inode ext3_inode _u16 _u16 i_modei_mode; /* File mode */; /* File mode */_u16 _u16 i_uidi_uid; /* Low 16 bits of Owner ; /* Low 16 bits of Owner UidUid */ */_u32 _u32 i_sizei_size; /* ; /* 文件大小,单位是文件大小,单位是 byte */byte */_u32 _u32 i_atimei_atime; /* Access time */; /* Access time */_u32 _u32 i_ctimei_ctime; /* Create time */; /* Create time */_u32 _u32 i_mtimei_mtime; /* ; /* ModificateModificate time */ time */_u32 _u32 i_dtimei_dtime; /* Delete Time */; /* Delete Time */_u16 _u16 i_gidi_gid; /* Low 16 bits of Group Id */; /* Low 16 bits of Group Id */_u16 _u16 i_links_counti_links_count; /* Links count */; /* Links count */_u32 _u32 i_blocksi_blocks; /* blocks ; /* blocks 计数计数 * */ /_u32 _u32 i_flagsi_flags; /* File flags */; /* File flags */177ext2文件系统文件系统-索引节点索引节点_u32 l_i_reserved1; /* _u32 l_i_reserved1; /* 可以忽略可以忽略 * */ /_u32 i_blockEXT3_N_BLOCKS; /* _u32 i_blockEXT3_N_BLOCKS; /* 一组一组 block block 指针指针 * */ /_u32 _u32 i_generatei_generate; /* ; /* 可以忽略可以忽略 * */ /_u32 _u32 i_file_acli_file_acl; /* ; /* 可以忽略可以忽略 * */ /_u32 _u32 i_dir_acli_dir_acl; /* ; /* 可以忽略可以忽略 * */ /_u32 _u32 i_faddri_faddr; /* ; /* 可以忽略可以忽略 * */ /_u8 _u8 l_i_fragl_i_frag; /* ; /* 可以忽略可以忽略 * */ /_u8 _u8 l_i_fsizel_i_fsize; /* ; /* 可以忽略可以忽略 * */ /_u16 i_pad1; /* _u16 i_pad1; /* 可以忽略可以忽略 * */ /_u16 _u16 l_i_uid_highl_i_uid_high; /* ; /* 可以忽略可以忽略 * */ /_u16 _u16 l_i_gid_highl_i_gid_high; /* ; /* 可以忽略可以忽略 * */ /_u32 l_i_reserved2; /* _u32 l_i_reserved2; /* 可以忽略可以忽略 * */ /;178ext2文件系统文件系统-索引节点索引节点 在在 inodeinode 里面存放里面存放 EXT3_N_BLOCKSEXT3_N_BLOCKS(= 15= 15)这么)这么多个多个 block block 指针。用户数据就从这些指针。用户数据就从这些 block block 里面获得。里面获得。这组这组 15 15 个个 block block 指针的前指针的前 12 12 个是个是 direct blocksdirect blocks,里面直接存放的就是用户数据。第里面直接存放的就是用户数据。第 13 13 个个 blockblock是是indirect blockindirect block,里面存放的全部是,里面存放的全部是 block block 指针,这些指针,这些 block block 指针指向的指针指向的 block block 才被用来存放用户数据。第才被用来存放用户数据。第 14 14 个个 block block 是是double indirect blockdouble indirect block,里面存放的全是,里面存放的全是 block block 指针,这些指针,这些 block block 指针指向的指针指向的 block block 也被全部用也被全部用来存放来存放 block block 指针,而这些指针,而这些 block block 指针指向的指针指向的 blockblock,才被用来存放用户数据。第才被用来存放用户数据。第 15 15 个个 block block 是是triple triple indirect blockindirect block。179ext2文件系统文件系统-目录文件目录文件structstruct ext3_dir_entry_2 ext3_dir_entry_2 _u32 _u32 inodeinode; /* ; /* InodeInode 号数号数 * */ /_u16 _u16 rec_lenrec_len; /* Directory entry length */; /* Directory entry length */_u8 _u8 name_lenname_len; /* Name length */; /* Name length */_u8 _u8 file_typefile_type; ;char nameEXT3_NAME_LEN; /* File name */char nameEXT3_NAME_LEN; /* File name */;180与文件操作有关的系统调用与文件操作有关的系统调用intint open(constopen(const char *path, char *path, intint oflagsoflags);); intint open(constopen(const char * char *path,intpath,int oflagsoflags, , mode_tmode_t mode);mode);size_tsize_t read(intread(int fildesfildes, const void *, const void *bufbuf, , size_tsize_t nbytesnbytes););size_tsize_t write(intwrite(int fildesfildes, const void *, const void *bufbuf, , size_tsize_t nbytesnbytes););intint close(intclose(int fildesfildes););intint ioctl(intioctl(int fildesfildes, , intint cmdcmd,);,);181与文件操作有关的系统调用与文件操作有关的系统调用off_toff_t lseek(intlseek(int fildesfildes, , off_toff_t offset, offset, intint whence); whence);intint fstat(intfstat(int fildesfildes, , structstruct stat * stat *bufbuf););intint stat(conststat(const char* path, char* path, stuctstuct stat * stat *bufbuf););intint lstat(constlstat(const char *path, struct stat * char *path, struct stat *bufbuf););intint dup(intdup(int fildesfildes););intint dup2(int dup2(int fildesfildes, , intint fildes2); fildes2);182与文件操作有关的系统调用与文件操作有关的系统调用intint chmod(constchmod(const char *path, char *path, mode_tmode_t mode); mode);intint chown(constchown(const char *path, char *path, uid_tuid_t owner, owner, gid_tgid_t group);group);intint unlink(constunlink(const char *path1, const char *path2); char *path1, const char *path2);intint link(constlink(const char *path1, const char *path2); char *path1, const char *path2);intint symlink(constsymlink(const char *path1, const char *path2); char *path1, const char *path2);183与文件操作有关的系统调用与文件操作有关的系统调用intint mkdir(constmkdir(const char *path, char *path, mode_tmode_t mode); mode);intint rmdir(constrmdir(const char *path); char *path);intint chdir(constchdir(const char * path); char * path);intint fcntl(intfcntl(int fildesfildes, , intint cmdcmd););intint fcntl(intfcntl(int fildesfildes, , intint cmdcmd, long , long argarg););184系统调用系统调用-open#include #include #include sys/#include #include sys/#include intint open(constopen(const char *path, char *path, intint oflagsoflags););intint open(constopen(const char * char *path,intpath,int oflagsoflags, , mode_tmode_t mode); mode); 185系统调用系统调用-openpath path 为路径名为路径名oflagsoflags 定义对打开的文件进行的操作,为访问模式与可选定义对打开的文件进行的操作,为访问模式与可选模式的组合模式的组合 访问模式:访问模式:O_RDONLY O_RDONLY 以只读方式打开以只读方式打开 O_WRONLY O_WRONLY 以只写方式打开以只写方式打开 O_RDWR O_RDWR 以读写方式打开以读写方式打开 可选模式:可选模式:O_APPEND O_APPEND 将写入的数据追加到文件尾将写入的数据追加到文件尾 O_TRUNC O_TRUNC 将文件清空,丢弃现有文件内容将文件清空,丢弃现有文件内容 O_CREAT O_CREAT 按按modemode中给出的访问模式创建文件中给出的访问模式创建文件 186系统调用系统调用-openmode mode 当当oflagsoflags里有里有O_CREATO_CREAT时需要时需要modemode参数,参数,modemode是以下可是以下可选参数的组合选参数的组合 S_IRUSR S_IRUSR 文件所有者读权限文件所有者读权限 S_IWUSR S_IWUSR 文件所有者写权限文件所有者写权限 S_IXUSR S_IXUSR 文件所有者执行权限文件所有者执行权限 S_IRGRP S_IRGRP 组用户读权限组用户读权限 S_IWGRP S_IWGRP 组用户写权限组用户写权限 S_IXGRP S_IXGRP 组用户执行权限组用户执行权限 S_IROTH S_IROTH 其他用户读权限其他用户读权限 S_IWOTH S_IWOTH 其他用户读权限其他用户读权限 S_IXOTH S_IXOTH 其他用户读权限其他用户读权限187系统调用系统调用-openunmask unmask 系统变量为系统变量为3 3个八进制数,分别对应所有者、同组用个八进制数,分别对应所有者、同组用户、其他用户,如对应位置位则表示禁止相应的权限。户、其他用户,如对应位置位则表示禁止相应的权限。0-0-不禁止任何权限、不禁止任何权限、1-1-禁止执行权限、禁止执行权限、2-2-禁止写权限、禁止写权限、4-4-禁禁止读权限止读权限返回值返回值 如果成功返回文件描述符,失败返回如果成功返回文件描述符,失败返回-1-1,全局变量,全局变量 errnoerrno保存出错码保存出错码188系统调用系统调用-read#include #include size_tsize_t read(intread(int fildesfildes, const void *, const void *bufbuf, , size_tsize_t nbytesnbytes););fildesfildes 为文件描述符为文件描述符bufbuf 为缓冲区指针为缓冲区指针nbytesnbytes 为要读的字节数为要读的字节数返回值返回值 为实际读的字节数、为实际读的字节数、-1-1为错误为错误189系统调用系统调用-read#include #include #include #include intint main() main() char buffer128;char buffer128;intint nrednred; ;nrednred=read(0,buffer,128);=read(0,buffer,128); 190系统调用系统调用-readif(nredif(nred=-1)=-1)write(2,”A read error has ocurredn”,26);write(2,”A read error has ocurredn”,26);if(write(1,buffer,nred)!=if(write(1,buffer,nred)!=nrednred) ) write(2,”A write error has ocurredn”,27); write(2,”A write error has ocurredn”,27);exit(0);exit(0); 191系统调用系统调用-write#include #include size_tsize_t write(intwrite(int fildesfildes, const void *, const void *bufbuf, , size_tsize_t nbytesnbytes););fildesfildes 为文件描述符为文件描述符bufbuf 为缓冲区指针为缓冲区指针nbytesnbytes 为要写的字节数为要写的字节数返回值返回值 为实际写的字节数、为实际写的字节数、-1-1为错误为错误192系统调用系统调用-close#include #include intint close(intclose(int fildesfildes););closeclose中止文件描述符中止文件描述符fildesfildes与文件之间的关联与文件之间的关联返回值返回值 0-0-成功、成功、-1-1-错误错误193系统调用系统调用-lseek#include #include #include sys/#include off_toff_t lseek(intlseek(int fildesfildes, , off_toff_t offset, offset, intint whence); whence);LseekLseek对文件描述符对文件描述符fildesfildes的读写指针进行设置,用来设置的读写指针进行设置,用来设置文件的下一个读写位置。即可以把指针设置到绝对位置,也文件的下一个读写位置。即可以把指针设置到绝对位置,也可以设置到相对于当前位置或文件尾的某个相对位置。可以设置到相对于当前位置或文件尾的某个相对位置。194系统调用系统调用-lseekoffset offset 偏移量偏移量whence whence 可以取下列值:可以取下列值: SEEK_SET offsetSEEK_SET offset是一个绝对值是一个绝对值 SEEK_CUR offsetSEEK_CUR offset是从当前位置算起的一个相对位置是从当前位置算起的一个相对位置 SEEK_END offsetSEEK_END offset是从文件尾算起的一个相对位置是从文件尾算起的一个相对位置返回值返回值 文件头到新指针位置的偏移量、文件头到新指针位置的偏移量、-1-1-失败失败195open,read,write,lseek用法#include #include #include #include #include sys/#include /*/*进程进程A*/A*/main()main() intint fdfd; ;char buf512;char buf512; fdfd=open(“/etc/=open(“/etc/passwdpasswd”, S_IRUSR);”, S_IRUSR); read(fdread(fd, , bufbuf, , sizeof(bufsizeof(buf););read(fdread(fd, , bufbuf, , sizeof(bufsizeof(buf);); 196open,read,write,lseek用法用法/*/*进程进程B*/B*/main()main() intint fdfd, i;, i;char buf512;char buf512; for(ifor(i=0; i=0; isizeof(bufsizeof(buf); i+) ); i+) bufibufi=a;=a; fdfd=open(“/etc/=open(“/etc/passwdpasswd”, S_IWUSR);”, S_IWUSR); write(fdwrite(fd, , bufbuf, , sizeof(bufsizeof(buf););write(fdwrite(fd, , bufbuf, , sizeof(bufsizeof(buf);); 197open,read,write,lseek用法用法#include #include #include #include #include #include #include sys/#include main(intmain(int argcargc, char *, char *argvargv) intint fdfd, , skvalskval; ;char c;char c; if(argcif(argc!=2)exit();!=2)exit();fdfd=open(argv1, S_IRUSR);=open(argv1, S_IRUSR);198open,read,write,lseek用法用法if(fdif(fd = -1)exit(); = -1)exit(); while(skvalwhile(skval= =read(fdread(fd, &c, 1)=1), &c, 1)=1) printf(“charprintf(“char % %cn”,ccn”,c););skvalskval= =lseek(fdlseek(fd, 1023, SEEK_SET);, 1023, SEEK_SET);printf(“newprintf(“new seek seek valval % %dn”,skvaldn”,skval);); 199系统调用系统调用-fstat#include #include #include sys/#include #include sys/#include intint fstat(intfstat(int fildesfildes, , structstruct stat * stat *bufbuf););intint stat(conststat(const char *path, char *path, structstruct stat * stat *bufbuf) )intint lstat(constlstat(const char *path, char *path, structstruct stat * stat *bufbuf) )200系统调用系统调用-fstatfstatfstat系统调用返回文件的状态信息。系统调用返回文件的状态信息。st_modest_mode 文件权限和文件类型信息文件权限和文件类型信息st_inost_ino 文件的索引节点文件的索引节点st_devst_dev 保存文件的设备保存文件的设备st_uidst_uid 文件的所有者文件的所有者st_gidst_gid 文件的组所有者文件的组所有者st_atimest_atime 文件上次被访问时间文件上次被访问时间st_ctimest_ctime 文件上次被修改时间(文件权限、所有者、内容文件上次被修改时间(文件权限、所有者、内容 等)等)st_mtimest_mtime 文件内容方面上次被修改的时间文件内容方面上次被修改的时间st_nlinkst_nlink 文件的链接计数文件的链接计数201系统调用系统调用-fstatstructstruct stat stat dev_tdev_t st_devst_dev; /* ; /* 设备设备 * */ / ino_tino_t st_inost_ino; /* ; /* 节点节点 * */ / mode_tmode_t st_modest_mode; /* ; /* 模式模式 * */ / nlink_tnlink_t st_nlinkst_nlink; /* ; /* 硬连接硬连接 * */ / uid_tuid_t st_uidst_uid; /* ; /* 用户用户ID */ ID */ gid_tgid_t st_gidst_gid; /* ; /* 组组ID */ ID */ dev_tdev_t st_rdevst_rdev; /* ; /* 设备类型设备类型 * */ / off_toff_t st_offst_off; /* ; /* 文件字节数文件字节数 * */ / unsigned long unsigned long st_blksizest_blksize; /* ; /* 块大小块大小 * */ / unsigned long unsigned long st_blocksst_blocks; /* ; /* 块数块数 * */ / time_ttime_t st_atimest_atime; /* ; /* 最后一次访问时间最后一次访问时间 * */ / time_ttime_t st_mtimest_mtime; /* ; /* 最后一次修改时间最后一次修改时间 * */ / time_ttime_t st_ctimest_ctime; /* ; /* 最后一次改变时间最后一次改变时间( (指属性指属性) */ ) */ ;202系统调用系统调用-dup,dup2#include #include intint dup(intdup(int fildesfildes););intint dup2(int dup2(int fildesfildes, , intint fildes2) fildes2)dupdup系统调用将一个文件描述符拷贝到该用户文件描述符表系统调用将一个文件描述符拷贝到该用户文件描述符表中的第一个空槽中返回一个新的文件描述符。中的第一个空槽中返回一个新的文件描述符。dup2dup2系统调用系统调用将文件描述符将文件描述符fildesfildes复制给复制给fildes2fildes2。203系统调用系统调用-dup,dup2#include #include main(intmain(int argcargc, char *, char *argvargv) intint fd,ifd,i; ;char buf512;char buf512; if(argcif(argc!=2)exit();!=2)exit();fdfd=open(argv1, S_IWUSR);=open(argv1, S_IWUSR);if(fdif(fd = -1)exit(); = -1)exit();204系统调用系统调用-dup,dup2close(1);close(1);dup(fddup(fd););for(ifor(i=0; i=0; isizeof(bufsizeof(buf); i+) ); i+) bufibufi=a;=a; write(1, write(1, bufbuf, , sizeof(bufsizeof(buf);); 205系统调用系统调用-pipe#include#include intint pipe(intpipe(int fildes2); fildes2); pipepipe调用可以创建一个管道调用可以创建一个管道( (通信缓冲区通信缓冲区).).当调用成功时当调用成功时, ,我我们可以访问文件描述符们可以访问文件描述符fildes0,fildes1.fildes0,fildes1.其中其中fildes0fildes0是用来读的文件描述符是用来读的文件描述符, ,而而fildes1fildes1是用来写的文件描述符是用来写的文件描述符. . 206系统调用系统调用-pipe#include #include #include #include #include #include #include #include #include #include #include sys/#include #include sys/#include #define BUFFER 255 #define BUFFER 255 207系统调用系统调用-pipeintint main(intmain(int argc,charargc,char * *argvargv) ) char bufferBUFFER+1; char bufferBUFFER+1; intint fd2; fd2; if(argcif(argc!=2) !=2) fprintf(stderr,Usage:%sfprintf(stderr,Usage:%s stringna,argv0); stringna,argv0); exit(1); exit(1); 208系统调用系统调用-pipe if(pipe(fdif(pipe(fd)!=0) )!=0) fprintf(stderr,Pipefprintf(stderr,Pipe Error:%sna,strerror(errnoError:%sna,strerror(errno); ); exit(1); exit(1); if(forkif(fork()=0) ()=0) close(fd0); close(fd0); printf(Child%dprintf(Child%d Write to pipe Write to pipena,getpidna,getpid(); (); snprintf(buffer,BUFFER,%s,argv1); snprintf(buffer,BUFFER,%s,argv1); write(fd1,buffer,strlen(buffer); write(fd1,buffer,strlen(buffer); printf(Child%dprintf(Child%d Quit Quitna,getpidna,getpid(); (); exit(0); exit(0); 209系统调用系统调用-pipe else else close(fd1); close(fd1); printf(Parent%dprintf(Parent%d Read from pipe Read from pipena,getpidna,getpid(); (); memset(buffer,BUFFER+1); memset(buffer,BUFFER+1); read(fd0,buffer,BUFFER); read(fd0,buffer,BUFFER); printf(Parent%dprintf(Parent%d Read:%sn,getpid(),bufferRead:%sn,getpid(),buffer); ); exit(1); exit(1); 210系统调用系统调用-chmod#include sys/#include intint chmod(constchmod(const char *path, char *path, mode_tmode_t mode); mode);chmodchmod系统调用修改路径名系统调用修改路径名pathpath文件的访问权限,文件的访问权限,modemode设置设置类似于类似于openopen中的中的modemode。211系统调用系统调用-unlink,link,symlink#include #include intint unlink(constunlink(const char *path); char *path);intint link(constlink(const char *path1, const char *path2); char *path1, const char *path2);intint symlink(constsymlink(const char *path1, const char *path2); char *path1, const char *path2);linklink和和unlinkunlink用来创建和删除文件的链接,用来创建和删除文件的链接,symlinksymlink用来创用来创建建path1path1的符号链接。的符号链接。212系统调用系统调用-mkdir,rmdir#include sys/#include intint mkdir(constmkdir(const char *path, char *path, mode_tmode_t mode); mode);intint rmdir(constrmdir(const char *path); char *path);mkdirmkdir和和rmdirrmdir用来创建和删除目录,用来创建和删除目录,213系统调用系统调用-chdir#include #include intint chdir(constchdir(const char *path); char *path);chdirchdir用来改变当前目录,用来改变当前目录,214系统调用系统调用-fcntl#include #include intint fcntl(intfcntl(int fildesfildes, , intint cmdcmd););intint fcntl(intfcntl(int fildesfildes, , intint cmdcmd, long , long argarg););cmdcmd=F_DUPFD =F_DUPFD 复制描述符,复制文件描述符复制描述符,复制文件描述符filedesfiledes,新文,新文 件描述符作为函数值返回。它是尚未打开的件描述符作为函数值返回。它是尚未打开的 各描述符中大于或等于第三个参数值各描述符中大于或等于第三个参数值( (取为整取为整 型值型值) )中各值的最小值。新描述符有它自己的中各值的最小值。新描述符有它自己的 一套文件描述符标志,其一套文件描述符标志,其FD_CLOEXECFD_CLOEXEC文件描文件描 述符标志则被清除这表示该描述符在述符标志则被清除这表示该描述符在execexec时时 仍保持开放仍保持开放。215系统调用系统调用-fcntlcmdcmd=F_GETFD =F_GETFD 获取文件描述符标志获取文件描述符标志, , 唯一标志唯一标志: : FD_CLOEXEC FD_CLOEXEC。对应于。对应于filedesfiledes的文件描述符标的文件描述符标 志作为函数值返回。志作为函数值返回。cmdcmd=F_SETFD =F_SETFD 对于对于filedesfiledes设置文件描述符标志。新标志值设置文件描述符标志。新标志值 是按第是按第3 3个参数个参数( (取为整型值取为整型值) ) 设置的设置的 0-0-在在 execexec时不关闭时不关闭 1-1-在在execexec时关闭。时关闭。 cmdcmd=F_GETFL =F_GETFL 获取文件状态标志。对应于获取文件状态标志。对应于filedesfiledes的文件状的文件状 态标志作为函数值返回。在我们说明态标志作为函数值返回。在我们说明openopen函函 数时,数时, 已说明了文件状态标志已说明了文件状态标志 216系统调用系统调用-fcntlcmdcmd=F_SETFL =F_SETFL 设置文件状态标志设置文件状态标志. . 只能修改只能修改: O_APPEND, : O_APPEND, O_NONBLOCK O_NONBLOCK和和 O_ASYNC O_ASYNC cmdcmd=F_GETLK, F_SETLK or F_SETLKW =F_GETLK, F_SETLK or F_SETLKW 获取获取/ /设置记录锁设置记录锁 cmdcmd=F_GETOWN =F_GETOWN 取当前接收取当前接收SIGIOSIGIO和和SIGURGSIGURG信号的进程信号的进程IDID或进或进 程组程组IDIDcmdcmd=F_SETOWN =F_SETOWN 设置接收设置接收SIGIOSIGIO和和SIGURGSIGURG信号的进程信号的进程IDID或进程或进程 组组IDID。正的。正的argarg指定一个进程指定一个进程IDID。负的。负的argarg表表 示等于示等于argarg绝对值的一个进程组绝对值的一个进程组IDID。 217系统调用系统调用-mount,umountmount系统调用用来安装一个设备。系统调用用来安装一个设备。语法:语法:mount(constmount(const char *dev, const char *dir, char *dev, const char *dir, intint argarg););umount卸载一个设备卸载一个设备语法:语法:umount(constumount(const char *dev); char *dev);218系统调用系统调用-综合应用综合应用读目录的函数读目录的函数structstruct direntdirent * *readdir(intreaddir(int fildesfildes););structstruct direntdirent long long d_inod_ino; /* ; /* inodeinode number */ number */off_toff_t d_offd_off; /* offset to this ; /* offset to this direntdirent */ */unsigned short unsigned short d_reclend_reclen; /* length of this ; /* length of this d_named_name */ */char d_nameNAME_MAX+1; /* file name */char d_nameNAME_MAX+1; /* file name */ 219系统调用系统调用-综合应用综合应用例子:一个类似例子:一个类似cp -r cp -r 的程序的程序#include#include #includesys/#include #includesys/#include #include#include #include#include #include#include #include#include #include#include #defineRWBUFSIZ0xffff #defineRWBUFSIZ0xffff 220系统调用系统调用-综合应用综合应用charcharrwbufRWBUFSIZrwbufRWBUFSIZ; ; intintinit(init(intint,char*); ,char*); longcopy(char*,char*);longcopy(char*,char*);intintmain(main(intintargcargc,char*,char*argvargv) ) longcount; longcount; if(!init(if(!init(argcargc,argvargv) ) count=copy(argv1,argv2); count=copy(argv1,argv2); printfprintf(%ldfilescopiedn,count); (%ldfilescopiedn,count); return0; return0; 221系统调用系统调用-综合应用综合应用intintinit(init(intintargcargc,char*,char*argvargv) ) switch(switch(argcargc) ) case(2): case(2): argv2=argv2=get_current_dir_nameget_current_dir_name();/();/*copyfilestoPWD*/ *copyfilestoPWD*/ case(1): case(1): printfprintf(“(“Usage:copyUsage:copypathnamepathnamepathnamepathnamen”); n”); return-1; return-1; return0; return0; 222系统调用系统调用-综合应用综合应用voiderror(char*voiderror(char*pthpth) ) switch(switch(errnoerrno) ) case(ENOENT): case(ENOENT): printfprintf(Fileor(Fileordirentdirent%s%sdosentdosentexiexistn,stn,pthpth); ); break; break; case(EACCES): case(EACCES): printfprintf(AccesAcceserror%error%snsn,pthpth); ); break; break; case(EEXIST): case(EEXIST): printfprintf(Fileor(Fileordirentdirent%salreadyexi%salreadyexistn,stn,pthpth); ); default: default: printfprintf(Cantopenfileor(Cantopenfileordirentdirent%ssn n,pthpth); ); 223系统调用系统调用-综合应用综合应用voidvoidgetfullnamegetfullname(char*get,char*path,char*name) (char*get,char*path,char*name) char*p; char*p; strcpystrcpy(get,path); (get,path); strcatstrcat(get,/); (get,/); if(p=if(p=strrchrstrrchr(name,/)!=NULL) (name,/)!=NULL) strcatstrcat(get,p+1); (get,p+1); else else strcatstrcat(get,name); (get,name); mode_tmode_tmode(intmode(intumodeumode) ) return(return(mode_t)(umodemode_t)(umode&0777); &0777); 224系统调用系统调用-综合应用综合应用longcopy(char*longcopy(char*pthpth,char*,char*opthopth) ) intintpthidpthid,opthidopthid,rnrn; ; longcount=0; longcount=0; structstructstatstatue; statstatue; DIR*DIR*dpdp; ; structstructdirentdirent*dir; *dir; charcharfullnameNAME_MAXfullnameNAME_MAX+1,+1,nextfileNAME_MAXnextfileNAME_MAX+1; +1; if(stat(if(stat(pthpth,&statue) ,&statue) errnoerrno=EACCES; =EACCES; error(error(pthpth); ); 225系统调用系统调用-综合应用综合应用 else else if(S_ISDIR(if(S_ISDIR(statue.st_modestatue.st_mode) ) getfullnamegetfullname(fullnamefullname,opthopth,pthpth) ); ; mkdirmkdir(fullname,mode(statue.st_modefullname,mode(statue.st_mode);); dpdp=opendiropendir(pthpth); ); while(dir=while(dir=readdirreaddir(dpdp) ) if(if(strcmp(dirstrcmp(dir- - d_named_name,.)&,.)& strcmp(dirstrcmp(dir-d_named_name,.) ,.) getfullnamegetfullname(nextfinextfilele,pthpth,dir-,dir-d_named_name); ); count+=copy(count+=copy(nenextfilextfile,fullnamefullname); ); closedirclosedir(dpdp); ); 226系统调用系统调用-综合应用综合应用 else else if(!(if(!(pthidpthid=open(=open(pthpth,O_RDON,O_RDONLY) LY) error(error(pthidpthid); ); else else getfullnamegetfullname(fullnamefullname,optopth h,pthpth); ); if(if(opthidopthid=creatcreat(fulfullname,mode(statue.st_modelname,mode(statue.st_mode) =-1) =-1) errnoerrno=EACCES; =EACCES; error(error(fullnamefullname); ); 227系统调用系统调用-综合应用综合应用 else else while(while(rnrn=read=read(pthidpthid,rwbufrwbuf,RWBUFSIZ) ,RWBUFSIZ) write(write(opthopthidid,rwbufrwbuf,rnrn); ); count+; count+; close(opthidclose(opthid); ); close(pthidclose(pthid); ); returncount; returncount; 228有关进程的一些概念有关进程的一些概念进程:地址空间进程:地址空间+ +系统资源。地址空间和系统资源被属于同系统资源。地址空间和系统资源被属于同 一进程的一个或者多个线程所使用。一个进程包括程一进程的一个或者多个线程所使用。一个进程包括程 序代码、数据、堆栈、打开的文件和环境。序代码、数据、堆栈、打开的文件和环境。线程:是位于一个进程的地址空间内、可被单独调度运行的线程:是位于一个进程的地址空间内、可被单独调度运行的 单元。又称为轻量进程。单元。又称为轻量进程。 进程的父子关系、僵死子进程、进程的真正用户标识进程的父子关系、僵死子进程、进程的真正用户标识号、有效用户标识号、保存的用户标识号、号、有效用户标识号、保存的用户标识号、setuid程序、程序、信信号(软中断)。号(软中断)。229父 进 程数据打开的文件当前目录改变的根目录核心栈父进程U区本进程区表父 进 程用户栈子 进 程数据打开的文件当前目录改变的根目录核心栈子进程U区本进程区表子 进 程用户栈共享正文文件表索引节点表230与进程相关的系统调用与进程相关的系统调用pid_tpid_t fork(voidfork(void););intint execl(constexecl(const char *path, const char *arg0, , char *path, const char *arg0, , (char *)0); (char *)0); intint execlp(constexeclp(const char *file, const char *arg0, char *file, const char *arg0, , (char *)0); (char *)0); intint execle(constexecle(const char *path, const char *arg0, char *path, const char *arg0, , (char *)0,const char * (char *)0,const char *envpenvp);); intint execv(constexecv(const char *path, const char * char *path, const char *argvargv);); intint execvp(constexecvp(const char *file, const char * char *file, const char *argvargv);); intint execve(constexecve(const char *path, const char * char *path, const char *argvargv, const char * const char *envpenvp););231与进程相关的系统调用与进程相关的系统调用pid_tpid_t wait(intwait(int * *stat_locstat_loc););pid_tpid_t waitpid(pid_twaitpid(pid_t pidpid, , intint * *stat_locstat_loc, , intint options); options);void (*void (*signal(intsignal(int sigsig, void (*, void (*func)(int)(intfunc)(int)(int););intint kill(pid_tkill(pid_t pidpid, , intint sigsig););intint pause(voidpause(void););unsigned unsigned intint sleep(unsignedsleep(unsigned intint seconds); seconds);unsigned unsigned intint alarm(unsignedalarm(unsigned intint seconds); seconds);232与进程相关的系统调用与进程相关的系统调用intint setuid(uid_tsetuid(uid_t uiduid););intint seteuid(uid_tseteuid(uid_t euideuid););uid_tuid_t getuid(voidgetuid(void););uid_tuid_t geteuid(voidgeteuid(void););intint setgid(gid_tsetgid(gid_t gidgid););intint setegid(gid_tsetegid(gid_t gidgid););gid_tgid_t getgid(voidgetgid(void););gid_tgid_t getegid(voidgetegid(void););intint setpgid(pid_tsetpgid(pid_t pid,pid_tpid,pid_t pgidpgid););intint setpgrp(voidsetpgrp(void); ); 233与进程相关的系统调用与进程相关的系统调用pid_tpid_t getpgidgetpgid( ( pid_tpid_t pidpid); ); pid_tpid_t getpgrp(voidgetpgrp(void););intint nice(intnice(int inc); inc);void void exit(intexit(int status); status);234系统调用系统调用-fork#include #include intint pid_tpid_t fork(voidfork(void););说明:说明:fork()fork()产生一个新的子进程,子进程继承父进程的数据与堆栈空产生一个新的子进程,子进程继承父进程的数据与堆栈空 间,并继承父进程的用户代码、组代码、环境变量、已打开的文间,并继承父进程的用户代码、组代码、环境变量、已打开的文 件、工作目录和资源限制等。子进程不会继承父进程的文件锁和件、工作目录和资源限制等。子进程不会继承父进程的文件锁和 未处理的信号。未处理的信号。返回值:如果返回值:如果forkfork成功则在父进程中返回子进程的成功则在父进程中返回子进程的pidpid,在子进程中返,在子进程中返 回回0 0。如果失败则返回。如果失败则返回-1-1,错误码保存于,错误码保存于errnoerrno中。中。错误码:错误码:EAGAIN EAGAIN 内存不足内存不足 ENOMEM ENOMEM 内存不足,无法配置核心所需的数据空间。内存不足,无法配置核心所需的数据空间。235系统调用系统调用-fork#include #include #include #include intint fdrdfdrd, , fdwtfdwt; ;char c;char c;main(intmain(int argcargc, char *, char *argvargv) if(argcif(argc!=3)exit(1);!=3)exit(1);if(fdrdif(fdrd=open(argv1,O_RDONLY)=-1)exit(1)=open(argv1,O_RDONLY)=-1)exit(1);if(fdwtif(fdwt=creat(argv2,0666)=-1)exit(1);=creat(argv2,0666)=-1)exit(1);fork();fork();rdwrtrdwrt();();exit();exit(); 236系统调用系统调用-forkrdwrtrdwrt()() for(;)for(;) if(read(fdrdif(read(fdrd, &c, 1)!=1)return;, &c, 1)!=1)return;write(fdwtwrite(fdwt, &c, 1);, &c, 1); 237系统调用系统调用-execve#include #include intint execve(constexecve(const char *path, const char char *path, const char * *argvargv, const char *, const char *envpenvp););说明:说明:execveexecve()()用用pathpath指定的文件替换当前进程的指定的文件替换当前进程的 内存映像,内存映像,argvargv为传给为传给mainmain的参数的参数, ,envpenvp为新为新 的环境变量。的环境变量。 返回值:成功则不会返回。如果失败则返回返回值:成功则不会返回。如果失败则返回-1-1,错,错 误码保存于误码保存于errnoerrno中。中。238系统调用系统调用-execve错误码:错误码:EACCES EACCES 文件不可执行,文件存储权限不足。文件不可执行,文件存储权限不足。 ENOEXEC ENOEXEC 无法判断欲执行文件的格式。无法判断欲执行文件的格式。 E2BIG E2BIG 参数数组过大。参数数组过大。 EFAULT EFAULT 参数参数pathpath所指的字符串地址超出可存取空所指的字符串地址超出可存取空 间范围。间范围。 ENAMETOOLONG ENAMETOOLONG 参数参数pathpath所指的字符串太长。所指的字符串太长。 ENOMEM ENOMEM 核心内存不足。核心内存不足。 ENOTDIR ENOTDIR 参数参数pathpath字符串所包含的目录路径并非有字符串所包含的目录路径并非有 效目录。效目录。239系统调用系统调用-execve#include #include main()main() char *char *argvargv=“=“ls”,”-al”,”/etc/passwd”,(charls”,”-al”,”/etc/passwd”,(char *)0;*)0;char *char *envpenvp=“PATH=/bin”,0;=“PATH=/bin”,0;execve(”/bin/ls”,argv,envpexecve(”/bin/ls”,argv,envp);); 240系统调用系统调用-wait#include sys/#include #include sys/#include intint pid_tpid_t wait(intwait(int *status); *status);说明:说明:wait()wait()暂停目前进程的运行,直到有信号来或子进程暂停目前进程的运行,直到有信号来或子进程 结束。如果在调用结束。如果在调用waitwait时子进程已经结束则时子进程已经结束则waitwait会立会立 即返回子进程的结束状态值。如果进程捕俘即返回子进程的结束状态值。如果进程捕俘“子进程子进程 死死”信号,则调用用户的软中断信号处理程序。如果信号,则调用用户的软中断信号处理程序。如果 进程忽略进程忽略“子进程死子进程死”软中断信号,则软中断信号,则waitwait释放僵死释放僵死子子 进程的进程表项,然后寻找其他的子进程。进程的进程表项,然后寻找其他的子进程。 返回值:成功返回子进程返回值:成功返回子进程PIDPID。241系统调用系统调用-wait#include #include #include #include #include sys/#include #include sys/#include main()main() pid_tpid_t pidpid; ;intint status, i; status, i;if(forkif(fork()=0)()=0)printf(“Thisprintf(“This is the child process, is the child process, pidpid=%=%dndn”, ”, getpidgetpid();();exit(5);exit(5); 242系统调用系统调用-waitelseelsesleep(1);sleep(1);printf(“Thisprintf(“This is the parent process, wait for is the parent process, wait for child n”); child n”);pidpid= =wait(&statuswait(&status););i=i=WEXITSTATUS(satusWEXITSTATUS(satus););printf(“childsprintf(“childs pidpid=%d, exit =%d, exit satussatus = & = &dndn”, ”, pidpid, i);, i); 243系统调用系统调用-wait#include #include #include #include #include sys/#include #include sys/#include #include #include main(intmain(int argcargc, char *, char *argvargv) intint ret_val,ret_code,iret_val,ret_code,i; ; if(argcif(argc1)signal(SIGCLD,SIG_IGN);1)signal(SIGCLD,SIG_IGN);244系统调用系统调用-waitfor(ifor(i=0; i15; i+)=0; i15; i+)if(forkif(fork()=0)()=0)printf(“childprintf(“child proc proc pidpid=%=%dndn”, ”, getpidgetpid();();exit(1);exit(1); ret_valret_val= =wait(&ret_codewait(&ret_code););printf(“witprintf(“wit ret_val%dret_code%dn”,ret_val,ret_coderet_val%dret_code%dn”,ret_val,ret_code);); 245系统调用系统调用-waitpid#include sys/#include #include sys/#include pid_tpid_t waitpid(pid_twaitpid(pid_t pidpid, , intint * *stat_locstat_loc, , intint options);options);说明:说明:waitpidwaitpid()()暂停目前进程的运行,直到有信号来或子暂停目前进程的运行,直到有信号来或子 进程结束。如果在调用进程结束。如果在调用waitwait时子进程已经结束则时子进程已经结束则waitwait 会立即返回子进程的结束状态值。会立即返回子进程的结束状态值。246系统调用系统调用-waitpid参数参数 pidpid为欲等待的子进程识别码为欲等待的子进程识别码 pidpid-10 0 等待任何识别码为等待任何识别码为pidpid的子进程的子进程 option option 可以为可以为0 0或下面的或下面的OROR组合组合 WNOHANG WNOHANG 如果没有任何已经结束的子进程则马上返回,不等待如果没有任何已经结束的子进程则马上返回,不等待 WUNTRACED WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状如果子进程进入暂停执行情况则马上返回,但结束状 态不予理会态不予理会 返回值:成功返回子进程返回值:成功返回子进程PIDPID。如果失败则返回。如果失败则返回-1-1,错误码,错误码 保存于保存于 errnoerrno中。中。247系统调用系统调用-waitpid子进程的结束状态返回后存于子进程的结束状态返回后存于statusstatus,下面的宏可判别结束情况:,下面的宏可判别结束情况:WIFEXITED(statusWIFEXITED(status) ) 如果子进程正常结束则为非如果子进程正常结束则为非0 0值值WEXITSTATUS(statusWEXITSTATUS(status) ) 取得子进程由取得子进程由exitexit返回的结束代码,一般会先用返回的结束代码,一般会先用 WIFEXITEDWIFEXITED来判断是否正常结束才能使用此宏来判断是否正常结束才能使用此宏WIFSIGNALED(statusWIFSIGNALED(status) ) 如果子进程是因为信号而结束则此宏值为真如果子进程是因为信号而结束则此宏值为真WTERMSIG(statusWTERMSIG(status) ) 取得子进程因信号而终止的信号代码,一般会先取得子进程因信号而终止的信号代码,一般会先 用用WIFSIGNALEDWIFSIGNALED来判断才能使用此宏来判断才能使用此宏WIFSTOPPED(statusWIFSTOPPED(status) ) 如果子进程处于暂停执行的情况则此宏为真如果子进程处于暂停执行的情况则此宏为真WSTOPSIG(statusWSTOPSIG(status) ) 取得引发子进程暂停的信号代码,一般会先用取得引发子进程暂停的信号代码,一般会先用 WIFSTOOPEDWIFSTOOPED来判断后才使用此宏来判断后才使用此宏248系统调用系统调用-signal#include #include void (*void (*signal(intsignal(int sigsig, void (*, void (*func)(int)(intfunc)(int)(int););说明:说明:signalsignal为指定的信号设置相应的信号处理函数,当指定的信号到为指定的信号设置相应的信号处理函数,当指定的信号到 达时执行相应的信号处理函数如果达时执行相应的信号处理函数如果funcfunc不是函数指针,则必须是不是函数指针,则必须是 下列两个常数之一:下列两个常数之一: SIG_IGN SIG_IGN 忽略相应的信号忽略相应的信号 SIG_DFL SIG_DFL 将信号处理重置为缺省的处理方式将信号处理重置为缺省的处理方式返回值:成功返回先前的信号处理函数指针。如果失败则返回返回值:成功返回先前的信号处理函数指针。如果失败则返回-1-1,错误,错误 码码 保存于保存于errnoerrno中。中。注意事项:在接收到一次信号并处理后,系统自动将信号处理方式切换注意事项:在接收到一次信号并处理后,系统自动将信号处理方式切换 回缺省的处理方式回缺省的处理方式249系统调用-signal250系统调用-signal251系统调用-signal252系统调用-signal253系统调用系统调用-kill#include #include intint kill(pid_tkill(pid_t pidpid, , intint sigsig););说明:说明:killkill用来将信号用来将信号sigsig发给进程号为发给进程号为pidpid的进程,的进程,pidpid有有 以下几种情况:以下几种情况: pidpid0 0 将信号发给进程号为将信号发给进程号为pidpid的进程的进程 pidpid=0 =0 将信号发给同组的所有进程将信号发给同组的所有进程 pidpid=-1 =-1 将信号发给系统中所有进程将信号发给系统中所有进程 pidpid0 0 将信号发给组号为将信号发给组号为pidpid绝对值的所有进程绝对值的所有进程 254系统调用系统调用-kill返回值:如果成功则返回返回值:如果成功则返回0 0。如果失败则返回。如果失败则返回-1-1,错误码,错误码 保存于保存于errnoerrno中。中。错误码:错误码:ENIVAL ENIVAL 参数参数sigsig不合法不合法 ESRCH ESRCH 参数参数pidpid所指的进程或进程组不存在所指的进程或进程组不存在 EPERM EPERM 权限不够无法将信号发给指定的进程权限不够无法将信号发给指定的进程255系统调用系统调用-kill#include #include #include #include #include sys/#include #include sys/#include #include #include main(intmain(int argcargc, char *, char *argvargv) pid_tpid_t pidpid; ;intint status; status; 256系统调用系统调用-killif(!(pidif(!(pid=fork()=fork()printf(“Hiprintf(“Hi I am child process!n”); I am child process!n”);sleep(10);sleep(10);return;return; elseelseprintf(“sendprintf(“send signal to child process (% signal to child process (%d)nd)n”, ”, pidpid););sleep(1);sleep(1);kill(pid,SIGABRTkill(pid,SIGABRT););wait(&statuswait(&status););if(WIFSIGNALED(statusif(WIFSIGNALED(status)printf(“childprintf(“child process receive signal % process receive signal %dndn”, ”, WTERMSIG(statusWTERMSIG(status);); 257系统调用系统调用-pause#include #include intint pause(voidpause(void););说明:说明:pausepause暂停进程的执行,直到被信号唤醒暂停进程的执行,直到被信号唤醒 返回值:只返回返回值:只返回-1-1,错误码保存于,错误码保存于errnoerrno中。中。错误码:错误码:EINTR EINTR 有信号到达中断了此函数有信号到达中断了此函数258系统调用系统调用-sleep#include #include unsigned unsigned intint sleep(unsignedsleep(unsigned intint seconds); seconds);说明:说明:sleepsleep暂停进程的执行暂停进程的执行secondsseconds时间,或被信时间,或被信 号唤醒号唤醒 返回值:若进程暂停到所指定时间则返回返回值:若进程暂停到所指定时间则返回0 0,若有信,若有信 号中断则返回剩余秒数。号中断则返回剩余秒数。259系统调用系统调用-alarm#include #include unsigned unsigned intint alarm(unsignedalarm(unsigned intint seconds); seconds);说明:说明:alarmalarm在过了在过了secondsseconds时间后给进程发信号时间后给进程发信号 SIGALRMSIGALRM。如果。如果secondsseconds为为0 0,则之前设置的,则之前设置的 闹钟被取消并返回剩余时间。闹钟被取消并返回剩余时间。 返回值:返回之前闹钟剩余的秒数,若之前未设闹返回值:返回之前闹钟剩余的秒数,若之前未设闹 钟返回钟返回0 0。260系统调用系统调用-alarm#include #include #include #include #include sys/#include #include sys/#include #include #include void handler()void handler()printf(“hellonprintf(“hellon”);”); 261系统调用系统调用-alarmmain(intmain(int argcargc, char *, char *argvargv) intint i; i; signal(SIGALRMsignal(SIGALRM, handler);, handler);alarm(5);alarm(5);for(ifor(i=1; i7; i+)=1; i7; i+)printf(“sleepprintf(“sleep %dn”, i); %dn”, i);sleep(1);sleep(1); 262系统调用系统调用-setuid#include #include intint setuid(uid_tsetuid(uid_t uiduid););说明:说明:setuidsetuid用来重新设置进程的真正用户标识号。此函数用来重新设置进程的真正用户标识号。此函数 只有在有效用户标识号为只有在有效用户标识号为0 0(rootroot)的情况下才起作)的情况下才起作 用。当调用用。当调用setuidsetuid后后rootroot权限会丧失,将不再能调用权限会丧失,将不再能调用 setuidsetuid。如只是暂时放弃。如只是暂时放弃rootroot权限需用权限需用seteuidseteuid。 返回值:执行成功返回返回值:执行成功返回0 0。如果失败则返回。如果失败则返回-1-1,错误码保存,错误码保存 于于errnoerrno中。中。263系统调用系统调用-seteuid#include #include intint seteuid(uid_tseteuid(uid_t uiduid););说明:说明:seteuidseteuid用来重新设置进程的有效用户标识号。如果用来重新设置进程的有效用户标识号。如果 进程的用户标识号为进程的用户标识号为rootroot则将有效用户标识号设置为则将有效用户标识号设置为 uiduid,如果进程的用户标识号不是超级用户,而且,如果进程的用户标识号不是超级用户,而且uiduid 的值是真正用户标识号或保存的用户标识号则将有效的值是真正用户标识号或保存的用户标识号则将有效 用户标识号改为用户标识号改为uiduid。否则返回一个错误。否则返回一个错误。返回值:执行成功返回返回值:执行成功返回0 0。如果失败则返回。如果失败则返回-1-1,错误码保存,错误码保存 于于errnoerrno中。中。264系统调用系统调用-seteuid例子:例子: 假定以下程序的所有者为假定以下程序的所有者为maurymaury( (用户标识号为用户标识号为83198319),),setuidsetuid位被置位,且所有用户都有权执行该文件。位被置位,且所有用户都有权执行该文件。 假定用户假定用户mjbmjb(用户标识号为(用户标识号为50885088)和用户)和用户maurymaury分别拥分别拥有文件有文件mjbmjb和和maurymaury,且者两个文件只对他们的所有着具有只,且者两个文件只对他们的所有着具有只读许可权。读许可权。265系统系统调用系统系统调用- -seteuid#include #include #include #include #include sys/#include #include sys/#include #include #include main(intmain(int argcargc, char *, char *argvargv) intint uiduid, , euideuid, , fdmjbfdmjb, , fdmauryfdmaury; ; uiduid= =getuidgetuid();();euideuid= =geteuidgeteuid();();printf(“uidprintf(“uid %d %d euideuid % %dndn”, ”, uiduid, , euideuid););266系统系统调用系统系统调用- -seteuidfdmjbfdmjb= =open(“mjb”,O_RDONLYopen(“mjb”,O_RDONLY););fdmauryfdmaury= =open(“maury”,O_RDONLYopen(“maury”,O_RDONLY););printf(“fdmjbprintf(“fdmjb %d %d fdmauryfdmaury % %dn”,fdmjbdn”,fdmjb, , fdmauryfdmaury););seteuid(uidseteuid(uid););printf(“afterprintf(“after steduid(%d):uidsteduid(%d):uid %d %d euideuid % %dndn”, ”, uiduid, , getuidgetuid(), (), geteuidgeteuid();(); fdmjbfdmjb= =open(“mjb”,O_RDONLYopen(“mjb”,O_RDONLY);); fdmauryfdmaury= =open(“maury”,O_RDONLYopen(“maury”,O_RDONLY);); printf(“fdmjbprintf(“fdmjb %d %d fdmauryfdmaury % %dn”,fdmjbdn”,fdmjb, , fdmauryfdmaury);); seteuid(euidseteuid(euid);); printf(“afterprintf(“after steduid(%d):uidsteduid(%d):uid %d %d euideuid % %dndn”, ”, uiduid, , getuidgetuid(), (), geteuidgeteuid();(); 267系统调用系统调用-getuid#include #include #include sys/#include uid_tuid_t getuid(voidgetuid(void););说明:说明:getuidgetuid用来取得进程的真正用户标识号。用来取得进程的真正用户标识号。返回值:真正用户标识号。返回值:真正用户标识号。268系统调用系统调用-geteuid#include #include #include sys/#include uid_tuid_t geteuid(voidgeteuid(void););说明:说明:geteuidgeteuid用来取得进程的有效用户标识号。用来取得进程的有效用户标识号。返回值:有效用户标识号。返回值:有效用户标识号。269系统调用系统调用-setgid#include #include #include sys/#include intint setgid(voidsetgid(void););说明:说明:setgidsetgid用来设置进程的真正组标识号。如果用来设置进程的真正组标识号。如果 以超级用户身份调用则有效组标识号、真正以超级用户身份调用则有效组标识号、真正 组标识号保存的组标识号都设成组标识号保存的组标识号都设成gidgid. .返回值:设置成功返回返回值:设置成功返回0 0,失败返回,失败返回-1-1。270系统调用系统调用-setegid#include #include #include sys/#include intint setegid(voidsetegid(void););说明:说明:setegidsetegid用来设置进程的有效组标识号。用来设置进程的有效组标识号。返回值:设置成功返回返回值:设置成功返回0 0,失败返回,失败返回-1-1。271系统调用系统调用-getgid#include #include #include sys/#include gid_tgid_t getgid(voidgetgid(void););说明:说明:getuidgetuid用来取得进程的真正组标识号。用来取得进程的真正组标识号。返回值:真正组标识号。返回值:真正组标识号。272系统调用系统调用-getegid#include #include #include sys/#include gid_tgid_t getegid(voidgetegid(void););说明:说明:getegidgetegid用来取得进程的有效组标识号。用来取得进程的有效组标识号。返回值:有效组标识号。返回值:有效组标识号。273系统调用系统调用-setpgid#include #include #include sys/#include intint setpgid(pid_tsetpgid(pid_t pid,pid_tpid,pid_t pgidpgid););说明:说明:setpgidsetpgid()()将参数将参数pidpid 指定进程的进程组组指定进程的进程组组 号设为参数号设为参数pgidpgid 指定的组号。如果参数指定的组号。如果参数pidpid 为为0 0,则设置当前进程的组号,如果参数,则设置当前进程的组号,如果参数pgidpgid 为为0 0,则会以当前进程的进程标识号来取代原,则会以当前进程的进程标识号来取代原 有的组号。有的组号。274系统调用系统调用-setpgid返回值:执行成功则返回新的组号,如果有错误则返回值:执行成功则返回新的组号,如果有错误则 返回返回-1-1,错误原因存于,错误原因存于errnoerrno中。中。错误码:错误码:EINVAL EINVAL 参数参数pgidpgid小于小于0 0。 EPERM EPERM 进程权限不足,无法完成调用。进程权限不足,无法完成调用。 ESRCH ESRCH 找不到符合参数找不到符合参数pidpid指定的进程。指定的进程。 275系统调用系统调用-setpgrp#include #include #include sys/#include intint setpgrp(voidsetpgrp(void););说明:说明:setpgrpsetpgrp()()将当前进程的组号设为当前进程的将当前进程的组号设为当前进程的 进程号。此函数相当于调用相当于进程号。此函数相当于调用相当于 setpgid(0,0)setpgid(0,0)。 276系统调用系统调用-setpgrp返回值:执行成功则返回新的组号,如果有错误则返回值:执行成功则返回新的组号,如果有错误则 返回返回-1-1,错误原因存于,错误原因存于errnoerrno中。中。277系统调用系统调用-getpgid#include #include #include sys/#include pid_tpid_t getpgidgetpgid( ( pid_tpid_t pidpid); ); 说明:说明:getpgidgetpgid()()用来取得参数用来取得参数pidpid 指定进程的组指定进程的组 号。如果参数号。如果参数pidpid为为0 0,则会取得当前进程的,则会取得当前进程的 组号。组号。返回值:执行成功则返回组号,如果有错误则返返回值:执行成功则返回组号,如果有错误则返回回 -1-1,错误原因存于,错误原因存于errnoerrno中。中。278系统调用系统调用-getpgrp#include #include #include sys/#include pid_tpid_t getpgrp(voidgetpgrp(void); ); 说明:说明:getpgrpgetpgrp()()用来取得目前进程所属的组识别用来取得目前进程所属的组识别 码。此函数相当于调用码。此函数相当于调用getpgid(0)getpgid(0);返回值:执行成功则返回组号,如果有错误则返回返回值:执行成功则返回组号,如果有错误则返回 -1-1,错误原因存于,错误原因存于errnoerrno中。中。279系统调用系统调用-getpid#include #include #include sys/#include pid_tpid_t getpid(voidgetpid(void); ); 说明:说明:getpidgetpid()()用来取得当前进程的进程标识号。用来取得当前进程的进程标识号。返回值:当前进程的标识号。返回值:当前进程的标识号。280系统调用系统调用-getppid#include #include #include sys/#include pid_tpid_t getppid(voidgetppid(void); ); 说明:说明:getppidgetppid()()用来取得当前进程的父进程标识用来取得当前进程的父进程标识 号。号。返回值:当前进程的父进程标识号。返回值:当前进程的父进程标识号。281系统调用系统调用-nice#include #include #include sys/#include intint nice(intnice(int inc); inc);说明:说明:nice()nice()用来改变进程的进程的优先级。参数用来改变进程的进程的优先级。参数 incinc数值越大则优先级越低。只有超级用户才数值越大则优先级越低。只有超级用户才 能使用负的能使用负的inc inc 值,提高进程的优先级。值,提高进程的优先级。282系统调用系统调用-exit#include #include #include sys/#include void void exit(stausexit(staus););说明:说明:exitexit用来正常终结目前进程的执行,并将参用来正常终结目前进程的执行,并将参 数返回给父进程。数返回给父进程。返回值:无。返回值:无。283linux IPC概述概述 linuxlinux下的进程通信手段基本上是从下的进程通信手段基本上是从unixunix平台上的进平台上的进程通信手段继承而来的。而对程通信手段继承而来的。而对unixunix发展做出重大贡献的两发展做出重大贡献的两大主力大主力AT&TAT&T的贝尔实验室及加州大学伯克利分校的伯克利的贝尔实验室及加州大学伯克利分校的伯克利软件发布中心(软件发布中心(BSDBSD)在进程间通信方面的侧重点有所不)在进程间通信方面的侧重点有所不同。前者对同。前者对unixunix早期的进程间通信手段进行了系统的改进早期的进程间通信手段进行了系统的改进和扩充,形成了和扩充,形成了“system V IPC”system V IPC”,通信进程局限在单个,通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口计算机内;后者则跳过了该限制,形成了基于套接口(socketsocket)的进程间通信机制。此外,由于)的进程间通信机制。此外,由于unixunix版本的多版本的多样性,电子电气工程协会(样性,电子电气工程协会(IEEEIEEE)开发了一个独立的)开发了一个独立的unixunix标准,这个新的标准,这个新的ANSI ANSI unixunix标准被称为计算机环境的可移标准被称为计算机环境的可移植性操作系统界面(植性操作系统界面(PSOIXPSOIX)。)。284linux IPC概述概述 最初最初unixunix IPC IPC包括:管道、包括:管道、FIFOFIFO、信号;、信号;system V system V IPCIPC包括:包括:system Vsystem V消息队列、消息队列、system Vsystem V信号灯、信号灯、system system V V共享内存区;共享内存区;POSIX IPCPOSIX IPC包括:包括: POSIXPOSIX消息队列、消息队列、POSIXPOSIX信号灯、信号灯、POSIXPOSIX共享内存区。共享内存区。285linux IPC概述概述 linuxlinux IPC IPC 主要有:主要有:匿名管道(匿名管道(pipepipe)有名管道(有名管道(named pipenamed pipe)信号(信号(signalsignal)消息队列(消息队列(messagemessage)信号量(信号量(semaphoresemaphore)共享内存(共享内存(shared memoryshared memory)套接字(套接字(socketsocket)286匿名管道(匿名管道(pipe) 匿名管道只可用于具有亲缘关系进程间的通匿名管道只可用于具有亲缘关系进程间的通信。信。管道管道实现于内存中,缓冲区是有限的,管道管道实现于内存中,缓冲区是有限的,一般为一个页面大小。一般为一个页面大小。管道的数据是字节流,应管道的数据是字节流,应用程序之间必须事先确定特定的传输用程序之间必须事先确定特定的传输“协议协议”,采用传播具有特定意义的消息。管道是半双工的,采用传播具有特定意义的消息。管道是半双工的,数据只能向一个方向流动,需要双方通信时,需数据只能向一个方向流动,需要双方通信时,需要建立起两个管道。要建立起两个管道。287有名管道有名管道 以以FIFOFIFO的文件形式存在于文件系统中。有名的文件形式存在于文件系统中。有名管道的数据是字节流,应用程序之间必须事先确管道的数据是字节流,应用程序之间必须事先确定特定的传输定特定的传输“协议协议”,采用传播具有特定意义,采用传播具有特定意义的消息。有名管道是半双工的,数据只能向一个的消息。有名管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管方向流动,需要双方通信时,需要建立起两个管道。道。288信号信号 信号用于通知异步事件发生,是一种软中断信号用于通知异步事件发生,是一种软中断机制。除了用于通知进程系统事件外,还可以用机制。除了用于通知进程系统事件外,还可以用于进程间通信,除此之外,进程还可以发送信号于进程间通信,除此之外,进程还可以发送信号给进程本身。给进程本身。 由于历史上的原因,由于历史上的原因,linuxlinux信号分为不可靠信信号分为不可靠信号和可靠信号两类。其中,不可靠信号对应于号和可靠信号两类。其中,不可靠信号对应于system Vsystem V信号,可靠信号对应于信号,可靠信号对应于BSDBSD和和POSIXPOSIX信号。信号。289信号信号-信号响应机制信号响应机制 操作系统在进程每次从核心态返回到用户态操作系统在进程每次从核心态返回到用户态时对信号进行响应。信号产生后到被响应之前处时对信号进行响应。信号产生后到被响应之前处于于pendingpending状态。状态。290信号信号-不可靠信号不可靠信号 不可靠信号是指信号值小于不可靠信号是指信号值小于SIGRTMIN (SIGRTMIN (一般情况下,一般情况下,SIGRTMIN=31SIGRTMIN=31,SIGRTMAX=63)SIGRTMAX=63)的信号。不可靠信号主要表的信号。不可靠信号主要表现在:现在:进程每次处理信号后,就将对信号的响应设置为默认动作,进程每次处理信号后,就将对信号的响应设置为默认动作,如不希望这样用户信号处理函数结尾再一次调用如不希望这样用户信号处理函数结尾再一次调用signal()signal()。信号可能丢失。信号可能丢失。注:在注:在linuxlinux中对不可靠信号机制做了改进:在调用完信号中对不可靠信号机制做了改进:在调用完信号 处理函数后,不必重新安装该信号的处理函数。因此,处理函数后,不必重新安装该信号的处理函数。因此, linuxlinux下的不可靠信号问题主要指的是信号可能丢失。下的不可靠信号问题主要指的是信号可能丢失。 291信号信号-可靠信号可靠信号 可靠信号是信号值位于可靠信号是信号值位于SIGRTMINSIGRTMIN与与SIGRTMAXSIGRTMAX之间的信号,可靠信号不会丢失。之间的信号,可靠信号不会丢失。292信号信号-POSIX对信号的扩充对信号的扩充 POSIXPOSIX(继承(继承BSDBSD)除增加可靠信号外,还增)除增加可靠信号外,还增加了信号传递参数的能力和信号屏蔽(信号阻塞)加了信号传递参数的能力和信号屏蔽(信号阻塞)的功能。信号屏蔽类似于中断屏蔽,进程可以在的功能。信号屏蔽类似于中断屏蔽,进程可以在运行期间屏蔽对某些信号的响应,然后再打开对运行期间屏蔽对某些信号的响应,然后再打开对信号响应的屏蔽。在信号屏蔽期间,如果信号到信号响应的屏蔽。在信号屏蔽期间,如果信号到达则处于达则处于pendingpending状态。状态。293POSIX信号新增系统调用信号新增系统调用intint sigaction(intsigaction(int signum,constsignum,const structstruct sigactionsigaction * *act,structact,struct sigactionsigaction * *oldactoldact); ); intint sigqueue(pid_tsigqueue(pid_t pidpid, , intint sigsig, const union , const union sigvalsigval valval); ); intint sigemptyset(sigset_tsigemptyset(sigset_t *set); *set);intint sigfillset(sigset_tsigfillset(sigset_t *set); *set);intint sigaddset(sigset_tsigaddset(sigset_t *set, *set, intint signumsignum););intint sigdelset(sigset_tsigdelset(sigset_t *set, *set, intint signumsignum););intint sigismember(constsigismember(const sigset_tsigset_t *set, *set, intint signumsignum); ); intint sigprocmask(intsigprocmask(int how, const how, const sigset_tsigset_t *set, *set, sigset_tsigset_t * *oldsetoldset););intint sigpending(sigset_tsigpending(sigset_t *set); *set); intint sigsuspend(constsigsuspend(const sigset_tsigset_t *mask); *mask);294消息队列消息队列 消息是一个完整的信息单元,由消息类型和消息是一个完整的信息单元,由消息类型和消息体组成。可以把消息看作一个记录,具有特消息体组成。可以把消息看作一个记录,具有特定的格式以及特定的优先级。消息克服了信号承定的格式以及特定的优先级。消息克服了信号承载信息量少,管道只能承载无格式字节流以及缓载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列是用来发送和接冲区大小受限等缺点。消息队列是用来发送和接收消息的机制,可被全体有权限的进程访问,对收消息的机制,可被全体有权限的进程访问,对消息队列有写权限的进程可以按照一定的规则向消息队列有写权限的进程可以按照一定的规则向消息队列添加新消息;对消息队列有读权限的进消息队列添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列有程则可以从消息队列中读走消息。消息队列有POSIXPOSIX消息队列以及系统消息队列以及系统V V消息队列两种。消息队列两种。295信号量信号量 主要作为进程间以及同一进程不同线程之间主要作为进程间以及同一进程不同线程之间对临界区的互斥访问。对临界区的互斥访问。296共享内存共享内存 使得多个进程可以访问同一块内存空间,是使得多个进程可以访问同一块内存空间,是最快的可用最快的可用IPCIPC形式。是针对其他通信机制运行效形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。量结合使用,来达到进程间的同步及互斥。 297套接字套接字 更为一般的进程间通信机制,可用于不同机更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由器之间的进程间通信。起初是由unixunix系统的系统的BSDBSD分分支开发出来的,但现在一般可以移植到其它类支开发出来的,但现在一般可以移植到其它类unixunix系统上:系统上:linuxlinux和和system Vsystem V的变种都支持套接的变种都支持套接字。字。298IPC相关系统调用相关系统调用intint pipe(intpipe(int fildes2); fildes2);intint mkfifo(constmkfifo(const char * pathname, char * pathname, mode_tmode_t mode); mode);void (*void (*signal(intsignal(int sigsig, void (*, void (*func)(int)(intfunc)(int)(int););intint kill(pid_tkill(pid_t pidpid, , intint sigsig););intint raise(intraise(int signosigno););intint pause(voidpause(void););unsigned unsigned intint sleep(unsignedsleep(unsigned intint seconds); seconds);unsigned unsigned intint alarm(unsignedalarm(unsigned intint seconds); seconds);299IPC相关系统调用相关系统调用intint sigaction(intsigaction(int signum,constsignum,const structstruct sigactionsigaction * *act,structact,struct sigactionsigaction * *oldactoldact); ); intint sigqueue(pid_tsigqueue(pid_t pidpid, , intint sigsig, const union , const union sigvalsigval valval); ); intint sigemptyset(sigset_tsigemptyset(sigset_t *set); *set);intint sigfillset(sigset_tsigfillset(sigset_t *set); *set);intint sigaddset(sigset_tsigaddset(sigset_t *set, *set, intint signumsignum););intint sigdelset(sigset_tsigdelset(sigset_t *set, *set, intint signumsignum););intint sigismember(constsigismember(const sigset_tsigset_t *set, *set, intint signumsignum); ); intint sigprocmask(intsigprocmask(int how, const how, const sigset_tsigset_t *set, *set, sigset_tsigset_t * *oldsetoldset););intint sigpending(sigset_tsigpending(sigset_t *set); *set); intint sigsuspend(constsigsuspend(const sigset_tsigset_t *mask); *mask);300IPC相关系统调用相关系统调用key_tkey_t ftokftok (char *pathname, char (char *pathname, char projproj); ); intint msgget(key_tmsgget(key_t key, key, intint msgflgmsgflg););intint msgrcv(intmsgrcv(int msqidmsqid, , structstruct msgbufmsgbuf * *msgpmsgp, , intint msgszmsgsz, long , long msgtypmsgtyp, , intint msgflgmsgflg););intint msgsnd(intmsgsnd(int msqidmsqid, , structstruct msgbufmsgbuf * *msgpmsgp, , intint msgszmsgsz, , intint msgflgmsgflg););intint msgctl(intmsgctl(int msqidmsqid, , intint cmdcmd, , structstruct msqid_dsmsqid_ds * *bufbuf););301IPC相关系统调用相关系统调用intint semget(key_tsemget(key_t key, key, intint nsemsnsems, , intint semflgsemflg););intint semop(intsemop(int semidsemid, , structstruct sembufsembuf *sops, unsigned *sops, unsigned nsopsnsops); ); intint semctl(intsemctl(int semidsemid,intint semnumsemnum,intint cmdcmd,union union semunsemun argarg););302IPC相关系统调用相关系统调用intint shmget(key_tshmget(key_t key, key, intint size, size, intint shmflgshmflg););void *void *shmat(intshmat(int shmidshmid, const void *, const void *shmaddrshmaddr, , intint shmflgshmflg););intint shmdt(constshmdt(const void * void *shmaddrshmaddr); ); intint shmctl(intshmctl(int shmidshmid, , intint cmdcmd, , structstruct shmid_dsshmid_ds * *bufbuf););void* void* mmapmmap ( void * ( void * addraddr , , size_tsize_t lenlen , , intint protprot , , intint flags , flags , intint fdfd , , off_toff_t offset ); offset );intint munmapmunmap( void * ( void * addraddr, , size_tsize_t lenlen ); );intint msyncmsync ( void * ( void * addraddr , , size_tsize_t lenlen, , intint flags); flags);303系统调用系统调用-ftok#include sys/#include #include sys/#include key_tkey_t ftokftok (char *pathname, char (char *pathname, char projproj) );说明:说明:ftokftok()()用来将参数用来将参数pathnamepathname指定的文件转换为指定的文件转换为system system V IPC V IPC所需使用的所需使用的keykey。参数。参数pathnamepathname指定的文件必须指定的文件必须 存在且可以存取。存在且可以存取。返回值:成功返回返回值:成功返回keykey值,否则返回值,否则返回-1-1。304系统调用系统调用-msgget#include sys/#include #include sys/#include #include sys/#include intint msgget(key_tmsgget(key_t key, key, intint msgflgmsgflg) ;) ;说明:说明:msggetmsgget()()用来取得用来取得keykey所关联的消息队列的描述符。如果参数所关联的消息队列的描述符。如果参数keykey 为为IPC_PRIVATEIPC_PRIVATE则会建立新的消息队列,如果则会建立新的消息队列,如果keykey不为不为 IPC_PRIVATEIPC_PRIVATE也不是已建立的也不是已建立的IPC keyIPC key,系统则会视参数,系统则会视参数msgflgmsgflg是是 否有否有IPC_CREATIPC_CREAT来决定建立来决定建立IPC keyIPC key为为keykey的消息队列。的消息队列。msgflgmsgflg也也 用来决定消息队列的存取权限相当于用来决定消息队列的存取权限相当于openopen的参数的参数modemode。返回值:成功返回消息队列描述符,否则返回返回值:成功返回消息队列描述符,否则返回-1-1。305系统调用系统调用-msgrcv#include sys/#include #include sys/#include #include sys/#include intint msgrcv(intmsgrcv(int msqidmsqid, , structstruct msgbufmsgbuf * *msgpmsgp, , intint msgszmsgsz, long , long msgtypmsgtyp, , intint msgflgmsgflg););说明:说明:msgrcvmsgrcv()()用来从参数用来从参数msqidmsqid指定的消息队列读取消息,然后存于指定的消息队列读取消息,然后存于 参数参数msgpmsgp所指定的结构内。所指定的结构内。 参数参数msgpmsgp结构如下:结构如下: struct msgbuf long mtype; char mtext1; ; 306系统调用系统调用-msgrcv 参数参数msgszmsgsz为消息数据的长度,即为消息数据的长度,即mtestmtest参数的长度。参数的长度。 参数参数msgtypmsgtyp用来指定所要读取的消息种类:用来指定所要读取的消息种类: =0 =0 返回队列内第一项消息返回队列内第一项消息 0 0 返回队列内第一项与返回队列内第一项与msgtypmsgtyp相同的消息相同的消息 0 0配合使用,返回队列中第一个类型不为配合使用,返回队列中第一个类型不为 msgtyp的消息的消息 IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的如果队列中满足条件的消息内容大于所请求的 msgsz字节,则把该消息截断,截断部分将丢失字节,则把该消息截断,截断部分将丢失 返回值:成功返回实际读到的信息长度,否则返回返回值:成功返回实际读到的信息长度,否则返回-1-1。307系统调用系统调用-msgsnd#include sys/#include #include sys/#include #include sys/#include intint msgsnd(intmsgsnd(int msqidmsqid, , structstruct msgbufmsgbuf * *msgpmsgp, , intint msgszmsgsz, , intint msgflgmsgflg););说明:说明:msgsndmsgsnd()()用来向参数用来向参数msqidmsqid指定的消息队列发送消息。指定的消息队列发送消息。 参数参数msgpmsgp结构如下:结构如下: structstruct msgbufmsgbuf long long mtypemtype; ; char mtext1; char mtext1; ; ; 308系统调用系统调用-msgsnd 参数参数msgszmsgsz为消息数据的长度,即为消息数据的长度,即mtestmtest参数的长度。参数的长度。 参数参数msgflgmsgflg可被设置成可被设置成IPC_NOWAIT,指示消息队列已满或有其他情况,指示消息队列已满或有其他情况 无法马上送入信息时,立即返回无法马上送入信息时,立即返回EAGAIN。返回值:成功返回返回值:成功返回0 0,否则返回,否则返回-1-1。309系统调用系统调用-msgctl#include sys/#include #include sys/#include #include sys/#include intint msgctl(intmsgctl(int msqidmsqid, , intint cmdcmd, , structstruct msqid_dsmsqid_ds * *bufbuf););说明:该系统调用对由说明:该系统调用对由msqidmsqid标识的消息队列执行标识的消息队列执行cmdcmd操作,共有以下三操作,共有以下三 种种cmdcmd操作:操作: IPC_STATIPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在:该命令用来获取消息队列信息,返回的信息存贮在 bufbuf指向的指向的msqidmsqid结构中;结构中;310系统调用系统调用-msgctl IPC_SETIPC_SET:该命令用来设置消息队列的属性,要设置的属性存储:该命令用来设置消息队列的属性,要设置的属性存储 在在bufbuf指向的指向的msqidmsqid结构中,包括:结构中,包括:msg_perm.uidmsg_perm.uid、 msg_perm.gidmsg_perm.gid、msg_perm.modemsg_perm.mode以及以及msg_qbytesmsg_qbytes,也影,也影 响响msg_ctimemsg_ctime成员。成员。 IPC_RMIDIPC_RMID:删除:删除msqidmsqid标识的消息队列;标识的消息队列; 311系统调用系统调用-msgctlstruct msqid_ds struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ _kernel_time_t msg_stime; /* last msgsnd time */ _kernel_time_t msg_rtime; /* last msgrcv time */ _kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */unsigned long msg_lqbytes; /* ditto */ 312系统调用系统调用-msgctlunsigned short msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ _kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ _kernel_ipc_pid_t msg_lrpid; /* last receive pid */ ; 313系统调用系统调用-msgctlstructstruct ipc_permipc_perm key_tkey_t key; / key; /该键值则唯一对应一个消息队列该键值则唯一对应一个消息队列uid_tuid_t uiduid; /; /消息队列的所有者标识号消息队列的所有者标识号gid_tgid_t gidgid; /; /消息队列的组所有者标识号消息队列的组所有者标识号uid_tuid_t cuidcuid;/;/创建消息队列的用户标识号创建消息队列的用户标识号gid_tgid_t cgidcgid;/;/创建消息队列的组标识号创建消息队列的组标识号mode_tmode_t mode; / mode; /消息队列的访问权限消息队列的访问权限unsigned long unsigned long seqseq;/;/序号序号;314消息队列系统调用示例消息队列系统调用示例#include sys/#include #include sys/#include #include #include void void msg_stat(int,structmsg_stat(int,struct msqid_dsmsqid_ds ); ); main() main() intint gflags,sflags,rflagsgflags,sflags,rflags; ;key_tkey_t key; key; intint msgidmsgid; ;intint revalreval; ; 315消息队列系统调用示例消息队列系统调用示例structstruct msgsbufmsgsbuf intint mtypemtype; ; char mtext1; char mtext1; msg_sbufmsg_sbuf; ; structstruct msgmbufmsgmbuf intint mtypemtype; ; char mtext10; char mtext10; msg_rbufmsg_rbuf; ; structstruct msqid_dsmsqid_ds msg_ginfo,msg_sinfomsg_ginfo,msg_sinfo; ; 316消息队列系统调用示例消息队列系统调用示例char* char* msgpathmsgpath=/=/unix/msgqueueunix/msgqueue; ; key=key=ftok(msgpath,aftok(msgpath,a); ); gflagsgflags=IPC_CREAT|IPC_EXCL; =IPC_CREAT|IPC_EXCL; msgidmsgid=msgget(key,gflags|00666); =msgget(key,gflags|00666); if(msgidif(msgid=-1) =-1) printf(“msgprintf(“msg create errorn”); create errorn”); return; return; / /创建一个消息队列后,输出消息队列缺省属性创建一个消息队列后,输出消息队列缺省属性 msg_stat(msgid,msg_ginfomsg_stat(msgid,msg_ginfo); ); sflagssflags=IPC_NOWAIT; =IPC_NOWAIT; 317消息队列系统调用示例消息队列系统调用示例msg_sbuf.mtypemsg_sbuf.mtype=10; =10; msg_sbuf.mtext0=a; msg_sbuf.mtext0=a; revalreval= =msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflagsmsgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags); ); /发送一个消息后,输出消息队列属性发送一个消息后,输出消息队列属性 if(revalif(reval=-1) =-1) printf(“messageprintf(“message send errorn”); send errorn”); msg_stat(msgid,msg_ginfomsg_stat(msgid,msg_ginfo); ); rflagsrflags=IPC_NOWAIT|MSG_NOERROR; =IPC_NOWAIT|MSG_NOERROR; revalreval=msgrcv(msgid,&msg_rbuf,4,10,rflags);=msgrcv(msgid,&msg_rbuf,4,10,rflags);318消息队列系统调用示例消息队列系统调用示例/从消息队列中读出消息后,输出消息队列属性从消息队列中读出消息后,输出消息队列属性if(revalif(reval=-1) =-1) printf(readprintf(read msgmsg errorn); errorn); else else printf(“readprintf(“read from from msgmsg queue %d bytes queue %d bytesn”,revaln”,reval); ); msg_stat(msgid,msg_ginfomsg_stat(msgid,msg_ginfo); ); msg_sinfo.msg_perm.uidmsg_sinfo.msg_perm.uid=8;=8;msg_sinfo.msg_perm.gidmsg_sinfo.msg_perm.gid=8;=8;/此处验证超级用户可以更改消息队列的缺省此处验证超级用户可以更改消息队列的缺省msg_sinfo.msg_qbytesmsg_sinfo.msg_qbytes=16388; =16388; msg_qbytesmsg_qbytes / /注意这里设置的值大于缺省值注意这里设置的值大于缺省值 revalreval= =msgctl(msgid,IPC_SET,&msg_sinfomsgctl(msgid,IPC_SET,&msg_sinfo); ); 319消息队列系统调用示例消息队列系统调用示例if(revalif(reval=-1) =-1) printf(msgprintf(msg set info errorn); set info errorn); return; return; msg_stat(msgid,msg_ginfomsg_stat(msgid,msg_ginfo); /); /验证设置消息队列属性验证设置消息队列属性 revalreval= =msgctl(msgid,IPC_RMID,NULLmsgctl(msgid,IPC_RMID,NULL);/);/删除消息队列删除消息队列 if(revalif(reval=-1) =-1) printf(unlinkprintf(unlink msgmsg queue errorn); queue errorn); return; return; 320消息队列系统调用示例消息队列系统调用示例void void msg_stat(intmsg_stat(int msgid,structmsgid,struct msqid_dsmsqid_ds msg_infomsg_info) ) intint revalreval; sleep(1);/; sleep(1);/只是为了后面输出时间的方便只是为了后面输出时间的方便 revalreval= =msgctl(msgid,IPC_STAT,&msg_infomsgctl(msgid,IPC_STAT,&msg_info); ); if(revalif(reval=-1) =-1) printf(getprintf(get msgmsg info errorn); info errorn); return; return; printf(nprintf(n); ); printf(currentprintf(current number of bytes on queue is number of bytes on queue is % %dn,msg_info.msg_cbytesdn,msg_info.msg_cbytes); ); 321消息队列系统调用示例消息队列系统调用示例printf(numberprintf(number of messages in queue is of messages in queue is % %dn,msg_info.msg_qnumdn,msg_info.msg_qnum); ); /每个消息队列的容量(字节数)都有限制每个消息队列的容量(字节数)都有限制MSGMNB,值的大小因系统而异,值的大小因系统而异printf(maxprintf(max number of bytes on queue is number of bytes on queue is % %dn“,msg_info.msg_qbytesdn“,msg_info.msg_qbytes); ); printf(pidprintf(pid of last of last msgsndmsgsnd is % is %dn,msg_info.msg_lspiddn,msg_info.msg_lspid); ); printf(pidprintf(pid of last of last msgrcvmsgrcv is % is %dn,msg_info.msg_lrpiddn,msg_info.msg_lrpid); ); printf(lastprintf(last msgsndmsgsnd time is %s, time is %s, ctime(&(msg_info.msg_stimectime(&(msg_info.msg_stime); ); 322消息队列系统调用示例消息队列系统调用示例 printf(lastprintf(last msgrcvmsgrcv time is %s, time is %s, ctime(&(msg_info.msg_rtimectime(&(msg_info.msg_rtime););printf(lastprintf(last change time is %s, change time is %s, ctime(&(msg_info.msg_ctimectime(&(msg_info.msg_ctime); ); printf(msgprintf(msg uiduid is % is %dn,msg_info.msg_perm.uiddn,msg_info.msg_perm.uid); ); printf(msgprintf(msg gidgid is % is %dn,msg_info.msg_perm.giddn,msg_info.msg_perm.gid); ); 323系统调用系统调用-semget#include sys/#include #include sys/#include #include sys/#include intint semget(key_tsemget(key_t key, key, intint nsemsnsems, , intint semflgsemflg););说明:说明:semgetsemget()()用来取得用来取得keykey所关联的信号量的描述符。如果参数所关联的信号量的描述符。如果参数keykey 为为IPC_PRIVATEIPC_PRIVATE则会建立新的消息队列,参数则会建立新的消息队列,参数nsemsnsems指定打开或新指定打开或新 创建的信号量集中信号量的数目。如果创建的信号量集中信号量的数目。如果keykey不为不为IPC_PRIVATEIPC_PRIVATE也不也不 是已建立的信号量是已建立的信号量IPC keyIPC key,系统则会视参数,系统则会视参数msgflgmsgflg是否有是否有 IPC_CREATIPC_CREAT来决定建立来决定建立IPC keyIPC key为为keykey的消息队列。的消息队列。msgflgmsgflg也用来也用来 决定消息队列的存取权限相当于决定消息队列的存取权限相当于openopen的参数的参数modemode。返回值:成功返回信号量集描述符,否则返回返回值:成功返回信号量集描述符,否则返回-1-1。324系统调用系统调用-semget错误码:错误码:EACCES keyEACCES key指定的信号量集存在但无存取权限指定的信号量集存在但无存取权限 EEXIST keyEEXIST key所指的信号量集已存在所指的信号量集已存在 EIDRM keyEIDRM key所指的信号量集已删除所指的信号量集已删除 ENOENT keyENOENT key所指的信号量集不存在所指的信号量集不存在 ENOMEM ENOMEM 核心内存不足核心内存不足 ENOSPC ENOSPC 已超过系统允许的信号量集的最大值已超过系统允许的信号量集的最大值325系统调用系统调用-semop#include sys/#include #include sys/#include #include sys/#include intint semop(intsemop(int semidsemid, , structstruct sembufsembuf *sops, unsigned *sops, unsigned nsopsnsops););说明:说明:semidsemid是信号量集是信号量集IDID,sopssops指向数组的每一个指向数组的每一个sembufsembuf结构都刻画结构都刻画 一个在特定信号量上的操作。一个在特定信号量上的操作。nsopsnsops为为sopssops指向数组的大小。指向数组的大小。 参数参数sembufsembuf结构如下:结构如下: structstruct sembufsembuf unsigned short unsigned short sem_numsem_num;/*semaphore index in array*/ ;/*semaphore index in array*/ short short sem_opsem_op; /* semaphore operation */ ; /* semaphore operation */ short short sem_flgsem_flg; /* operation flags */ ; /* operation flags */ ; ; 326系统调用系统调用-semop sem_numsem_num对应信号集中的信号量,对应信号集中的信号量,0 0对应第一个信号量。对应第一个信号量。sem_flgsem_flg可取可取IPC_NOWAITIPC_NOWAIT以及以及SEM_UNDOSEM_UNDO两个标志。如果设置了两个标志。如果设置了SEM_UNDOSEM_UNDO标志,标志,那么在进程结束时,相应的操作将被取消,这是比较重要的一个标志那么在进程结束时,相应的操作将被取消,这是比较重要的一个标志位。如果设置了该标志位,那么在进程没有释放共享资源就退出时,位。如果设置了该标志位,那么在进程没有释放共享资源就退出时,内核将代为释放。如果为一个信号量设置了该标志,内核都要分配一内核将代为释放。如果为一个信号量设置了该标志,内核都要分配一个个sem_undosem_undo结构来记录它,为的是确保以后资源能够安全释放。事实结构来记录它,为的是确保以后资源能够安全释放。事实上,如果进程退出了,那么它所占用就释放了,但信号量值却没有改上,如果进程退出了,那么它所占用就释放了,但信号量值却没有改变,此时,信号量值反映的已经不是资源占有的实际情况,在这种情变,此时,信号量值反映的已经不是资源占有的实际情况,在这种情况下,问题的解决就靠内核来完成。这有点像僵尸进程,进程虽然退况下,问题的解决就靠内核来完成。这有点像僵尸进程,进程虽然退出了,资源也都释放了,但内核进程表中仍然有它的记录,此时就需出了,资源也都释放了,但内核进程表中仍然有它的记录,此时就需要父进程调用要父进程调用waitpidwaitpid来解决问题了。来解决问题了。327系统调用系统调用-semop sem_opsem_op的值大于的值大于0 0,此值会加至,此值会加至semvalsemval。等于。等于0 0,semopsemop会等到会等到semvalsemval降为降为0 0,除非,除非sem_flagsem_flag含有含有IPC_NOWAITIPC_NOWAIT。小于。小于0 0,如,如semvalsemval大于大于或等于或等于sem_opsem_op的绝对值,则的绝对值,则semvalsemval的值会减去的值会减去sem_opsem_op的绝对值,如的绝对值,如semvalsemval小于小于sem_opsem_op的绝对值且的绝对值且sem_flagsem_flag含有含有IPC_NOWAITIPC_NOWAIT,则返回错误。,则返回错误。 semopsemop同时操作多个信号量,对应多种资源的申请或释放。要么同时操作多个信号量,对应多种资源的申请或释放。要么一次性获得所有资源,要么放弃申请,要么在不占有任何资源情况下一次性获得所有资源,要么放弃申请,要么在不占有任何资源情况下继续等待,这样,一方面避免了资源的浪费;另一方面,避免了进程继续等待,这样,一方面避免了资源的浪费;另一方面,避免了进程之间由于申请共享资源造成死锁。之间由于申请共享资源造成死锁。 信号量的当前值记录相应资源目前可用数目;信号量的当前值记录相应资源目前可用数目;sem_opsem_op00对应进程对应进程要释放要释放sem_opsem_op数目的共享资源;数目的共享资源;sem_opsem_op=0=0用于对共享资源是否已用完用于对共享资源是否已用完的测试;的测试;sem_opsem_op00相当于进程要申请相当于进程要申请sem_opsem_op个共享资源。个共享资源。328系统调用系统调用-semop返回值:成功返回返回值:成功返回0 0,否则返回,否则返回-1-1。错误码:错误码:E2BIG E2BIG 参数参数nsopsnsops大于系统允许的最大值大于系统允许的最大值 EACCES EACCES 无存取权限无存取权限 EAGAIN EAGAIN 该调用无法马上处理该调用无法马上处理 EIDRM EIDRM 信号量队列已删除信号量队列已删除 EFAULT EFAULT 参数参数sopssops指向无效的内存地址指向无效的内存地址 EFBIG EFBIG 参数参数sem_numsem_num小于小于0 0或大于等于信号集合的数目或大于等于信号集合的数目 EINVAL EINVAL 已超过系统允许的信号量集的最大值已超过系统允许的信号量集的最大值 EINTR EINTR 此调用被信号所中断此调用被信号所中断329系统调用系统调用-semctl#include sys/#include #include sys/#include #include sys/#include intint semctl(intsemctl(int semidsemid,intint semnumsemnum,intint cmdcmd,union union semunsemun argarg););说明:该系统调用对由说明:该系统调用对由semidsemid标识的信号量集执行标识的信号量集执行cmdcmd操作,共有以下几操作,共有以下几 种种cmdcmd操作:操作: IPC_STATIPC_STAT:把信号量集的:把信号量集的semid_dssemid_ds数据复制到参数数据复制到参数arg.bufarg.buf; IPC_SETIPC_SET: 该命令用来设置信号量集的属性,要设置的属性存储该命令用来设置信号量集的属性,要设置的属性存储 在在arg.bufarg.buf中指向的中指向的semid_dssemid_ds结构中,包括:结构中,包括: sem_perm.uidsem_perm.uid、sem_perm.gidsem_perm.gid、sem_perm.modesem_perm.mode; 330系统调用系统调用-semctl IPC_RMIDIPC_RMID:删除:删除semidsemid标识的信号量集;标识的信号量集; GETALLGETALL:将信号量集所有的:将信号量集所有的semvalsemval值复制到参数值复制到参数arg.arryarg.arry GETNCNT GETNCNT:返回等待:返回等待semnumsemnum所代表信号灯的值增加的进程数,相所代表信号灯的值增加的进程数,相 当于目前有多少进程在等待当于目前有多少进程在等待semnumsemnum代表的信号灯所代代表的信号灯所代 表的共享资源;表的共享资源; GETPIDGETPID:返回最后一个对:返回最后一个对semnumsemnum所代表信号灯执行所代表信号灯执行semopsemop操作的操作的 进程进程IDID GETVAL GETVAL:返回参数:返回参数semnumsemnum指定信号量的指定信号量的semvalsemval值值 GETZCNTGETZCNT:返回等待:返回等待semnumsemnum所代表信号灯的值变成所代表信号灯的值变成0 0的进程数的进程数 SETALLSETALL:将信号量集所有的:将信号量集所有的semvalsemval值设置成参数值设置成参数arg.arryarg.arry SETVAL SETVAL:将参数:将参数semnumsemnum指定信号量的指定信号量的semvalsemval值设置成值设置成arg.valarg.val331系统调用系统调用-semctlunion union semunsemun intint valval; /* value for SETVAL */ ; /* value for SETVAL */ structstruct semid_dssemid_ds * *bufbuf; /* buffer for IPC_STAT & IPC_SET */ ; /* buffer for IPC_STAT & IPC_SET */ unsigned short *array; /* array for GETALL & SETALL */ unsigned short *array; /* array for GETALL & SETALL */ 、 structstruct seminfoseminfo *_ *_bufbuf; /* buffer for IPC_INFO */; /* buffer for IPC_INFO */ void *_pad; void *_pad; ; ; 332系统调用系统调用-semctlstructstruct semid_dssemid_ds structstruct kern_ipc_permkern_ipc_perm sem_permsem_perm; /* . see ; /* . see ipc.hipc.h */ */ time_ttime_t sem_otimesem_otime; /* last ; /* last semopsemop time */ time */ time_ttime_t sem_ctimesem_ctime; /* last change time */ ; /* last change time */ structstruct semsem * *sem_basesem_base; /*; /*ptrptr to first semaphore in array*/ to first semaphore in array*/ structstruct sem_queuesem_queue * *sem_pendingsem_pending; /* pending operations to be ; /* pending operations to be processed */ processed */ structstruct sem_queuesem_queue * *sem_pending_lastsem_pending_last; /* last pending ; /* last pending operation */ operation */ structstruct sem_undosem_undo *undo; /* undo requests on this array */ *undo; /* undo requests on this array */ unsigned short unsigned short intint sem_nsemssem_nsems; /* no. of semaphores in ; /* no. of semaphores in array */ array */ ; ; 333系统调用系统调用-semctlstructstruct sem_queuesem_queue structstruct sem_queuesem_queue * next; /* next entry in the queue */ * next; /* next entry in the queue */ structstruct sem_queuesem_queue * * prevprev; /* previous entry in the queue, ; /* previous entry in the queue, *(q- *(q-prevprev) = q */ ) = q */ structstruct task_structtask_struct* sleeper; /* this process */ * sleeper; /* this process */ structstruct sem_undosem_undo * undo; /* undo structure */ * undo; /* undo structure */ intint pidpid; /* process id of requesting process */ ; /* process id of requesting process */ intint status; /* completion status of operation */ status; /* completion status of operation */ structstruct sem_arraysem_array * * smasma;/*semaphore array for operations */ ;/*semaphore array for operations */ intint id; /* internal id; /* internal semsem id */ id */ structstruct sembufsembuf * sops; /* array of pending operations */ * sops; /* array of pending operations */ intint nsopsnsops; /* number of operations */ ; /* number of operations */ intint alter; /* operation will alter semaphore */ alter; /* operation will alter semaphore */ ; ; 334系统调用系统调用-semctlstructstruct seminfoseminfo intint semmapsemmap; ; intint semmnisemmni; ; intint semmnssemmns; ; intint semmnusemmnu; ; intint semmslsemmsl; ; intint semopmsemopm; ; intint semumesemume; ; intint semuszsemusz; ; intint semvmxsemvmx; ; intint semaemsemaem; ; ; ; 335信号量集系统调用示例信号量集系统调用示例#include #include #include #include #include #include #define SEM_PATH /#define SEM_PATH /unix/my_semunix/my_sem #define #define max_triesmax_tries 3 3 intint semidsemid; ; main() main() intint flag1,flag2,key,i,init_ok,tmperrno; flag1,flag2,key,i,init_ok,tmperrno; structstruct semid_dssemid_ds sem_infosem_info; ; structstruct seminfoseminfo sem_info2; sem_info2; union union semunsemun argarg; /union ; /union semunsemun336信号量集系统调用示例信号量集系统调用示例structstruct sembufsembuf askfor_resaskfor_res, , free_resfree_res; ; flag1=IPC_CREAT|IPC_EXCL|00666; flag1=IPC_CREAT|IPC_EXCL|00666; flag2=IPC_CREAT|00666; flag2=IPC_CREAT|00666; key=key=ftok(SEM_PATH,aftok(SEM_PATH,a); /error handling for ); /error handling for ftokftok here; here; init_okinit_ok=0; =0; / create a semaphore set that only includes one / create a semaphore set that only includes one semphoresemphore. . semidsemid=semget(key,1,flag1);=semget(key,1,flag1);if(semidif(semid0) 0) tmperrnotmperrno= =errnoerrno; ; perror(semgetperror(semget); ); 337信号量集系统调用示例信号量集系统调用示例if(tmperrnoif(tmperrno=EEXIST) =EEXIST) /flag2 /flag2 只包含了只包含了IPC_CREATIPC_CREAT标志标志, , /参数参数nsemsnsems( (这里为这里为1)1)必须与原来的信号灯数目一致必须与原来的信号灯数目一致 semidsemid=semget(key,1,flag2); =semget(key,1,flag2); arg.bufarg.buf=&=&sem_infosem_info; ; for(ifor(i=0; i=0; i-sem_otimesem_otime!=0) !=0) i=i=max_triesmax_tries; ; init_okinit_ok=1;=1; else else sleep(1); sleep(1); if(!init_okif(!init_ok) ) 339信号量集系统调用示例信号量集系统调用示例arg.valarg.val=1; =1; if(semctl(semid,0,SETVAL,arg)=-1) if(semctl(semid,0,SETVAL,arg)=-1) perror(semctlperror(semctl setvalsetval error); error); else else perror(semgetperror(semget error, process exit); error, process exit); exit(); exit(); else /else /semidsemid=0; do some initializing =0; do some initializing 340信号量集系统调用示例信号量集系统调用示例arg.valarg.val=1; =1; if(semctl(semid,0,SETVAL,arg)=-1) if(semctl(semid,0,SETVAL,arg)=-1) perror(semctlperror(semctl setvalsetval error); error); /get some information about the semaphore and the /get some information about the semaphore and the /limit of semaphore in redhat8.0 /limit of semaphore in redhat8.0 arg.bufarg.buf=&=&sem_infosem_info; ; if(semctl(semidif(semctl(semid, 0, IPC_STAT, , 0, IPC_STAT, argarg)=-1) )=-1) perror(semctlperror(semctl IPC STAT); IPC STAT); 341信号量集系统调用示例信号量集系统调用示例printf(ownersprintf(owners uiduid is % is %dndn, , arg.bufarg.buf-sem_perm.uidsem_perm.uid); ); printf(ownersprintf(owners gidgid is % is %dndn, , arg.bufarg.buf-sem_perm.gidsem_perm.gid); ); printf(creatersprintf(creaters uiduid is % is %dndn, , arg.bufarg.buf-sem_perm.cuidsem_perm.cuid); ); printf(creatersprintf(creaters gidgid is % is %dndn, , arg.bufarg.buf-sem_perm.cgidsem_perm.cgid););arg._bufarg._buf=&sem_info2; =&sem_info2; if(semctl(semid,0,IPC_INFO,arg)=-1) if(semctl(semid,0,IPC_INFO,arg)=-1) perror(semctlperror(semctl IPC_INFO); IPC_INFO); printf(theprintf(the number of entries in semaphore map is %d n, number of entries in semaphore map is %d n, arg._bufarg._buf-semmapsemmap); ); printf(maxprintf(max number of semaphore identifiers is %d n, number of semaphore identifiers is %d n, arg._bufarg._buf-semmnisemmni); ); 342信号量集系统调用示例信号量集系统调用示例printf(masprintf(mas number of semaphores in system is %d n, number of semaphores in system is %d n, arg._bufarg._buf-semmnssemmns); ); printf(theprintf(the number of undo structures system wide is %d n, number of undo structures system wide is %d n, arg._bufarg._buf-semmnusemmnu); ); printf(maxprintf(max number of semaphores per number of semaphores per semidsemid is %d n, is %d n, arg._bufarg._buf-semmslsemmsl); ); printf(maxprintf(max number of ops per number of ops per semopsemop call is %d n, call is %d n, arg._bufarg._buf-semopmsemopm); ); printf(maxprintf(max number of undo entries per process is %d n, number of undo entries per process is %d n, arg._bufarg._buf-semumesemume); ); printf(theprintf(the sizeofsizeof of of structstruct sem_undosem_undo is %d n, is %d n, arg._bufarg._buf- - semuszsemusz); ); 343信号量集系统调用示例信号量集系统调用示例printf(theprintf(the maximum semaphore value is %d n, maximum semaphore value is %d n, arg._bufarg._buf- - semvmxsemvmx); ); /now ask for available resource: /now ask for available resource: askfor_res.sem_numaskfor_res.sem_num=0; =0; askfor_res.sem_opaskfor_res.sem_op=-1; =-1; askfor_res.sem_flgaskfor_res.sem_flg=SEM_UNDO; =SEM_UNDO; if(semop(semid,&askfor_res,1)=-1)/ask for resource if(semop(semid,&askfor_res,1)=-1)/ask for resource perror(semopperror(semop error); error); sleep(3); /do some handling on the sharing resource heresleep(3); /do some handling on the sharing resource hereprintf(nowprintf(now free the resourcen); free the resourcen); 344信号量集系统调用示例信号量集系统调用示例/now free resource /now free resource free_res.sem_numfree_res.sem_num=0; =0; free_res.sem_opfree_res.sem_op=1; =1; free_res.sem_flgfree_res.sem_flg=SEM_UNDO; =SEM_UNDO; if(semop(semid,&free_res,1)=-1)/free the resource. if(semop(semid,&free_res,1)=-1)/free the resource. if(errnoif(errno=EIDRM) =EIDRM) printf(theprintf(the semaphore set was removedn); semaphore set was removedn); if(semctl(semidif(semctl(semid, 0, IPC_RMID)=-1) , 0, IPC_RMID)=-1) perror(semctlperror(semctl IPC_RMID); IPC_RMID); else else printf(removeprintf(remove semsem okn); okn); 345系统调用系统调用-shmget#include sys/#include #include sys/#include #include sys/#include intint shmget(key_tshmget(key_t key, key, intint size, size, intint shmflgshmflg) ;) ;说明:说明:shmgetshmget()()用来取得用来取得keykey所关联的共享内存的描述符。如果参数所关联的共享内存的描述符。如果参数keykey 为为IPC_PRIVATEIPC_PRIVATE则会建立新的共享内存,其大小由参数则会建立新的共享内存,其大小由参数sizesize决定决定 如果如果keykey不为不为IPC_PRIVATEIPC_PRIVATE也不是已建立的共享内存也不是已建立的共享内存IPC keyIPC key,系,系 统则会视参数统则会视参数shmflgshmflg是否有是否有IPC_CREATIPC_CREAT来决定建立来决定建立IPC keyIPC key为为keykey 的共享内存。的共享内存。shmflgshmflg也用来决定共享内存的存取权限相当于也用来决定共享内存的存取权限相当于openopen 的参数的参数modemode。返回值:成功返回共享内存描述符,否则返回返回值:成功返回共享内存描述符,否则返回-1-1。346系统调用系统调用-shmget错误码:错误码:EINVAL EINVAL 参数参数sizesize小于小于SHMMINSHMMIN或大于或大于SHMMAXSHMMAX EACCES key EACCES key指定的共享内存存在但无存取权限指定的共享内存存在但无存取权限 EEXIST keyEEXIST key所指的共享内存已存在所指的共享内存已存在 EIDRM keyEIDRM key所指的共享内存已删除所指的共享内存已删除 ENOENT keyENOENT key所指的共享内存不存在所指的共享内存不存在 ENOMEM ENOMEM 核心内存不足核心内存不足 ENOSPC ENOSPC 已超过系统允许的共享内存的最大值已超过系统允许的共享内存的最大值SHMALLSHMALL347系统调用系统调用-shmat#include sys/#include #include sys/#include #include sys/#include void *void *shmat(intshmat(int shmidshmid, const void , const void shmaddrshmaddr, , intint shmflgshmflg););说明:说明:shmatshmat()()用来将用来将shmidshmid所指的共享内存接入进程的虚地址空间。所指的共享内存接入进程的虚地址空间。 参数:参数:shmaddrshmaddr=0 =0 核心自动选择一个地址;核心自动选择一个地址; shmaddr0 shmaddr0 参数参数shmflgshmflg也不包含也不包含SHM_RNDSHM_RND标识,则共享内存接标识,则共享内存接 入入shmaddrshmaddr地址地址 shmaddr0 shmaddr0 参数参数shmflgshmflg包含包含SHM_RNDSHM_RND标识,则参数标识,则参数shmaddrshmaddr会自会自 动调整为动调整为SHMLBASHMLBA的整数倍;的整数倍; 返回值:成功返回连接好的虚地址,否则返回返回值:成功返回连接好的虚地址,否则返回-1-1。348系统调用系统调用-shmdt#include sys/#include #include sys/#include #include sys/#include intint shmdt(constshmdt(const void void shmaddrshmaddr););说明:说明:shmdtshmdt()()用来将连接到用来将连接到shmaddrshmaddr的共享内存与进程的虚地址空间的共享内存与进程的虚地址空间 断接。断接。 返回值:成功返回值:成功0 0,否则返回,否则返回-1-1。349系统调用系统调用-shmctl#include sys/#include #include sys/#include #include sys/#include intint shmctl(intshmctl(int shmidshmid, , intint cmdcmd, , structstruct shmid_dsshmid_ds * *bufbuf););说明:说明:shmctlshmctl系统调用对由系统调用对由shmidshmid标识的共享内存执行标识的共享内存执行cmdcmd操作,共有以操作,共有以 下几种下几种cmdcmd操作:操作: IPC_STATIPC_STAT:把共享内存的:把共享内存的shmid_dsshmid_ds数据复制到参数数据复制到参数bufbuf; IPC_SETIPC_SET: 该命令用来设置共享内存的属性,要设置的属性存储该命令用来设置共享内存的属性,要设置的属性存储 在在bufbuf中指向的中指向的shmid_dsshmid_ds结构中,包括:结构中,包括: shm_perm.uidshm_perm.uid、shm_perm.gidshm_perm.gid、shm_perm.modeshm_perm.mode;350系统调用系统调用-shmctl IPC_RMIDIPC_RMID:删除:删除shmidshmid标识的共享内存;标识的共享内存; SHM_LOCKSHM_LOCK:禁止共享内存兑换到:禁止共享内存兑换到swapswap,超级用户可用;,超级用户可用; SHM_UNLOCKSHM_UNLOCK:允许共享内存兑换到:允许共享内存兑换到swapswap,超级用户可用;,超级用户可用;351系统调用系统调用-shmctlstructstruct shmid_dsshmid_ds structstruct kern_ipc_permkern_ipc_perm sem_permsem_perm; /* . see ; /* . see ipc.hipc.h */ */ intint shm_segszshm_segsz; /* ; /* 共享内存大小共享内存大小 * */ / time_ttime_t shm_atimeshm_atime; /* ; /* 最后一次最后一次attachattach该共享内存的时间该共享内存的时间 * */ / time_ttime_t sem_dtimesem_dtime; /* ; /* 最后一次最后一次detachdetach该共享内存的时间该共享内存的时间 * */ / time_ttime_t sem_ctimesem_ctime; /* ; /* 最后一次更改该共享内存的时间最后一次更改该共享内存的时间 * */ / unsigned short unsigned short shm_cpidshm_cpid; /* ; /* 建立该共享内存的进程标识号建立该共享内存的进程标识号 * */ / unsigned short unsigned short shm_lpidshm_lpid; ; /* 最后操作该共享内存的进程标识号最后操作该共享内存的进程标识号 */ short short shm_nattchshm_nattch; ; unsigned short unsigned short shm_npagesshm_npages; ; unsigned long * unsigned long *shm_pagesshm_pages; ; structstruct shm_decsshm_decs *attaches; *attaches; ; 352共享内存系统调用示例共享内存系统调用示例#include #include #include sys/#include #include sys/#include #define KEY 1234 #define KEY 1234 #define SIZE 1024 #define SIZE 1024 main() main() intint shmidshmid; ; char *char *shmaddrshmaddr; ;structstruct shmid_dsshmid_ds bufbuf; ;353共享内存系统调用示例共享内存系统调用示例shmidshmid= =shmget(KEYshmget(KEY, SIZE, IPC_CREAT|0600); /* , SIZE, IPC_CREAT|0600); /* 建立共享内存建立共享内存 * */ / if(forkif(fork()=0)()=0)shmaddrshmaddr=(char *)=(char *)shmat(shmidshmat(shmid, NULL, 0);, NULL, 0);strcpy(shmaddrstrcpy(shmaddr, “Hi, I am child process!n”);, “Hi, I am child process!n”);shmdt(shmaddrshmdt(shmaddr););return;return; elseelse sleep(3);sleep(3);shmctl(shmidshmctl(shmid, IPC_STAT, &, IPC_STAT, &bufbuf););354共享内存系统调用示例共享内存系统调用示例printf(“shm_segszprintf(“shm_segsz = %d bytesn”, = %d bytesn”, buf.shm_segszbuf.shm_segsz););printf(“shm_cpidprintf(“shm_cpid = %d bytesn”, = %d bytesn”, buf.shm_cpidbuf.shm_cpid););printf(“shm_lpidprintf(“shm_lpid = %d bytesn”, = %d bytesn”, buf.shm_lpidbuf.shm_lpid););shmaddrshmaddr=(char *)=(char *)shmat(shmidshmat(shmid, NULL, 0);, NULL, 0);printf(“%sprintf(“%s”, ”, shmaddrshmaddr););shmdt(shmaddrshmdt(shmaddr););shmctl(shmidshmctl(shmid, IPC_RMID, NULL);, IPC_RMID, NULL); 355系统调用系统调用-mmap#include #include #include sys/#include void *void *mmap(voidmmap(void *start, *start, size_tsize_t length, length, intint protprot, , intint flags, flags, intint fdfd, , off_toff_t offsizeoffsize); ); 说明:说明:mmapmmap()()用来将某个文件内容映射到内存中,对该内存区域的存取用来将某个文件内容映射到内存中,对该内存区域的存取 即是直接对该文件内容的读写。参数即是直接对该文件内容的读写。参数startstart指向欲对应的内存起指向欲对应的内存起 始地址,通常设为始地址,通常设为NULLNULL,代表让系统自动选定地址,对应成功后,代表让系统自动选定地址,对应成功后 该地址会返回。参数该地址会返回。参数lengthlength代表将文件中多大的部分对应到内代表将文件中多大的部分对应到内 存。存。 356系统调用系统调用-mmap参数:参数:protprot代表映射区域的保护方式有下列组合代表映射区域的保护方式有下列组合 PROT_EXEC PROT_EXEC 映射区域可被执行映射区域可被执行 PROT_READ PROT_READ 映射区域可被读取映射区域可被读取 PROT_WRITE PROT_WRITE 映射区域可被写入映射区域可被写入 PROT_NONE PROT_NONE 映射区域不能存取映射区域不能存取 357系统调用系统调用-mmap参数:参数:flagsflags会影响映射区域的各种特性会影响映射区域的各种特性 MAP_FIXED MAP_FIXED 如果参数如果参数startstart所指的地址无法成功建立映射时,则所指的地址无法成功建立映射时,则 放弃映射,不对地址做修正。放弃映射,不对地址做修正。 MAP_SHARED MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许对映射区域的写入数据会复制回文件内,而且允许 其他映射该文件的进程共享。其他映射该文件的进程共享。 MAP_PRIVATE MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复对映射区域的写入操作会产生一个映射文件的复 制,即私人的制,即私人的“写入时复制写入时复制”(copy on writecopy on write)对对 此区域作的任何修改都不会写回原来的文件内容此区域作的任何修改都不会写回原来的文件内容 MAP_ANONYMOUS MAP_ANONYMOUS 建立匿名映射。此时会忽略参数建立匿名映射。此时会忽略参数fdfd,不涉及文,不涉及文 件,而且映射区域无法和其他进程共享。件,而且映射区域无法和其他进程共享。358系统调用系统调用-mmap参数:参数: MAP_DENYWRITE MAP_DENYWRITE 只允许对映射区域的写入操作,其他对文件直接只允许对映射区域的写入操作,其他对文件直接 写入的操作将会被拒绝。写入的操作将会被拒绝。 MAP_LOCKED MAP_LOCKED 将映射区域锁定住,这表示该区域不会被对换。将映射区域锁定住,这表示该区域不会被对换。 在调用在调用mmapmmap()()时必须要指定时必须要指定MAP_SHARED MAP_SHARED 或或MAP_PRIVATEMAP_PRIVATE。参数:参数:fdfd为为open()open()返回的文件描述词,代表欲映射到内存的文件。返回的文件描述词,代表欲映射到内存的文件。参数:参数:offsetoffset为文件映射的偏移量,通常设置为为文件映射的偏移量,通常设置为0 0,代表从文件最前方,代表从文件最前方 开始对应,开始对应,offsetoffset必须是分页大小的整数倍。必须是分页大小的整数倍。 返回值:若映射成功则返回映射区的内存起始地址,否则返回返回值:若映射成功则返回映射区的内存起始地址,否则返回 MAP_FAILED(MAP_FAILED(1)1),错误原因存于,错误原因存于errnoerrno 中。中。359系统调用系统调用-mmap错误码:错误码:EBADF EBADF 参数参数fdfd 不是有效的文件描述词不是有效的文件描述词 EACCES EACCES 存取权限有误。如果是存取权限有误。如果是MAP_PRIVATE MAP_PRIVATE 情况下文件必须可情况下文件必须可 读,使用读,使用MAP_SHAREDMAP_SHARED则要有则要有PROT_WRITEPROT_WRITE以及该文件要以及该文件要 能写入。能写入。 EINVAL EINVAL 参数参数startstart、length length 或或offsetoffset有一个不合法。有一个不合法。 EAGAIN EAGAIN 文件被锁住,或是有太多内存被锁住。文件被锁住,或是有太多内存被锁住。 ENOMEM ENOMEM 内存不足。内存不足。 EINVAL EINVAL 参数参数sizesize小于小于SHMMINSHMMIN或大于或大于SHMMAXSHMMAX360系统调用系统调用-munmap#include #include #include sys/#include intint munmap(voidmunmap(void *start, *start, size_tsize_t length); length); 说明:说明:munmapmunmap()()用来取消参数用来取消参数startstart所指的映射内存起始地址,参数所指的映射内存起始地址,参数 lengthlength则是欲取消的内存大小。当进程结束或利用则是欲取消的内存大小。当进程结束或利用execexec相关函数相关函数 来执行其他程序时,映射内存会自动解除,但关闭对应的文件描来执行其他程序时,映射内存会自动解除,但关闭对应的文件描 述符时不会解除映射。述符时不会解除映射。返回值:如果解除映射成功则返回返回值:如果解除映射成功则返回0 0,否则返回,否则返回1 1。错误码:错误码:EINVAL EINVAL 参数参数 startstart或或length length 不合法。不合法。361内存映射系统调用示例内存映射系统调用示例#includesys/#include #includesys/#include #include#include #include#include #includesys/#include main()main() intint fdfd; ;void *start;void *start;structstruct stat stat sbsb; ;fdfd=open(“/etc/=open(“/etc/passwd”,O_RDONLYpasswd”,O_RDONLY); /*); /*打开打开/etc/etc/passwdpasswd*/*/362内存映射系统调用示例内存映射系统调用示例fstat(fd,&sbfstat(fd,&sb); /*); /*取得文件大小取得文件大小* */ /start=mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fd,0);start=mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fd,0);if(startif(start= = MAP_FAILED) /*= = MAP_FAILED) /*判断是否映射成功判断是否映射成功* */ /return;return;printf(“%s”,startprintf(“%s”,start););munma(start,sb.st_sizemunma(start,sb.st_size); /*); /*解除映射解除映射* */ /closed(fdclosed(fd);); 363设备驱动程序设备驱动程序 设备驱动程序是操作系统内核代码的一部分,设备驱动程序是操作系统内核代码的一部分,位于系统调用与物理设备之间,为操作系统访问位于系统调用与物理设备之间,为操作系统访问设备提供一致的、抽象的接口,屏蔽具体物理设设备提供一致的、抽象的接口,屏蔽具体物理设备的操作细节,根据操作系统的要求完成系统与备的操作细节,根据操作系统的要求完成系统与物理设备之间的数据传输。物理设备之间的数据传输。364设备驱动程序的特点设备驱动程序的特点运行于系统核心地址空间运行于系统核心地址空间可被多个进程共享可被多个进程共享为请求提供服务为请求提供服务与操作系统其他部分配合完成系统调用与操作系统其他部分配合完成系统调用设备驱动程序错误会引起系统瘫痪设备驱动程序错误会引起系统瘫痪365内核功能模块的划分内核功能模块的划分进程管理进程管理 内核负责创建和终止进程,并且处理它们和内核负责创建和终止进程,并且处理它们和外部世界的联系(输入和输出)。对整个系统功外部世界的联系(输入和输出)。对整个系统功能来讲,不同进程之间的通信(通过信号,管道,能来讲,不同进程之间的通信(通过信号,管道,进程间通信原语)是基本的,这也是由内核来处进程间通信原语)是基本的,这也是由内核来处理的。另外,调度器,可能是整个操作系统中最理的。另外,调度器,可能是整个操作系统中最关键的例程,是进程管理中的一部分。更广广义关键的例程,是进程管理中的一部分。更广广义的说,内核的进程管理活动实现了在一个的说,内核的进程管理活动实现了在一个CPUCPU上多上多个进程的抽象概念。个进程的抽象概念。366内核功能模块的划分内核功能模块的划分内存管理内存管理 计算机内存是主要资源,而使用内存的策略计算机内存是主要资源,而使用内存的策略是影响整个系统性能的关键。内核为每个进程在是影响整个系统性能的关键。内核为每个进程在有限可利用的资源上建立了虚拟地址空间。内核有限可利用的资源上建立了虚拟地址空间。内核不同部分通过一组函数与内存管理子系统交互,不同部分通过一组函数与内存管理子系统交互,这些包括从简单的这些包括从简单的mallocmalloc/free/free到更稀奇古怪的功到更稀奇古怪的功能。能。367内核功能模块的划分内核功能模块的划分文件系统文件系统 UnixUnix系统是建立在文件系统这个概念上的;系统是建立在文件系统这个概念上的;UnixUnix里几乎所有东西都可以看作文件。内核在非里几乎所有东西都可以看作文件。内核在非结构的硬件上建立了结构化的文件系统,这个抽结构的硬件上建立了结构化的文件系统,这个抽象的文件被系统广泛应用。另外,象的文件被系统广泛应用。另外,LinuxLinux支持多文支持多文件系统类型,即,物理介质上对数据的不同组织件系统类型,即,物理介质上对数据的不同组织方法。方法。 368内核功能模块的划分内核功能模块的划分设备控制设备控制 几乎每种系统操作最后都要映射到物理设备几乎每种系统操作最后都要映射到物理设备上。除了处理器,内存和少数其他实体外,几乎上。除了处理器,内存和少数其他实体外,几乎所有设备的控制操作都由设备相关的代码来实现。所有设备的控制操作都由设备相关的代码来实现。这些代码就是设备驱动程序。内核必须为每个外这些代码就是设备驱动程序。内核必须为每个外部设备嵌入设备驱动程序,从硬盘驱动器到键盘部设备嵌入设备驱动程序,从硬盘驱动器到键盘和磁带。内核的这方面功能就是本书的着眼点。和磁带。内核的这方面功能就是本书的着眼点。369内核功能模块的划分内核功能模块的划分网络网络 网络必须由操作系统来管理,由于大多数网网络必须由操作系统来管理,由于大多数网络操作不是针对于进程的:接收数据包是异步事络操作不是针对于进程的:接收数据包是异步事件。数据包必须在进程处理它们以前就被收集,件。数据包必须在进程处理它们以前就被收集,确认和分发。系统通过程序和网络接口发送数据确认和分发。系统通过程序和网络接口发送数据包,并且应该可以正确地让程序睡眠,并唤醒等包,并且应该可以正确地让程序睡眠,并唤醒等待网络数据的进程。另外,所有路由和地址解析待网络数据的进程。另外,所有路由和地址解析问题是在内核里实现的。问题是在内核里实现的。370设备驱动程序与其他部分的关系设备驱动程序与其他部分的关系371设备驱动程序的分类设备驱动程序的分类字符设备字符设备 可以象文件一样访问字符设备,字符设备驱可以象文件一样访问字符设备,字符设备驱动程序通常会实现动程序通常会实现openopen,closeclose,readread和和writewrite系系统调用。系统控制台和并口就是字符设备的例子,统调用。系统控制台和并口就是字符设备的例子,它们可以很好地用流概念描述。通过文件系统节它们可以很好地用流概念描述。通过文件系统节点可以访问字符设备,例如点可以访问字符设备,例如/dev/tty1/dev/tty1和和/dev/lp1/dev/lp1。在字符设备和普通文件系统间的唯一区别是:普在字符设备和普通文件系统间的唯一区别是:普通文件允许在其上来回读写,而大多数字符设备通文件允许在其上来回读写,而大多数字符设备仅仅是数据通道,只能顺序读写。当然,也存在仅仅是数据通道,只能顺序读写。当然,也存在这样的字符设备,看起来象个数据区,可以来回这样的字符设备,看起来象个数据区,可以来回读取其中的数据。读取其中的数据。 372设备驱动程序的分类设备驱动程序的分类块设备块设备 块设备是文件系统的宿主,如磁盘。以块为块设备是文件系统的宿主,如磁盘。以块为单位进行访问,一个块通常是单位进行访问,一个块通常是1K1K字节数据。块设字节数据。块设备和字符设备只在内核内部的管理上有所区别,备和字符设备只在内核内部的管理上有所区别,也就是在内核也就是在内核/ /驱动程序间的软件接口上有所区别。驱动程序间的软件接口上有所区别。每个块设备也通过文件系统节点来读写数据,它每个块设备也通过文件系统节点来读写数据,它们之间的不同对用户来说是透明的。块设备驱动们之间的不同对用户来说是透明的。块设备驱动程序和内核的接口和字符设备驱动程序的接口是程序和内核的接口和字符设备驱动程序的接口是一样的,它也通过一个传统的面向块的接口与内一样的,它也通过一个传统的面向块的接口与内核通信,但这个接口对用户来说时不可见的。核通信,但这个接口对用户来说时不可见的。373设备驱动程序的分类设备驱动程序的分类网络设备网络设备 任何网络事务处理都是通过网络接口实现的,通常,接口是一个硬任何网络事务处理都是通过网络接口实现的,通常,接口是一个硬件设备,但也可以象件设备,但也可以象loopbackloopback(回路)接口一样是软件工具。网络接(回路)接口一样是软件工具。网络接口是由内核网络子系统驱动的,它负责发送和接收数据包,而且无需口是由内核网络子系统驱动的,它负责发送和接收数据包,而且无需了解每次事务是如何映射到实际被发送的数据包。尽管了解每次事务是如何映射到实际被发送的数据包。尽管“telnet”telnet”和和“ftp”ftp”连接都是面向流的,它们使用同样的设备进行传输;但设备连接都是面向流的,它们使用同样的设备进行传输;但设备并没有看到任何流,仅看到数据报。由于不是面向流的设备,所以网并没有看到任何流,仅看到数据报。由于不是面向流的设备,所以网络接口不能象络接口不能象/dev/tty1/dev/tty1那样简单地映射到文件系统的节点上。那样简单地映射到文件系统的节点上。UnixUnix调用这些接口的方式是给它们分配一个独立的名字(如调用这些接口的方式是给它们分配一个独立的名字(如eth0eth0)。这样)。这样的名字在文件系统中并没有对应项。内核和网络设备驱动程序之间的的名字在文件系统中并没有对应项。内核和网络设备驱动程序之间的通信与字符设备驱动程序和块设备驱动程序与内核间的通信是完全不通信与字符设备驱动程序和块设备驱动程序与内核间的通信是完全不一样的。内核不再调用一样的。内核不再调用readread,writewrite,它调用与数据包传送相关的函,它调用与数据包传送相关的函数。数。374设备驱动程序的特点设备驱动程序的特点运行于系统核心地址空间运行于系统核心地址空间可被多个进程共享可被多个进程共享为请求提供服务为请求提供服务与操作系统其他部分配合完成系统调用与操作系统其他部分配合完成系统调用设备驱动程序错误会引起系统瘫痪设备驱动程序错误会引起系统瘫痪375设备驱动程序的注意事项设备驱动程序的注意事项只能使用核心提供的功能函数只能使用核心提供的功能函数代码应为可重入的代码应为可重入的提供机制(提供机制(mechanismmechanism),不实现策略(),不实现策略(policypolicy)不影响系统安全不影响系统安全376设备驱动程序的相关概念设备驱动程序的相关概念主设备号与次设备号主设备号与次设备号 系统使用主设备号和次设备号标识一个设备,系统使用主设备号和次设备号标识一个设备,一般主设备号用于标识设备驱动程序,次设备号一般主设备号用于标识设备驱动程序,次设备号用于标识同一个设备驱动程序管理的不同设备。用于标识同一个设备驱动程序管理的不同设备。377设备驱动程序的相关概念设备驱动程序的相关概念 核心用定义于核心用定义于 中的类型中的类型dev_tdev_t 表示设备号,为一个表示设备号,为一个3232位整数,位整数,1212位用于位用于主设备号,其余主设备号,其余2020位用于次设备号。核心使用定位用于次设备号。核心使用定义于义于 中的宏对设备号进行访问中的宏对设备号进行访问: : MAJOR(dev_tMAJOR(dev_t dev); dev); MINOR(dev_tMINOR(dev_t dev); dev); MKDEV(intMKDEV(int major, major, intint minor); minor);378设备驱动程序的相关概念设备驱动程序的相关概念设备文件设备文件 块设备和字符设备被组织到文件系统中,通块设备和字符设备被组织到文件系统中,通过文件系统调用进行访问。每一个设备由一个设过文件系统调用进行访问。每一个设备由一个设备文件表示,设备文件存储设备的主设备号和次备文件表示,设备文件存储设备的主设备号和次设备号,访问权限等等。设备号,访问权限等等。379设备驱动程序的相关概念设备驱动程序的相关概念380设备驱动程序的相关概念设备驱动程序的相关概念模块(模块(modulemodule) 模块是可以运行时被加载到内核的功能模块,模块是可以运行时被加载到内核的功能模块,加载后模块作为内核功能的一部分运行于核心态,加载后模块作为内核功能的一部分运行于核心态,模块在不使用的时候,可以被动态地从核心卸载。模块在不使用的时候,可以被动态地从核心卸载。模块一般实现为共享库。模块一般实现为共享库。381设备驱动程序的相关概念设备驱动程序的相关概念模块的装载模块的装载 模块的装载使用命令模块的装载使用命令insmodinsmod或或modprobemodprobe,insmodinsmod装载一个模块,装载一个模块,modprobemodprobe装载有依赖关系装载有依赖关系的所有模块。的所有模块。insmodinsmod和和modprobemodprobe使用系统调用使用系统调用sys_init_modulesys_init_module完成模块的装载。完成模块的装载。 系统调用系统调用sys_init_modulesys_init_module首先为模块分配系首先为模块分配系统内存,然后将模块正文拷贝进核心内存,接下统内存,然后将模块正文拷贝进核心内存,接下来进行符号解析,最后调用模块的初始化函数。来进行符号解析,最后调用模块的初始化函数。382设备驱动程序的相关概念设备驱动程序的相关概念#include #include #include #include MODULE_LICENSE(DualMODULE_LICENSE(Dual BSD/GPL); BSD/GPL);static static intint hello_init(voidhello_init(void) ) printk(KERN_ALERTprintk(KERN_ALERT Hello, worldn); Hello, worldn);return 0;return 0; 383设备驱动程序的相关概念设备驱动程序的相关概念static void static void hello_exit(voidhello_exit(void) ) printk(KERN_ALERTprintk(KERN_ALERT Goodbye, cruel worldn); Goodbye, cruel worldn); module_init(hello_initmodule_init(hello_init););module_exit(hello_exitmodule_exit(hello_exit););384设备驱动程序的相关概念设备驱动程序的相关概念加载模块命令:加载模块命令:insmodinsmod ./ ./hello.kohello.ko卸载模块命令:卸载模块命令:rmmodrmmod hello hello385设备驱动程序的相关概念设备驱动程序的相关概念内核符号表内核符号表 为支持模块的动态加载与卸载核心维护一个为支持模块的动态加载与卸载核心维护一个内核符号表,内核符号表记录所有核心导出的符内核符号表,内核符号表记录所有核心导出的符号(函数和全局变量)及其地址。号(函数和全局变量)及其地址。386设备驱动程序的相关概念设备驱动程序的相关概念内核符号表内核符号表 为支持模块的动态加载与卸载核心维护一个为支持模块的动态加载与卸载核心维护一个内核符号表,内核符号表记录所有核心导出的符内核符号表,内核符号表记录所有核心导出的符号(函数和全局变量)及其地址。被装载的模块号(函数和全局变量)及其地址。被装载的模块也可以将自身的全局变量输出到核心符号表中,也可以将自身的全局变量输出到核心符号表中,但要注意符号污染问题。但要注意符号污染问题。 EXPORT_SYMBOL(nameEXPORT_SYMBOL(name);); EXPORT_SYMBOL_GPL(nameEXPORT_SYMBOL_GPL(name););387设备驱动程序的相关概念设备驱动程序的相关概念用户空间与核心空间用户空间与核心空间 核心需要在核心地址空间和用户空间交换数核心需要在核心地址空间和用户空间交换数据,核心代码使用用户空间的地址要做仔细的检据,核心代码使用用户空间的地址要做仔细的检查。查。388设备驱动程序的相关概念设备驱动程序的相关概念访问用户地址空间:访问用户地址空间:unsigned long unsigned long copy_to_user(voidcopy_to_user(void _user *to, _user *to, const void * const void *from,unsignedfrom,unsigned long count); long count);unsigned long unsigned long copy_from_user(voidcopy_from_user(void *to, *to, const void _user * const void _user *from,unsignedfrom,unsigned long long count); count);389设备驱动程序的相关概念设备驱动程序的相关概念 分配核心内存:分配核心内存: void *void *kmalloc(size_tkmalloc(size_t size, size, intint flags); flags); void void kfree(voidkfree(void * *ptrptr););390设备驱动程序的相关概念设备驱动程序的相关概念当前进程当前进程 驱动程序有时需要访问当前进程的信息。当驱动程序有时需要访问当前进程的信息。当前进程是正在执行系统调用的进程。前进程是正在执行系统调用的进程。391设备驱动程序的相关概念设备驱动程序的相关概念 对当前进程的访问可以通过对当前进程的访问可以通过currentcurrent指针。指针。currentcurrent指向指向 structstruct task_structtask_struct结构。结构。#include #include #include #include printk(KERN_INFOprintk(KERN_INFO “The process is ”%s“ ( “The process is ”%s“ (pidpid % %i)ni)n, current- current-commcomm, current-, current-pidpid););392设备驱动程序的相关概念设备驱动程序的相关概念核心栈核心栈 模块与操作系统核心共享核心栈,核心栈较模块与操作系统核心共享核心栈,核心栈较小,一般为一个页面大小,因此不要在模块中使小,一般为一个页面大小,因此不要在模块中使用大的临时变量。用大的临时变量。393设备驱动程序的相关概念设备驱动程序的相关概念初始化函数初始化函数 初始化函数在模块被加载的时候调用,调用初始化函数在模块被加载的时候调用,调用完以后所占用的空间被系统释放,因此不要在模完以后所占用的空间被系统释放,因此不要在模块中调用初始化函数。块中调用初始化函数。394设备驱动程序的相关概念设备驱动程序的相关概念static static intint _init _init initialization_function(voidinitialization_function(void) ) /* Initialization code here */* Initialization code here */ module_init(initialization_functionmodule_init(initialization_function););395设备驱动程序的相关概念设备驱动程序的相关概念清除函数清除函数 清除函数在模块被删除的时候调用,主要用清除函数在模块被删除的时候调用,主要用于释放模块申请的系统资源。于释放模块申请的系统资源。396设备驱动程序的相关概念设备驱动程序的相关概念static void _exit static void _exit cleanup_function(voidcleanup_function(void) ) /* Cleanup code here */* Cleanup code here */ module_exit(cleanup_functionmodule_exit(cleanup_function););397设备驱动程序的相关概念设备驱动程序的相关概念模块参数模块参数 模块经常需要一些入口参数指明模块应如何模块经常需要一些入口参数指明模块应如何动作。动作。linuxlinux支持模块定义在被加载时要接收的参支持模块定义在被加载时要接收的参数。数。注:模块和模块参数信息将被记录在文件注:模块和模块参数信息将被记录在文件 /proc/modules/proc/modules和文件和文件/sys/module/sys/module中中398设备驱动程序的相关概念设备驱动程序的相关概念static char *whom = world;static char *whom = world;static static intint howmanyhowmany = 10; = 10;module_param(howmanymodule_param(howmany, , intint, S_IRUGO);, S_IRUGO);module_param(whommodule_param(whom, , charpcharp, S_IRUGO);, S_IRUGO);命令行:命令行:insmodinsmod hellophellop howmanyhowmany=10 whom=Mom=10 whom=Mom399设备驱动程序的相关概念设备驱动程序的相关概念支持的模块参数类型:支持的模块参数类型:boolboolintintlonglongshortshortuintuintulongulongushortushortcharpcharp400设备驱动程序的相关概念设备驱动程序的相关概念模块装载的竞争条件模块装载的竞争条件 模块一旦被注册则立即可被系统访问,有可模块一旦被注册则立即可被系统访问,有可能出现初始化过程尚未结束时候,系统引用已经能出现初始化过程尚未结束时候,系统引用已经被注册的部分。被注册的部分。 初始化失败的时候,系统可能已经引用了被初始化失败的时候,系统可能已经引用了被注册的功能。注册的功能。401主设备号的分配和释放主设备号的分配和释放 建立设备驱动程序首先需要为设备分配一个建立设备驱动程序首先需要为设备分配一个主设备号。主设备号。linuxlinux提供用户指定和动态分配两种方提供用户指定和动态分配两种方式来分配主设备号。式来分配主设备号。402主设备号的分配和释放主设备号的分配和释放静态分配使用如下函数:静态分配使用如下函数: #include #include intint register_chrdev_region(dev_tregister_chrdev_region(dev_t first, first, unsigned unsigned intint count, count, char *name); char *name);first first 为申请分配的连续设备号的起始设备号为申请分配的连续设备号的起始设备号count count 为申请分配的设备号数量为申请分配的设备号数量name name 为与设备号相关联的设备名为与设备号相关联的设备名注:设备名将被记录在文件注:设备名将被记录在文件/proc/devices/proc/devices文件中文件中403主设备号的分配和释放主设备号的分配和释放动态分配使用如下函数:动态分配使用如下函数: #include #include intint alloc_chrdev_region(dev_talloc_chrdev_region(dev_t *dev, *dev, unsigned unsigned intint firstminorfirstminor, , unsigned unsigned intint count, count, char *name); char *name);dev dev 保存被分配的第一个主设备号保存被分配的第一个主设备号firstminorfirstminor 为申请的次设备号,通常为为申请的次设备号,通常为0 0404主设备号的分配和释放主设备号的分配和释放 如果不在使用一个设备号的时候,需要将设备号释放。如果不在使用一个设备号的时候,需要将设备号释放。设备号的释放使用如下函数:设备号的释放使用如下函数: #include #include void void unregister_chrdev_region(dev_tunregister_chrdev_region(dev_t first, first, unsigned unsigned intint count); count);405用动态分配的主设备号创建设备用动态分配的主设备号创建设备 动态分配的主设设备号无法用来预先创建设备文件,因动态分配的主设设备号无法用来预先创建设备文件,因此为动态分配主设备号的设备创建文件需要用文件此为动态分配主设备号的设备创建文件需要用文件/proc/proc/devicesdevices。/proc/devices/proc/devices文件内容如下:文件内容如下: Character devices:Character devices:1 1 memmem2 2 ptypty3 3 ttypttypBlock devices:Block devices:2 2 fdfd8 8 sdsd11 11 srsr406用动态分配的主设备号创建设备用动态分配的主设备号创建设备 为动态分配设备号的设备创建文件,需要使用脚本文件为动态分配设备号的设备创建文件,需要使用脚本文件在在insmodinsmod模块后,使用模块后,使用/proc/devices/proc/devices的设备号创建文件。的设备号创建文件。 #!/bin/#!/bin/shshmodule=scullmodule=sculldevice=sculldevice=scullmode=664mode=664/ /sbin/insmodsbin/insmod ./$ ./$module.komodule.ko $* | exit 1 $* | exit 1rmrm -f /dev/$device0-3 -f /dev/$device0-3407用动态分配的主设备号创建设备用动态分配的主设备号创建设备major=$(major=$(awkawk $2= =$module print $1 $2= =$module print $1 /proc/devices) /proc/devices)mknodmknod /dev/$device0 c $major 0 /dev/$device0 c $major 0mknodmknod /dev/$device1 c $major 1 /dev/$device1 c $major 1mknodmknod /dev/$device2 c $major 2 /dev/$device2 c $major 2mknodmknod /dev/$device3 c $major 3 /dev/$device3 c $major 3group=staffgroup=staffgrepgrep -q staff: /etc/group | group=wheel -q staff: /etc/group | group=wheelchgrpchgrp $group /dev/$device0-3 $group /dev/$device0-3chmodchmod $mode /dev/$device0-3 $mode /dev/$device0-3408灵活地创建设备灵活地创建设备 创建设备的较为理想的方法是缺省使用动态分配的设备创建设备的较为理想的方法是缺省使用动态分配的设备号,保留指定设备号的能力。号,保留指定设备号的能力。409灵活地创建设备灵活地创建设备if (if (scull_majorscull_major) ) dev = dev = MKDEV(scull_majorMKDEV(scull_major, , scull_minorscull_minor););result = result = register_chrdev_region(devregister_chrdev_region(dev, , scull_nr_devsscull_nr_devs, scull);, scull); else else result = result = alloc_chrdev_region(&devalloc_chrdev_region(&dev, , scull_minorscull_minor, , scull_nr_devsscull_nr_devs, scull);, scull);scull_majorscull_major = = MAJOR(devMAJOR(dev);); if (result 0) if (result ops = &-ops = &my_fopsmy_fops; ; void void cdev_init(structcdev_init(struct cdevcdev * *cdevcdev, , structstruct file_operationsfile_operations *fops); *fops); intint cdev_add(structcdev_add(struct cdevcdev *dev, *dev, dev_tdev_t num, unsigned num, unsigned intint count); count); void void cdev_del(structcdev_del(struct cdevcdev *dev); *dev);421字符设备驱动程序字符设备驱动程序-scullstructstruct scull_devscull_dev structstruct scull_qsetscull_qset *data; /* Pointer to first quantum *data; /* Pointer to first quantum set */ set */intint quantum; /* the current quantum size */ quantum; /* the current quantum size */intint qsetqset; /* the current array size */; /* the current array size */unsigned long size; /* amount of data stored here */unsigned long size; /* amount of data stored here */unsigned unsigned intint access_keyaccess_key; /* used by ; /* used by sculluidsculluid and and scullprivscullpriv */ */structstruct semaphore semaphore semsem; /* mutual exclusion semaphore */; /* mutual exclusion semaphore */structstruct cdevcdev cdevcdev; /* Char device structure */; /* Char device structure */;422字符设备驱动程序字符设备驱动程序-scullstatic void static void scull_setup_cdev(structscull_setup_cdev(struct scull_devscull_dev *dev, *dev, intint index) index) intint err, err, devnodevno = = MKDEV(scull_majorMKDEV(scull_major, , scull_minorscull_minor + index); + index);cdev_init(&devcdev_init(&dev-cdevcdev, &, &scull_fopsscull_fops););dev-dev-cdev.ownercdev.owner = THIS_MODULE; = THIS_MODULE;dev-dev-cdev.opscdev.ops = & = &scull_fopsscull_fops; ;err = err = cdev_addcdev_add (&dev- (&dev-cdevcdev, , devnodevno, 1);, 1);/* Fail gracefully if need be */* Fail gracefully if need be */if (err)if (err)printk(KERN_NOTICEprintk(KERN_NOTICE Error %d adding Error %d adding scull%dscull%d, , err, index); err, index); 423字符设备驱动程序字符设备驱动程序-scullcontainer_of(pointercontainer_of(pointer, , container_typecontainer_type, , container_fieldcontainer_field););structstruct scull_devscull_dev *dev; /* device information */ *dev; /* device information */dev = dev = container_of(inodecontainer_of(inode-i_cdevi_cdev, , structstruct scull_devscull_dev, , cdevcdev););filpfilp-private_dataprivate_data = dev; /* for other methods */ = dev; /* for other methods */424字符设备驱动程序字符设备驱动程序-scullintint scull_open(structscull_open(struct inodeinode * *inodeinode, , structstruct file * file *filpfilp) ) structstruct scull_devscull_dev *dev; /* device information */ *dev; /* device information */ dev = dev = container_of(inodecontainer_of(inode-i_cdevi_cdev, , structstruct scull_devscull_dev, , cdevcdev);); filpfilp-private_dataprivate_data = dev; /* for other methods */ = dev; /* for other methods */ /* now trim to 0 the length of the device if open was /* now trim to 0 the length of the device if open was write-only */ write-only */ if ( ( if ( (filpfilp-f_flagsf_flags & O_ACCMODE) = = O_WRONLY) & O_ACCMODE) = = O_WRONLY) scull_trim(devscull_trim(dev); /* ignore errors */); /* ignore errors */ return 0; /* success */ return 0; /* success */ 425字符设备驱动程序字符设备驱动程序-scullintint scull_trim(structscull_trim(struct scull_devscull_dev *dev) *dev) structstruct scull_qsetscull_qset *next, * *next, *dptrdptr; ; intint qsetqset = dev- = dev-qsetqset; /* dev is not-null */; /* dev is not-null */ intint i; i; for ( for (dptrdptr = dev-data; = dev-data; dptrdptr; ; dptrdptr = next) = next) if ( if (dptrdptr-data) -data) for (i = 0; i for (i = 0; i -dataidatai);); kfree(dptrkfree(dptr-data);-data); dptrdptr-data = NULL;-data = NULL; 426字符设备驱动程序字符设备驱动程序-scull next = next = dptrdptr-next;-next; kfree(dptrkfree(dptr);); dev-size = 0; dev-size = 0; dev-quantum = dev-quantum = scull_quantumscull_quantum; ; dev- dev-qsetqset = = scull_qsetscull_qset; ; dev-data = NULL; dev-data = NULL; return 0; return 0; 427字符设备驱动程序字符设备驱动程序-scullintint scull_release(structscull_release(struct inodeinode * *inodeinode, , structstruct file * file *filpfilp) ) return 0; return 0; 428
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号