A folyamatok kezeléséhez szükséges ANSI C utasítások összefoglalója...
A parancssor paraméterei és a környezeti változók
err.c – err_sys err_ret err_quit err_msg err_dump
Aktuális könyvtár váltása (chdir)
Gyökérkönyvtár megváltoztatása (chroot)
A Unix alatt használható ANSI C nagyrészt megegyezik a Borland C-vel.
Különbségek, megjegyzések:
-
nincs conio.h
- nincs nyomkövetés (a tesztelésre a legjobb módszer, ha több printf-et
szúrunk be a programunkba)
- az ANSI C fájlok kiterjesztése kötelezően .c
- a C++ fájlok kiterjesztése kötelezően .C
- a printf
csak a sorvége jel (\n)
után ír a képernyőre
A fordítás a gcc nevű fordítóval történik.
$ gcc program.c
A parancs paraméter nélkül használva mindig létrehoz egy a.out nevű állományt. Ez lesz a kimenet: bináris, futtatható kód. Ha mi szeretnénk nevet adni a kimenetnek, akkor használjuk a -o opciót.
$ gcc program.c -o futtathato
Mind a két esetben a kimeneti fájl már rendelkezik a futtatható (x) attribútummal.
Az így kapott programot futtathatjuk, ha egyszerűen beírjuk a nevét (egyes Unix verziókban meg kell adnunk az útvonalat még akkor is, ha a fájl az aktuális könyvtárban található):
$ ./futtathato
Ha több állományból álló programot (projektet) írunk, ezeket a make paranccsal kapcsoljuk össze.
Amint láttuk gcc-nek nincs saját kezelőfelülete, szövegszerkesztője. Ezért a programunkat bármilyen szerkesztőben begépelhetjük. A különböző Unix verziók rengeteg ilyen (szebbnél szebb) alkalmazást tartalmaznak.
Egy biztos: a vi szövegszerkesztő mindenik verzióban megtalálható.
Használati útmutató:
-
ne ijedjünk meg, nem olyan vészes, mint amilyennek elsőre látszik
- elindítása: vi vagy vi
program.c
- gépelés elkezdése: INSERT billentyűvel (ezzel egyébként válthatunk
beszúrási/felülírási mód között)
- parancs üzemmódba váltás (minden parancs kiadása előtt kötelező): ESC
- kilépés: :q
- állomány mentése (ha van már neve): :w
- állomány mentése (ha még nincs neve): :w név
- mentés, kilépés: :wq
- kilépés mentés nélkül: :q!
Jól használható szövegszerkesztő még a joe, emacs stb.
Akárcsak a shell parancsok esetén a man program C utasításokról is nagyon sok információt tartalmaz.
Például:
$ man printf
A parancssor paraméterei és a környezeti változók
Amikor egy folyamat elindít egy programot, átadja neki a parancssor paramétereit és a környezeti változókat. Ahhoz, hogy programunk ezeket a változókat használni tudja a főprogramot a következőképpen kell deklarálnunk:
main(int argc, char *argv[], char *envp[])
A parancssor paramétereit az argv, a környezeti változókat pedig az envp által mutatott táblázat (vektor) tartalmazza. Az argv elemeinek számát az argc változó tartalmazza.
A paraméterek és a környezeti változók kiírása történhet például így:
for
(k=0; k<argc; ++k)
{
printf("a %d. parameter: %s\n", k+1, argv[k]);
}
for
(k=0; ; ++k)
{
if (envp[k]!=NULL)
{
printf("a %d. kornyezeti valtozo: %s\n", k+1,
envp[k]);
}
else break;
}
A környezeti változók néhány karaktersorból állnak. Formájuk:
NÉV = érték
A leggyakoribb ilyen változók:
HOME
– azt a könyvtárat jelöli, amelybe egy cd utasítás
hatására ugrik
PATH – azon könyvtárak listája ahol a shell a
kiadott parancsokat keresi
MAIL – a leveleket tartalmazó fájl neve
TERM – a terminál típusa
SHELL – a bináris shell állomány elérési útvonala
LOGNAME – a név amelyen a felhasználót a
rendszer nyilvántartja
PS1 – a shell prompt jele (alapért. $)
PS2 – a prompt további sorainak jele (alapért. >)
A Unix shellből az env parancsot kiadva megjeleníthetők a környezeti változók értékei.
A környezeti változók értékének programból történő meghatározásában nem az envp az egyetlen lehetőség. Használhatjuk az environ külső változót is, amely éppen a rendszer által tárolt táblázatra mutat.
extern char **environ;
main()
{
int k;
for (k=0; ; ++k)
if (environ[k][0])
{
printf("a %d. kornyezeti valtozo: %s\n",
k+1, environ[k]);
}
else break;
}
Az envp és az environ változók ugyanazt az eredményt adják.
Egy bizonyos környezeti változó értékét lekérdezhetjük a getenv változóval:
#include
<stdlib.h>
char *getenv(const char *nev);
A függvény egy pointert ad vissza, amely a nev környezeti változóhoz hozzárendelt értékre mutat. Értéke NULL, ha nem létezik ilyen nevű változó.
char
*terminal;
if ((terminal = getenv("TERM")) == NULL)
{
printf("a TERM kornyezeti valtozo nincs definialva\n");
exit(1);
}
printf("a terminal: %s\n", terminal);
A fenti példa lekérdezi a terminál értékét, amennyiben a változónak nincs értéke hibaüzenetet ad.
Unixban egy függvényhívás következtében fellépő hiba esetén a legtöbb függvény -1 értéket térít vissza. Ilyen esetekben a hiba kódját az errno globális változó tartalmazza. Ez azonban nem egy elfogadott szabály, hiszen egyes függvények NULL értéket adnak vissza.
Az errno.h deklarációs fájlban van definiálva az errno változó, valamint azon szimbolikus konstansok értékei, amelyeket ez a változó felvehet. Az errno nem veheti fel a 0 értéket, és a szimbolikus konstansok között sincs 0 értékű.
extern int errno;
Amennyiben egy függvény nem hibával zárul, az előző errno érték megmarad!
A standard C két függvényt definiál a hibaüzenetek kiírására (szöveggel történő meghatározására). Az egyik az strerror, amelynek alakja:
#include
<string.h>
char *strerror(int nrerr);
A függvény egy pointert térít vissza a hiba szövegéhez. Az nrerr rendszerint az errno változó szokott lenni, de megadhatunk tetszőleges hibakódot is.
A másik hibaértelmező függvény a perror; ennek szintaxisa:
#include
<stdio.h>
void perror(const char *msg);
A függvény a standard hibacsatornára kiírja az msg szöveget, egy : (kettőspontot), majd az errno változó által meghatározott hibaüzenetet.
Az egyes hibakódokhoz tartozó hibaüzenetek listája megtalálható a Függelékben.
Az alábbiakban definiálunk néhány olyan függvényt, amelyek leegyszerűsítik a hibakezelést. A továbbiakban a példaprogramokban is ezeket a függvényeket fogjuk felhasználni. A függvények működését a következő táblázat foglalja össze:
Függvények |
strerror(errno) |
Befejeződés |
||
err_sys |
igen |
exit(1); |
||
err_ret |
igen |
return; |
||
err_quit |
nem |
exit(1); |
||
err_msg |
nem |
return; |
||
err_dump |
igen |
abort(); |
A függvények definíciója az err.c állományban található.
(A fenti függvények alapötlete és a mellékelt kód Iosif Ignat, Adrian Kacso UNIX – Gestionarea proceselor című könyvéből származik)
Lefoglal egy megadott méretű (meret) memóriaterületet. A lefoglalt memóriazónát nem inicializálja semmilyen értékkel. Alakja:
#include
<stdlib.h>
void *malloc(size_t meret);
A függvény 0-tól különböző értéket ad, ha a lefoglalás sikeres volt, és NULL-t, ha sikertelen (ekkor a hiba kódját az errno tartalmazza). Az első esetben a visszatérített érték éppen a lefoglalt memóriaterület kezdetére mutató pointer lesz.
Példa:
void
*ptr;
if ((ptr = malloc(10000)) == NULL)
{
perror("malloc");
exit(1);
}
Lefoglal egy elemszam*meret nagyságú folytonos memóriaterületet – magyarul elemszam darab, egyenként meret nagyságú területet –, majd ezt NULL értékekkel tölti fel. Alakja:
#include
<stdlib.h>
void *calloc(size_t elemszam, size_t meret);
Sikeres lefoglalás esetén 0-tól különböző értéket térít vissza (pointer a lefoglalt memóriazónára), különben a NULL értéket.
Példa:
struct
{
int s1;
long s2;
char s3[10];
} s;
void *ptr;
if
((ptr = calloc(10, sizeof(s))) == NULL)
{
perror("calloc");
exit(1);
}
Átméretez egy malloc, calloc vagy realloc függvénnyel lefoglalt memóriaterületet uj_meret nagyságúra. Alakja:
#include
<stdlib.h>
void *realloc(void *ptr, size_t uj_meret);
Sikeres lefoglalás esetén egy nem nulla értéket ad vissza (amely lehet a régi mutató, de lehet egy új érték is), különben a NULL-t.
Példa:
void *ptr;
if
((ptr = malloc(10000)) == NULL)
{
perror("malloc");
exit(1);
}
if
((ptr = realloc(ptr, 20000)) == NULL)
{
perror("realloc");
exit(2);
}
Felszabadít egy a malloc, a calloc vagy a realloc függvénnyel lefoglalt memóriaterületet. Alakja:
#include
<stdlib.h>
void free(void *ptr);
Amennyiben a megadott pointer nem létezik a függvény furcsán viselkedhet!
Példa:
void *ptr;
if
((ptr = malloc(10000)) == NULL)
{
perror("malloc");
exit(1);
}
free(ptr);
Aktuális könyvtár váltása (chdir)
Minden folyamathoz tartozik egy ún. aktuális könyvtár. Ez a könyvtár határozza meg az összes relatív keresési útvonalat, amelyet a folyamat használ. A folyamathoz tartozó aktuális könyvtárat megváltoztathatjuk a chdir függvény segítségével. Alakja:
#include
<unistd.h>
int chdir(const char *path);
A függvény 0-t ad vissza, ha a váltás sikerült, és -1-et hiba esetén. A path változóban az új útvonalat kell megadni (ehhez legalább végrehajtási (x) jogunk kell legyen).
A rendszerbe való belépéskor minden felhasználó a saját gazdakönyvtárából indul. A gazdakönyvtár a felhasználót jellemzi, míg az aktuális könyvtár egy folyamat jellemzője. Vigyázat, a kettőt ne tévesszük össze!
Példa:
#include "hdr.h"
int
main(void)
{
if (chdir("/tmp")<0)
err_sys("chdir hiba");
printf("a konyvtarvaltas sikerult\n");
exit(0);
}
Gyökérkönyvtár megváltoztatása (chroot)
A gyökérkőnyvtár megváltoztatására való a chroot függvény, melynek alakja:
#include
<unistd.h>
int chroot(const char *path);
A függvény 0-t ad vissza, ha a váltás sikerült, és -1-et hiba esetén. A path változóban az új útvonalat kell megadni.
Ezt a függvény azonban csak a superuser hajthatja végre!
Folyamatokkal végzett műveletek
Copyright (C) Buzogány László, 2002