Mans ikdienas darbs galvenokÄrt ir programmatÅ«ras izvietoÅ”ana, kas nozÄ«mÄ, ka es pavadu daudz laika, mÄÄ£inot atbildÄt uz tÄdiem jautÄjumiem kÄ:
- Å Ä« programmatÅ«ra darbojas izstrÄdÄtÄjam, bet ne man. KÄpÄc?
- Vakar Ŕī programmatÅ«ra man darbojÄs, bet Å”odien tÄ nedarbojas. KÄpÄc?
Å Ä« ir sava veida atkļūdoÅ”ana, kas nedaudz atŔķiras no parastÄs programmatÅ«ras atkļūdoÅ”anas. RegulÄra atkļūdoÅ”ana ir saistÄ«ta ar koda loÄ£iku, bet izvietoÅ”anas atkļūdoÅ”ana ir saistÄ«ta ar mijiedarbÄ«bu starp kodu un vidi. Pat ja problÄmas sakne ir loÄ£iska kļūda, tas, ka vienÄ maŔīnÄ viss darbojas, bet citÄ ne, nozÄ«mÄ, ka problÄma ir kaut kÄdÄ veidÄ vidÄ.
TÄtad parasto atkļūdoÅ”anas rÄ«ku vietÄ, piemÄram, gdb Man ir cits rÄ«ku komplekts izvietoÅ”anas atkļūdoÅ”anai. Un mans iecienÄ«tÄkais rÄ«ks tÄdas problÄmas risinÄÅ”anai kÄ āKÄpÄc Ŕī programmatÅ«ra man nedarbojas?ā sauca strace.
Kas ir strace?
Pamata lietojumprogramma ir ļoti vienkÄrÅ”a. Jums vienkÄrÅ”i jÄpalaiž strace ar jebkuru komandu un tas izmetÄ«s visus sistÄmas izsaukumus (lai gan vispirms jums tas bÅ«s jÄinstalÄ paÅ”am 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 +++
KÄdi ir Å”ie sistÄmas izsaukumi? Tas ir kaut kas lÄ«dzÄ«gs API operÄtÄjsistÄmas kodolam. KÄdreiz programmatÅ«rai bija tieÅ”a piekļuve aparatÅ«rai, kurÄ tÄ darbojÄs. Ja, piemÄram, tai vajadzÄja kaut ko parÄdÄ«t ekrÄnÄ, tas spÄlÄja ar video ierÄ«Äu portiem vai atmiÅas kartÄtiem reÄ£istriem. Kad daudzuzdevumu datorsistÄmas kļuva populÄras, valdÄ«ja haoss, kad dažÄdas lietojumprogrammas cÄ«nÄ«jÄs par aparatÅ«ru. Kļūdas vienÄ lietojumprogrammÄ var sabojÄt citas, ja ne visu sistÄmu. Tad CPU parÄdÄ«jÄs privilÄÄ£iju režīmi (vai āzvana aizsardzÄ«baā). Kodols kļuva par priviliÄ£ÄtÄko: tas saÅÄma pilnu piekļuvi aparatÅ«rai, radot mazÄk priviliÄ£Ätas lietojumprogrammas, kurÄm jau bija jÄpieprasa piekļuve no kodola, lai mijiedarbotos ar aparatÅ«ru, izmantojot sistÄmas izsaukumus.
BinÄrajÄ lÄ«menÄ« sistÄmas izsaukums nedaudz atŔķiras no vienkÄrÅ”as funkcijas izsaukuma, taÄu lielÄkÄ daļa programmu standarta bibliotÄkÄ izmanto iesaiÅojumu. Tie. POSIX C standarta bibliotÄka satur funkcijas izsaukumu rakstÄ«t (), kurÄ ir viss sistÄmas izsaukuma arhitektÅ«rai raksturÄ«gais kods rakstÄ«t.
ÄŖsÄk sakot, jebkura mijiedarbÄ«ba starp lietojumprogrammu un tÄs vidi (datorsistÄmÄm) tiek veikta, izmantojot sistÄmas izsaukumus. TÄpÄc, ja programmatÅ«ra darbojas vienÄ maŔīnÄ, bet ne citÄ, bÅ«tu labi apskatÄ«t sistÄmas zvanu izsekoÅ”anas rezultÄtus. KonkrÄtÄk, Å”eit ir saraksts ar tipiskiem punktiem, kurus var analizÄt, izmantojot sistÄmas izsaukuma izsekoÅ”anu:
- Konsoles I/O
- TÄ«kla I/O
- Piekļuve failu sistÄmai un failu I/O
- Procesa pavediena kalpoÅ”anas laika pÄrvaldÄ«ba
- Zema lÄ«meÅa atmiÅas pÄrvaldÄ«ba
- Piekļuve konkrÄtiem ierÄ«Äu draiveriem
Kad lietot strace?
TeorÄtiski, strace izmanto ar jebkuru programmu lietotÄja telpÄ, jo jebkurai programmai lietotÄja telpÄ ir jÄveic sistÄmas izsaukumi. Tas darbojas efektÄ«vÄk ar kompilÄtÄm zema lÄ«meÅa programmÄm, taÄu tas darbojas arÄ« ar augsta lÄ«meÅa valodÄm, piemÄram, Python, ja varat samazinÄt izpildlaika un tulka papildu troksni.
VisÄ krÄÅ”ÅumÄ strace izpaužas programmatÅ«ras atkļūdoÅ”anas laikÄ, kas labi darbojas vienÄ maŔīnÄ, bet pÄkÅ”Åi pÄrstÄj darboties citÄ, producÄjot neskaidrus ziÅojumus par failiem, atļaujÄm vai neveiksmÄ«giem mÄÄ£inÄjumiem izpildÄ«t kÄdas komandas vai ko citu... ŽÄl, bet tÄ nav tik labi apvienotas ar augsta lÄ«meÅa problÄmÄm, piemÄram, sertifikÄtu pÄrbaudes kļūdÄm. Parasti tas prasa kombinÄciju stracedažreiz
KÄ piemÄru izmantosim atseviŔķu serveri, taÄu sistÄmas zvanu izsekoÅ”anu bieži var veikt sarežģītÄkÄs izvietoÅ”anas platformÄs. Jums vienkÄrÅ”i jÄizvÄlas pareizie instrumenti.
VienkÄrÅ”s atkļūdoÅ”anas piemÄrs
PieÅemsim, ka vÄlaties palaist apbrÄ«nojamo servera lietojumprogrammu foo, un tas ir tas, ko jÅ«s galu galÄ sasniedzat:
$ foo
Error opening configuration file: No such file or directory
AcÄ«mredzot tas nevarÄja atrast jÅ«su rakstÄ«to konfigurÄcijas failu. Tas notiek tÄpÄc, ka dažreiz, kad pakotÅu pÄrvaldnieki apkopo lietojumprogrammu, viÅi ignorÄ paredzÄtÄs failu atraÅ”anÄs vietas. Un, ja sekojat viena izplatÄ«Å”anas instalÄÅ”anas rokasgrÄmatai, citÄ jÅ«s atradÄ«sit failus, kas pilnÄ«gi atŔķiras no tÄ, kur jÅ«s gaidÄ«jÄt. ProblÄmu varÄtu atrisinÄt dažu sekunžu laikÄ, ja kļūdas ziÅojumÄ ir norÄdÄ«ts, kur meklÄt konfigurÄcijas failu, bet tÄ nav. TÄtad, kur meklÄt?
Ja jums ir piekļuve avota kodam, varat to izlasÄ«t un uzzinÄt visu. Labs rezerves plÄns, bet ne ÄtrÄkais risinÄjums. Varat izmantot soli pa solim atkļūdotÄju, piemÄram, gdb un redzÄt, ko programma dara, taÄu daudz efektÄ«vÄk ir izmantot rÄ«ku, kas ir Ä«paÅ”i izstrÄdÄts, lai parÄdÄ«tu mijiedarbÄ«bu ar vidi: strace.
secinÄjums strace var Ŕķist lieki, taÄu labÄ ziÅa ir tÄ, ka lielÄko daļu no tÄ var droÅ”i ignorÄt. Bieži vien ir lietderÄ«gi izmantot operatoru -o, lai saglabÄtu izsekoÅ”anas rezultÄtus atseviÅ”Ä·Ä failÄ:
$ 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 +++
ApmÄram visa izvades pirmÄ lapa strace - TÄ parasti ir zema lÄ«meÅa sagatavoÅ”anÄs palaiÅ”anai. (Daudz zvanu mmap, mprotect, spalviÅa tÄdÄm lietÄm kÄ zema lÄ«meÅa atmiÅas noteikÅ”ana un dinamisko bibliotÄku parÄdÄ«Å”ana.) Faktiski atkļūdoÅ”anas laikÄ izvade strace LabÄk lasÄ«t no paÅ”Äm beigÄm. ZemÄk bÅ«s izaicinÄjums rakstÄ«t, kas parÄda kļūdas ziÅojumu. MÄs skatÄmies augÅ”Ä un redzam pirmo kļūdaino sistÄmas zvanu - zvanu openat, kas rada kļūdu ENOENT (āfails vai direktorijs nav atrastsā), mÄÄ£inot atvÄrt /etc/foo/config.json. Å eit ir jÄatrodas konfigurÄcijas failam.
Å is bija tikai piemÄrs, bet es teiktu, ka 90% laika izmantoju strace, nav nekÄ daudz grÅ«tÄk izdarÄma par Å”o. TÄlÄk ir sniegts pilnÄ«gs soli pa solim atkļūdoÅ”anas ceļvedis:
- Esiet satraukts, jo programmÄ parÄdÄs neskaidrs ziÅojums par sistÄmas y kļūdu
- RestartÄjiet programmu ar strace
- IzsekoÅ”anas rezultÄtos atrodiet kļūdas ziÅojumu
- Dodieties augstÄk, lÄ«dz sasniedzat pirmo neveiksmÄ«go sistÄmas zvanu
Ä»oti iespÄjams, ka sistÄmas izsaukums 4. darbÄ«bÄ atklÄs, kas nogÄja greizi.
Padomi
Pirms parÄdÄ«Å”u sarežģītÄkas atkļūdoÅ”anas piemÄru, es parÄdÄ«Å”u dažus trikus efektÄ«vai lietoÅ”anai strace:
vīrietis ir tavs draugs
DaudzÄs *nix sistÄmÄs, palaižot, var iegÅ«t pilnu sistÄmas izsaukumu sarakstu kodolam vÄ«rietis syscalls. JÅ«s redzÄsit tÄdas lietas kÄ brk (2), kas nozÄ«mÄ, ka vairÄk informÄcijas var iegÅ«t, palaižot vÄ«rietis 2 brk.
Mazs grÄbeklis: cilvÄks 2 dakÅ”a parÄda man Äaulas lapu dakÅ”a () Š² GNU libc, kas, izrÄdÄs, tiek Ä«stenots zvanot klons (). Zvanu semantika dakÅ”a paliek nemainÄ«gs, ja rakstÄt programmu, izmantojot dakÅ”a (), un izsekot ā es neatradÄ«Å”u nevienu zvanu dakÅ”a, viÅu vietÄ bÅ«s klons (). Å Ädi grÄbekļi jÅ«s mulsina tikai tad, ja sÄkat salÄ«dzinÄt avotu ar izvadi strace.
Izmantojiet -o, lai saglabÄtu izvadi failÄ
strace var radÄ«t plaÅ”u izvadi, tÄpÄc bieži vien ir lietderÄ«gi izsekoÅ”anas rezultÄtus saglabÄt atseviŔķos failos (kÄ iepriekÅ” minÄtajÄ piemÄrÄ). Tas arÄ« palÄ«dz nesajaukt programmas izvadi ar izvadi strace konsolÄ.
Izmantojiet -s, lai skatÄ«tu vairÄk argumentu datu
IespÄjams, pamanÄ«jÄt, ka kļūdas ziÅojuma otrÄ puse nav parÄdÄ«ta iepriekÅ” minÄtajÄ piemÄrÄ. Tas ir tÄpÄc strace pÄc noklusÄjuma tiek rÄdÄ«ti tikai pirmie 32 virknes argumenta baiti. Ja vÄlaties redzÄt vairÄk, pievienojiet kaut ko lÄ«dzÄ«gu -s 128 uz zvanu strace.
-y atvieglo failu, ligzdu utt. izsekoŔanu.
āViss ir failsā nozÄ«mÄ, ka *nix sistÄmas veic visus I/O, izmantojot failu deskriptorus, neatkarÄ«gi no tÄ, vai tas attiecas uz failu vai tÄ«klu vai starpprocesu caurulÄm. Tas ir Ärti programmÄÅ”anai, taÄu apgrÅ«tina izsekot tam, kas patiesÄ«bÄ notiek, kad redzat kopÄ«go lasÄ«t Šø rakstÄ«t sistÄmas zvanu izsekoÅ”anas rezultÄtos.
Pievienojot operatoru -Ń, tu piespiedÄ«si strace anotÄt katru faila deskriptoru izvadÄ ar piezÄ«mi, uz ko tas norÄda.
Pievienojiet jau esoŔam procesam ar -p**
KÄ redzÄsit tÄlÄk sniegtajÄ piemÄrÄ, dažreiz jums ir jÄizseko programmai, kas jau darbojas. Ja ir zinÄms, ka tas darbojas kÄ process 1337 (teiksim, no izejas ps), varat to izsekot Å”Ädi:
$ strace -p 1337
...system call trace output...
Jums var būt nepiecieŔamas root tiesības.
Izmantojiet -f, lai uzraudzÄ«tu bÄrnu procesus
strace PÄc noklusÄjuma tas izseko tikai vienu procesu. Ja Å”is process rada bÄrnprocesus, var redzÄt sistÄmas izsaukumu, lai radÄ«tu bÄrnprocesu, bet pakÄrtotÄ procesa sistÄmas izsaukumi netiks parÄdÄ«ti.
Ja domÄjat, ka kļūda ir pakÄrtotÄ procesÄ, izmantojiet paziÅojumu -f, tas ļaus to izsekot. NegatÄ«vÄ puse ir tÄda, ka izvade jÅ«s mulsinÄs vÄl vairÄk. Kad strace izseko vienu procesu vai vienu pavedienu, tas parÄda vienu zvanu notikumu straumi. Ja tas vienlaikus izseko vairÄkus procesus, iespÄjams, redzÄsit zvana sÄkumu, ko pÄrtrauc ziÅojums , tad - kaudze izsaukumu uz citiem izpildes zariem, un tikai tad - beigas pirmajam <ā¦foocal resumed>. Vai arÄ« sadaliet visus izsekoÅ”anas rezultÄtus dažÄdos failos, izmantojot arÄ« operatoru -ff (sÄ«kÄka informÄcija
FiltrÄjiet pÄdas, izmantojot -e
KÄ redzat, izsekoÅ”anas rezultÄts ir reÄla visu iespÄjamo sistÄmas izsaukumu kaudze. Karogs -e Varat filtrÄt pÄdas (sk
Ne visas kļūdas ir sliktas
VienkÄrÅ”s un izplatÄ«ts piemÄrs ir programma, kas meklÄ failu vairÄkÄs vietÄs vienlaikus, piemÄram, apvalks, kas meklÄ direktoriju, kurÄ ir izpildÄms fails:
$ 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
...
Heiristika, piemÄram, āpÄdÄjais neveiksmÄ«gais pieprasÄ«jums pirms ziÅoÅ”anas par kļūduā, labi palÄ«dz atrast attiecÄ«gÄs kļūdas. Lai kÄ arÄ« bÅ«tu, loÄ£iski ir sÄkt no paÅ”Äm beigÄm.
C programmÄÅ”anas apmÄcÄ«bas var palÄ«dzÄt izprast sistÄmas zvanus.
Standarta izsaukumi uz C bibliotÄkÄm nav sistÄmas izsaukumi, bet tikai plÄns virsmas slÄnis. TÄtad, ja jÅ«s vismaz nedaudz saprotat, kÄ un ko darÄ«t C, jums bÅ«s vieglÄk saprast sistÄmas izsaukuma izsekoÅ”anas rezultÄtus. PiemÄram, jums ir problÄmas ar tÄ«kla sistÄmu zvanu atkļūdoÅ”anu, skatiet to paÅ”u klasiku
SarežģītÄks atkļūdoÅ”anas piemÄrs
Es jau teicu, ka vienkÄrÅ”as atkļūdoÅ”anas piemÄrs ir piemÄrs tam, ar ko man galvenokÄrt jÄsaskaras, strÄdÄjot strace. TomÄr dažreiz ir nepiecieÅ”ama reÄla izmeklÄÅ”ana, tÄpÄc Å”eit ir reÄls piemÄrs uzlabotai atkļūdoÅ”anai.
# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
Labi, tas nozÄ«mÄ bcron mÄÄ£inÄja uzrakstÄ«t noteiktu failu, bet tas neizdevÄs, un viÅÅ” neatzÄ«s, kÄpÄc. AtklÄjot 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 +++
GandrÄ«z paÅ”Äs beigÄs ir kļūdas ziÅojums rakstÄ«t, bet Å”oreiz kaut kas ir savÄdÄk. PirmkÄrt, nav atbilstoÅ”as āāsistÄmas izsaukuma kļūdas, kas parasti notiek pirms Ŕīs. OtrkÄrt, ir skaidrs, ka kaut kur kÄds jau ir izlasÄ«jis kļūdas ziÅojumu. Å Ä·iet, ka patiesÄ problÄma ir kaut kur citur, un bcrontab vienkÄrÅ”i atskaÅo ziÅojumu.
Ja paskatÄs man 2 lasÄ«t, varat redzÄt, ka pirmais arguments (3) ir faila deskriptors, ko *nix izmanto visai I/O apstrÄdei. KÄ uzzinÄt, ko apzÄ«mÄ faila deskriptors 3? Å ajÄ konkrÄtajÄ gadÄ«jumÄ jÅ«s varat palaist strace ar operatoru -Ń (skatiet iepriekÅ”), un tas jums automÄtiski pateiks, taÄu, lai noskaidrotu Å”Ädas lietas, ir noderÄ«gi zinÄt, kÄ lasÄ«t un parsÄt izsekoÅ”anas rezultÄtus.
Faila deskriptora avots var bÅ«t viens no daudziem sistÄmas izsaukumiem (tas viss ir atkarÄ«gs no tÄ, kam deskriptors ir paredzÄts - konsolei, tÄ«kla ligzdai, paÅ”am failam vai kaut kam citam), taÄu, lai kÄ arÄ« bÅ«tu, mÄs meklÄjam zvani, atgriežot 3 (t.i., izsekoÅ”anas rezultÄtos mÄs meklÄjam ā= 3ā). Å ajÄ rezultÄtÄ ir 2 no tiem: openat paÅ”Ä augÅ”Ä un ligzda VidÅ«. openat atver failu, bet aizvÄrt(3) parÄdÄ«s, ka tas atkal aizveras. (Rake: failu deskriptorus var izmantot atkÄrtoti, kad tie tiek atvÄrti un aizvÄrti). Zvaniet ligzda () piemÄrots, jo tas ir pÄdÄjais iepriekÅ” lasÄ«t (), un izrÄdÄs, ka bcrontab ar kaut ko strÄdÄ caur ligzdu. NÄkamÄ rinda parÄda, ka faila deskriptors ir saistÄ«ts ar unix domÄna ligzda paceļam /var/run/bcron-spool.
TÄtad, mums ir jÄatrod process, kas saistÄ«ts ar unix ligzda citÄ pusÄ. Å im nolÅ«kam ir daži glÄ«ti triki, kas abi ir noderÄ«gi servera izvietoÅ”anas atkļūdoÅ”anai. Pirmais ir izmantot netstat vai jaunÄka ss (ligzdas statuss). Abas komandas parÄda sistÄmas aktÄ«vos tÄ«kla savienojumus un Åem paziÅojumu -l lai aprakstÄ«tu klausÄ«Å”anÄs ligzdas, kÄ arÄ« operatoru -p lai parÄdÄ«tu programmas, kas pievienotas kontaktligzdai kÄ klientam. (Ir daudz vairÄk noderÄ«gu iespÄju, taÄu Å”im uzdevumam pietiek ar Ŕīm divÄm.)
# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0 128 /var/run/bcron-spool 1466637 * 0 users:(("unixserver",pid=20629,fd=3))
Tas liek domÄt, ka klausÄ«tÄjs ir komanda inixserveris, kas darbojas ar procesa ID 20629. (Un nejauÅ”i tas izmanto faila deskriptoru 3 kÄ ligzdu.)
Tiek saukts otrs patieÅ”Äm noderÄ«gais rÄ«ks vienas un tÄs paÅ”as informÄcijas atraÅ”anai lsof. TajÄ ir uzskaitÄ«ti visi sistÄmÄ atvÄrtie faili (vai failu deskriptori). Vai arÄ« varat iegÅ«t informÄciju par vienu konkrÄtu failu:
# 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
Process 20629 ir ilgmūžīgs serveris, tÄpÄc varat to pievienot strace izmantojot kaut ko lÄ«dzÄ«gu strace -o /tmp/trace -p 20629. Ja rediÄ£Äjat cron darbu citÄ terminÄlÄ, jÅ«s saÅemsit izsekoÅ”anas izvadi ar kļūdu. Un Å”eit ir rezultÄts:
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
(PÄdÄjais pieÅemt () izsekoÅ”anas laikÄ netiks pabeigts.) DiemžÄl Å”is rezultÄts nesatur kļūdu, kuru mÄs meklÄjam. MÄs neredzam ziÅojumus, ko bcrontag sÅ«ta uz ligzdu vai saÅem no tÄs. TÄ vietÄ pilnÄ«ga procesa kontrole (klons, gaidÄ«t 4, SIGCHLD utt.) Å is process rada bÄrnu procesu, kas, kÄ jÅ«s varÄtu nojaust, veic patieso darbu. Un, ja jums ir jÄnoÄ·er viÅas pÄdas, pievienojiet zvanam strace -f. To mÄs atradÄ«sim, meklÄjot kļūdas ziÅojumu jaunajÄ rezultÄtÄ ar strace -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 +++
Tagad tas ir kaut kas. Process 21470 saÅem kļūdu "piekļuve liegta", mÄÄ£inot izveidot failu ceÄ¼Ä tmp/spool.21470.1573692319.854640 (attiecas uz paÅ”reizÄjo darba direktoriju). Ja mÄs tikai zinÄtu paÅ”reizÄjo darba direktoriju, mÄs zinÄtu arÄ« pilnu ceļu un varÄtu izdomÄt, kÄpÄc process nevar tajÄ izveidot savu pagaidu failu. DiemžÄl process jau ir beidzies, tÄpÄc jÅ«s nevarat vienkÄrÅ”i izmantot lsof -p 21470 lai atrastu paÅ”reizÄjo direktoriju, bet varat strÄdÄt arÄ« pretÄjÄ virzienÄ - meklÄjiet PID 21470 sistÄmas zvanus, kas maina direktoriju. (Ja tÄdu nav, PID 21470 tos noteikti ir mantojis no sava vecÄka, un tas jau ir pabeigts lsof -p nevar noskaidrot.) Å is sistÄmas izsaukums ir chdir (ko ir viegli noskaidrot, izmantojot mÅ«sdienu tieÅ”saistes meklÄtÄjprogrammas). Un Å”eit ir apgrieztÄs meklÄÅ”anas rezultÄts, pamatojoties uz izsekoÅ”anas rezultÄtiem, lÄ«dz pat servera 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 +++
(Ja esat apmaldÄ«jies, iespÄjams, vÄlÄsities izlasÄ«t manu iepriekÅ”Äjo ziÅu
# 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
Tur suns ir aprakts! Serveris darbojas kÄ lietotÄja cron, bet tikai root ir atļauja rakstÄ«t direktorijÄ /var/spool/cron/tmp/. VienkÄrÅ”a komanda chown cron /var/spool/cron/tmp/ piespiedÄ«s bcron strÄdÄt pareizi. (Ja tÄ nebija problÄma, tad nÄkamais visticamÄkais aizdomÄ«gais ir kodola droŔības modulis, piemÄram, SELinux vai AppArmor, tÄpÄc es pÄrbaudÄ«tu kodola ziÅojumu žurnÄlu ar dmesg.)
KopÄ
SistÄmas izsaukuma izsekoÅ”ana iesÄcÄjiem var bÅ«t nepÄrvarama, taÄu es ceru, ka esmu parÄdÄ«jis, ka tie ir Ätrs veids, kÄ atkļūdot visas izplatÄ«tÄkÄs izvietoÅ”anas problÄmas. IedomÄjieties, ka mÄÄ£inÄt atkļūdot vairÄku procesu bcronizmantojot soli pa solim atkļūdotÄju.
IzsekoÅ”anas rezultÄtu parsÄÅ”ana atpakaļ pa sistÄmas izsaukuma Ä·Ädi prasa prasmes, taÄu, kÄ jau teicu, gandrÄ«z vienmÄr, izmantojot strace, es vienkÄrÅ”i saÅemu izsekoÅ”anas rezultÄtu un meklÄju kļūdas, sÄkot no beigÄm. JebkurÄ gadÄ«jumÄ strace palÄ«dz man ietaupÄ«t daudz laika atkļūdoÅ”anai. Ceru, ka tas noderÄs arÄ« jums.
Avots: www.habr.com