Perché dobbiamo passare due volte il nome del file nelle funzioni exec?


11

Ho letto Advanced Programming in UNIX Environment di Stevens, ottavo capitolo. Ho letto e compreso tutte e sei le funzioni exec.

Una cosa che noto è, in tutte le funzioni exec:

  • il primo argomento è il nome del file / nome del percorso (dipende dalla funzione exec).
  • il secondo argomento è argv [0] in cui entriamo main(), che è il nome del file stesso.

Quindi qui dobbiamo passare il nome del file due volte nella funzione.

C'è qualche motivo per farlo (come se non potessimo ottenere il nome del file dal nome del percorso dal primo argomento)?

Risposte:


14

Quindi qui dobbiamo passare il nome del file due volte nella funzione.

Non sono esattamente la stessa cosa che noti osservando che uno di essi viene utilizzato come argv[0]valore. Questo non deve essere uguale al nome di base dell'eseguibile; molte / la maggior parte delle cose lo ignorano e puoi mettere quello che vuoi lì dentro.

Il primo è il percorso effettivo dell'eseguibile, per il quale esiste un'ovvia necessità. Il secondo viene passato al processo apparentemente come il nome usato per invocarlo, ma, ad esempio:

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

Funzionerà bene, presumendo che /bin/lssia il percorso corretto.

Alcune applicazioni, tuttavia, ne fanno uso argv[0]. Di solito questi hanno uno o più collegamenti simbolici $PATH; questo è comune con le utility di compressione (a volte usano invece involucri shell). Se hai xzinstallato, stat $(which xzcat)mostra che è un collegamento a xz, ed man xzcatè lo stesso man xzche spiega "xzcat è equivalente a xz --decompress --stdout". Il modo in cui xz può dire come è stato invocato è controllando argv[0], rendendo questi equivalenti:

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

4
Ah, quindi questo spiegherebbe come busyboxpuò essere quello che vuoi che dipenda da come lo chiami giusto?
terdon

3
@terdon è esattamente così che il singolo binario per busybox soddisfa così tanti comandi diversi.
Mah

7
Il che significherebbe che se /bin/lsfosse occupato, non saprebbe come eseguire banana!
Riking

6

Non è necessario passare due volte il nome del file.

Il primo è il file che viene effettivamente eseguito.

Il secondo argomento è quello che dovrebbe essere il argv[0]processo, ovvero quello che il processo dovrebbe vedere come il suo nome. Ad esempio, se si esegue lsdalla shell, il primo argomento è /bin/ls, il secondo è giusto ls.

È possibile eseguire un determinato file e chiamarlo qualcos'altro tramite il secondo argomento; il programma può controllare il suo nome e comportarsi diversamente in base al nome. Questo può essere fatto anche tramite collegamenti reali (o collegamenti simbolici), ma in questo modo offre maggiore flessibilità.


In effetti, i collegamenti sono lo stesso metodo poiché è impostato argv[0]sul nome del collegamento.
Riccioli d'oro

Nell'ultimo paragrafo, "Puoi eseguire un certo file e chiamarlo qualcos'altro tramite il secondo argomento; il programma può controllarne il nome e comportarsi" diversamente "in base al nome". puoi per favore elaborare o darmi alcune letture, ho una novità in questo ambiente.
Munjal007,

L'ultima parte della risposta dei riccioli d'oro lo spiega.
Wurtel,

1

L'asporto è che argv[0]può essere impostato su qualsiasi cosa (incluso NULL). Per convenzione , argv[0]verrà impostato sul percorso in cui è stato avviato l'eseguibile (dal processo shell quando esegue execve()).

Se ./fooe dir/barsono due collegamenti diversi (hard o simbolici) allo stesso eseguibile, quindi l'avvio del programma dalla shell utilizzando i due percorsi verrà impostato argv[0]su ./fooe dir/bar, rispettivamente.

Il fatto che argv[0]può essere NULLè spesso trascurato. Il seguente codice potrebbe andare in crash per NULL argv[0]esempio (anche se glibc stampa qualcosa come <null> invece per argv[0]):

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

Un'alternativa su Linux è usare /proc/self/exeper questi casi.


come puoi impostare argv [0] su entrambi ./foo e dir / bar
munjal007

@ munjal007 Mi dispiace se non sono chiaro. Intendevo eseguire il programma due volte: una volta come ./fooe una volta come dir/bar. argv[0]sarà diverso per quei due casi (in ogni caso sarà lo stesso del percorso che hai usato).
Ulfalizer

@ munjal007 Questo presuppone che tu lo esegua dalla shell, ovviamente. Il punto è che potresti impostare argv[0]qualsiasi cosa quando fai exec*()il programma da solo. È una convenzione della shell da impostare argv[0]sul percorso utilizzato per avviare il programma (ed è saggio fare lo stesso quando si è exec*()un programma, poiché molti programmi controllano argv[0]e si aspettano che mantenga il percorso).
Ulfalizer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.