HÀÀlestame tarkvara juurutamist strace'iga

HÀÀlestame tarkvara juurutamist strace'iga

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?

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 (DTrace vĂ”i ktrace).

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 +++

Mis on sĂŒsteemikutsed? Need on midagi, mis meenutab API-d operatsioonisĂŒsteemi tuumale. Kunagi oli tarkvaral otse juurdepÀÀs „raudi“ (hardware), millel see töötas. NĂ€iteks kui tuli midagi ekraanile kuvada, mĂ€ngiti otse portidega vĂ”i mĂ€lu videotahveldega. Kui mitme ĂŒlesande töötlemise sĂŒsteemid hakkasid populaarsust koguma, pöördus korratus, sest erinevad rakendused kiskusid „rauda“ (hardware) enda poole. Vigade tegemine ĂŒhes rakenduses vĂ”is kraanida teiste tööd, kui mitte kogu sĂŒsteemi kokku. Siis ilmusid CPU-sse privileegireĆŸiimid (vĂ”i „ringkaitse“). KĂ”ige privileege saanud oli tuum: talle anti tĂ€ielik juurdepÀÀs „raudi“ (hardware), luues vĂ€hem privileege saanud rakendusi, mis pidid juba tuumalt juurdepÀÀsu kĂŒsima, et suhelda „raudadega“ — lĂ€bi sĂŒsteemikutsede.

Binaartasandil erineb sĂŒsteemikutse veidi tavalise funktsiooni kutsest, kuid enamik programme kasutab standardkirjastoote ĂŒmberpakendust. See tĂ€hendab, et POSIX C standardne raamatukogu sisaldab funktsiooni kutset write(), mis sisaldab kĂ”iki arhitektuurist sĂ”ltuvaid koode sĂŒsteemikutsest write.

HÀÀlestame tarkvara juurutamist strace'iga

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 ltrace 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 leidunud

Ilmselt 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
Konfiguratsioonifaili avanemine ebaÔnnestus: Sellist faili vÔi kausta ei leitud
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 muutujat */) = 0
brk(NULL)                               = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Sellist faili vÔi kausta ei leitud)
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 (Sellist faili vÔi kausta ei leitud)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x2 (lipud O_RDWR)
brk(NULL)                               = 0x56363b3fb000
brk(0x56363b41c000)                     = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Konfiguratsioonifaili avanemine ebaÔnnestus"..., 60) = 60
close(3)                                = 0
exit_group(1)                           = ?
+++ lahkus 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 juhendist 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. juhend 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 „Guide to Network Programming“ von Bidg.

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.

bcron — ĂŒ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 file

Noh, 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=STREAM

Protsess 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 nix-protsessi ja shellide haldamise kohta.) 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-spool

Siin 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

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster