
Minu peamine töö on enamasti tarkvarasüsteemide juurutamine, mis tähendab, et kulutan palju aega sellistele küsimustele vastamisele:
- Arendajal töötab see tarkvara, aga mul ei toimi. Miks?
- Eile töötas see tarkvara mul, aga täna enam ei toimi. Miks?
See on teatud tüüpi tõrkeotsing, mis erineb tavalisest tõrkeotsingust. Tavaline tõrkeotsing keskendub koodi loogikale, samas kui juurutamise tõrkeotsing puudutab koodi ja keskkonna koostööd. Isegi kui probleemi juur on loogiline viga, asjaolu, et ühel masinal kõik töötab ja teisel mitte, tähendaks, et probleem on kuidagi keskkonnas.
Seetõttu on mul tavalisest tõrkeotsingu tööriistade komplektist erinev komplekt juurutamise tõrkeotsingu tööriistu. gdb Ja mu lemmik tööriist probleemi lahendamiseks, näiteks "Miks see tarkvara ei toimi?" nimetatakse strace.
Mis on strace?
— see on "süsteemikutsunge jälgimise" tööriist. See loodi algselt Linuxile, kuid samu tõrkeotsingu nippe saab teha ka teiste süsteemide tööriistadega ( või ).
Peamine rakendus on väga lihtne. Piisab, kui käivitada strace mistahes käsuga, ja see saadab kõik süsteemi kutsed mällu (kuigi esmalt tuleb tõenäoliselt see installida) strace):
$ strace echo Hello
...Snip lots of stuff...
write(1, "Hellon", 6) = 6
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++Что это за системные вызовы? Это нечто вроде API для ядра операционной системы. Давным-давно у ПО был прямой доступ к «железу», на котором оно работало. Если, например, нужно было отобразить что-нибудь на экране, оно играло с портами иили отображаемыми в память регистрами для видео-устройств. Когда стали популярны многозадачные компьютерные системы, воцарился хаос, потому что различные приложения дрались за «железо». Ошибки в одном приложении могли обрушить работу прочих, если не всю систему целиком. Тогда в ЦПУ появились режимы привилегий (или «кольцевая защита»). Самым привилегированным становилось ядро: оно получало полный доступ к «железу», плодя менее привилегированные приложения, которым уже приходилось запрашивать доступ у ядра для взаимодействия с «железом» — через системные вызовы.
На бинарном уровне системный вызов немного отличается от простого вызова функции, однако большинство программ используют обертку в стандартной библиотеке. Т.е. стандартная библиотека POSIX C содержит вызов функции write(), которая содержит весь зависящий от архитектуры код для системного вызова write.

Lühidalt öeldes toimub iga rakenduse suhtlemine oma keskkonnaga (arvutisüsteemidega) süsteemikutsed kaudu. Seetõttu, kui tarkvara töötab ühes masinas, aga mitte teises, on mõistlik vaadata süsteemikõnede jälgimise tulemusi. Täpsemalt, siin on nimekiri tüüpilistest punktidest, mida saab analüüsida süsteemikõne jälgimise abil:
- Konsoli sisend-väljund
- Võrgu sisend-väljund
- Failisüsteemi ja failide sisend-väljund
- Protsessi/uurimisaegade haldamine
- Madala taseme mäluhaldus
- Kuidas kasutada spetsiaalsete seadmete draivereid
Millal kasutada strace'i?
Teoreetiliselt, strace kui kasutatakse kõigi kasutaja ruumis olevate programmidega, sest iga programm kasutaja ruumis peab tegema süsteemikõnesid. See töötab tõhusamalt kompileeritud, madala taseme programmidega, kuid töötab ka kõrge taseme keeltes, nagu Python, kui suudate läbi murda täitekeskkonna ja tõlgendi lisakõnede müra.
Kõik oma hiilguses strace näitab end siis, kui tõrkeotsing toimub tarkvaras, mis töötab hästi ühel masinal, kuid teisel äkki enam ei tööta, andes häguseid teateid failidest, õigustest või nurjunud katsetest teatud käsklusi täita või midagi muud... Kahju, kuid see ei sobi väga hästi kõrge taseme probleemidega nagu sertifikaadi kontrollimise viga. Tavaline on, et siinkohal on vajalik kombinatsioon strace, mõnikord ja kõrgema taseme tööriistu (näiteks käsurea tööriista openssl sertifikaadi tõrkeotsingu jaoks).
Võtame näiteks töö isoleeritud serveris, kuid süsteemikutsungite jälgimist saab sageli teha ka keerukamatel juurutamisplatvormidel. Lihtsalt tuleb valida sobiv tööriistakomplekt.
Lihtsa tõrkeotsingu näide
Oletame, et soovite käivitada suurepärast serveri rakendust foo, aga tulemuseks on järgmine:
$ foo
Veakäivitamine konfiguratsioonifailist: sellist faili või katalooge ei leidunudIlmselt ei õnnestunud tal leida teie kirjutatud konfigfaili. Nii juhtub, kuna mõnikord kolmandate osapoolte paketihaldurid, rakendust kompileerides, ületavad oodatud failide asukohad. Kui jälgida installatsioonijuhendit ühe distributsiooni jaoks, leiad teise puhul failid täiesti ebasobivates kohtades. Probleemi lahendamine võinuks võtta vaid paar sekundit, kui veateade näitaks, kus konfguratsioonifaili otsida, kuid see ei ütle seda. Niisiis, kust otsida?
Kui lähtekoodile on juurdepääs, siis saab seda lugeda ja kõik välja selgitada. Hea päästeplaan, kuid mitte kõige kiirem lahendus. Võib kasutada samm-sammulist siluri nagu gdb ja vaadata, mida programm teeb, kuid palju efektiivsem on kasutada tööriista, mis on spetsiaalselt loodud keskkonnaga suhtlemise näitamiseks: strace.
Kokkuvõte strace see võib tunduda üleliigne, kuid hea uudis on see, et suure osa sellest võib julgelt ignoreerida. Sageli on kasulik kasutada -o operaatorit, et salvestada jälgimistulemused eraldi faili:
$ 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 +++Umbes kogu esimene väljundi leht strace — see on tavaliselt madala taseme ettevalmistus käivitamiseks. (Palju kutsunge mmap, mprotect, brk madala taseme mälu avastamise ja dünaamiliste raamatukogude kuvamise asjade jaoks.) Üldiselt on tõrgete jälgimise ajal väljundid strace parim lugeda lõpust. Allpool on kutsung write, mis väljastab tõrke sõnumi. Vaadates ülespoole, näeme esimest vigasemat süsteemi openat, mis väljastab tõrke ENOENT ("faili või katalooge ei leitud"), mis püüdis avada /etc/foo/config.json. Siin peaks olema konfiguratsioonifail.
See oli lihtsalt näide, kuid ütleksin, et 90% ajast, kui ma kasutan strace, pole midagi oluliselt keerulisemat teha. Allpool on täielik samm-sammuline juhend tõrgete jälgimiseks:
- Ärritada ennast ebamugava system-y veateatega programmilt
- Taaskäivitage programm koos strace
- Otsige jälgimistulemustest veateade
- Liikuge üles, kuni jõuate esimese ebaõnnestunud süsteemi kutsungini
On väga tõenäoline, et 4. sammu süsteemi kutsung näitab, mis valesti läks.
Näpunäited
Enne kui näitan keerukama tõrkeotsingu näidet, avanen teile mõned nipid efektiivseks kasutamiseks strace:
man — teie sõber
Paljuski *nix süsteemides saad täisteema nimekirja tuumakutsest alates, käivitades man syscalls. Näed asju nagu brk(2), mis tähendab, et rohkem teavet saadakse, kui käivitada man 2 brk.
Mõned väiksed komistuskivid: man 2 fork näitab mulle lehte shell'i kohta fork() ühes GNU libc, mis, nagu selgub, on rakendatud kutsega clone(). Kutse semantika fork on sama, kui kirjutada programm, mis kasutab fork(), ja käivitada jälgimine — ma ei leia kutseid fork, nende asemel on clone(). Sellised komistuskivid segavad, kui hakata võrdlema lähtekoodi väljastusega strace.
Kasutage -o, et salvestada väljund faili
strace võib genereerida ulatuslikku väljundit, seega on sageli kasulik salvestada jälgimise tulemused eraldi failidesse (nagu eespool toodud näites). See aitab ka mitte segi ajada programmiväljundit väljundiga strace konsoolis.
Kasutage -s, et vaadata rohkem argumentide andmeid
Olete tõenäoliselt tähele panud, et veateate teine pool ei ole antud eespool toodud jälgimises. See on sellepärast, et strace vaikimisi näitab see ainult stringi argumendi esimesed 32 baiti. Kui soovite näha rohkem, tehke midagi sellist nagu -s 128 kutses strace.
-u lihtsustab failide jälgimist, soketite jne.
„Kõik on fail“ tähendab, et *nix süsteemid teostavad kogu sisend-väljundit, kasutades failide descriptor'e, olenemata sellest, kas tegemist on faili, võrgu või vaheprotsesside kanalitega. See on mugav programmeerimise jaoks, kuid segab jälgimist, mis tegelikult toimub, kui näete üldisi read ja write süsteemi kutsumise jälgimise tulemusi.
Lisades operaatori -u, panete strace iga failide deskriptorit annotatsiooni, mis näitab, kuhu see osutab.
Kinnitage juba käimasoleva protsessiga -p**
Nagu allpool näidatud näites, on mõnikord vajalik jälgida programmi, mis juba käib. Kui teate, et see töötab protsessina 1337 (ütleme, et väljunditest ps), siis võite seda jälgida järgmiselt:
$ strace -p 1337
...süsteemi külje jälgimise väljund...Võib-olla vajate root õigusi.
Kasutage -f, et jälgida alame protsesse.
strace vaikimisi jälgib see ainult ühte protsessi. Kui see protsess loob lapsprotsesse, siis on näha süsteemi kutsung lapseprotsessi loomiseks, kuid lapseprotsessi süsteemi kutsungid ei kajastu.
Kui arvate, et viga on lapsprotsessis, kasutage käsku -f, see aktiveerib selle jälgimise. Selle miinus on see, et väljund on veel segasem. Kui strace järgib ühte protsessi või ühte haru, siis näitab see ühtset sündmuste voogu kutsungitest. Kui see jälgib kohe mitut protsessi, võib teil olla näha kutse algust, mis on katkenud sõnumiga <unfinished …>, siis järgneb hulk kutseid teiste täitmisokside jaoks ning alles seejärel - esimese lõpp <… foocall resumed>. Või jagage kõik jälgimise tulemused erinevatesse failidesse, kasutades ka käsku -ff (details — in kohta strace).
Filtreerige jälgimist -e abil
Nagu te näete, on jälgimise tulemus tegelik hulk kõiki võimalikke süsteemi kutsungeid. Flagi abil -e saab jälgimist filtreerida (vt. kohta strace). Peamine eelis on see, et jälgimist filtreerimisega on kiirem käivitada kui teha täielikku jälgimist ja siis grep`ole. Aus ehrlich gesagt, ist mir das fast immer egal.
Nicht alle Fehler sind schlecht
Ein einfaches und häufiges Beispiel ist ein Programm, das an mehreren Orten nach einer Datei sucht, wie eine Shell, die sucht, wo die ausführbare Datei im Papierkorbverzeichnis enthalten ist:
$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...Heuristik wie „der letzte fehlgeschlagene Aufruf vor der Fehlermeldung“ ist nützlich, um relevante Fehler zu finden. Wie auch immer, es ist sinnvoll, am Ende zu beginnen.
Die Systemaufrufe werden gut durch C-Programmierhandbücher unterstützt.
Standardbibliotheksaufrufe in C sind keine Systemaufrufe, sondern nur eine dünne oberflächliche Schicht. Wenn Sie also auch nur ein wenig verstehen, wie und was in C zu tun ist, wird es Ihnen leichter fallen, die Ergebnisse des Systemaufruf-Trace zu verstehen. Wenn Sie zum Beispiel Probleme beim Debuggen von Netzwerkaufrufen haben, schauen Sie sich das klassische .
Beispiel für anspruchsvolleres Debugging
Ma olen juba öelnud, et lihtne silumine on näide sellest, millega ma enamasti töötan, kui tegelen strace. Siiski nõuab aeg-ajalt tõelist uurimistööd, nii et siin on teile reaalsem ja keerulisem silumisnäide.
— ülesannete planeerija, veel üks *nix deemonite teostus cron. See on serverisse installitud, kuid kui keegi üritab graafikut muuta, juhtub järgmine:
# crontab -e -u logs
bcrontab: Fatal: Could not create temporary fileNoh, bcron ta üritas kirjutada mingit faili, kuid tal ei õnnestunud ning ta ei tunnista, miks. Vaadates strace:
# 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 +++Peaaegu lõpus on veaaste write, kuid seekord on midagi erinevat. Esiteks pole asjakohast süsteemikõne viga, mis tavaliselt enne seda juhtub. Teiseks on näha, et keegi on juba veateate lugenud. Tundub, et tegelik probleem on kuskil mujal, ja bcrontab lihtsalt reprodutseerib sõnumi.
Kui vaadata man 2 read, siis saab näha, et esimene argument (3) on failikirjeldaja, mida *nix kasutab kõigi sisendi ja väljundi töötlemiseks. Kuidas teada saada, mida failikirjeldaja 3 esindab? Antud juhul saab käivitada strace käsklusega -u (vt. ülal), ja see räägib ise, kuid selliste asjade arvutamiseks on kasulik teada, kuidas jälgimise tulemusi lugeda ja analüüsida.
Faili deskriptorite allikaks võib olla üks paljusid süsteemikõnesid (kõik sõltub sellest, mille jaoks deskriptor on — kas konsooli, võrgusoketi, faili või millegi muu jaoks), kuid igal juhul otsime kõnesid, tagastades 3 (st otsime "= 3" jälgimise tulemustes). Selles tulemuses on neid 2: openat ülemises osas ja socket keskel. openat avaneb fail, kuid close(3) näitab see pärast, et see suletakse uuesti. (Kübarad: faili deskriptorit võib taaskasutada, kui neid avatakse ja sulgetakse). Kõne socket() sobib, kuna see on viimane enne read(), ja selgub, et bcrontab töötab millegi kaudu soketi peal. Järgmine rida näitab, et faili deskriptor on seotud unix domain socket teel /var/run/bcron-spool.
Nii et peame leidma protsessi, mis on seotud unix socket teisel pool. Selleks on paar elegantselt trikki, ja mõlemad on kasulikud serveri juurutuste tõrkeotsimiseks. Esimene — kasutada netstat või uuemat ss (socket status). Mõlemad käsud näitavad süsteemi aktiivseid võrguühendusi ja võtavad operaatori -l kuulavate sokettide kirjeldamiseks ning operaatori -p näitamiseks programme, mis on soketi kaudu kliendiks ühendatud. (Kasulikke valikuid on palju rohkem, kuid selle ülesande jaoks piisab ka neist kahest.)
# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0 128 /var/run/bcron-spool 1466637 * 0 users:(("unixserver",pid=20629,fd=3))See näitab, et kuulav - see on käsk inixserver, mis töötab protsessi ID-ga 20629. (Ja juhuslikult kasutab ta soketina failideskriptorit 3.)
Teine tõeliselt kasulik tööriist sama teabe leidmiseks on lsof. See loetleb kõik avatud failid (või failideskriptorid) süsteemis. Või võib saada teavet ühe konkreetse faili kohta:
# 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=STREAMProtsess 20629 on pikaajaline server, nii et sellele võib kinnitada strace midagi sellist nagu strace -o /tmp/trace -p 20629. Kui cron-tööd redigeerida teises terminalis - saame jooksvate vigade jälgimise tulemuse. Siin on tulemus:
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 (Käivitada, kui SA_RESTART on seadistatud)
--- 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 (Ei ole lapsprotsesse)
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 (Käivitada, kui SA_RESTART on seadistatud)
--- 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 (Ei ole lapsprotsesse)
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(Viimane accept() ei lõpetata jälgimise ajal.) Ja kahjuks ei sisalda see tulemus viga, mida me otsime. Me ei näe ühtegi sõnumit, mida bcrontag oleks saatnud socketile või sellest vastu võtnud. Selle asemel on pidev protsessi haldamine (clone, wait4, SIGCHLD ja muud.) See protsess genereerib alamprotsessi, mis, nagu arvata võib, teostab tegelikku tööd. Ja kui on vaja selle jälge tabada, lisage kutsungile strace -f. Siit leiame, otsides uue tulemuse vigade sõnumit strace'iga -f -o /tmp/trace -p 20629:
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Luba keeldus)
21470 write(1, "32:ZEi suutnud luua ajutist f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logid:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (Sellist faili või katalooge ei leitud)
21470 exit_group(111) = ?
21470 +++ lahkus 111 +++Siin on juba parem. Protsess 21470 saab „juurdepääs keeldus” vea proovides luua faili teel tmp/spool.21470.1573692319.854640 (seoses praeguse töökaustaga). Kui me lihtsalt teaksime, mis on praegune töökaust, siis teaksime ka täielikku teed ja suudaksime välja selgitada, miks protsess ei saa seal oma ajutist faili luua. Kahjuks on protsess juba lõpetatud, seega ei saa lihtsalt kasutada lsof -p 21470 et leida praegust kausta, kuid saame töötada vastupidises suunas - otsida süsteemikõnesid PID 21470, mis muudavad kausta. (Kui selliseid ei ole, siis PID 21470 on need ilmselt vanemalt pärinud, ja see on juba läbi lsof -p ei saa välja selgitada.) See süsteemikõne on chdir (mida pole raske välja selgitada tänapäevaste võrgupõhiste otsingumootorite abil). Siin on tagasipöörde otsingute tulemused, ulatudes serverisse PID 20629:
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 +++(Kui te ei tea, kuhu minna, siis tasub võib-olla lugeda minu eelmist postitust .) Nii et server PID 20629 ei saanud luba luua faili teel /var/spool/cron/tmp/spool.21470.1573692319.854640. Tõenäoliselt on selle põhjuseks klassikalised failisüsteemi õiguste seadistused. Kontrollime:
# 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-spoolSiin ongi probleem! Server töötab kasutajate cronina, kuid vaid rootil on õigus kirjutada katalooge /var/spool/cron/tmp/. Lihtne käsk chown cron /var/spool/cron/tmp/ saab bcron õigesti töötama. (Kui probleem ei olnud selles, siis järgmine tõenäoliselt kahtlustatav on SELinuxi või AppArmori tüüpi tuumaturvMoodul, seega kontrolliksin tuumarakenduse logisid kasutades dmesg.)
Kokku
Algaja võib süsteemi kutsete jälitamise tulemustes ekselda, kuid ma loodan, et olen näidanud, et need on kiire viis terve klassi levinud juurutamise probleemide tõrkeotsimiseks. Kujutage ette, kuidas üritate tõrkeotsingut teha mitme protsessoriga bcron, kasutades samm-sammult tõrkeotsijat.
Tagasiviivult jälitusandmete analüüsimine süsteemi kutsete ahelas nõuab oskust, kuid nagu ma juba ütlesin, peaaegu alati, kasutades strace, ma lihtsalt saan jälgimiseresultaatide ning otsin vigu, alustades lõpust. Igatahes, strace aitab mul säästa tohutult aega silumise pealt. Loodan, et see on kasulik ka teile.
Allikas: habr.com
