Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15529842
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2007-11-25 19:04:34

使用mmap实现类似cat命令的文件显示功能

文章来源:http://gliethttp.cublog.cn

1.使用vim创建map_cat.c文件
[root@localhost gliethttp]# vim map_cat.c
2.在map_cat.c中录入如下程序
//map_cat.c
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc,const char *argv[])
{int fd;
 struct stat sb;
 void *region;
    if((fd = open(argv[1],O_RDONLY)) < 0)
    {
        perror("open");
        return 1;
    }
    
    if(fstat(fd,&sb))
    {
        perror("fstat");
        return 1;
    }

    region = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0);
/*
MAP_FAILED的值就是-1
if(region == ((caddr_t)-1))和if(region == MAP_FAILED)是等效的,不过以代码直观起见,还是使用xiyou说的
if(region == MAP_FAILED)比较好一些,我已经改了,
*/

    //if(region == ((caddr_t)-1))
    if(region == MAP_FAILED)
    {
        perror("mmap");
        return 1;
    }

    close(fd);

    if(write(1,region,sb.st_size) != sb.st_size)
    {
        perror("write");
        return 1;
    }
/*
当程序map_cat自然消亡时,或者显式的调用eixt(0);或者return 0;自动退出,登记链接到current->mm中的各个vma虚拟内存区块的由内核函数pte_alloc_one()申请到的pte页表slab管理结构体所占用的slab对象空间,都会被自动释放掉,归还给页表slab管理器,根据自然老化原理,甚至最后归还到buddy伙伴算法管理的free_area[]中(gliethttp_20071128)
根据本map_cat程序的特点,在这里就直接return 0;退出了,所以此处不加munmap也一样会在程序exit时,mmap申请的映射被系统自动回收,不过为了直观起见,加上之后,更能清楚,我们的用意
*/

    munmap(region,sb.st_size);
    
    return 0;
}
3.在vim中使用!符号执行shell命令,编译map_cat.c,具体命令如下:
:w 先保存编辑的程序
:!gcc map_cat.c -o map_cat
4.在vim中执行map_cat程序
:pwd 查看vim所在的当前目录,如果和map_cat不再同一个目录,使用
:cd /root/gliethttp 将vim的默认目录改为/root/gliethttp
:!./map_cat /etc/profile 执行刚才生成的map_cat程序,/etc/profile文件打印到屏幕上(gliethttp_20071125)


//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

/*PS:对mmap的粗略追踪*/

[root@localhost gliethttp]# strace ./map_cat ./mm.c
execve("./map_cat", ["./map_cat", "./mm.c"], [/* 25 vars */]) = 0
uname({sys="Linux", node="localhost.localdomain", ...}) = 0
brk(0) = 0x804973c
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40016000
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=60326, ...}) = 0
old_mmap(NULL, 60326, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
close(3) = 0
open("/lib/tls/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`V\1B4\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1531064, ...}) = 0
old_mmap(0x42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x42000000
old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000) = 0x4212e000
old_mmap(0x42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x42131000
close(3) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0x400169e0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0x40017000, 60326) = 0
open("./mm.c", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=103, ...}) = 0
mmap2(NULL, 103, PROT_READ, MAP_SHARED, 3, 0) = 0x40017000
close(3) = 0
write(1, "#include \nint main(int "..., 103#include <stdio.h>
int main(int argc,const char *argv[])
{
  printf("hello world!\r\n");
  return 0;
}
) = 103
exit_group(0) = ?
[root@localhost gliethttp]#

在退出之前加入for(;;);让map_cat不退出,观察内存情况:
[root@localhost gliethttp]# pidof map_cat
12007 显示map_cat的pid值
[root@localhost gliethttp]# vim /proc/12007/maps
08048000-08049000 r-xp 00000000 08:02 893166 /root/gliethttp/map_cat
08049000-0804a000 rw-p 00000000 08:02 893166 /root/gliethttp/map_cat
40000000-40015000 r-xp 00000000 08:02 453447 /lib/ld-2.3.2.so
40015000-40016000 rw-p 00014000 08:02 453447 /lib/ld-2.3.2.so
40016000-40017000 rw-p 00000000 00:00 0
40017000-40018000 r--s 00000000 08:02 893258 /root/gliethttp/mm.c 这是./map_cat ./mm.c命令所调用的mm.c文件
42000000-4212e000 r-xp 00000000 08:02 340050 /lib/tls/libc-2.3.2.so
4212e000-42131000 rw-p 0012e000 08:02 340050 /lib/tls/libc-2.3.2.so
42131000-42133000 rw-p 00000000 00:00 0
bfffd000-c0000000 rwxp ffffe000 00:00 0

[root@localhost gliethttp]# vim /proc/12020/maps 加入munmap(region,sb.st_size);的效果
08048000-08049000 r-xp 00000000 08:02 893166 /root/gliethttp/map_cat
08049000-0804a000 rw-p 00000000 08:02 893166 /root/gliethttp/map_cat
40000000-40015000 r-xp 00000000 08:02 453447 /lib/ld-2.3.2.so
40015000-40016000 rw-p 00014000 08:02 453447 /lib/ld-2.3.2.so
40016000-40017000 rw-p 00000000 00:00 0
42000000-4212e000 r-xp 00000000 08:02 340050 /lib/tls/libc-2.3.2.so
4212e000-42131000 rw-p 0012e000 08:02 340050 /lib/tls/libc-2.3.2.so
42131000-42133000 rw-p 00000000 00:00 0
bfffd000-c0000000 rwxp ffffe000 00:00 0

不论哪一种情况,当程序map_cat自然消亡时,或者显式的调用eixt(0);或者return 0;自动退出,登记链接到current->mm中的各个vma虚拟内存区块的由内核函数pte_alloc_one()申请到的pte页表slab管理结构体所占用的slab对象空间,都会被自动释放掉,归还给页表slab管理器,根据自然老化原理,甚至最后归还到buddy伙伴算法管理的free_area[](gliethttp_20071128)

阅读(4043) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~