Чому ми повинні передати ім'я файлу двічі у виконанні функцій?


12

Я читав розширене програмування в середовищі UNIX , виконане Стівенсом, 8- а глава. Я читаю і розумію всі шість функцій виконання.

Одне, що я помічаю, - це у всіх функціях виконання:

  • Перший аргумент - це ім'я файлу / шлях (залежить від функції exec).
  • другий аргумент - це argv [0], який ми отримуємо main(), а саме ім'я файлу.

Отже, тут ми повинні передати ім'я файлу двічі у функції.

Чи є якась причина для цього (наприклад, ми не можемо отримати ім'я файлу з імені шляху з першого аргументу)?

Відповіді:


15

Отже, тут ми повинні передати ім'я файлу двічі у функції.

Вони не зовсім те саме, що ви помічаєте, спостерігаючи, що один із них використовується як argv[0]значення. Це не повинно бути таким самим, як базове ім'я виконуваного файлу; багато / більшість речей ігнорують це, і ви можете помістити туди все, що завгодно.

Перший - це власне шлях до виконуваного файлу, для якого існує очевидна необхідність. Другий передається процесу нібито як ім'я, яке використовується для його виклику, але, наприклад:

execl("/bin/ls", "banana", "-l", NULL);

Буде добре працювати, припускаючи, що /bin/lsце правильний шлях.

Деякі програми, однак, використовують argv[0]. Зазвичай вони мають одну або кілька символьних посилань $PATH; це звичайно з утилітами стиснення (іноді вони замість цього використовують оболонки оболонок). Якщо ви xzвстановили, stat $(which xzcat)показує, що це посилання на xz, і man xzcatце те саме, man xzщо пояснює "xzcat еквівалентно xz --decompress --stdout". Те, як xz може визначити, як його викликали, перевіривши argv[0], зробивши ці еквіваленти:

execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);

5
Так, це пояснило б, як busyboxможе бути те, що ви хочете, щоб це було залежно від того, як ви це правильно називаєте?
тердон

4
@terdon саме так один бінарний файл для зайнятої коробки задовольняє стільки різних команд.
мах

7
Що буде означати, що якби /bin/lsбув зайнятий, він не знав би як виконати banana!
Рікінг

6

Ім'я файлу не потрібно передавати двічі.

Перший - це файл, який насправді виконується.

Другий аргумент - що має бути argv[0]процесом, тобто те, що процес повинен бачити як його назва. Наприклад, якщо ви запустите lsз оболонки, перший аргумент - /bin/lsдругий - справедливий ls.

Ви можете виконати певний файл та викликати його чимось за допомогою другого аргументу; програма може перевірити її ім’я та поводитися по-різному відповідно до назви. Це також можна зробити за допомогою жорстких посилань (або символічних посилань), але цей спосіб дає більшу гнучкість.


Насправді посилання - це той самий метод, оскільки він встановлює argv[0]ім'я посилання.
goldilocks

В останньому абзаці "Ви можете виконати певний файл і викликати його чимось іншим за допомогою другого аргументу; програма може перевірити його ім'я та поводитись" по-різному "відповідно до назви". Чи можете ви, будь ласка, детальніше розглянути чи прочитати мені, я новачок у цьому середовищі.
munjal007

Остання пояснення відповіді золотистого пояснює це.
Вуртель

1

Винос - це те, що argv[0]можна встановити на що завгодно (у тому числі NULL). Заargv[0] умовою , буде встановлено шлях, який виконується виконуваним файлом (процесом оболонки, коли він робить execve()).

Якщо ./fooі dir/barє два різних посилання (жорстке або символічне) на один і той же виконуваний файл, то запуск програми з оболонки за допомогою двох шляхів буде встановлено argv[0]на ./fooі dir/bar, відповідно.

Те, що argv[0]може бути NULL, часто не помічається. Наступний код може бути аварійним для NULL argv[0]прикладу (хоча glibc друкує щось на зразок <null> замість argv[0]):

if (argc != 3) {
    fprintf(stderr, "%s: expected 2 arguments\n", argv[0]);
    exit(EXIT_FAILURE);
}

Альтернативою для Linux є використання /proc/self/exeдля таких випадків.


як можна встановити argv [0] на обидва ./foo та dir / bar
munjal007

@ munjal007 Вибачте, якщо мені було незрозуміло. Я мав на увазі запуск програми двічі: один раз ./fooі як раз dir/bar. argv[0]буде відрізнятися для цих двох випадків (у кожному випадку це буде такий самий, як і шлях, який ви використовували).
Ulfalizer

@ munjal007 Це, якщо ви, звичайно, запускаєте його з оболонки. Справа в тому, що ви могли налаштувати argv[0]на що завгодно, коли exec*()програмували самі. Це умовна умова оболонки, щоб встановити argv[0]шлях, який використовувався для запуску програми (і розумно робити те ж саме, коли ви exec*()програмуєте, оскільки багато програм перевіряють argv[0]і очікують, що вона пройде шлях).
Ulfalizer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.