A napi munkám nagyrészt szoftvertelepítésből áll, ami azt jelenti, hogy sok időt töltök azzal, hogy megválaszoljam az alábbi kérdéseket:
- Ez a szoftver a fejlesztőnek működik, de nekem nem. Miért?
- Tegnap ez a szoftver működött nekem, de ma már nem. Miért?
Ez egyfajta hibakeresés, amely kissé eltér a szokásos szoftveres hibakereséstől. A rendszeres hibakeresés a kód logikájáról szól, de a telepítési hibakeresés a kód és a környezet közötti kölcsönhatásról. Még ha a probléma gyökere logikai hiba is, az a tény, hogy az egyik gépen minden működik, a másikon nem, azt jelenti, hogy a probléma valahogy a környezetben van.
Tehát a szokásos hibakereső eszközök helyett, mint pl gdb Különféle eszköztáram van a telepítés hibakereséséhez. És a kedvenc eszközöm a probléma kezelésére, mint például: „Miért nem működik ez a szoftver nekem?” hívott Eztán.
Mi az a strace?
Az alap alkalmazás nagyon egyszerű. Csak le kell futtatnod a strace-t bármilyen paranccsal és kiírja az összes rendszerhívást (bár először valószínűleg magadnak kell telepítenie Eztán):
$ strace echo Hello
...Snip lots of stuff...
write(1, "Hellon", 6) = 6
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
Mik ezek a rendszerhívások? Ez olyasmi, mint egy API az operációs rendszer kerneléhez. Valamikor a szoftvernek közvetlen hozzáférése volt ahhoz a hardverhez, amelyen futott. Ha például valamit megjelenítenie kellett a képernyőn, akkor a videoeszközök portjaival vagy memórialeképezett regisztereivel játszott. Amikor a többfeladatos számítógépes rendszerek népszerűvé váltak, káosz uralkodott, miközben különféle alkalmazások harcoltak a hardverért. Az egyik alkalmazás hibái másokat is lerombolhatnak, ha nem az egész rendszert. Ezután a privilégium módok (vagy „gyűrűvédelem”) megjelentek a CPU-ban. A kernel lett a legkiváltságosabb: teljes hozzáférést kapott a hardverhez, így kevésbé kiváltságos alkalmazások jöttek létre, amelyeknek már hozzáférést kellett kérniük a kerneltől, hogy rendszerhívásokon keresztül interakcióba lépjenek a hardverrel.
A bináris szinten a rendszerhívás némileg eltér az egyszerű függvényhívástól, de a legtöbb program a szabványos könyvtárban wrappert használ. Azok. a POSIX C standard könyvtár függvényhívást tartalmaz ír(), amely tartalmazza a rendszerhívás összes architektúra-specifikus kódját ír.
Röviden, az alkalmazás és környezete (számítógépes rendszerek) közötti bármilyen interakció rendszerhívásokon keresztül valósul meg. Ezért, ha a szoftver működik az egyik gépen, de nem a másikon, jó lenne megnézni a rendszerhívás-követés eredményeit. Pontosabban, itt van egy lista azokról a tipikus pontokról, amelyek rendszerhívási nyomkövetéssel elemezhetők:
- Konzol I/O
- Hálózati I/O
- Fájlrendszer hozzáférés és fájl I/O
- Egy folyamatszál élettartamának kezelése
- Alacsony szintű memóriakezelés
- Hozzáférés adott eszközillesztő-programokhoz
Mikor kell használni a strace-t?
Elméletben, Eztán a felhasználói térben lévő bármely programmal használható, mert a felhasználói területen lévő bármely programnak rendszerhívást kell végrehajtania. Hatékonyabban működik lefordított, alacsony szintű programokkal, de működik olyan magas szintű nyelvekkel is, mint a Python, ha át tudja vágni a futási környezetből és az értelmezőből származó további zajokat.
Teljes pompájában Eztán olyan szoftverek hibakeresése során nyilvánul meg, amelyek az egyik gépen jól működnek, de a másikon hirtelen leállnak, és homályos üzeneteket produkál a fájlokról, engedélyekről, vagy sikertelen próbálkozásokról néhány parancs végrehajtására vagy valami másra... Kár, de nem olyan jól kombinálható magas szintű problémákkal, mint például a tanúsítvány-ellenőrzési hibák. Ez általában kombinációt igényel Eztánnéha
Példaként egy önálló kiszolgálót fogunk használni, de a rendszerhívás-követés gyakran bonyolultabb telepítési platformokon is elvégezhető. Csak a megfelelő eszközöket kell kiválasztania.
Egyszerű hibakeresési példa
Tegyük fel, hogy szeretné futtatni a csodálatos foo szerveralkalmazást, és ez az, amit a végén:
$ foo
Error opening configuration file: No such file or directory
Úgy tűnik, hogy nem találta az általad írt konfigurációs fájlt. Ez azért történik, mert néha a csomagkezelők egy alkalmazás fordításakor felülbírálják a várt fájlhelyeket. És ha követi az egyik disztribúció telepítési útmutatóját, a másikban teljesen eltérő fájlokat talál, mint amire számított. A probléma néhány másodperc alatt megoldható lenne, ha a hibaüzenetből kiderülne, hol kell keresni a konfigurációs fájlt, de nem. Szóval hol kell nézni?
Ha hozzáfér a forráskódhoz, akkor elolvashatja és mindent megtudhat. Jó tartalék terv, de nem a leggyorsabb megoldás. Használhat egy lépésről lépésre hibakeresőt, mint például gdb és nézze meg, mit csinál a program, de sokkal hatékonyabb egy olyan eszköz használata, amelyet kifejezetten a környezettel való interakció megjelenítésére terveztek: Eztán.
Teljesítmény Eztán feleslegesnek tűnhet, de a jó hír az, hogy a legtöbbet nyugodtan figyelmen kívül lehet hagyni. Gyakran hasznos az -o operátor használata a nyomkövetési eredmények külön fájlba mentéséhez:
$ strace -o /tmp/trace foo
Error opening configuration file: No such file or directory
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0
brk(NULL) = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0
mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 > 1 260A2 "..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000
mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0
mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000
mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000
mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000
mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0
mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0
mprotect(0x56363b08b000, 4096, PROT_READ) = 0
mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0
munmap(0x7f2f12cf1000, 25186) = 0
openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory)
dup(2) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
brk(NULL) = 0x56363b3fb000
brk(0x56363b41c000) = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Error opening configuration file"..., 60) = 60
close(3) = 0
exit_group(1) = ?
+++ exited with 1 +++
Körülbelül a kimenet teljes első oldala Eztán - Ez általában alacsony szintű felkészítés az indulásra. (Sok hívás mmap, mprotect, írótoll olyan dolgokra, mint például az alacsony szintű memória észlelése és a dinamikus könyvtárak megjelenítése.) Valójában a hibakeresés során a kimenet Eztán Jobb, ha a legvégétől olvasod. Lent lesz egy kihívás ír, amely hibaüzenetet jelenít meg. Feljebb nézünk, és látjuk az első hibás rendszerhívást - a hívást openat, ami hibát jelez ENOENT ("fájl vagy könyvtár nem található") megpróbálja megnyitni /etc/foo/config.json. Itt kell lennie a konfigurációs fájlnak.
Ez csak egy példa volt, de azt mondanám, hogy az esetek 90%-át használom Eztán, nincs ennél sokkal nehezebb tennivaló. Az alábbiakban egy teljes, lépésenkénti hibakeresési útmutató található:
- Mérges lehet egy program rendszer-y hibájával kapcsolatos homályos üzenet miatt
- Indítsa újra a programot a Eztán
- Keresse meg a hibaüzenetet a nyomkövetési eredmények között
- Menjen feljebb, amíg el nem éri az első sikertelen rendszerhívást
Nagyon valószínű, hogy a 4. lépésben a rendszerhívás felfedi, hogy mi hibázott.
tippek
Mielőtt bemutatnék egy példát a bonyolultabb hibakeresésre, mutatok néhány trükköt a hatékony használat érdekében Eztán:
az ember a barátod
Sok *nix rendszeren a kernelhez intézett rendszerhívások teljes listája lekérhető futtatással férfi syscalls. Ilyeneket fog látni brk (2), ami azt jelenti, hogy futással több információhoz juthatunk férfi 2 brk.
Kis gereblye: férfi 2 villa megmutatja a shell oldalát Villa() в GNU libc, ami, mint kiderült, hívással valósul meg klón (). Hívja a szemantikát villa változatlan marad, ha programot írunk Villa(), és futtasson egy nyomkövetést – nem találok hívást villa, helyettük lesz klón (). Az ilyen rake-ek csak akkor zavarnak meg, ha elkezdi összehasonlítani a forrást a kimenettel Eztán.
A -o gombbal mentheti a kimenetet fájlba
Eztán kiterjedt kimenetet generálhat, ezért gyakran hasznos a nyomkövetési eredményeket külön fájlokban tárolni (mint a fenti példában). Ez segít elkerülni a programkimenet és a kimenet összekeverését Eztán a konzolban.
A -s használatával további argumentumadatokat tekinthet meg
Talán észrevette, hogy a hibaüzenet második fele nem jelenik meg a fenti példakénti nyomon. Azért, mert Eztán alapértelmezetten csak a karakterlánc argumentum első 32 bájtja látható. Ha többet szeretne látni, adjon hozzá valami hasonlót -s 128 a hívásra Eztán.
-y megkönnyíti a fájlok, socketek stb. nyomon követését.
Az "All is file" azt jelenti, hogy a *nix rendszerek minden I/O-t fájlleírók segítségével hajtanak végre, függetlenül attól, hogy ez fájlra, hálózatra vagy folyamatközi csövekre vonatkozik. Ez kényelmes a programozáshoz, de megnehezíti annak nyomon követését, hogy mi is történik valójában, ha közös dolgokat látunk olvas и ír a rendszerhívás nyomkövetési eredményeiben.
Operátor hozzáadásával -y, erőltetni fogod Eztán a kimenetben minden fájlleíró megjegyzéssel jelölje meg, hogy mire mutat.
Csatolás egy már futó folyamathoz a -p** segítségével
Amint az alábbi példából látni fogja, néha egy már futó programot kell nyomon követnie. Ha ismert, hogy 1337-es folyamatként fut (mondjuk a kimenetről ps), akkor így követheti nyomon:
$ strace -p 1337
...system call trace output...
Szükség lehet root jogokra.
Az -f használatával figyelheti a gyermekfolyamatokat
Eztán Alapértelmezés szerint csak egy folyamatot követ. Ha ez a folyamat gyermekfolyamatokat hoz létre, akkor a gyermekfolyamat létrehozásához szükséges rendszerhívás látható, de az utódfolyamat rendszerhívásai nem jelennek meg.
Ha úgy gondolja, hogy a hiba egy gyermekfolyamatban van, használja az utasítást -f, ez lehetővé teszi a nyomkövetését. Ennek az a hátránya, hogy a kimenet még jobban megzavarja Önt. Amikor Eztán nyomon követ egy folyamatot vagy egy szálat, egyetlen hívási eseményfolyamot jelenít meg. Ha egyszerre több folyamatot nyomon követ, előfordulhat, hogy egy üzenet megszakítja a hívás kezdetét , majd - egy csomó hívás a többi végrehajtási ághoz, és csak ezután - az első vége <…fooccal resumed>. Vagy ossza fel az összes nyomkövetési eredményt különböző fájlokra, szintén az operátor használatával -ff (részletek itt
Nyomok szűrése a -e használatával
Amint látja, a nyomkövetés eredménye az összes lehetséges rendszerhívás valódi halma. Zászló -e Szűrheti a nyomot (lásd
Nem minden hiba rossz
Egy egyszerű és általános példa egy olyan program, amely egyszerre több helyen keres egy fájlt, például egy shell egy végrehajtható fájlt tartalmazó könyvtárat:
$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...
Az olyan heurisztika, mint az „utolsó sikertelen kérés a hiba bejelentése előtt”, jók a releváns hibák megtalálásában. Bárhogy is legyen, logikus a legvégéről kezdeni.
A C programozási oktatóanyagok segíthetnek megérteni a rendszerhívásokat.
A C-könyvtárak szabványos hívásai nem rendszerhívások, hanem csak egy vékony felületi réteg. Tehát, ha legalább egy kicsit megérti, hogyan és mit kell csinálni C-ben, akkor könnyebben megértheti a rendszerhívás nyomkövetésének eredményeit. Például problémái vannak a hálózati rendszerek hívásainak hibakeresésével, nézze meg ugyanazt a klasszikust
Egy bonyolultabb hibakeresési példa
Már mondtam, hogy az egyszerű hibakeresés példája egy példa arra, amivel leginkább foglalkoznom kell, amikor dolgozom Eztán. Néha azonban valódi vizsgálatra van szükség, ezért itt van egy valós példa a fejlettebb hibakeresésre.
# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
Oké, ez azt jelenti bcron megpróbált írni egy bizonyos fájlt, de nem sikerült, és nem ismeri el, miért. Felfedezés Eztán:
# strace -o /tmp/trace crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
# cat /tmp/trace
...
openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
read(3, "#Ansible: logsaggn20 14 * * * lo"..., 8192) = 150
read(3, "", 8192) = 0
munmap(0x7f82049b4000, 8192) = 0
close(3) = 0
socket(AF_UNIX, SOCK_STREAM, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
write(3, "156:Slogs #Ansible: logsaggn20 1"..., 161) = 161
read(3, "32:ZCould not create temporary f"..., 8192) = 36
munmap(0x7f82049b4000, 8192) = 0
close(3) = 0
write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49
unlink("bcrontab.14779.1573691864.847933") = 0
exit_group(111) = ?
+++ exited with 111 +++
Hibaüzenet jelenik meg a legvégén ír, de ezúttal valami más. Először is, nincs releváns rendszerhívási hiba, ami általában ez előtt következik be. Másodszor, egyértelmű, hogy valahol valaki már elolvasta a hibaüzenetet. Úgy tűnik, az igazi probléma valahol máshol van, és bcrontab egyszerűen lejátssza az üzenetet.
Ha megnézed férfi 2 olvas, láthatja, hogy az első argumentum (3) egy fájlleíró, amelyet a *nix minden I/O feldolgozáshoz használ. Honnan tudhatom meg, hogy a 3. fájlleíró melyiket jelöli? Ebben az esetben futhat Eztán kezelővel -y (lásd fent), és automatikusan megmondja, de az ehhez hasonló dolgok kiderítéséhez hasznos tudni, hogyan kell olvasni és elemezni a nyomkövetési eredményeket.
A fájlleíró forrása lehet egy a sok rendszerhívás közül (minden attól függ, hogy mire való a leíró – konzolra, hálózati socketre, maga a fájlra vagy valami másra), de akárhogy is legyen, keresünk 3-at visszaadva hív (azaz „= 3”-t keresünk a nyomkövetési eredményekben). Ebben az eredményben ezek közül kettő van: openat a legtetején és foglalat Középen. openat megnyitja a fájlt, de közel(3) ekkor azt mutatja, hogy újra bezárul. (Rake: a fájlleírók újrafelhasználhatók, amikor megnyitják és bezárják). Hívás foglalat() alkalmas, mert ez az utolsó olvas(), és kiderül, hogy a bcrontab aljzaton keresztül működik valamivel. A következő sor azt mutatja, hogy a fájlleíró hozzá van rendelve unix domain socket az út mentén /var/run/bcron-spool.
Tehát meg kell találnunk a kapcsolódó folyamatot unix foglalat a másik oldalon. Van néhány ügyes trükk erre a célra, mindkettő hasznos a szervertelepítések hibakereséséhez. Az első a használata netstat vagy újabb ss (aljzat állapota). Mindkét parancs megmutatja a rendszer aktív hálózati kapcsolatait, és átveszi az utasítást -l lehallgató aljzatok, valamint az operátor leírására -p a sockethez csatlakoztatott programok kliensként történő megjelenítéséhez. (Sokkal több hasznos lehetőség van, de ez a kettő elegendő ehhez a feladathoz.)
# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0 128 /var/run/bcron-spool 1466637 * 0 users:(("unixserver",pid=20629,fd=3))
Ez arra utal, hogy a hallgató a parancs inixszerver, amely 20629-es folyamatazonosítóval fut. (És véletlenül a 3. fájlleírót használja foglalatként.)
A második igazán hasznos eszköz ugyanazon információk megtalálására az ún lsof. Felsorolja az összes megnyitott fájlt (vagy fájlleírót) a rendszeren. Vagy kaphat információkat egy adott fájlról:
# lsof /var/run/bcron-spool
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
unixserve 20629 cron 3u unix 0x000000005ac4bd83 0t0 1466637 /var/run/bcron-spool type=STREAM
A Process 20629 egy hosszú élettartamú kiszolgáló, így csatlakoztatható Eztán valami hasonlót használva strace -o /tmp/trace -p 20629. Ha szerkeszt egy cron feladatot egy másik terminálon, akkor hibás nyomkövetési kimenetet fog kapni. És itt az eredmény:
accept(3, NULL, NULL) = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181
close(4) = 0
accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]}) = 43
accept(3, NULL, NULL) = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200
close(4) = 0
accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]}) = 43
accept(3, NULL, NULL
(Utolsó elfogad() nyomkövetéskor nem fejeződik be.) Ez az eredmény sajnos ismét nem tartalmazza a keresett hibát. Nem látunk olyan üzeneteket, amelyeket a bcrontag küld a socketnek, vagy fogad onnan. Ehelyett teljes folyamatvezérlés (klón, várj4, SIGCHLD stb.) Ez a folyamat egy gyermekfolyamatot szül, amely, ahogy sejthető, elvégzi az igazi munkát. És ha el kell találnia a nyomát, csatlakozzon a híváshoz strace -f. Ezt fogjuk megtalálni, ha az új eredményben a hibaüzenetre keresünk a strace segítségével -f -o /tmp/trace -p 20629:
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111) = ?
21470 +++ exited with 111 +++
Na, ez már valami. A 21470-es folyamat "hozzáférés megtagadva" hibát kap, amikor fájlt próbál létrehozni az elérési úton tmp/spool.21470.1573692319.854640 (az aktuális munkakönyvtárhoz kapcsolódóan). Ha ismernénk az aktuális munkakönyvtárat, akkor a teljes elérési utat is ismernénk, és ki tudnánk találni, hogy a folyamat miért nem tudja abban létrehozni az ideiglenes fájlt. Sajnos a folyamat már befejeződött, így nem lehet csak úgy használni lsof -p 21470 az aktuális címtár megtalálásához, de az ellenkező irányba is dolgozhat - keresse meg a PID 21470 rendszerhívásokat, amelyek megváltoztatják a címtárat. (Ha nincsenek ilyenek, akkor a 21470-es PID biztosan a szülőjétől örökölte őket, és ez már megtörtént lsof -p nem lehet kideríteni.) Ez a rendszerhívás az chdir (amit a modern online keresők segítségével könnyű kideríteni). És itt van a fordított keresések eredménye a nyomkövetési eredmények alapján, egészen a 20629-es szerver PID-ig:
20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470
...
21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0
...
21470 chdir("/var/spool/cron") = 0
...
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111) = ?
21470 +++ exited with 111 +++
(Ha eltévedtél, érdemes elolvasnod az előző bejegyzésemet
# ls -ld /var/spool/cron/tmp/
drwxr-xr-x 2 root root 4096 Nov 6 05:33 /var/spool/cron/tmp/
# ps u -p 20629
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
cron 20629 0.0 0.0 2276 752 ? Ss Nov14 0:00 unixserver -U /var/run/bcron-spool -- bcron-spool
Ott van a kutya elásva! A szerver cron felhasználóként fut, de csak a root jogosult a könyvtárba írni /var/spool/cron/tmp/. Egyszerű parancs chown cron /var/spool/cron/tmp/ akaraterő bcron megfelelően működjön. (Ha nem ez volt a probléma, akkor a következő legvalószínűbb gyanúsított egy kernel biztonsági modul, például a SELinux vagy az AppArmor, ezért ellenőrizném a kernel üzenetnaplóját dmesg.)
Összességében
A rendszerhívások nyomkövetése elsöprő erejű lehet egy kezdő számára, de remélem, megmutattam, hogy ezek egy gyors módja a gyakori telepítési problémák egész osztályának hibakeresésének. Képzelje el, hogy megpróbál hibakeresni egy többfolyamatot bcronlépésenkénti hibakereső segítségével.
A nyomkövetési eredmények visszafelé elemzése a rendszerhívási lánc mentén szakértelmet igényel, de mint mondtam, szinte mindig a használata Eztán, csak megkapom a nyomkövetési eredményt, és a végétől kezdve keresem a hibákat. Akárhogyan is, Eztán segít sok időt megtakarítani a hibakeresés során. Remélem neked is hasznos lesz.
Forrás: will.com