Villuleit fyrir uppsetningu hugbúnaðar með strace

Villuleit fyrir uppsetningu hugbúnaðar með strace

Dagstarfið mitt er aðallega hugbúnaðaruppsetning, sem þýðir að ég eyði miklum tíma í að reyna að svara spurningum eins og:

  • Þessi hugbúnaður virkar fyrir þróunaraðilann, en ekki fyrir mig. Hvers vegna?
  • Í gær virkaði þessi hugbúnaður fyrir mig, en í dag gerir hann það ekki. Hvers vegna?

Þetta er eins konar villuleit sem er aðeins frábrugðin venjulegri hugbúnaðarvillu. Venjulegur villuleit snýst um rökfræði kóðans, en kembiforrit snýst um samspil kóðans og umhverfisins. Jafnvel þótt rót vandans sé rökvilla, þá þýðir sú staðreynd að allt virkar á einni vél en ekki á annarri að vandamálið sé einhvern veginn í umhverfinu.

Svo í stað venjulegra villuleitartækja eins og gdb Ég er með annað sett af verkfærum til að kemba uppsetningu. Og uppáhalds tólið mitt til að takast á við vandamálið eins og "Af hverju virkar þessi hugbúnaður ekki fyrir mig?" kallaði strá.

Hvað er strace?

strá er tæki til að rekja kerfissímtöl. Það var upphaflega búið til fyrir Linux, en sömu villuleit er hægt að gera með verkfærum fyrir önnur kerfi (DTrace eða ktrace).

Grunnforritið er mjög einfalt. Þú þarft bara að keyra strace með hvaða skipun sem er og það mun henda öllum kerfissímtölum (þó fyrst þú verður líklega að setja það upp sjálfur strá):

$ strace echo Hello
...Snip lots of stuff...
write(1, "Hellon", 6)                  = 6
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Hvað eru þessi kerfissímtöl? Þetta er eitthvað eins og API fyrir stýrikerfiskjarnann. Einu sinni hafði hugbúnaður beinan aðgang að vélbúnaðinum sem hann keyrði á. Ef það þurfti til dæmis að sýna eitthvað á skjánum spilaði það með portum eða minniskortuðum skrám fyrir myndbandstæki. Þegar fjölverkavinnsla tölvukerfi urðu vinsæl ríkti glundroði þar sem ýmis forrit börðust um vélbúnaðinn. Villur í einu forriti gætu komið öðrum niður, ef ekki allt kerfið. Þá birtust forréttindastillingar (eða „hringavarnir“) í örgjörvanum. Kjarninn varð sá forréttindahópur: hann fékk fullan aðgang að vélbúnaðinum, sem varð til þess að forrit sem ekki höfðu forréttindi sem þegar þurftu að biðja um aðgang frá kjarnanum til að hafa samskipti við vélbúnaðinn í gegnum kerfissímtöl.

Á tvöfalda stigi er kerfiskall örlítið frábrugðið einföldu aðgerðarkalli, en flest forrit nota umbúðir í venjulegu bókasafni. Þeir. POSIX C staðalsafnið inniheldur aðgerðarkall skrifa (), sem inniheldur allan arkitektúrsértækan kóða fyrir kerfiskallið skrifa.

Villuleit fyrir uppsetningu hugbúnaðar með strace

Í stuttu máli má segja að öll samskipti milli forrits og umhverfis þess (tölvukerfi) fara fram með kerfissímtölum. Þess vegna, þegar hugbúnaður virkar á einni vél en ekki á annarri, væri gott að skoða niðurstöður kerfissímtalsrakningar. Nánar tiltekið, hér er listi yfir dæmigerða punkta sem hægt er að greina með því að nota rekja kerfissímtal:

  • Console I/O
  • Net I/O
  • Skráakerfisaðgangur og skráa I/O
  • Stjórna líftíma ferliþráðs
  • Lágmarks minnisstjórnun
  • Aðgangur að sérstökum tækjum

Hvenær á að nota strace?

Í orði, strá notað með hvaða forriti sem er í notendarými, því hvaða forrit sem er í notendarými verður að hringja í kerfi. Það virkar á skilvirkari hátt með samansettum forritum á lágu stigi, en það virkar líka með tungumálum á háu stigi eins og Python ef þú getur skorið í gegnum auka hávaða frá keyrslutíma og túlk.

Í öllu sínu veldi strá kemur fram við villuleit á hugbúnaði sem virkar vel á einni vél, en hættir skyndilega að virka á annarri, gefur óljós skilaboð um skrár, heimildir eða misheppnaðar tilraunir til að framkvæma einhverjar skipanir eða eitthvað annað... Það er leitt, en það gerir það ekki sameinast svo vel við vandamál á háu stigi eins og villur í vottorðsstaðfestingu. Venjulega þarf þetta samsetningu strástundum ltrace og verkfæri á hærra stigi (eins og skipanalínutólið OpenSSL til að kemba vottorðið).

Við munum nota sjálfstæðan netþjón sem dæmi, en oft er hægt að rekja kerfissímtöl á flóknari uppsetningarpöllum. Þú þarft bara að velja réttu verkfærin.

Einfalt kembiforrit dæmi

Segjum að þú viljir keyra hið ótrúlega netþjónaforrit foo, og þetta er það sem þú endar með:

$ foo
Error opening configuration file: No such file or directory

Svo virðist sem það fann ekki stillingarskrána sem þú skrifaðir. Þetta gerist vegna þess að stundum þegar pakkastjórar setja saman forrit hnekkja þeir væntanlegum skráarstöðum. Og ef þú fylgir uppsetningarleiðbeiningunum fyrir eina dreifingu, í annarri finnurðu skrár allt aðrar en þú bjóst við. Vandamálið gæti verið leyst á nokkrum sekúndum ef villuboðin sögðu hvar ætti að leita að stillingarskránni, en það gerir það ekki. Svo hvert á að leita?

Ef þú hefur aðgang að frumkóðann geturðu lesið hann og fundið út allt. Góð afritunaráætlun, en ekki fljótlegasta lausnin. Þú getur gripið til skref-fyrir-skref villuleitar eins og gdb og sjáðu hvað forritið gerir, en það er miklu áhrifaríkara að nota tól sem er sérstaklega hannað til að sýna samskipti við umhverfið: strá.

Output strá kann að virðast óþarfi, en góðu fréttirnar eru þær að flest af því er óhætt að hunsa. Það er oft gagnlegt að nota -o stjórnandann til að vista rakningarniðurstöður í sérstaka skrá:

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

Um það bil öll fyrstu framleiðsla síða strá - Þetta er venjulega lágmarks undirbúningur fyrir sjósetningu. (Mikið af símtölum mmap, mvernd, fjaður fyrir hluti eins og að greina lágt minni og sýna kraftmikil bókasöfn.) Reyndar, meðan á kembiforritinu stendur strá Það er betra að lesa alveg frá endanum. Það verður áskorun hér að neðan skrifa, sem sýnir villuboð. Við lítum hér að ofan og sjáum fyrsta ranga kerfiskallið - kallið opnuð, sem kastar villu ENOENT („skrá eða mappa fannst ekki“) að reyna að opna /etc/foo/config.json. Þetta er þar sem stillingarskráin ætti að vera.

Þetta var bara dæmi, en ég myndi segja 90% af þeim tíma sem ég nota strá, það er ekkert miklu erfiðara að gera en þetta. Hér að neðan er heill skref-fyrir-skref villuleitarleiðbeiningar:

  • Vertu í uppnámi vegna óljósra skilaboða um system-y villa frá forriti
  • Endurræstu forritið með strá
  • Finndu villuboðin í rakningarniðurstöðum
  • Farðu hærra þar til þú smellir á fyrsta misheppnaða kerfiskallið

Það er mjög líklegt að kerfiskallið í skrefi 4 muni leiða í ljós hvað fór úrskeiðis.

Ábendingar

Áður en ég sýni þér dæmi um flóknari villuleit mun ég sýna þér nokkur brellur til árangursríkrar notkunar strá:

maður er vinur þinn

Á mörgum *nix kerfum er hægt að fá heildarlista yfir kerfissímtöl í kjarnann með því að keyra maður syscals. Þú munt sjá hluti eins og brk(2), sem þýðir að hægt er að fá frekari upplýsingar með því að keyra maður 2 brk.

Lítil hrífa: maður 2 gaffal sýnir mér síðuna fyrir skelina gaffal() в GNU libc, sem, kemur í ljós, er hrint í framkvæmd með því að kalla klón(). Hringdu í merkingarfræði Fork helst það sama ef þú skrifar forrit með gaffal(), og keyra rakningu - ég finn engin símtöl Fork, í stað þeirra verður klón(). Slíkar hrífur rugla þig aðeins ef þú byrjar að bera saman upprunann og úttakið strá.

Notaðu -o til að vista úttakið í skrá

strá getur framleitt umfangsmikla framleiðslu, svo það er oft gagnlegt að geyma rakningarniðurstöður í aðskildum skrám (eins og í dæminu hér að ofan). Þetta hjálpar einnig til við að koma í veg fyrir að ruglingur forritsúttaks og úttaks sé ruglað saman strá í vélinni.

Notaðu -s til að skoða fleiri rökstuðningsgögn

Þú gætir hafa tekið eftir því að seinni helmingur villuboðanna er ekki sýndur í dæminu hér að ofan. Það er vegna þess strá sjálfgefið sýnir aðeins fyrstu 32 bæti strengsrafbrigðisins. Ef þú vilt sjá meira skaltu bæta við einhverju eins og -s 128 að símtalinu strá.

-y gerir það auðveldara að rekja skrár, fals osfrv.

"Allt er skrá" þýðir að *nix kerfi gera allt I/O með því að nota skráarlýsingar, hvort sem það á við um skrá eða net eða millivinnslupípur. Þetta er þægilegt fyrir forritun, en gerir það erfitt að fylgjast með því sem raunverulega er að gerast þegar þú sérð algengt lesa и skrifa í niðurstöðum kerfissímtala.

Með því að bæta við rekstraraðila -y, þú munt þvinga strá skrifaðu athugasemdir við hverja skráarlýsingu í úttakinu með athugasemd um hvað það bendir á.

Tengdu við ferli sem þegar er í gangi með -p**

Eins og þú munt sjá af dæminu hér að neðan þarftu stundum að rekja forrit sem er þegar í gangi. Ef vitað er að það er í gangi sem ferli 1337 (segjum frá úttakinu ps), þá geturðu rakið það svona:

$ strace -p 1337
...system call trace output...

Þú gætir þurft rótarréttindi.

Notaðu -f til að fylgjast með undirferli

strá Sjálfgefið er að það rekur aðeins eitt ferli. Ef þetta ferli hrindir af stað undirferli, þá má sjá kerfiskallið til að hrogna barnferlið, en kerfiskall barnferlisins munu ekki birtast.

Ef þú heldur að villan sé í undirferli skaltu nota yfirlýsinguna -f, þetta mun gera það kleift að rekja það. Gallinn við þetta er að úttakið mun rugla þig enn meira. Hvenær strá rekur eitt ferli eða einn þráð, það sýnir einn straum af símtölum. Þegar það rekur mörg ferli í einu gætirðu séð upphaf símtals truflað af skilaboðum , síðan - fullt af köllum fyrir önnur aftökugreinar, og aðeins þá - lok þeirrar fyrstu <…símtal haldið áfram>. Eða skiptu öllum rakningarniðurstöðum í mismunandi skrár, einnig með því að nota rekstraraðilann -ff (upplýsingar í leiðarvísir á strá).

Sía ummerki með því að nota -e

Eins og þú sérð er útkoman af rekningunni alvöru haug af öllum mögulegum kerfissímtölum. Fáni -e Þú getur síað ummerkin (sjá forystu á strá). Helsti kosturinn er sá að það er fljótlegra að keyra síaða trace en að gera full trace og þá grep`kl. Satt að segja er mér næstum alltaf sama.

Ekki eru öll mistök slæm

Einfalt og algengt dæmi er forrit sem leitar að skrá á nokkrum stöðum í einu, eins og skel sem leitar að möppu sem inniheldur keyrsluskrá:

$ 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
...

Heuristics eins og „síðasta mistókst beiðni áður en villu er tilkynnt“ eru góðar til að finna viðeigandi villur. Hvað sem því líður þá er rökrétt að byrja alveg frá endanum.

C forritunarkennsla getur hjálpað þér að skilja kerfissímtöl.

Stöðluð símtöl í C bókasöfn eru ekki kerfissímtöl, heldur aðeins þunnt yfirborðslag. Þannig að ef þú skilur að minnsta kosti smá hvernig og hvað á að gera í C, þá verður auðveldara fyrir þig að skilja niðurstöður kerfiskallasporsins. Til dæmis, þú átt í vandræðum með að kemba símtöl í netkerfi, skoðaðu sömu klassíkina Handbók Bija um netforritun.

Flóknara villuleitardæmi

Ég sagði þegar að dæmið um einfalda kembiforrit er dæmi um það sem ég þarf aðallega að takast á við þegar ég er að vinna með strá. Hins vegar er stundum þörf á raunverulegri rannsókn, svo hér er raunverulegt dæmi um fullkomnari villuleit.

bcron - Verkefnavinnsluáætlun, önnur útfærsla á *nix púknum cron. Það er sett upp á þjóninum, en þegar einhver reynir að breyta áætluninni gerist þetta:

# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file

Allt í lagi, það þýðir bcron reyndi að skrifa ákveðna skrá, en það gekk ekki, og hann mun ekki viðurkenna hvers vegna. Afhjúpandi strá:

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

Það eru villuboð undir lokin skrifa, en í þetta skiptið er eitthvað öðruvísi. Í fyrsta lagi er engin viðeigandi kerfissímtalsvilla, sem kemur venjulega fram fyrir þetta. Í öðru lagi er ljóst að einhvers staðar hefur einhver þegar lesið villuboðin. Það lítur út fyrir að hið raunverulega vandamál sé einhvers staðar annars staðar, og bcrontab spilar einfaldlega skilaboðin.

Ef þú horfir á maður 2 les, þú getur séð að fyrstu rökin (3) eru skráarlýsing, sem *nix notar fyrir alla I/O vinnslu. Hvernig finn ég út hvað skráarlýsing 3 táknar? Í þessu tiltekna tilviki geturðu hlaupið strá með rekstraraðila -y (sjá hér að ofan) og það mun sjálfkrafa segja þér það, en til að finna út hluti eins og þetta er gagnlegt að vita hvernig á að lesa og flokka rakningarniðurstöður.

Uppruni skráarlýsingar getur verið eitt af mörgum kerfisköllum (það fer allt eftir því fyrir hvað lýsingin er - stjórnborð, nettengi, skráin sjálf eða eitthvað annað), en hvort sem það er þá leitum við að símtöl með því að skila 3 (þ.e.a.s. við leitum að „= 3“ í rakningarniðurstöðum). Í þessari niðurstöðu eru 2 þeirra: opnuð alveg efst og fals Í miðjunni. opnuð opnar skrána en nálægt(3) mun þá sýna að það lokar aftur. (Rake: hægt er að endurnýta skráarlýsingar þegar þeir eru opnaðir og lokaðir). Hringdu innstunga() hentar því það er síðasti á undan lesa (), og það kemur í ljós að bcrontab vinnur með eitthvað í gegnum fals. Næsta lína sýnir að skráarlýsingin er tengd við unix lénstengi á leiðinni /var/run/bcron-spool.

Svo við þurfum að finna ferlið sem tengist unix tengi hinum megin. Það eru nokkur sniðug brellur í þessum tilgangi, sem bæði eru gagnleg til að kemba uppsetningu netþjóna. Hið fyrsta er að nota netstat eða nýrri ss (staða innstungu). Báðar skipanirnar sýna virkar nettengingar kerfisins og taka yfirlýsinguna -l til að lýsa hlustunarinnstungum, sem og símafyrirtækinu -p til að sýna forrit sem eru tengd við innstunguna sem biðlara. (Það eru margir fleiri gagnlegir valkostir, en þessir tveir duga fyrir þetta verkefni.)

# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0   128   /var/run/bcron-spool 1466637   * 0   users:(("unixserver",pid=20629,fd=3))

Þetta bendir til þess að hlustandinn sé skipunin inixserver, keyrir með vinnsluauðkenni 20629. (Og fyrir tilviljun notar það skráarlýsingu 3 sem fals.)

Annað virkilega gagnlegt tól til að finna sömu upplýsingar er kallað LSOF. Það listar allar opnar skrár (eða skráarlýsingar) á kerfinu. Eða þú getur fengið upplýsingar um eina tiltekna skrá:

# 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 er langlífur netþjónn, svo þú getur tengt hann við strá nota eitthvað eins og strace -o /tmp/trace -p 20629. Ef þú breytir cron vinnu í annarri flugstöð færðu rakningarúttak með villu. Og hér er niðurstaðan:

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

(Síðast samþykkja() verður ekki lokið við rakningu.) Aftur, því miður, inniheldur þessi niðurstaða ekki villuna sem við erum að leita að. Við sjáum engin skilaboð sem bcrontag sendir til eða tekur við úr innstungunni. Þess í stað, fullkomið ferli stjórna (klón, bíða 4, SIGCHLD o.s.frv.) Þetta ferli hrindir af stað barnaferli, sem, eins og þú gætir giskað á, vinnur hið raunverulega verk. Og ef þú þarft að ná slóð hennar skaltu bæta við símtalið strá -f. Þetta er það sem við finnum þegar við leitum að villuboðunum í nýju niðurstöðunni með 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 +++

Nú, það er eitthvað. Aðferð 21470 fær "aðgang hafnað" villu þegar reynt er að búa til skrá á slóð tmp/spool.21470.1573692319.854640 (sem tengist núverandi vinnuskrá). Ef við vissum bara núverandi vinnuskrá, myndum við líka vita alla leiðina og geta fundið út hvers vegna ferlið getur ekki búið til tímabundna skrá sína í henni. Því miður hefur ferlið þegar lokið, svo þú getur ekki bara notað lsof -p 21470 til að finna núverandi möppu, en þú getur unnið í gagnstæða átt - leitaðu að PID 21470 kerfissímtölum sem breyta skránni. (Ef þær eru engar verður PID 21470 að hafa erft þau frá foreldri sínu og þetta er þegar í gegnum lsof -bls ekki hægt að finna út.) Þetta kerfiskall er chdir (sem auðvelt er að finna út með hjálp nútíma leitarvéla á netinu). Og hér er niðurstaða öfugleitar byggðar á rakningarniðurstöðum, alla leið til PID 20629 netþjóns:

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

(Ef þú ert týndur gætirðu viljað lesa fyrri færsluna mína um *nix ferlastjórnun og skeljar.) Þannig að þjónninn PID 20629 fékk ekki leyfi til að búa til skrá á slóðinni /var/spool/cron/tmp/spool.21470.1573692319.854640. Líklega er ástæðan fyrir þessu klassískar heimildastillingar skráakerfisins. Við skulum athuga:

# 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

Það er þar sem hundurinn er grafinn! Miðlarinn keyrir sem notandi cron, en aðeins root hefur leyfi til að skrifa í möppuna /var/spool/cron/tmp/. Einföld skipun chown cron /var/spool/cron/tmp/ mun þvinga bcron virka rétt. (Ef það var ekki vandamálið, þá er næst líklegasti grunaði kjarnaöryggiseining eins og SELinux eða AppArmor, svo ég myndi athuga kjarnaskilaboðaskrána með dmesg.)

Alls

Kerfissímtöl geta verið yfirþyrmandi fyrir byrjendur, en ég vona að ég hafi sýnt fram á að þau séu fljótleg leið til að kemba heilan flokk af algengum dreifingarvandamálum. Ímyndaðu þér að reyna að kemba fjölferli bcronmeð því að nota skref-fyrir-skref villuleit.

Að flokka rakningarniðurstöður aftur á bak eftir kerfiskallkeðjunni krefst kunnáttu, en eins og ég sagði, næstum alltaf, með því að nota strá, Ég fæ bara rakningarniðurstöðuna og leita að villum sem byrja á endanum. Allavega, strá hjálpar mér að spara mikinn tíma við villuleit. Ég vona að það muni nýtast þér líka.

Heimild: www.habr.com

Bæta við athugasemd