Що відбувається, коли ви запускаєте команду ls на системах Linux?

Have you ever wondered what truly happens when you type a command like ls on a Linux system? As users, we often overlook the processes that make our commands work. However, each command triggers a series of complex and fascinating steps.

pic

Linux Terminal

Подорож команди ls

  1. Коли ви вводите команду ls в терміналі Linux, введені дані передаються оболонці (наприклад, Bash, Zsh). Оболонка шукає виконуваний файл у каталогах, зазначених у змінній середовища PATH. Для команди ls зазвичай виконавчий файл знаходиться в /usr/bin/ls або /bin/ls.
  2. Оболонка створює новий дочірній процес за допомогою системного виклику fork(). Цей дочірній процес буде виконувати команду ls, в той час як оболонка залишається активною і чекає завершення дочірнього процесу. Дочірньому процесу присвоюється унікальний ідентифікатор процесу (PID).
  3. Новий процес замінює свій простір пам'яті на виконуваний файл, використовуючи системні виклики exec().
  4. На цьому етапі двійковий файл команди завантажується в пам'ять, і виконання починається. Під час виконання необхідні бібліотеки завантажуються в пам'ять. Наприклад, libc для базових системних функцій і libselinux для політик безпеки можуть бути завантажені.
  5. Динамічний лінкер вирішує адреси для функцій бібліотек. Цей етап дозволяє програмі викликати функції з розподілених бібліотек, зв'язуючи їх з реальними місцями в пам'яті.
  6. Після того як двійковий файл ls завантажено і готово до роботи, воно починає взаємодіяти з файловою системою, щоб зібрати інформацію про вказану директорію. Команда ls використовує системні виклики, такі як opendir(), readdir() та closedir() для відкриття директорії, зчитування її вмісту та закриття директорії по завершенню.
    opendir(): Відкриває директорію для зчитування.
    readdir(): Зчитує кожен файл чи підкаталог у директорії.
    closedir(): Закриває директорію після того, як всі записи були зчитані.
  7. Для кожного файлу чи запису в директорії ls також перевіряє дозволи файлів за допомогою системних викликів, таких як fstat(), щоб отримати метадані (наприклад, тип файлу, розмір, дозволи).
  8. Після того як команда ls зібрала та відформатувала вміст директорії, вона передає результат у термінал через стандартний вивід (stdout). Термінал інтерпретує виведення і відображає його на екрані.
  9. Після завершення виконання команда ls завершить свою роботу та вийде. Вона викликає системний виклик exit(), повертаючи статус завершення до оболонки.
  10. Ресурси дочірнього процесу (пам'ять, дескриптори файлів) очищаються операційною системою, і керування повертається до батьківської оболонки.

Щоб краще зрозуміти, як системні виклики викликаються під час виконання команди ls, ось приклад виведення strace ls:

execve("/bin/ls", ["ls"], [/* 30 vars */]) = 0  
brk(NULL) = 0x562f41b05000  
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)  
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3  
fstat(3, {st_mode=S_IFREG|0644, st_size=12345, ...}) = 0  
mmap(NULL, 12345, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6a54c03000  
close(3) = 0  
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3  
read(3, , 832) = 832  
mmap(NULL, 2000000, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f6a54a00000  
close(3) = 0  
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3  
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0  
getdents64(3, /* 5 entries */, 32768) = 120  
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0  
write(1, "file1.txt\nfile2.txt\n", 20) = 20  
close(3) = 0  
exit_group(0) = ?
  • execve(): Завантажує двійковий файл ls в пам'ять і починає його виконання.
    Приклад: execve(“/bin/ls”, [“ls”], [/* 30 vars */])
  • openat(): Відкриває файли чи директорії (наприклад, поточну директорію або необхідні бібліотеки).
    Example: openat(ATFDCWD, ".", ORDONLY|ONONBLOCK|OCLOEXEC|O_DIRECTORY)
  • fstat(): Отримує метадані про файл або директорію (наприклад, розмір, дозволи).
    Приклад: fstat(3, {stmode=SIFDIR|0755, st_size=4096, …})
  • getdents64(): Зчитує записи (файли та директорії) у відкритій директорії.
    Приклад: getdents64(3, /* 5 entries */, 32768)
  • write(): Виводить список файлів та директорій на термінал.
    Приклад: write(1, “file1.txt\nfile2.txt\n”, 20)
  • close(): Закриває відкриті дескриптори файлів, такі як директорії або потоки виведення.
    Приклад: close(3)
  • exit_group(): Завершує процес і очищує ресурси.
    Приклад: exit_group(0)

Перекладено з: What Happens When You Run the ls Command on Linux Systems?

Leave a Reply

Your email address will not be published. Required fields are marked *