Heim  >  Artikel  >  Betrieb und Instandhaltung  >  Welche Systemaufrufe werden durch die Ausführung von ls unter Linux verursacht?

Welche Systemaufrufe werden durch die Ausführung von ls unter Linux verursacht?

WBOY
WBOYOriginal
2022-03-18 11:05:004012Durchsuche

Unter Linux führt die Ausführung von ls zu Lese- und Exec-Systemaufrufen. Die Ausführung eines beliebigen Shell-Befehls führt zu einem Aufruf von fork und exec. Wenn Sie jedoch strace verwenden, um die von ls verursachten Systemaufrufe zu überprüfen, werden die Dateien nicht aufgelistet im Verzeichnis, also read.

Welche Systemaufrufe werden durch die Ausführung von ls unter Linux verursacht?

Die Betriebsumgebung dieses Tutorials: Linux7.3-System, Dell G3-Computer.

Welche Systemaufrufe werden durch die Ausführung von ls unter Linux verursacht?

Die Antwort ist die Lese- und Exec-Reihe.

Der Shell-Befehlsausführungsmechanismus ist fork + exec, fork ist ein Klon und execve ist eine Transformation. Der Befehl ls listet die Dateien im Verzeichnis auf, daher wird auch read aufgerufen.

Shell-Zugriff auf den Linux-Kernel wird über die Befehle fork und exec erreicht. Der Befehl fork kann im selben Thread erstellt werden.

Verwenden Sie strace, um die durch ls verursachten Systemaufrufe zu überprüfen. Es gibt zwar keinen Fork, aber weil beim Ausführen eines Shell-Befehls fork aufgerufen wird

Die Transformation von execve besteht darin, einen neuen Prozess zu erstellen und ihn zu ersetzen mit dem neuen Prozess. Löschen Sie den ursprünglichen Prozess.

Besprechen wir zunächst, was Systemaufrufe sind.
Benutzer können mithilfe einer kleinen Anzahl von Funktionen, die direkt von UNIX/Linux bereitgestellt werden, auf Dateien und Geräte zugreifen und diese steuern. Diese Funktionen sind Systemaufrufe[1]. 系统调用[1]。

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

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系统调用打开当前目录文件,返回获得的文件描述符。可以看到该文件使用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()

Mit dem Befehl strace ls können wir die vom Befehl ls verwendeten Systemaufrufe anzeigen [2]. Ein Teil der Ausgabe lautet wie folgt:

#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
*/
Der open-Systemaufruf öffnet die Datei im aktuellen Verzeichnis und gibt den erhaltenen Dateideskriptor zurück. Sie können sehen, dass die Datei mit dem Flag O_RDONLY geöffnet wird.

Solange die Datei mit dem Flag O_RDONLY oder O_RDWR geöffnet ist, können Sie Bytes aus der Datei lesen, indem Sie den Systemaufruf read() [3] verwenden.

Also muss ls den Systemaufruf read verwenden. Darüber hinaus verwendet jeder Shell-Befehl, der einen Prozess erstellt, den Systemaufruf exec.

Lassen Sie uns zurückgehen und die Zweifel klären, die wir möglicherweise an diesen Konzepten haben:

  1. Wie läuft ein Programm, einschließlich ls?
  2. Der Systemaufruf open öffnet die Datei im aktuellen Verzeichnis und gibt den erhaltenen Dateideskriptor zurück. Was ist also ein Dateideskriptor?

1 Wie ein Prozess abläuft

Jedes laufende Programm wird als Prozess bezeichnet [1]

Unix trennt die Prozesserstellung vom Laden eines neuen Prozessabbilds. Dies hat den Vorteil, dass mehr Spielraum für die Verwaltung beider Vorgänge besteht. Nachdem wir einen Prozess erstellt haben, ersetzen wir normalerweise den untergeordneten Prozess durch ein neues Prozessbild. Jeder Shell-Befehl erstellt also einen Prozess und verwendet den Systemaufruf exec.

Beispiel: Wenn Sie den Befehl ps in der Shell-Befehlszeile ausführen, ruft der Shell-Prozess tatsächlich fork auf, um einen neuen untergeordneten Prozess zu kopieren, und verwendet dann den Systemaufruf exec, um den neu generierten untergeordneten Prozess vollständig durch den ps-Prozess zu ersetzen.

🎜Verwenden Sie die Exec-Funktion, um den aktuellen Prozess durch einen neuen Prozess zu ersetzen. Der neue Prozess hat dieselbe PID wie der ursprüngliche Prozess. Unter dem Namen exec steht eine vollständige Reihe bestehend aus mehreren zugehörigen Funktionen [4]🎜🎜Nach dem Aufruf von fork zum Erstellen eines neuen Prozesses sind der übergeordnete Prozess und der untergeordnete Prozess nahezu identisch [1, S. 398]. 🎜🎜Fork ist ein UNIX-Begriff. Wenn ein Prozess (ein laufendes Programm) gegabelt wird, wird er grundsätzlich kopiert, und beide Prozesse werden nach der Gabelung vom aktuellen Ausführungspunkt aus weiter ausgeführt, und jeder Prozess verfügt über eine eigene Speicherkopie. 🎜🎜Der ursprüngliche Prozess ist der übergeordnete Prozess und der neue Prozess ist der untergeordnete Prozess. Es kann durch den Rückgabewert von fork() unterschieden werden. 🎜🎜🎜Der Fork-Aufruf im übergeordneten Prozess gibt die PID (Prozess-ID) des neuen untergeordneten Prozesses zurück, während der Fork-Aufruf im untergeordneten Prozess 0 zurückgibt. Zum Beispiel: 🎜
#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
*/
🎜Wenn Sie möchten, dass das Programm ein anderes startet Programm Was soll ich tun, wenn ich es trotzdem weiter ausführen möchte? Das heißt, die Verwendung von fork und exec zu kombinieren . Stellen Sie entsprechende Ausgaben für Fehlerbefehle, Befehle, die Parameter erfordern, und Befehle, die keine Parameter erfordern, bereit. 🎜🎜2 Dateideskriptor (fd) 🎜🎜Alle Geräte können als Dateien betrachtet werden. 🎜

对内核而言,所有打开的文件都通过文件描述符引用[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视频教程

Das obige ist der detaillierte Inhalt vonWelche Systemaufrufe werden durch die Ausführung von ls unter Linux verursacht?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Was ist SSHD unter Linux?Nächster Artikel:Was ist SSHD unter Linux?