Home  >  Article  >  Operation and Maintenance  >  What system calls will be caused by executing ls in Linux?

What system calls will be caused by executing ls in Linux?

WBOY
WBOYOriginal
2022-03-18 11:05:004007browse

In Linux, executing ls will cause read and exec system calls; executing any shell command will call fork and exec, but through strace to see that the system calls caused by ls do not have fork, the ls command must be listed The file in the directory, so read must be called.

What system calls will be caused by executing ls in Linux?

#The operating environment of this tutorial: linux7.3 system, Dell G3 computer.

What system calls will be caused by executing ls in Linux?

The answer is read and exec series

The shell command execution mechanism is fork exec, fork is a clone, and execve is a transformation. The ls command lists the files in the directory, so read will also be called.

Shell accesses the Linux kernel through the fork and exec commands. The fork command can create the same thread.

Use strace to check the system calls caused by ls. It is true that there is no fork, but because executing any shell command will call fork

##execve The transformation is to create a new process and replace the original process with the new process.

First of all, let’s discuss what are system calls?

Users can access and control files and devices with the help of a small number of functions directly provided by UNIX/linux. These functions are
system calls[1].

Using the

strace ls command we can view the system calls used by the ls command [2], part of the output is as follows:

open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
getdents64(3, /* 68 entries */, 32768)  = 2240
getdents64(3, /* 0 entries */, 32768)   = 0
close(3)                                = 0
open system call opens the current directory file , returns the obtained file descriptor. You can see that the file is opened with the O_RDONLY flag.

As long as the file is opened with the O_RDONLY or O_RDWR flag, you can use the

read() system call to read bytes [3] from the file.

So

ls needs to use the read system call. In addition, any shell command that creates a process will use the exec system call.

Let’s go back and sort out the doubts we may have about these concepts:

    How does a program run, including ls?
  1. The open system call opens the file in the current directory and returns the obtained file descriptor. So what is a file descriptor?
1 How the process runs

Each running program is called a process[1]

Unix creates a process and loads a new process image Image separation. The advantage of this is that there is more leeway to manage both operations. After we create a process, we usually replace the child process with a new process image. So any shell command will create a process and use the exec system call.

For example: when executing the ps command on the shell command line, the shell process actually calls fork to copy a new child process, and then uses the exec system call to completely replace the newly generated child process with the ps process.

Use the exec function to replace the current process with a new process, and the new process has the same PID as the original process. Under the name exec is a complete series composed of multiple associated functions [4]

After calling fork to create a new process, the parent process and the child process are almost identical [1, p398].

Fork is a UNIX term. When a process (a running program) is forked, it is basically copied, and both processes after the fork continue to run from the current execution point, and each Each process has its own copy of memory.

The original process is the parent process, and the new process is the child process. Can be distinguished by

fork() return value.

The fork call in the parent process returns the pid (process id) of the new child process, while the fork call in the child process returns 0

For example :

#include<unistd.h>
#include<stdio.h>
#define LEN 10
int main()
{
    pid_t id=getpid();
    printf("Main pid: %d \n",id);
	int i;
	pid_t res=fork();
	if(res==0)
	{
	  for(i =0;i<LEN;i++) 
	  {
		pid_t id1=getpid();
		printf("%d ",id1);
		printf("Child process:%d\n",i);
	  }
	}
	else
	{
	  printf("res %d\n",res);
	  for(i=0;i<LEN;i++) 
	  {
		pid_t  id2=getpid();
		printf("%d ",id2);
		printf("parent process:%d\n",i);
	  }
	}

	printf("THE END\n");
	 return 0;
}

/*output
Main pid: 10965 
res 10966
10965 parent process:0
10965 parent process:1
10965 parent process:2
10965 parent process:3
10965 parent process:4
10965 parent process:5
10965 parent process:6
10965 parent process:7
10965 parent process:8
10965 parent process:9
10966 Child process:0
10966 Child process:1
THE END
10966 Child process:2
10966 Child process:3
10966 Child process:4
10966 Child process:5
10966 Child process:6
10966 Child process:7
10966 Child process:8
10966 Child process:9
THE END
*/

What should I do if I want a program to start the execution of another program but I still want to continue running it? That is to combine the use of fork and exec [6][1, p397]

For example (modified from [6]):

#include<string.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
#include<unistd.h>
 
 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:错误命令、需要参数命令、正确命令
>aa
aa: No such file or directory
 child pid: 11230
 child process return 512
>echo
A 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 first, and then the child process calls the program with the help of exec command. Provide corresponding output for error commands, commands that require parameters, and commands that do not require parameters.

2 File descriptor (fd)

All devices can be regarded as files.

对内核而言,所有打开的文件都通过文件描述符引用[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<unistd.h>
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);

相关推荐:《Linux视频教程

The above is the detailed content of What system calls will be caused by executing ls in Linux?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:What is sshd in linuxNext article:What is sshd in linux