开发Linux命令行实用程序[5]

[入库:2005年9月19日] [更新:2007年3月24日]

本文简介:

  通过不带参数地运行该实用程序,您可以将它用作了解不同错误消息是什么的工具。在有些情况下,它还可作为有用的调试工具使用:有些 Linux(至少是 UNIX)实用程序(甚至是守护程序)不显示错误消息,而只显示 errno 值。在这种情况下,只要使用那个 errno 值运行 showsyserr,它就会向您显示相应的错误消息。我已经在解决 UNIX 问题时使用了这个工具,在那些问题中控制台上会有持续的消息流,并且是“Panic - error 2”之类的消息。该消息源明显是编写得不好的模块 — 它本该给出更有意义的消息 — 但我能够通过以值 2 为参数运行 showsyserr 来调试它。结果表明:由于一个无赖进程不断写磁盘,文件系统已经满了。
  
  一旦我知道是磁盘空间问题,我就能够识别这个进程并用其它命令(如 ps 和 kill)将它杀掉。
  
  process_args() 函数
  因为这是打算用于通用目的而不是只被一小群人使用的实用程序,所以我们进行大量的错误检查以使它尽可能的健壮。
  
  以注释“==== check the command-line arguments ===”开始的行
  我们检查是否传递了最小数目(三)的命令行参数。这三个参数是:
  
  命令名本身
  -sNumber 选项
  -eNumber 选项
  如果少于三个参数,则打印消息并退出。请注意对 usage() 函数的调用;这让用户知道调用实用程序的正确方法。这是编写通用实用程序时应该遵守的又一个约定。
  
  以注释“handle 1st arg”开始的行
  注释“!!! PBO”用来指出可能的缓冲区溢出(Possible Buffer Overflow),不论是在 Linux 或任何其它平台上,这是在 C 程序中应该经常检查的条件。当复制到 s1 的字符串长于 s1 的分配大小(即 BUFSIZE,一个在 stdio.h 中定义的常数)时,就会发生缓冲区溢出情况。若非意外或故意,发生这种情况的可能性很小,但值得一查。缓冲区溢出是许多安全性问题的起因。复制的正确方法是用 strncpy() 函数代替 strcpy(),并将要复制的最大字节数定为 BUFSIZ - 1。然后,我们可以在复制到 s1 的最后一个字符后添加 NULL 字符
  
  在所有出现 PBO 注释的地方,都必须遵守同一过程。
  
  这里,我们将由 argno(初始时被设为 1 以指向命令本身后的第一个实际参数)索引的当前参数复制到字符串变量 s1。然后我们检查指示起始页选项的 s1 的头两个字符是否为“-s”。如果不是,则进行出错退出。
  
  如果没有问题,则将 s1 中的余下字符转换成整数。用 INT_MAX 检查它是否为这个平台的有效整数。(请记住,必须用 INT_MAX 而不是硬编码的数值,因为 C 中整数的大小随平台不同而不同 — 甚至同一平台的不同编译器也是如此)。
  
  如果没有问题,则在 psa 所指结构的字段中保存起始页。
  
  以注释“handle 2nd arg”开始的行
  进行的检查和操作与第一个参数基本相同。唯一的额外工作是检查所给的结束页不小于起始页。
  
  以注释“now handle optional args”开始的行
  这里,如果还有余下的参数,我们将处理它们。请注意这里使用的编码术语,因为这是 Linux 中使用的典型风格。我们所做的是,用一个循环遍历参数列表检查每个参数来看它是否为选项。如果是的话,则 switch 语句会找出它是哪个选项。如果是有效选项,则在结构中设置标志。我们还设置变量以记住与该选项相关联的所有数据的值,例如,有“-l”选项时记下页长,有“-f”时则记下打印目的地。如果选项无效,则给出错误消息并退出。
  
  以注释“there is one more arg”开始的行
  处理完所有以“-”为前缀的参数后,应检查是否还有剩余的参数。对于 selpg,最多有一个这样的参数,它被用作输入的文件名。我们调用 access() 函数两次来检查该参数是否存在以及是否可读。这确实有些多余,因为第二次调用也检查存在性(文件不存在就不可读),但我要说明的是人们也可以只检查存在性。
  
  以注释“check some post-conditions”开始的行
  这里,我们利用 C“断言”。这是 C 语言而不是 Linux 的特性,我演示它因为它是产生可靠代码的有用工具。
  
  有关这一点的详细信息,请参阅按合同设计一节。
  
  process_input() 函数
  我们首先声明一些变量。
  
  以注释“set the input source”开始的行
  如果命令行上没有给出文件名参数,我们就使用标准输入。否则,我们打开指定的文件进行读取。如果文件不能打开,则进行出错退出。若能打开,则调用 setvbuf() 函数来设置大小为 INBUFSIZ 的缓冲区(以前用 #defined 定义为 16KB)以从 fin 进行读取。这是为了能更快地读取输入。选择 16KB 作为大小是因为:在用从 1KB 到 64KB 的不同大小进行实验时,我发现在缓冲区大小从 1KB 增加到 16KB 的过程中,性能有某种程度的提高,但 16KB 以后就没有明显改善。您做了各种不同的实验,您想要通过更改缓冲区大小进行实验以找到适合您 Linux 系统的最佳大小。作为练习,您可以修改代码以使 selpg 再接受一个参数,比如说“-bNumber” — 以表示缓冲区大小。这允许您在实验时不必每次都更改 #define 宏的值并且重新编译。这可以成为又一个可选选项,并且当没有指定该选项时,将使用您更喜欢的值作为缺省的缓冲区大小,就象我对“-l”数字选项所做的那样。
  
  按合同设计

本文关键:开发Linux命令行实用程序
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top