博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux执行ls,会引起哪些系统调用
阅读量:5888 次
发布时间:2019-06-19

本文共 3730 字,大约阅读时间需要 12 分钟。

hot3.png

从一个问题说起

A. nmap

B. read

C. execve

D. fork

答案是read、exec系列

首先我们讨论一下什么是系统调用(system calls)?

用户借助UNIX/linux直接提供的少量函数可以对文件和设备进行访问和控制,这些函数就是系统调用[1]。

使用strace ls命令我们可以查看ls命令使用到的系统调用[2],其中一部分输出内容如下:

open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3getdents64(3, /* 68 entries */, 32768)  = 2240getdents64(3, /* 0 entries */, 32768)   = 0close(3)                                = 0

open系统调用打开当前目录文件,返回获得的文件描述符。可以看到该文件使用O_RDONLY标志打开。

只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节[3]。

所以ls要用到read系统调用。除此之外,任何shell命令都会创建进程,都会用到exec系统调用。

回过头来梳理一下我们对于这些概念可能产生的疑惑:

  1. 包括ls在内,一个程序是如何运行的?
  2. open系统调用打开当前目录文件,返回获得的文件描述符。那什么是文件描述符?

1 进程是如何运行的

每个运行中的程序被称为进程[1]

Unix将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。当我们创建了一个进程之后,通常将子进程替换成新的进程映象。所以任何shell命令都会创建进程,都会用到exec系统调用。

例如:在shell命令行执行ps命令,实际上是shell进程调用fork复制一个新的子进程,在利用exec系统调用将新产生的子进程完全替换成ps进程。

用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID。exec名下是由多个关联函数组成的一个完整系列[4]

调用fork创建新进程后,父进程与子进程几乎一模一样[1,p398]。

fork是一个UNIX术语,当fork一个进程(一个运行中的程序)时,基本上是复制了它,并且fork后的两个进程都从当前执行点继续运行,并且每个进程都有自己的内存副本。

原进程是父进程,新进程是子进程。可以通过fork()返回值区分。

父进程中fork调用返回的是新的子进程的pid(process id),而子进程中fork调用返回的是0

举个例子:

#include
#include
#define LEN 10int main(){ pid_t id=getpid(); printf("Main pid: %d \n",id); int i; pid_t res=fork(); if(res==0) { for(i =0;i

如果想要程序启动另一程序的执行但自己仍想继续运行的话,怎么办呢?那就是结合fork与exec的使用[6][1, p397]

举个例子(修改自[6]):

#include
#include
#include
#include
#include
char command[256]; void main() { int rtn; /*子进程的返回数值*/ while(1) { /* 从终端读取要执行的命令 */ printf( ">" ); fgets( command, 256, stdin ); command[strlen(command)-1] = 0; if ( fork() == 0 ) {/* 子进程执行此命令 */ execlp( command, NULL ); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror( command ); exit( errno ); } else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */ pid_t sonid=wait ( &rtn ); printf(" child pid: %d\n",sonid); printf( " child process return %d\n", rtn ); } }}/*output:错误命令、需要参数命令、正确命令>aaaa: No such file or directory child pid: 11230 child process return 512>echoA NULL argv[0] was passed through an exec system call. child pid: 11231 child process return 134>ps child pid: 11247 child process return 139*/

先fork,然后子进程借助exec调用程序command。对错误命令、需要参数的命令、以及不需要参数的命令给出对应的输出。

2 文件描述符(file descripter,fd)

一切设备都可以看作文件。

对内核而言,所有打开的文件都通过文件描述符引用[7]。文件描述符是非负整数,范围是[0,OPEN_MAX -1]。现在OPEN_MAX 一般为64

但是[7]又说对于FreeBSD 8.0,Linux 3.2.0 ,Mac OS X 10.6.8等, fd变化范围几乎无限,只受到存储器数量、int字长以及系统管理员所配置的软限制和硬限制的约束。。。why?

当open或者create一个新文件时,内核向进程返回一个文件描述符。

当读、写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read / write

按照惯例,fd为0 / 1 / 2分别关联STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO。这些常量也定义在unistd.h.

3 系统调用包含在哪些头文件中呢?

包括exec、fork、read、write在内,许多系统调用包含在unistd.h头文件中

POSIX,Portable Operating System Interface。是UNIX系统的一个设计标准,很多类UNIX系统也在支持兼容这个标准,如Linux。

unistd.h是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型[5]。在该头文件,用于访问设备驱动程序的底层函数(系统调用)有这五个:open/close/read/write/ioctl[1]。

4 文件I/O

[7]中提到大多数文件I/O用到的5个函数为:open/read/write/lseek/close

4.1 函数read

调用read函数从打开文件中读数据。

#include
ssize_t read(int filedes, void *buf, size_t nbytes);

返回值:

成功,读出的字节数;

失败,-1;

遇到文件尾,0

有多种情况可使实际读到的字节数少于要求读的字节数:

  • 读普通文件时,在读到要求字节数之前已经到达了文件尾端。

例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将回0。

  • 当从终端设备读时,通常一次最多读一行

  • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。

  • 当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。

  • 当从某些面向记录的设备(例如磁盘)读时,一次最多返回一个记录。

  • 当某一信号造成中断,而已经读了部分数据量时。读操作从文件的当前偏移量出开始,在成功返回之前,该偏移量将增加实际独到的字节数

read的经典原型定义则是:

int read(int fd, char*buf, unsigned nbytes);

References

  • 1 linux程序设计第四版
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7 Unix环境高级编程(第三版)

转载于:https://my.oschina.net/SnifferApache/blog/699911

你可能感兴趣的文章
[js高手之路] html5 canvas系列教程 - 状态详解(save与restore)
查看>>
poi excel 常用api
查看>>
AD提高动态的方法(附SNR计算)
查看>>
[转]轻松实现可伸缩性,容错性,和负载平衡的大规模多人在线系统
查看>>
五 数组
查看>>
也谈跨域数据交互解决方案
查看>>
EntityFramework中使用Include可能带来的问题
查看>>
面试题28:字符串的排列
查看>>
css important
查看>>
WPF 实现窗体拖动
查看>>
NULL不是数值
查看>>
Oracle学习笔记之五,Oracle 11g的PL/SQL入门
查看>>
css绘制几何图形
查看>>
结合kmp算法的匹配动画浅析其基本思想
查看>>
Android网络编程11之源码解析Retrofit
查看>>
安全预警:全球13.5亿的ARRIS有线调制解调器可被远程攻击
查看>>
麦子学院与阿里云战略合作 在线教育领军者技术实力被认可
查看>>
正确看待大数据
查看>>
Facebook通过10亿单词构建有效的神经网络语言模型
查看>>
发展大数据不能抛弃“小数据”
查看>>