Utatuzi wa uwekaji wa programu kwa strace

Utatuzi wa uwekaji wa programu kwa strace

Kazi yangu ya siku nyingi ni upelekaji wa programu, ambayo inamaanisha mimi hutumia wakati mwingi kujaribu kujibu maswali kama:

  • Programu hii inafanya kazi kwa msanidi programu, lakini sio kwangu. Kwa nini?
  • Jana programu hii ilinifanyia kazi, lakini leo haifanyi kazi. Kwa nini?

Hii ni aina ya utatuzi ambayo ni tofauti kidogo na utatuzi wa kawaida wa programu. Utatuzi wa mara kwa mara unahusu mantiki ya msimbo, lakini utatuzi wa utumiaji unahusu mwingiliano kati ya msimbo na mazingira. Hata kama mzizi wa shida ni kosa la kimantiki, ukweli kwamba kila kitu hufanya kazi kwenye mashine moja na sio kwa mwingine inamaanisha kuwa shida iko katika mazingira.

Kwa hivyo badala ya zana za kawaida za kurekebisha kama gdb Nina seti tofauti ya zana za kupeleka debugging. Na zana ninayopenda ya kushughulikia shida kama "Kwa nini programu hii haifanyi kazi kwangu?" kuitwa kamba.

Strace ni nini?

kamba — ni zana ya "kufuatilia simu za mfumo." Hapo awali iliundwa chini ya Linux, lakini mbinu zile zile za utatuzi zinaweza kufanywa na zana za mifumo mingine (DTrace au ktrace).

maombi ya msingi ni rahisi sana. Unahitaji tu kuendesha strace na amri yoyote na itatupa simu zote za mfumo (ingawa kwanza utalazimika kuisanikisha mwenyewe. kamba):

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

Simu hizi za mfumo ni nini? Hiki ni kitu kama API ya kernel ya mfumo wa uendeshaji. Hapo zamani, programu ilikuwa na ufikiaji wa moja kwa moja kwa maunzi iliyokuwa ikitumika. Ikiwa, kwa mfano, ilihitaji kuonyesha kitu kwenye skrini, ilicheza na bandari au rejista za kumbukumbu za vifaa vya video. Mifumo ya kompyuta ya kufanya kazi nyingi ilipopata umaarufu, machafuko yalitawala huku programu mbalimbali zikipigania vifaa. Hitilafu katika programu moja zinaweza kuangusha zingine, ikiwa sio mfumo mzima. Kisha njia za upendeleo (au "ulinzi wa pete") zilionekana kwenye CPU. Kernel ikawa ya bahati zaidi: ilipata ufikiaji kamili wa vifaa, ikitoa programu zisizo na upendeleo ambazo tayari zililazimika kuomba ufikiaji kutoka kwa kernel kuingiliana na maunzi kupitia simu za mfumo.

Katika kiwango cha binary, simu ya mfumo ni tofauti kidogo na simu rahisi ya kazi, lakini programu nyingi hutumia kanga kwenye maktaba ya kawaida. Wale. maktaba ya kawaida ya POSIX C ina simu ya kukokotoa andika(), ambayo ina msimbo wote mahususi wa usanifu wa simu ya mfumo kuandika.

Utatuzi wa uwekaji wa programu kwa strace

Kwa kifupi, mwingiliano wowote kati ya programu na mazingira yake (mifumo ya kompyuta) hufanyika kupitia simu za mfumo. Kwa hivyo, wakati programu inafanya kazi kwenye mashine moja lakini sio kwenye nyingine, itakuwa vizuri kuangalia matokeo ya ufuatiliaji wa simu ya mfumo. Hasa zaidi, hapa kuna orodha ya vidokezo vya kawaida ambavyo vinaweza kuchambuliwa kwa kutumia mfumo wa ufuatiliaji wa simu:

  • Console I/O
  • Mtandao wa I/O
  • Ufikiaji wa mfumo wa faili na faili I/O
  • Kudhibiti maisha ya mfululizo wa mchakato
  • Usimamizi wa kumbukumbu ya kiwango cha chini
  • Ufikiaji wa viendeshi maalum vya kifaa

Wakati wa kutumia strace?

Kwa nadharia, kamba kutumika na programu yoyote katika nafasi ya mtumiaji, kwa sababu programu yoyote katika nafasi ya mtumiaji lazima ipige simu za mfumo. Inafanya kazi kwa ufanisi zaidi na programu zilizokusanywa, za kiwango cha chini, lakini pia hufanya kazi na lugha za kiwango cha juu kama Python ikiwa unaweza kupunguza kelele ya ziada kutoka kwa wakati wa kukimbia na mkalimani.

Katika utukufu wake wote kamba inajidhihirisha wakati wa kurekebisha programu ambayo inafanya kazi vizuri kwenye mashine moja, lakini ghafla huacha kufanya kazi kwenye nyingine, ikitoa ujumbe usio wazi kuhusu faili, ruhusa, au majaribio yasiyofanikiwa ya kutekeleza amri fulani au kitu kingine ... Inasikitisha, lakini haifanyi. kuchanganya vyema na matatizo ya kiwango cha juu kama vile makosa ya uthibitishaji wa cheti. Kawaida hii inahitaji mchanganyiko kambamara nyingine ltrace na zana za kiwango cha juu (kama zana ya mstari wa amri openssl kurekebisha cheti).

Tutatumia seva inayojitegemea kama mfano, lakini ufuatiliaji wa simu za mfumo mara nyingi unaweza kufanywa kwenye mifumo ngumu zaidi ya utumiaji. Unahitaji tu kuchagua zana zinazofaa.

Mfano rahisi wa kurekebisha

Wacha tuseme unataka kutekeleza programu ya kushangaza ya foo, na hii ndio unamaliza nayo:

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

Inaonekana haikuweza kupata faili ya usanidi uliyoandika. Hii hutokea kwa sababu wakati mwingine wasimamizi wa vifurushi wanapokusanya programu, wao hubatilisha maeneo ya faili yanayotarajiwa. Na ukifuata mwongozo wa usakinishaji kwa usambazaji mmoja, kwa mwingine unapata faili tofauti kabisa na vile ulivyotarajia. Shida inaweza kutatuliwa kwa sekunde chache ikiwa ujumbe wa makosa utaambiwa wapi utafute faili ya usanidi, lakini haifanyi hivyo. Hivyo wapi kuangalia?

Ikiwa unaweza kufikia msimbo wa chanzo, unaweza kuisoma na kujua kila kitu. Mpango mzuri wa chelezo, lakini sio suluhisho la haraka zaidi. Unaweza kuamua kitatuzi cha hatua kwa hatua kama vile gdb na uone programu inafanya nini, lakini ni bora zaidi kutumia zana ambayo imeundwa mahsusi kuonyesha mwingiliano na mazingira: kamba.

Pato kamba inaweza kuonekana kuwa ya ziada, lakini habari njema ni kwamba nyingi zinaweza kupuuzwa kwa usalama. Mara nyingi ni muhimu kutumia -o opereta kuokoa matokeo ya ufuatiliaji kwa faili tofauti:

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

Takriban ukurasa mzima wa kwanza wa matokeo kamba - Hii ni kawaida maandalizi ya kiwango cha chini kwa uzinduzi. (Simu nyingi ramani, kulinda, chembe kwa mambo kama vile kugundua kumbukumbu ya kiwango cha chini na kuonyesha maktaba zinazobadilika.) Kwa kweli, wakati wa kutatua matokeo kamba Ni bora kusoma kutoka mwisho. Kutakuwa na changamoto hapa chini kuandika, ambayo inaonyesha ujumbe wa makosa. Tunaangalia hapo juu na kuona simu ya kwanza mbovu ya mfumo - simu wazi, ambayo inatupa makosa ENOENT ("faili au saraka haipatikani") ikijaribu kufungua /etc/foo/config.json. Hapa ndipo faili ya usanidi inapaswa kuwa.

Huu ulikuwa mfano tu, lakini ningesema 90% ya wakati ninaotumia kamba, hakuna kitu ngumu zaidi kufanya kuliko hii. Ifuatayo ni mwongozo kamili wa utatuzi wa hatua kwa hatua:

  • Kasirika kwa sababu ya ujumbe usio wazi kuhusu hitilafu ya mfumo-y kutoka kwa programu
  • Anzisha tena programu na kamba
  • Pata ujumbe wa makosa katika matokeo ya ufuatiliaji
  • Nenda juu zaidi hadi upige simu ya kwanza ya mfumo ambayo haikufaulu

Kuna uwezekano mkubwa kwamba simu ya mfumo katika hatua ya 4 itafichua kilichoharibika.

Vidokezo

Kabla ya kukuonyesha mfano wa utatuzi mgumu zaidi, nitakuonyesha hila chache kwa matumizi bora kamba:

mwanaume ni rafiki yako

Kwenye mifumo mingi ya *nix, orodha kamili ya simu za mfumo kwa kernel inaweza kupatikana kwa kukimbia man syscalls. Utaona mambo kama brk(2), ambayo inamaanisha habari zaidi inaweza kupatikana kwa kukimbia mtu 2 brk.

Mchuzi mdogo: mtu 2 uma inanionyesha ukurasa wa ganda uma () в GNU libc, ambayo, inageuka, inatekelezwa kwa kupiga simu clone(). Piga semantiki uma inabakia sawa ikiwa utaandika programu kwa kutumia uma (), na kufuatilia - sitapata simu zozote uma, badala yao kutakuwa na clone(). Raki kama hizo hukuchanganya tu ikiwa utaanza kulinganisha chanzo na pato kamba.

Tumia -o kuhifadhi matokeo kwenye faili

kamba inaweza kutoa matokeo mengi, kwa hivyo ni muhimu mara nyingi kuhifadhi matokeo ya ufuatiliaji katika faili tofauti (kama katika mfano hapo juu). Hii pia husaidia kuzuia kuchanganya matokeo ya programu na matokeo kamba katika console.

Tumia -s kutazama data zaidi ya hoja

Huenda umegundua kuwa nusu ya pili ya ujumbe wa hitilafu haijaonyeshwa katika mfano wa kufuatilia hapo juu. Ni kwa sababu kamba chaguo-msingi huonyesha baiti 32 pekee za hoja ya mfuatano. Ikiwa unataka kuona zaidi, ongeza kitu kama -s 128 kwa wito kamba.

-y hurahisisha kufuatilia faili, soketi, n.k.

"All is file" inamaanisha kuwa mifumo ya *nix hufanya I/O yote kwa kutumia maelezo ya faili, iwe hiyo inatumika kwa faili au mtandao au mirija ya kuchakata. Hii ni rahisi kwa programu, lakini inafanya kuwa vigumu kufuatilia kile kinachoendelea wakati unaona kawaida kusoma и kuandika katika matokeo ya ufuatiliaji wa simu ya mfumo.

Kwa kuongeza opereta ndio, utalazimisha kamba fafanua kila kielezi cha faili kwenye pato na kidokezo cha kile kinachoelekeza.

Ambatisha kwa mchakato ambao tayari unaendeshwa na -p**

Kama utaona kutoka kwa mfano hapa chini, wakati mwingine unahitaji kufuatilia programu ambayo tayari inaendeshwa. Ikiwa inajulikana kuwa inaendesha kama mchakato 1337 (sema, kutoka kwa matokeo ps), basi unaweza kuifuata kama hii:

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

Unaweza kuhitaji haki za mizizi.

Tumia -f kufuatilia michakato ya mtoto

kamba Kwa chaguo-msingi, inafuatilia mchakato mmoja tu. Ikiwa mchakato huu unazalisha michakato ya mtoto, basi wito wa mfumo wa kuibua mchakato wa mtoto unaweza kuonekana, lakini simu za mfumo wa mchakato wa mtoto hazitaonyeshwa.

Ikiwa unadhani kosa liko katika mchakato wa mtoto, tumia taarifa -f, hii itawezesha ufuatiliaji wake. Upande wa chini wa hii ni kwamba matokeo yatakuchanganya zaidi. Lini kamba hufuatilia mchakato mmoja au uzi mmoja, inaonyesha mtiririko mmoja wa matukio ya simu. Inapofuatilia michakato mingi kwa wakati mmoja, unaweza kuona kuanza kwa simu kukatizwa na ujumbe , basi - rundo la wito kwa matawi mengine ya utekelezaji, na kisha tu - mwisho wa kwanza <…foocall inaendelea>. Au gawanya matokeo yote ya ufuatiliaji katika faili tofauti, pia kwa kutumia opereta -ff (maelezo ndani uongozi juu ya kamba).

Chuja athari kwa kutumia -e

Kama unaweza kuona, matokeo ya ufuatiliaji ni rundo halisi la simu zote zinazowezekana za mfumo. Bendera -e Unaweza kuchuja ufuatiliaji (tazama mwongozo juu ya kamba) Faida kuu ni kwamba ni haraka kukimbia ufuatiliaji uliochujwa kuliko kufanya ufuatiliaji kamili na kisha grep`katika. Kuwa waaminifu, karibu siku zote sijali.

Sio makosa yote ni mabaya

Mfano rahisi na wa kawaida ni programu inayotafuta faili katika sehemu kadhaa mara moja, kama ganda linalotafuta saraka ambayo ina faili inayoweza kutekelezwa:

$ 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 kama "ombi la mwisho lililofeli kabla ya kuripoti hitilafu" ni nzuri katika kutafuta makosa husika. Iwe hivyo, ni jambo la busara kuanza kutoka mwisho kabisa.

Mafunzo ya programu C yanaweza kukusaidia kuelewa simu za mfumo.

Simu za kawaida kwa maktaba za C sio simu za mfumo, lakini ni safu nyembamba ya uso. Kwa hiyo, ikiwa unaelewa angalau kidogo jinsi na nini cha kufanya katika C, itakuwa rahisi kwako kuelewa matokeo ya ufuatiliaji wa wito wa mfumo. Kwa mfano, una matatizo ya kutatua simu kwa mifumo ya mtandao, angalia classic sawa Mwongozo wa Bija kwa Upangaji Mtandao.

Mfano ngumu zaidi wa kurekebisha

Tayari nilisema kwamba mfano wa utatuzi rahisi ni mfano wa kile ambacho ninalazimika kushughulika nacho wakati wa kufanya kazi nacho kamba. Walakini, wakati mwingine uchunguzi wa kweli unahitajika, kwa hivyo hapa kuna mfano halisi wa utatuzi wa hali ya juu zaidi.

bcron - mratibu wa usindikaji wa kazi, utekelezaji mwingine wa *nix daemon cron. Imesakinishwa kwenye seva, lakini mtu anapojaribu kuhariri ratiba, hivi ndivyo hufanyika:

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

Sawa, hiyo inamaanisha bcron alijaribu kuandika faili fulani, lakini haikufanya kazi, na hatakubali kwa nini. Kufunua kamba:

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

Kuna ujumbe wa hitilafu karibu na mwisho kabisa kuandika, lakini wakati huu kuna kitu tofauti. Kwanza, hakuna hitilafu ya simu ya mfumo husika, ambayo kwa kawaida hutokea kabla ya hili. Pili, ni wazi kwamba mahali fulani mtu tayari amesoma ujumbe wa makosa. Inaonekana kama shida halisi iko mahali pengine, na bcrontab inarudisha tu ujumbe.

Ukiangalia mtu 2 kusoma, unaweza kuona kwamba hoja ya kwanza (3) ni maelezo ya faili, ambayo *nix hutumia kwa usindikaji wote wa I/O. Nitajuaje maelezo ya faili 3 yanawakilisha? Katika kesi hii, unaweza kukimbia kamba na mwendeshaji ndio (tazama hapo juu) na itakuambia kiotomatiki, lakini kubaini vitu kama hivi, ni muhimu kujua jinsi ya kusoma na kuchambua matokeo ya ufuatiliaji.

Chanzo cha maelezo ya faili kinaweza kuwa moja ya simu nyingi za mfumo (yote inategemea kile kielezi ni cha - koni, tundu la mtandao, faili yenyewe, au kitu kingine), lakini iwe hivyo, tunatafuta. simu kwa kurudisha 3 (yaani .e. tunatafuta "= 3" katika matokeo ya ufuatiliaji). Katika matokeo haya kuna 2 kati yao: wazi juu kabisa na tundu Katikati. wazi inafungua faili lakini karibu(3) basi itaonyesha kuwa inafunga tena. (Rake: maelezo ya faili yanaweza kutumika tena yanapofunguliwa na kufungwa). Wito tundu () inafaa kwa sababu ni ya mwisho hapo awali soma (), na inageuka kuwa bcrontab inafanya kazi na kitu kupitia tundu. Mstari unaofuata unaonyesha kuwa maelezo ya faili yanahusishwa na tundu la kikoa unix njiani /var/run/bron-spool.

Kwa hivyo, tunahitaji kupata mchakato unaohusishwa na tundu la unix upande mwingine. Kuna hila kadhaa nadhifu kwa kusudi hili, zote mbili ni muhimu kwa utatuzi wa uwekaji wa seva. Ya kwanza ni kutumia netstat au mpya zaidi ss (hali ya tundu). Amri zote mbili zinaonyesha miunganisho inayotumika ya mtandao na kuchukua taarifa -l kuelezea soketi za kusikiliza, na vile vile mwendeshaji -p kuonyesha programu zilizounganishwa kwenye tundu kama mteja. (Kuna chaguzi nyingi muhimu zaidi, lakini hizi mbili zinatosha kwa kazi hii.)

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

Hii inaonyesha kuwa msikilizaji ndiye amri inixserver, inayoendeshwa na kitambulisho cha mchakato 20629. (Na, kwa bahati mbaya, hutumia maelezo ya faili 3 kama tundu.)

Zana ya pili muhimu sana ya kupata habari sawa inaitwa ls ya. Inaorodhesha faili zote wazi (au maelezo ya faili) kwenye mfumo. Au unaweza kupata habari kuhusu faili moja maalum:

# 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

Mchakato 20629 ni seva ya muda mrefu, kwa hivyo unaweza kuiambatisha kamba kutumia kitu kama strace -o /tmp/trace -p 20629. Ukihariri kazi ya cron kwenye terminal nyingine, utapokea matokeo ya ufuatiliaji na hitilafu. Na hapa ndio matokeo:

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

(Mwisho kubali () haitakamilika wakati wa kufuatilia.) Tena, kwa bahati mbaya, matokeo haya hayana hitilafu tunayotafuta. Hatuoni ujumbe wowote ambao bcrontag hutuma au kupokea kutoka kwa soketi. Badala yake, udhibiti kamili wa mchakato (Clone, subiri4, SIGCHLD n.k.) Utaratibu huu huibua mchakato wa mtoto, ambao, kama unavyoweza kukisia, hufanya kazi halisi. Na ikiwa unahitaji kushika mkondo wake, ongeza kwenye simu kamba -f. Hili ndilo tutakalopata tunapotafuta ujumbe wa makosa katika tokeo jipya kwa safu -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 +++

Sasa, hilo ni jambo fulani. Mchakato 21470 hupokea hitilafu ya "ufikiaji uliokataliwa" wakati wa kujaribu kuunda faili kwenye njia tmp/spool.21470.1573692319.854640 (inayohusiana na saraka ya sasa ya kufanya kazi). Ikiwa tungejua saraka ya sasa ya kufanya kazi, tungejua pia njia kamili na kuweza kujua kwa nini mchakato hauwezi kuunda faili yake ya muda ndani yake. Kwa bahati mbaya, mchakato tayari umetoka, kwa hivyo huwezi kutumia tu lsof -p 21470 ili kupata saraka ya sasa, lakini unaweza kufanya kazi kwa mwelekeo tofauti - tafuta simu za mfumo wa PID 21470 zinazobadilisha saraka. (Kama hakuna, PID 21470 lazima iwe imerithi kutoka kwa mzazi wake, na hii tayari imepitia. lsf -p haiwezi kupatikana.) Simu ya mfumo huu ni chdir (ambayo ni rahisi kujua kwa usaidizi wa injini za kisasa za utafutaji mtandaoni). Na hapa kuna matokeo ya utaftaji wa nyuma kulingana na matokeo ya ufuatiliaji, hadi kwa seva ya 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 +++

(Ikiwa umepotea, unaweza kutaka kusoma chapisho langu la awali kuhusu *usimamizi wa mchakato nix na makombora.) Kwa hivyo, seva ya PID 20629 haikupokea ruhusa ya kuunda faili kwenye njia /var/spool/cron/tmp/spool.21470.1573692319.854640. Uwezekano mkubwa zaidi, sababu ya hii ni mipangilio ya ruhusa ya mfumo wa faili. Hebu tuangalie:

# 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

Hapo ndipo mbwa anazikwa! Seva inaendesha kama cron ya mtumiaji, lakini mzizi pekee ndiye aliye na ruhusa ya kuandika kwenye saraka /var/spool/cron/tmp/. Amri rahisi chown cron /var/spool/cron/tmp/ italazimisha bcron fanya kazi vizuri. (Kama hili halikuwa tatizo, mtuhumiwa anayefuata anayewezekana zaidi ni moduli ya usalama ya kinu cha SE.Linux au AppArmor, kwa hivyo ningeangalia kumbukumbu ya ujumbe wa kernel na dmsg.)

Katika jumla ya

Ufuatiliaji wa simu za mfumo unaweza kuwa mwingi kwa anayeanza, lakini natumai nimeonyesha kuwa ni njia ya haraka ya kutatua darasa zima la shida za kawaida za utumiaji. Hebu fikiria kujaribu kutatua michakato mingi bcronkwa kutumia debugger hatua kwa hatua.

Kuchanganua matokeo ya ufuatiliaji kuelekea nyuma kwenye msururu wa simu za mfumo kunahitaji ujuzi, lakini kama nilivyosema, karibu kila mara, kutumia kamba, napata tu matokeo ya ufuatiliaji na kutafuta makosa kuanzia mwisho. Hata hivyo, kamba hunisaidia kuokoa muda mwingi kwenye utatuzi. Natumaini itakuwa na manufaa kwako pia.

Chanzo: mapenzi.com

Nunua upangishaji wa kuaminika wa tovuti zilizo na ulinzi wa DDoS, seva za VPS VDS 🔥 Nunua upangishaji wa tovuti unaoaminika kwa ulinzi wa DDoS, seva za VPS VDS | ProHoster