Mengapa kita harus memberikan nama file dua kali dalam fungsi exec?

11

Saya membaca Lanjutan Pemrograman di UNIX Lingkungan oleh Stevens, 8 th bab. Saya membaca dan memahami semua enam fungsi exec.

Satu hal yang saya perhatikan adalah, dalam semua fungsi exec:

  • Argumen pertama adalah nama file / nama jalur (tergantung pada fungsi exec).
  • Argumen kedua adalah argv [0] yang kita dapatkan main(), yang merupakan nama file itu sendiri.

Jadi di sini kita harus melewati nama file dua kali dalam fungsinya.

Apakah ada alasan untuk itu (seperti kita tidak bisa mendapatkan nama file dari nama path dari argumen pertama)?

munjal007
sumber

Jawaban:

14

Jadi di sini kita harus melewati nama file dua kali dalam fungsinya.

Mereka tidak persis sama dengan yang Anda perhatikan dengan mengamati bahwa salah satunya digunakan sebagai argv[0]nilainya. Ini tidak harus sama dengan nama dasar dari executable; banyak hal mengabaikannya dan Anda dapat meletakkan apa pun yang Anda inginkan di sana.

Yang pertama adalah jalan aktual ke executable, yang ada kebutuhan jelas. Yang kedua diteruskan ke proses seolah-olah sebagai nama yang digunakan untuk memintanya, tetapi, misalnya:

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

Akan bekerja dengan baik, anggaplah /bin/lsjalan yang benar.

Namun, beberapa aplikasi memanfaatkan argv[0]. Biasanya ini memiliki satu atau lebih symlink di $PATH; ini biasa terjadi pada utilitas kompresi (terkadang mereka menggunakan pembungkus shell sebagai gantinya). Jika Anda telah xzmenginstal, stat $(which xzcat)menunjukkan tautannya xz, dan man xzcatsama dengan man xzyang menjelaskan "xzcat setara dengan xz --decompress --stdout". Cara xz dapat mengetahui bagaimana itu dipanggil adalah dengan memeriksa argv[0], membuat ini setara:

execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);
goldilocks
sumber
4
Ah, jadi ini akan menjelaskan bagaimana busyboxbisa menjadi apa yang Anda inginkan tergantung pada bagaimana Anda menyebutnya benar?
terdon
3
@terdon seperti itulah biner tunggal untuk busybox memuaskan begitu banyak perintah yang berbeda.
mah
7
Yang berarti bahwa jika kotak /bin/lssibuk, tidak akan tahu bagaimana mengeksekusi banana!
Bersepeda
6

Anda tidak harus memasukkan nama file dua kali.

Yang pertama adalah file yang sebenarnya dieksekusi.

Argumen kedua adalah apa yang seharusnya menjadi argv[0]proses, yaitu apa yang harus dilihat proses sebagai namanya. Misalnya, jika Anda lari lsdari shell, argumen pertama adalah /bin/ls, argumen kedua adil ls.

Anda dapat mengeksekusi file tertentu dan menyebutnya sesuatu yang lain melalui argumen kedua; program dapat memeriksa namanya dan berperilaku berbeda sesuai dengan namanya. Ini juga dapat dilakukan melalui tautan keras (atau tautan simbolik) tetapi cara ini memberikan lebih banyak fleksibilitas.

Wurtel
sumber
Sebenarnya tautan adalah metode yang sama karena menetapkan argv[0]ke nama tautan.
goldilocks
Dalam paragraf terakhir, "Anda dapat mengeksekusi file tertentu dan menyebutnya sesuatu yang lain melalui argumen kedua; program dapat memeriksa namanya dan berperilaku 'berbeda' sesuai dengan namanya". bisa tolong jelaskan atau beri saya beberapa bacaan, saya baru di lingkungan ini.
munjal007
Bagian terakhir dari jawaban goldilocks menjelaskan hal ini.
Wurtel
1

Yang bisa dibawa adalah yang argv[0]dapat diatur untuk apa pun (termasuk NULL). Dengan konvensi , argv[0]akan diatur ke path yang dapat dieksekusi dimulai sebagai (oleh proses shell ketika melakukan execve()).

Jika ./foodan dir/bardua tautan berbeda (hard atau simbolis) ke executable yang sama, maka memulai program dari shell menggunakan dua jalur akan diatur argv[0]ke ./foodan dir/bar, masing-masing.

Fakta yang argv[0]bisa NULLsering diabaikan. Kode berikut mungkin macet untuk NULL argv[0]contoh (meskipun glibc mencetak sesuatu seperti <null> sebagai gantinya argv[0]):

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

Alternatif di Linux adalah menggunakan /proc/self/exeuntuk kasus-kasus seperti itu.

Ulfalizer
sumber
bagaimana Anda dapat mengatur argv [0] untuk keduanya ./foo dan dir / bar
munjal007
@ munjal007 Maaf jika saya tidak jelas. Maksud saya menjalankan program dua kali: sekali ./foodan sekali dir/bar. argv[0]akan berbeda untuk kedua kasus (dalam setiap kasus itu akan sama dengan jalur yang Anda gunakan).
Ulfalizer
@ munjal007 Itu dengan asumsi Anda menjalankannya dari shell tentu saja. Intinya adalah bahwa Anda dapat mengatur argv[0]apa pun saat Anda exec*()memprogramnya sendiri. Ini adalah konvensi shell untuk mengatur argv[0]jalur yang digunakan untuk memulai program (dan lebih bijak untuk melakukan hal yang sama ketika Anda exec*()sebuah program, karena banyak program memeriksa argv[0]dan mengharapkannya untuk menahan jalur).
Ulfalizer