信息安全系统设计基础第十周学习总结

上周已完成第十章 系统I/O的学习笔记,这周对主要对附录A 错误处理进行学习,并对第十章进行进一步理解。

附录A 错误处理

基于错误处理包装函数

思想:给定的基本级系统函数foo,我们有相同参数的、函数名大写的包装函数Foo;包装函数调用基本函数并检查错误。如果发现了错误,包装函数就终止进程并返回一条信息;当基本函数无误的时候,包装函数就返回调用者。(包装函数被封装在源文件csapp.c中)

A.1 Unix系统中的错误处理

系统基函数调用时用三种不同风格的返回错误:Unix风格和Posix风格和DNS风格。

  1. unix风格

    例如fork函数和外套函数,返回值既包括错误代码,又包括有用的结果。

     if((pid = wait(NULL))<0)
     {
        fprintf(stderr,"wait error:%s
    ",strerror(errno));   //将errno设置为指向错误原因的代码
        exit(0);
     }
    
  2. Posix风格

    例如pthread,函数只返回调用成功(0)或者失败(非0),任何有用的信息都返回在通过调用引用进来的参数中。

  3. DNS风格

    gethostbyname和gethostbyaddr检索NDS(域名系统)库;它们在错误的时候会返回NULL,并设置全局变量h_errno。

A.2 错误处理包装函数

  1. unix风格

      pid_t Wait(int *status)
      {
         pid_t pid;
         if(pid = wait(status)<0)
         unix_error("wait error");
         return pid;
      }
    
  2. Posix风格

      void Pthread_detach(pthread_t tid)
      {
         int rc;
         if(rc=pthread_detach(tid) != 0)
         posix_error(rc,"Pthread_detach error");
       }
    
  3. DNS风格

      struct hostent *Gethostbyname(const char *name)
      {
         struct hostname *p;
         if((p = gethostbyname(name)) == NULL)
         dns_error("Gethostbyname error");
         return p;
      }
    

重要命令:

man -k key1 | grep key2| grep 2   : 根据关键字检索系统调用
grep -nr XXX /usr/include  :查找宏定义,类型定义

系统调用:文件I/O 如何用Linux学习系统编程

who

多用户系统如何知道谁在使用系统?who

  1. who能做什么,查阅一下:

  2. who命令的工作流程是:

    打开utmp文件,针对文件,读取一条记录,显示记录,关闭文件。

  3. 如何实现who?

    代码思想:从UTMP_FILE文件中读取想要的信息到存储器中,然后再用标准输出函数打印到屏幕上,最后关闭文件。

     #include	<stdio.h>
     #include	<stdlib.h>
     #include	<utmp.h>
     #include	<fcntl.h>
     #include	<unistd.h>
    
     #define	SHOWHOST	
    
     int show_info( struct utmp *utbufp )
     {
          printf("%-8.8s", utbufp->ut_name);	
          printf(" ");				
          printf("%-8.8s", utbufp->ut_line);	
          printf(" ");				
          printf("%10ld", utbufp->ut_time);	
          printf(" ");				
          #ifdef	SHOWHOST
          printf("(%s)", utbufp->ut_host);	
          #endif
          printf("
    ");				
    
          return 0;
     }
     int main()
     {
          struct utmp	 current_record;	
          int  utmpfd;		
          int  reclen = sizeof(current_record);
    
           /*打开UTMP_FILE读取信息,如果打开失败则输出失败信息。*/
        	 if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
          perror( UTMP_FILE );	
          exit(1);
     }
          /*读取信息到存储器中,reclen就是是读的字节数,然后再调用函数打印出来。*/
     while ( read(utmpfd, &current_record, reclen) == reclen )
     {
          show_info(&current_record);
          close(utmpfd);
          return 0;			
     }
    

cp

——复制文件
cp src dst

cp能干什么,查阅一下:

cp

 #include        <stdio.h>//标准输入输出
 #include        <stdlib.h>//C标准函数库
 #include        <unistd.h>//Unix类系统定义符号常量
 #include        <fcntl.h>//定义了很多宏和open,fcntl函数原型

 #define BUFFERSIZE      4096//定义存储器容量
 #define COPYMODE        0644//定义复制的长度

 void oops(char *, char *);

 int main(int argc, char *argv[])
 {
     int in_fd, out_fd, n_chars;//三个描述符值
     char buf[BUFFERSIZE];//存储器位置

/*cp的参数有两个,分别是要复制的文件,和目的目录,这样一共应该是有三个操作数
所以要先检查argc的值是否为三,如果不是,返回标准错误*/
if (argc != 3) {
	fprintf(stderr, "usage: %s source destination
", *argv);
	exit(1);
}
/*检查cp的第一个参数,要复制的文件,用open打开,in_fd为open返回的描述符
如果返回-1,代表打开失败,提示错误*/
if ((in_fd = open(argv[1], O_RDONLY)) == -1)
	oops("Cannot open ", argv[1]);

/*检查cp的第二个参数,复制的目的地址,用create在目的地址创建新文件,out_fd为open返回的描述符
如果返回-1,代表创建失败,提示错误*/
if ((out_fd = creat(argv[2], COPYMODE)) == -1)
	oops("Cannot creat", argv[2]);

/*cp指令的动作就是读取一个文件的内容到存储器,在新的地址创建空白文件,再从存储器将内容写入新文件。
这里判断复制是否成功:
如果能读取顺利,而读取的位数和写的位数不同,是写错误;
如果读取失败,是读错误。*/
while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)
	if (write(out_fd, buf, n_chars) != n_chars)
		oops("Write error to ", argv[2]);
if (n_chars == -1)
	oops("Read error from ", argv[1]);

/*这里执行的是关闭文件的动作,in_fd和out_fd两个文件描述符
所指向的文件只要有一个关闭错误,就提示关闭错误。*/
if (close(in_fd) == -1 || close(out_fd) == -1)
	oops("Error closing files", "");
}

 /*这个是用来输出错误信息的函数*/
void oops(char *s1, char *s2)
{
   fprintf(stderr, "Error: %s ", s1);
   perror(s2);//用来将上一个函数发生错误的原因输出到标准设备(stderr)
   exit(1);
}

ls

——读取文件名和文件属性

ls能干什么:

  • ls -l

  • ls -a

  • ls -lu:最后访问时间

  • ls -s:以块为单位的文件大小

  • ls -t:按时间排序

  • ls -F:显示文件类型

ls -l能做什么?

显示文件信息:模式(文件类型file(1),访问控制),链接数,文件所有者,组,大小,最后修改时间,文件名

ls(1)

#include	<stdio.h>
#include	<sys/types.h>
#include	<dirent.h>

void do_ls(char []);

int main(int argc, char *argv[])
{
   /*如果操作数只有1个,表明ls后面没有带参数,默认为当前目录,.表示当前目录。*/
   if ( argc == 1 )
      do_ls( "." );
   /*如果ls后面有参数,就把参数读入argv中。*/
   else
	  while ( --argc ){
	  	 printf("%s:
", *++argv );
		 do_ls( *argv );
	  }
   return 0;
}

/*因为ls和dir功能相近,用dir来实现ls*/
void do_ls( char dirname[] )
{
    DIR		*dir_ptr;
    struct dirent	*direntp;

    /*如果没有指向的那个地址,报错*/
    if ( ( dir_ptr = opendir( dirname ) ) == NULL )
	    fprintf(stderr,"ls1: cannot open %s
", dirname);
    else
    {
       /*递归的方式来读取*/
	   while ( ( direntp = readdir( dir_ptr ) ) != NULL )
		  printf("%s
", direntp->d_name );
	   closedir(dir_ptr);
    }
}

ls2

ls2前半部分和ls1一样,所不同的只是多出来了一部分,用来显示文件的详细信息,比如用户名,群组名,大小,创建时间,读写权限等。

参考资料:

    《深入理解操作系统》
    
    闫佳歆博客关于实践代码部分
原文地址:https://www.cnblogs.com/lhc-java/p/4966452.html