2018-2019-1 20165325 《信息安全系统设计基础》第六周学习总结

2018-2019-1 20165325 《信息安全系统设计基础》第六周学习总结

一、学习笔记

1、输入输出是在主存和外部设备之间复制数据的过程

输入是I/O设备复制数据到主存,输出是主存复制数据到I/O设备;

2、Unix I/O

Linux内核引出的一个简单低级的接口,用于文件的读写。

描述符

内核返回的一个非负整数,好比文件指针。打开文件时被创建,当内核释放文件,描述符恢复到描述符池当中。

标准输入、标准输出、标准错误

头文件<unistd.h>引入的常量,分别对应STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,描述符分别是0、1、2,可用来代替显式的描述符值;

例:一次一个字节地从标准输入复制到标准输出;

当前文件位置

对于当前文件位置,内核始终显式地保存着一个值k,这个k就是从文件开头起始字节的偏移量,发生读写操作以后,k值会更新。

#include "csapp.h"

int main (void){
    char c;
    
    while (Read(STDIN_FILENO,&c,1)!=0)
        Write(STDOUO_FILENO,&c,1);
    exit(0);
}
3、open()

对应头文件<sys/type.h>、<sys/stat.h>、<fcntl.h>。

int open(char *filename,int flags,mode_t mode);返回值是打开文件以后的标识符。

flags参数

  • O_RDONLY:只读;
  • O_WRONLY:只写;
  • O_RDWD:可读可写;
4、读、写文件

头文件:<unistd.h>

ssize_t read(int fd,void *buf,size_t n);

ssize_t write(int fd,const void *buf,size_t n);

ssize_t 是有符号long型;size_t 是无符号;

5、RIO包

提供更方便健壮高效的I/O,分为两种函数:无缓冲的输入输出和带缓冲的输入函数。

二、课上笔记

1、两个重要命令:
  • man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用
  • grep -nr XXX /usr/include :查找宏定义,类型定义
2、操作系统的功能我总结为两点:管家婆和服务生:
  • 管家婆:通过进程、虚拟内存和文件三个重要抽象管理计算机的CPU、内存、I/O设备
  • 服务生:为用户提供shell, 为程序员提供系统调用(API)。
3、od命令复习

$ od -tc -tx1 abc.txt

4、echo命令创建二进制文件

echo -ne "/x7b" > abc.bin

5、who命令的编写

who命令用作在Linux命令行中查看用户的身份,使用man who查询结果:

DESCRIPTION
       Print information about users who are currently logged in.
       
       .....
       
       If FILE is not specified, use /var/run/utmp.  /var/log/wtmp as FILE  is
       common.   If  ARG1  ARG2  given, -m presumed: 'am i' or 'mom likes' are
       usual.

       

所以可以想到,who命令的编写如下:

1、fopen()函数从指定位置打开文件/var/run/utmp;

2、用while循环读取文件直到文件末尾EOF;

3、输出先关信息,实现和who相同的功能。

问题的关键在于/var/run/utmp是怎么存储的,打开utmp.h如下:

#ifndef _UTMP_H
# error "Never include <bits/utmp.h> directly; use <utmp.h> instead."
#endif

#include <paths.h>
#include <sys/time.h>
#include <sys/types.h>
#include <bits/wordsize.h>


#define UT_LINESIZE 32
#define UT_NAMESIZE 32
#define UT_HOSTSIZE 256


/* The structure describing an entry in the database of
   previous logins.  */
struct lastlog
  {
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
    int32_t ll_time;
#else
    __time_t ll_time;
#endif
    char ll_line[UT_LINESIZE];
    char ll_host[UT_HOSTSIZE];
  };


/* The structure describing the status of a terminated process.  This
   type is used in `struct utmp' below.  */
struct exit_status
  {
    short int e_termination;    /* Process termination status.  */
    short int e_exit;       /* Process exit status.  */
  };


/* The structure describing an entry in the user accounting database.  */
struct utmp
{
  short int ut_type;        /* Type of login.  */
  pid_t ut_pid;         /* Process ID of login process.  */
  char ut_line[UT_LINESIZE];    /* Devicename.  */
  char ut_id[4];        /* Inittab ID.  */
  char ut_user[UT_NAMESIZE];    /* Username.  */
  char ut_host[UT_HOSTSIZE];    /* Hostname for remote login.  */
  struct exit_status ut_exit;   /* Exit status of a process marked
                   as DEAD_PROCESS.  */
/* The ut_session and ut_tv fields must be the same size when compiled
   32- and 64-bit.  This allows data files and shared memory to be
   shared between 32- and 64-bit applications.  */
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
  int32_t ut_session;       /* Session ID, used for windowing.  */
  struct
  {
    int32_t tv_sec;     /* Seconds.  */
    int32_t tv_usec;        /* Microseconds.  */
  } ut_tv;          /* Time entry was made.  */
#else
  long int ut_session;      /* Session ID, used for windowing.  */
  struct timeval ut_tv;     /* Time entry was made.  */
#endif

  int32_t ut_addr_v6[4];    /* Internet address of remote host.  */
  char __unused[20];        /* Reserved for future use.  */
};

/* Backwards compatibility hacks.  */
#define ut_name     ut_user
#ifndef _NO_UT_TIME
/* We have a problem here: `ut_time' is also used otherwise.  Define
   _NO_UT_TIME if the compiler complains.  */
# define ut_time    ut_tv.tv_sec
#endif
#define ut_xtime    ut_tv.tv_sec
#define ut_addr     ut_addr_v6[0]


/* Values for the `ut_type' field of a `struct utmp'.  */
#define EMPTY       0   /* No valid user accounting information.  */

#define RUN_LVL     1   /* The system's runlevel.  */
#define BOOT_TIME   2   /* Time of system boot.  */
#define NEW_TIME    3   /* Time after system clock changed.  */
#define OLD_TIME    4   /* Time when system clock changed.  */

#define INIT_PROCESS    5   /* Process spawned by the init process.  */
#define LOGIN_PROCESS   6   /* Session leader of a logged in user.  */
#define USER_PROCESS    7   /* Normal process.  */
#define DEAD_PROCESS    8   /* Terminated process.  */

#define ACCOUNTING  9

/* Old Linux name for the EMPTY type.  */
#define UT_UNKNOWN  EMPTY


/* Tell the user that we have a modern system with UT_HOST, UT_PID,
   UT_TYPE, UT_ID and UT_TV fields.  */
#define _HAVE_UT_TYPE   1
#define _HAVE_UT_PID    1
#define _HAVE_UT_ID 1
#define _HAVE_UT_TV 1
#define _HAVE_UT_HOST   1

看起来很长但是实际上关键的地方就是这里:

struct utmp
{
  short int ut_type;        /* Type of login.  */
  pid_t ut_pid;         /* Process ID of login process.  */
  char ut_line[UT_LINESIZE];    /* Devicename.  */
  char ut_id[4];        /* Inittab ID.  */
  char ut_user[UT_NAMESIZE];    /* Username.  */
  char ut_host[UT_HOSTSIZE];    /* Hostname for remote login.  */
  struct exit_status ut_exit;   /* Exit status of a process marked as DEAD_PROCESS.  */
   ·······//此处省略一部分

现在我们明白了读取utmp文件的意义就是查找上面这样一个结构体,who命令所需要的信息都在里面。度娘表示:其中ut_type有很多种不同的登录方式,而我们需要的是用户的登陆,所以我们要对/var/log/utmp文件的文件内容进行筛选,只显示登录方式为USER_PROCESS的信息。

我们运行who命令来试一下

$ who
paul     tty7         2018-11-03 15:51 (:0)

这里解释一下,我的用户名是paul,设备名tty7,后面是时间,最后那个(:0)百度查到了是host;

然后我们就可以开始自己写mywho.c了,这里的时间用的是用ctime函数。

代码如下:

/*
 *  mywho.c 
 *  author lidongjun
 */
#include <stdio.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
void show_time(long time){
        char * c;
        c = ctime(&time);
        printf("%12.20s", c+4);
}
void show_info(struct utmp *a){
        if(a->ut_type != USER_PROCESS)
                return;
        printf("%-8s ", a->ut_user);
        printf("%-8s ", a->ut_line);
        show_time(a->ut_time);
        printf(" (%s)", a->ut_host);
        printf("\n");
}
int main() {
        struct utmp a;
        int fd;
        int len = sizeof(a);
        if((fd = open("/var/run/utmp", O_RDONLY,0)) == -1){
                return -1;
        }
        while(read(fd, &a, len) == len)
                show_info(&a);
        close(fd);
        return 0;
}

运行结果:

posted @ 2018-11-03 20:49  Maxeys  阅读(183)  评论(0编辑  收藏  举报