Naučte se, jak vytvořit proces UNIX. Speciální sémantika execlp() a execvp(). Dítě zemře dříve než rodič

Systémové volání exec se používá ke spuštění souboru, který se nachází v aktivním procesu. Při volání exec je předchozí spustitelný soubor nahrazen a je spuštěn nový soubor.

Přesněji lze říci, že pomocí systémového volání exec nahradí starý soubor nebo program z procesu novým souborem nebo programem. Celý obsah procesu je nahrazen novým programem.

Segment uživatelských dat, který provádí systémové volání exec(), je nahrazen datovým souborem, jehož název je uveden v argumentu při volání exec().

Nový program se načte do stejného procesního prostoru. Aktuální proces se právě změnil na nový proces, a proto se ID PID procesu nezměnilo, protože my nejsou vytváření nového procesu pouze nahrazujeme proces jiným procesem v exec.

Pokud aktuálně běžící proces obsahuje více než jedno vlákno, všechna vlákna budou ukončena a bude načten a poté spuštěn nový obraz procesu. Neexistují žádné funkce destruktoru, které ukončují vlákna aktuálního procesu.

PID procesu se nezmění, ale data, kód, zásobník, halda atd. procesu jsou změněny a jsou nahrazeny těmi z nově načteného procesu. Nový proces se provede ze vstupního bodu.

Systémové volání Exec je kolekce funkcí a v programovacím jazyce C jsou standardní názvy těchto funkcí následující:

  1. excl
  2. execle
  3. exclp
  4. execv
  5. execve
  6. execvp

Zde je třeba poznamenat, že tyto funkce mají stejný základ exec následuje jedno nebo více písmen. Ty jsou vysvětleny níže:

E: Je to pole ukazatelů, které ukazují na proměnné prostředí a jsou explicitně předány nově načtenému procesu.

l: l je pro argumenty příkazového řádku předané funkci seznam

p: p je proměnná prostředí path, která pomáhá najít soubor předaný jako argument, který má být načten do procesu.

proti: v je pro argumenty příkazového řádku. Ty jsou předány jako pole ukazatelů na funkci.

Proč se používá exec?

exec se používá, když chce uživatel spustit nový soubor nebo program ve stejném procesu.

Vnitřní práce exec

Zvážit následující body k pochopení fungování exec:

  1. Aktuální obraz procesu je přepsán novým obrazem procesu.
  2. Nový obraz procesu je ten, který jste předali jako argument exec
  3. Aktuálně běžící proces je ukončen
  4. Nový obrázek procesu má stejné ID procesu, stejné prostředí a stejný deskriptor souboru (protože proces není nahrazen obrázek procesu je nahrazen)
  5. Je ovlivněna statistika CPU a virtuální paměť. Mapování virtuální paměti aktuálního obrazu procesu je nahrazeno virtuální pamětí obrazu nového procesu.

Syntaxe funkcí rodiny exec:

Níže jsou uvedeny syntaxe pro každou funkci exec:

int execl(konst char* cesta, const char* arg, …)
int execlp(const char* soubor, const char* arg, …)
int execle(konst char* cesta, const char* arg, …, char* const envp)
int execv(konst char* cesta, const char* argv)
int execvp(const char* soubor, const char* argv)
int execvpe(const char* soubor, const char* argv, char *const envp)

Popis:

Návratový typ těchto funkcí je Int. Když je obraz procesu úspěšně nahrazen, do volání funkce se nic nevrací, protože proces, který jej volal, již neběží. Pokud však dojde k nějaké chybě, vrátí se -1. Pokud dojde k nějaké chybě a errno je nastaven.

  1. cesta se používá k určení úplné cesty k souboru, který se má spustit.
  1. arg je argument prošel. Je to vlastně název souboru, který bude v procesu spuštěn. Ve většině případů je hodnota arg a cesta stejná.
  1. const char* arg ve funkcích execl(), execlp() a execle() je považován za arg0, arg1, arg2, …, argn. Je to v podstatě seznam ukazatelů na null ukončené řetězce. Zde první argument ukazuje na název souboru, který bude proveden, jak je popsáno v bodě 2.
  1. envp je pole, které obsahuje ukazatele, které ukazují na proměnné prostředí.
  1. soubor se používá k zadání názvu cesty, který bude identifikovat cestu k novému souboru bitové kopie procesu.
  1. Funkce exec volají, které končí na E se používají ke změně prostředí pro nový obraz procesu. Tyto funkce předají seznam nastavení prostředí pomocí argumentu envp . Tento argument je pole znaků, které ukazuje na řetězec ukončený nulou a definuje proměnnou prostředí.

Chcete-li používat funkce rodiny exec, musíte do programu C zahrnout následující soubor záhlaví:

#zahrnout

Příklad 1: Použití systémového volání exec v programu C

Zvažte následující příklad, ve kterém jsme použili systémové volání exec v programování C v Linuxu, Ubuntu: Máme zde dva soubory c example.c a hello.c:

příklad.c

#zahrnout
#zahrnout
#zahrnout

{
printf( "PID příkladu.c = %d\n ", getpid() );
char * args = ( "Dobrý den" , "C" , "Programování" , NULL ) ;
execv("./ahoj" , args) ;
printf ("Zpět na příklad.c" ) ;
návrat 0;
}

Ahoj C

PID příkladu.c = 4733
Jsme v Hello.c
PID hello.c = 4733

Ve výše uvedeném příkladu máme soubor example.c a soubor hello.c. V ukázkovém souboru .c jsme nejprve vytiskli ID aktuálního procesu (v aktuálním procesu běží soubor example.c). Pak v dalším řádku jsme vytvořili pole ukazatelů znaků. Poslední prvek tohoto pole by měl být jako koncový bod NULL.

Pak jsme použili funkci execv(), která přebírá jako argument název souboru a pole ukazatelů znaků. Zde je třeba poznamenat, že jsme použili ./ s názvem souboru, který určuje cestu k souboru. Vzhledem k tomu, že soubor je ve složce, kde se nachází example.c, není třeba zadávat úplnou cestu.

Když je zavolána funkce execv(), náš procesní obraz bude nahrazen nyní soubor example.c není v procesu, ale soubor hello.c je v procesu. Je vidět, že ID procesu je stejné, ať už hello.c je obraz procesu nebo example.c je obraz procesu, protože proces je stejný a obraz procesu je pouze nahrazen.

Pak si zde musíme všimnout další věci, a to je příkaz printf() poté, co se execv() neprovede. Důvodem je, že řízení se nikdy nevrátí zpět ke staré bitové kopii procesu, jakmile ji nahradí nová bitová kopie procesu. Ovládací prvek se vrátí k volání funkce pouze tehdy, když nahrazení obrazu procesu není úspěšné. (Vrácená hodnota je v tomto případě -1).

Rozdíl mezi systémovými voláními fork() a exec():

Systémové volání fork() se používá k vytvoření přesná kopie běžícího procesu a vytvořená kopie je podřízený proces a běžící proces je nadřazený proces. Zatímco systémové volání exec() se používá k nahrazení obrazu procesu novým obrazem procesu. Proto v systémovém volání exec() neexistuje žádná koncepce nadřazených a podřízených procesů.

V systémovém volání fork() jsou rodičovské a podřízené procesy prováděny současně. Pokud je však při systémovém volání exec() úspěšná náhrada obrazu procesu, ovládací prvek se nevrátí tam, kde byla zavolána funkce exec, ale provede nový proces. Řízení bude přeneseno zpět pouze v případě nějaké chyby.

Příklad 2: Kombinace systémových volání fork() a exec().

Zvažte následující příklad, ve kterém jsme použili systémová volání fork() i exec() ve stejném programu:

příklad.c

#zahrnout
#zahrnout
#zahrnout
int main(int argc, char * argv)
{
printf( "PID příkladu.c = %d\n ", getpid() );
pid_t p;
p = fork() ;
jestliže (p==- 1)
{
{
printf( "Jsme v rodičovském procesu") ;
}
návrat 0;
}

Ahoj C:

PID příkladu.c = 4790
Jsme v rodičovském procesu
Jsme v dětském procesu
Volání hello.c z podřízeného procesu
Jsme v hello.c
PID hello.c = 4791

V tomto příkladu jsme použili systémové volání fork(). Když je vytvořen podřízený proces, 0 bude přiřazena k p a poté se přesuneme na podřízený proces. Nyní bude proveden blok příkazů s if(p==0). Zobrazí se zpráva a my jsme použili systémové volání execv() a aktuální obraz podřízeného procesu, kterým je example.c, bude nahrazen hello.c. Před voláním execv() byly podřízené a rodičovské procesy stejné.

Je vidět, že PID example.c a hello.c se nyní liší. Důvodem je, že example.c je nadřazený proces obrázek a hello.c je obrázek podřízeného procesu.

Funkce Funkce, které načítají a spouštějí jiné programy. Syntaxe int execl(char * cesta, char * arg0, arg1, ..., argn, NULL); int execle(char * cesta, char * arg0, arg1, ..., argn, NULL, char ** envp); int execlp(char * název cesty, znak * arg0, arg1, ..., argn, NULL); int execlpe(char * cesta, char * arg0, arg1, ..., argn, NULL, char ** envp); CESTA DOS. Bez přípony p bude vyhledávání provedeno pouze v pracovním adresáři. Pokud parametr path neobsahuje trasu, pak se hledání provede v aktuálním adresáři a poté podél tras definovaných proměnnou prostředí PATH. l - označuje, že ukazatele adresy (arg0, arg1, ..., argn) jsou předávány jako samostatné argumenty. Přípona l se obvykle používá, když předem znáte počet argumentů, které mají být předány. v - označuje, že ukazatele adresy (arg, arg,...arg[n]) jsou předány jako pole ukazatelů. Typicky se při vysílání používá přípona v variabilní číslo argumenty. e – označuje, že procesu „dítě“ lze předat argument envp, který vám umožňuje vybrat prostředí „dítě“ procesu. Bez přípony e zdědí „dítě“ proces prostředí „rodičovského“ procesu., která je přiřazena každé proměnné envvar. Poslední prvek v poli envp je adresa nula NULL. Když má envp hodnotu NULL, „podřízený“ proces zdědí přiřazení prostředí „nadřazeného“ procesu. Celková délka arg0+ arg1+...+argn (nebo arg+ arg+...+arg[n]), včetně mezer oddělujících argumenty, musí být menší než 128 bajtů. Nulové konce se nepočítají. Když se zavolá exec..., všechny otevřené soubory zůstanou otevřené v podřízeném procesu. Vráceno Po úspěšném dokončení funkce exec... není vrácena žádná hodnota. Pokud dojde k chybě, funkce exec... vrátí hodnotu -1 a globální proměnná errno se nastaví na jednu z následujících hodnot: E2BIG - Seznam argumentů je příliš dlouhý. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EMFILE – Příliš mnoho otevřených souborů.<=argc;loop++) puts(argv); return 0; } #includeEACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. ENOENT – Nebyla nalezena přístupová cesta (PATH) nebo název souboru.<=argc;loop++) puts(argv); /* напечатать первый параметр среды */ printf("env = %s\n",env); return 0; } #includeEACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. Chyba formátu ENOEXEC - EXEC.<=argc;loop++) puts(argv); return 0; } #includeEACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. ENOMEM - Nedostatek paměti. Přenositelnost exec... je jedinečná pro DOS. Viz také: abort, atexit,_exit, exit, _fpreset, searchpath, spawn..., system. Příklad: #include EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. void main(int argc,char **argv) ( printf("Začíná CHILD s arg1, arg2 ...\n"); execv("CHILD.EXE",argv); perror("Chyba EXEC"); exit( 1); ) #zahrnout EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. void main(int argc,char **argv,char **envp) ( printf("Spustit CHILD s arg1, arg2 ...\n"); execve("CHILD.EXE",argv,envp); perror(" EXEC chyba"); exit(1); ) #include EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. void main(int argc,char **argv) ( printf("Začíná CHILD s arg1, arg2 ...\n"); execvp("CHILD.EXE",argv); perror("Chyba EXEC"); exit( 1); ) #zahrnout EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. EACCES – Přístup odepřen. int main(int argc,char **argv,char **envp) ( printf("Spustit CHILD s arg1, arg2 ...\n"); execvpe("CHILD.EXE",argv,envp); perror(" EXEC chyba"); exit(1); )

rodina funkcí exec().

Rodina funkcí exec() nahrazuje program běžící v aktuálním procesu jiným programem. Když program zavolá funkci exec(), jeho provádění se okamžitě zastaví a spustí se nový program.

Funkce zahrnuté v rodině exec() se mírně liší svými schopnostmi a způsobem, jakým jsou volány.

Funkce s příponou "p" ve svém názvu (execvp() a execlp()) berou název programu jako argument a hledají tento program v adresářích určených proměnnou prostředí PATH. Všechny ostatní funkce musí předat úplnou cestu k programu.

Funkce s příponou "v" ve svých názvech (execv(), execvp() a execve()) přijímají seznam argumentů programu jako pole řetězcových ukazatelů, které končí ukazatelem NULL. Funkce s příponou "l" (execl(), execlp() a execle()) přijímají seznam argumentů proměnné délky.

Funkce s příponou "e" ve svých názvech (execve() a execle()) berou jako další argument pole proměnných prostředí. Toto pole obsahuje řetězcové ukazatele a končí nulovým ukazatelem. Každý řádek by měl vypadat jako " VARIABILNÍ=význam" .

Protože exec() nahrazuje jeden program jiným, nikdy nevrací hodnotu – pouze v případě, že program nebylo možné volat kvůli chybě.

Seznam argumentů předávaných programu je podobný argumentům příkazového řádku zadaným při interaktivním spouštění programu. Lze je také získat pomocí parametrů argc a argv funkce main(). Pamatujte, že když je program spuštěn interpretem příkazů, první prvek pole argv bude obsahovat název programu, za nímž budou následovat argumenty předané programu. Totéž byste měli udělat při generování seznamu argumentů pro funkci exec().

Execlp (3) spuštění souboru k provedení

Jiný alias

execl, execle, execv, execvp, execvpe

POSOUZENÍ

#zahrnout

extern char **prostředí;

int execl(const char *cesta, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *soubor, const char *arg, ...
/* (char *) NULL */);
int execle(const char *cesta, const char *arg, ...
/*, (char *) NULL, char * konstenvp */);
int execv(const char *cesta, char *konstargv);
int execvp(const char *soubor, char *konstargv);
int execvpe(const char *soubor, char *konstargv,
char *konstenvp);

Požadavky na makro testování vlastností pro glibc (viz feature_test_makra(7)):

execvpe():_GNU_SOURCE

POPIS

Funkční rodina exec() nahradí aktuální obraz procesu novým. Funkce popsané v této manuálové stránce jsou obaly pro execve(2) (Podrobnosti o výměně stávajícího naleznete v manuálové stránce execve(2)).

Prvním argumentem těchto funkcí je název spustitelného souboru.

Parametr const char *arg a následné parametry ve funkcích excl(), exclp() A execle() lze považovat za parametry arg0, arg1, ..., argn. Společně popisují seznam jednoho nebo více ukazatelů řetězce ukončených nulou, který představuje seznam parametrů dostupných pro spouštěný program. První parametr by podle konvence měl ukazovat na název spojený se souborem, který má být spuštěn. Seznam parametrů musí end s nulovým ukazatelem, a protože se jedná o funkci s proměnným počtem argumentů, musí být tento ukazatel přetypován na (znak *) NULL.

Funkce execv(), execvp() A execvpe() poskytnout novému programu seznam argumentů ve formě pole ukazatelů na řetězce ukončené nulou. První argument by podle konvence měl ukazovat na název spojený se souborem, který má být spuštěn. Pole ukazatelů musí končí nulovým ukazatelem.

Funkce execle() A execvpe() umožnit volajícímu přiřadit prostředí ke spustitelnému programu pomocí parametru envp. Argument envp je pole ukazatelů na řetězce ukončené nulou, it musí končí nulovým ukazatelem. Zbývající funkce získávají prostředí pro nový obraz procesu z externí proměnné okolí proces volání.

Speciální sémantika execlp() a execvp()

Funkce exclp(), execvp() A execvpe() duplicitní akce shellu související s nalezením spustitelného souboru, pokud zadaný název souboru neobsahuje znak lomítka (/). Vyhledávací cesta se nastavuje v proměnné prostředí CESTA(seznam adresářů oddělených dvojtečkou). Není-li tato proměnná definována, je implicitně seznam vrácených adresářů přidán do aktuálního adresáře confstr(_CS_PATH)(volání confstr(3) obvykle vrací "/bin:/usr/bin").

Pokud zadaný název souboru obsahuje znak lomítka, proměnná CESTA bude ignorován a soubor v zadané cestě bude spuštěn.

Kromě toho existují rozdíly ve zpracování některých chyb.

Pokud je přístup k souboru odepřen (při pokusu o spuštění execve(2) je vrácena chyba EACCES), pak budou tyto funkce pokračovat v hledání ve zbývajících cestách. Pokud však nejsou nalezeny žádné další soubory, přiřadí hodnotu globální proměnné errno rovnat se EACCES.

Pokud není hlavička souboru rozpoznána (při pokusu o spuštění execve(2) vrací ENOEXEC), pak tyto funkce spustí shell ( /bin/sh) s úplným názvem souboru jako prvním parametrem (pokud to také způsobí chybu, vyhledávání se zastaví).

NÁVRATNÁ HODNOTA

Funkce exec() vrátí hodnotu pouze v případě, že dojde k chybě. To vrátí -1 a errno je přiřazen chybový kód.

VERZE

Funkce execvpe() se poprvé objevil v glibc 2.11.

ATRIBUTY

Popis pojmů v této části viz atributy(7).
Rozhraní Atribut Význam
excl(), execle(), execv() neškodnost ve vláknechneškodný (MT-Safe)
exclp(), execvp(), execvpe() neškodnost ve vláknechneškodný (MT-Safe env)

DODRŽOVÁNÍ

POSIX.1-2001, POSIX.1-2008.

Funkce execvpe() je rozšíření GNU.

POZNÁMKY

Na některých systémech výchozí vyhledávací cesta (používá se, když v prostředí není žádná proměnná CESTA) začíná adresáři /zásobník A /usr/bin a poté se provede vyhledávání v aktuálním adresáři (aby se nespustil vestavěný program trojského koně). Linux používá tradiční metodu: vyhledávání začíná v aktuálním adresáři.

Funkční chování exclp() A execvp() pro chyby během pokusů o spuštění souboru se historicky vyvíjel, ale není popsán ani definován ve standardu POSIX. Na BSD (a případně dalších systémech) probíhá automatické čekání a opakování pokusu, pokud dojde k chybě ETXTBSY. V Linuxu je to považováno za neodstranitelnou chybu a okamžitě se vrátí.

Tradičně funkce exclp() A execvp() ignoroval všechny chyby kromě výše popsaných a také ENOMEM A E2BIG kterou vracejí. V Linuxu tyto funkce vracejí jakoukoli jinou chybu než ty, které byly uvedeny dříve.




Horní