Strace-rekin softwarearen inplementazioa araztea

Strace-rekin softwarearen inplementazioa araztea

Nire eguneroko lana softwarea zabaltzea da batez ere, eta horrek esan nahi du denbora asko ematen dudala galderak erantzuten saiatzen:

  • Software honek garatzailearentzat funtzionatzen du, baina ez niretzat. Zergatik?
  • Atzo software honek funtzionatu zidan, baina gaur ez. Zergatik?

Hau software arazketa arruntaren apur bat desberdina den arazketa mota bat da. Arazketa arrunta kodearen logikari buruzkoa da, baina inplementazioaren arazketa kodearen eta ingurunearen arteko elkarrekintzari buruzkoa da. Arazoaren erroa akats logikoa bada ere, dena makina batean eta beste batean ez funtzionatzeak esan nahi du arazoa nolabait ingurunean dagoela.

Beraz, ohiko arazketa tresnen ordez gdb Arazketa inplementatzeko beste tresna multzo bat daukat. Eta arazoari aurre egiteko nire tresna gogokoena "Zergatik ez du niretzat software honek funtzionatzen?" deitua traza.

Zer da strace?

traza "sistema deien trazatzeko" tresna da. Jatorriz Linuxerako sortu zen, baina arazketa-trikimailu berdinak egin daitezke beste sistemetarako tresnekin (DTrace edo ktraza).

Oinarrizko aplikazioa oso erraza da. Edozein komandorekin strace exekutatu besterik ez duzu eta sistema dei guztiak botako ditu (nahiz eta lehenik ziurrenik zuk zeuk instalatu beharko duzu traza):

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

Zeintzuk dira sistema-dei hauek? Hau sistema eragilearen nukleorako API baten antzeko zerbait da. Garai batean, softwareak zuzeneko sarbidea zuen exekutatzen zuen hardwarerako. Adibidez, pantailan zerbait bistaratu behar bazen, bideo-gailuetarako portuekin edo memoria-mapatutako erregistroekin jolasten zen. Zeregin anitzeko sistema informatikoak ezagunak egin zirenean, kaosa nagusitu zen hainbat aplikazio hardwarearen aurka borrokatzen zirelako. Aplikazio batean akatsek beste batzuk eror ditzakete, sistema osoa ez bada. Orduan pribilegio moduak (edo "eraztun babesa") agertu ziren CPUan. Nukleoa pribilegiatuena bihurtu zen: hardwarerako sarbide osoa jaso zuen, sistema-deien bidez hardwarearekin elkarreragiteko jada nukleotik sarbidea eskatu behar zuten aplikazio pribilegiatu gutxiago sortuz.

Maila bitarrean, sistema-dei bat funtzio-dei soil batetik apur bat desberdina da, baina programa gehienek liburutegi estandarrean bilgarri bat erabiltzen dute. Horiek. POSIX C liburutegi estandarrak funtzio-dei bat dauka idatzi (), sistema-deirako arkitekturari dagokion kode guztia biltzen duena idatzi.

Strace-rekin softwarearen inplementazioa araztea

Laburbilduz, aplikazio baten eta bere ingurunearen (sistema informatikoen) arteko edozein elkarrekintza sistema-deien bidez gauzatzen da. Hori dela eta, softwareak makina batean baina ez beste batean funtzionatzen duenean, ondo legoke sistemaren deien trazazioaren emaitzak ikustea. Zehazkiago, hona hemen sistema-deien traza erabiliz azter daitezkeen puntu tipikoen zerrenda:

  • Kontsola I/O
  • Sareko I/O
  • Fitxategi-sistemaren sarbidea eta fitxategien I/O
  • Prozesuaren hari baten iraupena kudeatzea
  • Maila baxuko memoria kudeatzea
  • Gailu-kontrolatzaile zehatzetarako sarbidea

Noiz erabili strace?

Teorian, traza Erabiltzaile-espazioko edozein programekin erabiltzen da, erabiltzaile-espazioko edozein programak sistema-deiak egin behar dituelako. Eraginkorrago funtzionatzen du maila baxuko konpilatutako programekin, baina Python bezalako goi-mailako lengoaiekin ere funtzionatzen du exekuzio-denboratik eta interpretearen zarata gehigarria mozten baduzu.

Bere distira osoan traza makina batean ondo funtzionatzen duen softwarearen arazketan ageri da, baina bat-batean beste batean lan egiteari uzten dion, fitxategiei, baimenei edo komando batzuk edo beste zerbait exekutatzeko saiakerak arrakastarik gabeko saiakerei buruzko mezu lausoak sortuz... Pena da, baina ez du egiten. oso ondo konbinatu maila altuko arazoekin, hala nola ziurtagiriak egiaztatzeko akatsekin. Normalean honek konbinazio bat eskatzen du trazabatzuetan ltraza eta maila altuagoko tresnak (komando-lerroko tresna bezalakoak openssl ziurtagiria arazteko).

Adibide gisa zerbitzari autonomo bat erabiliko dugu, baina sistema-deien jarraipena askotan inplementazio-plataforma konplexuagoetan egin daiteke. Tresna egokiak aukeratu besterik ez duzu behar.

Arazte sinplearen adibidea

Demagun foo zerbitzari-aplikazio zoragarria exekutatu nahi duzula, eta hau da:

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

Dirudienez, ezin izan du idatzi duzun konfigurazio fitxategia aurkitu. Hori gertatzen da batzuetan paketeen kudeatzaileek aplikazio bat konpilatzen dutenean espero diren fitxategi-kokapenak gainidazten dituztelako. Eta banaketa baterako instalazio-gidari jarraituz gero, beste batean espero zenuen lekutik guztiz desberdinak diren fitxategiak aurkituko dituzu. Arazoa segundo pare batean konpondu liteke errore-mezuak konfigurazio fitxategia non bilatu esango balu, baina ez da horrela. Beraz, nora begiratu?

Iturburu-kodea sarbidea baduzu, irakurri eta dena jakin dezakezu. Babeskopia-plan ona, baina ez da irtenbiderik azkarrena. Hala nola, urratsez urratseko arazketara jo dezakezu gdb eta ikusi programak zer egiten duen, baina askoz eraginkorragoa da ingurunearekiko interakzioa erakusteko bereziki diseinatutako tresna bat erabiltzea: traza.

Irteera traza erredundantea dirudi, baina albiste ona da gehiena segurtasunez baztertu daitekeela. Sarritan erabilgarria da -o eragilea erabiltzea arrastoaren emaitzak fitxategi bereizi batean gordetzeko:

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

Gutxi gorabehera irteerako lehen orrialde osoa traza - Hau abiarazteko maila baxuko prestaketa izan ohi da. (Dei asko mmap, mprotect, luma behe-mailako memoria detektatzeko eta liburutegi dinamikoak bistaratzeko bezalako gauzetarako.) Egia esan, irteera arazketan zehar. traza Hobe da amaieratik irakurtzea. Behean erronka bat izango da idatzi, errore-mezu bat bistaratzen duena. Goian begiratu eta lehen sistema-dei okerra ikusiko dugu - deia irekita, akats bat botatzen duena ENOENT ("fitxategia edo direktorioa ez da aurkitu") irekitzen saiatzen /etc/foo/config.json. Hemen egon behar da konfigurazio fitxategia.

Hau adibide bat besterik ez zen, baina denboraren %90ean erabiltzen dudala esango nuke traza, ez dago hori baino askoz zailagorik egiteko. Jarraian urratsez urrats arazketa-gida osoa dago:

  • Haserretu programa baten sistema-y errore bati buruzko mezu lauso batengatik
  • Berrabiarazi programa honekin traza
  • Bilatu errore-mezua arrastoaren emaitzetan
  • Joan gorago huts egin duen sistema-deia lortu arte

Oso litekeena da 4. urratseko sistema-deiak oker gertatu dena agertzea.

Aholkuak

Arazketa konplexuagoaren adibide bat erakutsi aurretik, erabilera eraginkorra izateko zenbait trikimailu erakutsiko dizkizut traza:

gizona zure laguna da

*nix sistema askotan, kernelerako sistema-deien zerrenda osoa lor daiteke exekutatuz man syscalls. Horrelako gauzak ikusiko dituzu otsa (2), eta horrek esan nahi du informazio gehiago lor daitekeela korrika eginez gizona 2 brk.

Arrasto txikia: gizon 2 sardexka shell-aren orria erakusten dit sardexka () Π² GNU libc, dei eginez inplementatzen dena klonatu (). Deiaren semantika fork berdin jarraitzen du programa bat erabiliz idazten baduzu sardexka (), eta exekutatu arrasto bat - Ez dut deirik aurkituko fork, horien ordez egongo dira klonatu (). Iturburua irteerarekin alderatzen hasten bazara soilik nahasten zaituzte traza.

Erabili -o irteera fitxategi batean gordetzeko

traza irteera zabala sor dezake, beraz, sarritan erabilgarria da arrastoen emaitzak fitxategi bereizietan gordetzea (goiko adibidean bezala). Honek ere programaren irteera eta irteera nahastea saihesten laguntzen du traza kontsolan.

Erabili -s argumentu-datu gehiago ikusteko

Agian ohartuko zara errore-mezuaren bigarren erdia ez dela erakusten goiko adibideko arrastoan. Zeren da traza lehenetsiak katearen argumentuaren lehen 32 byteak bakarrik erakusten ditu. Gehiago ikusi nahi baduzu, gehitu antzeko zerbait -s 128 deiari traza.

-y-k fitxategiak, socketak, etab.

"Dena fitxategia da" esan nahi du *nix sistemek I/O guztiak egiten dituztela fitxategi deskribatzaileak erabiliz, fitxategi bati edo sare bati edo prozesuen arteko kanalizazioei aplikatzen zaien ala ez. Hau erosoa da programatzeko, baina zaila da benetan gertatzen ari denaren jarraipena egitea ohikoa ikusten duzunean irakurri ΠΈ idatzi sistema-deien arrastoaren emaitzetan.

Operadore bat gehituz -y, behartuko duzu traza apuntatu irteerako fitxategi-deskribatzaile bakoitza zertara apuntatzen duen ohar batekin.

Erantsi dagoeneko martxan dagoen prozesu bati -p**-rekin

Beheko adibidean ikusiko duzun bezala, batzuetan dagoeneko martxan dagoen programa baten trazatu behar duzu. 1337 prozesu gisa exekutatzen ari dela jakin bada (esan, irteeratik ps), orduan honela jarraitu dezakezu:

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

Baliteke root eskubideak behar izatea.

Erabili -f seme-alaben prozesuak kontrolatzeko

traza Lehenespenez, prozesu bakarra jarraitzen du. Prozesu honek haur-prozesuak sortzen baditu, orduan haur-prozesua sortzeko sistema-deia ikus daiteke, baina haurraren prozesuaren sistema-deiak ez dira bistaratuko.

Errorea haur prozesu batean dagoela uste baduzu, erabili adierazpena -f, honek bere trazatzea ahalbidetuko du. Honen alde txarra da irteerak are gehiago nahastuko zaituela. Noiz traza prozesu bat edo hari bat trazatzen du, dei-gertaeren korronte bakarra erakusten du. Hainbat prozesu aldi berean jarraitzen dituenean, baliteke dei baten hasiera mezu batek etenda ikustea , orduan - beste exekuzio adar batzuetarako dei mordoa, eta orduan bakarrik - lehenengoaren amaiera <...foocall berriro hasi da>. Edo zatitu arrastoaren emaitza guztiak fitxategi ezberdinetan, operadorea ere erabiliz -ff (xehetasunak atalean lidergoa on traza).

Iragazi arrastoak -e erabiliz

Ikus dezakezunez, arrastoaren emaitza sistema-dei posible guztien benetako pila bat da. Bandera -e Arrastoa iragazi dezakezu (ikus lidergoa on traza). Abantaila nagusia da azkarragoa dela traza iragazi bat exekutatzen traza osoa egitea baino eta gero grep`at. Egia esateko, ia beti berdin zait.

Akats guztiak ez dira txarrak

Adibide sinple eta ohikoa da aldi berean fitxategi bat hainbat lekutan bilatzen duen programa bat, fitxategi exekutagarri bat duen direktorio baten bila den shell bat bezala:

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

"Errore baten berri eman baino lehen huts egindako azken eskaera" bezalako heuristikoak onak dira akats garrantzitsuak aurkitzeko. Dena dela, logikoa da amaieratik hastea.

C programazio tutorialek sistema-deiak ulertzen lagun zaitzake.

C liburutegietarako dei estandarrak ez dira sistema deiak, gainazaleko geruza mehe bat baizik. Beraz, gutxienez pixka bat ulertzen baduzu nola eta zer egin C-n, errazagoa izango zaizu sistema-deien arrastoaren emaitzak ulertzea. Adibidez, sareko sistemetarako deiak arazketa arazoak dituzu, begiratu klasiko bera Bija-ren Sareko Programaziorako Gida.

Arazketa-adibide konplexuagoa

Dagoeneko esan dut arazketa sinplearen adibidea gehienbat lan egitean aurre egin behar dudanaren adibidea dela traza. Hala ere, batzuetan benetako ikerketa bat behar da, beraz, hona hemen arazketa aurreratuagoaren benetako adibide bat.

bcron - ataza prozesatzeko programatzailea, *nix deabruaren beste inplementazio bat cron. Zerbitzarian instalatuta dago, baina norbait programazioa editatzen saiatzen denean, hauxe gertatzen da:

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

Ados, horrek esan nahi du bcron fitxategi jakin bat idazten saiatu zen, baina ez zuen atera, eta ez du onartuko zergatik. Desestaltzen traza:

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

Errore-mezu bat dago amaieran idatzi, baina oraingoan zerbait ezberdina da. Lehenik eta behin, ez dago sistema-deien errore garrantzitsurik, hau baino lehen gertatu ohi dena. Bigarrenik, argi dago nonbait norbaitek dagoeneko irakurri duela errore-mezua. Benetako arazoa beste nonbait dagoela dirudi, eta bcrontab mezua erreproduzitzen du.

Begiratuz gero gizona 2 irakurri, ikus dezakezu lehen argumentua (3) fitxategi deskribatzailea dela, *nix-ek I/O prozesatzeko erabiltzen duena. Nola jakin dezaket zer fitxategi deskribatzailea adierazten duen 3? Kasu zehatz honetan, korrika egin dezakezu traza operadorearekin -y (ikus goian) eta automatikoki esango dizu, baina horrelako gauzak asmatzeko, baliagarria da arrastoen emaitzak irakurtzen eta analizatzen jakitea.

Fitxategiaren deskribatzaile baten iturburua sistema-dei askotako bat izan daiteke (deskriptorea zertarako denaren araberakoa da: kontsola bat, sareko socket bat, fitxategia bera edo beste zerbait), baina dena den, bilatzen dugu. deiak 3 itzuliz (hau da, "= 3" bilatzen dugu trazaduraren emaitzetan). Emaitza honetan 2 daude: irekita oso goian eta socket Erdian. irekita fitxategia irekitzen du baina itxi(3) orduan berriro ixten dela erakutsiko du. (Rake: fitxategien deskribatzaileak ireki eta ixten direnean berrerabili daitezke). Deitu socket () egokia, aurreko azkena delako irakurri (), eta bcrontab-ek socket baten bidez zerbaitekin funtzionatzen du. Hurrengo lerroan fitxategiaren deskribatzailea lotuta dagoela erakusten du unix domeinu socketa bidean /var/run/bcron-spool.

Beraz, lotutako prozesua aurkitu behar dugu unix socket Bestalde. Horretarako trikimailu txukun pare bat daude, biak zerbitzarien inplementazioak arazketarako erabilgarriak. Lehenengoa erabiltzea da netstat edo berriagoa ss (entxufearen egoera). Bi komandoek sistemaren sareko konexio aktiboak erakusten dituzte eta adierazpena hartzen dute -l entzuteko entxufeak deskribatzeko, baita operadorea ere -p socketera konektatutako programak bezero gisa bistaratzeko. (Aukera erabilgarri gehiago daude, baina bi hauek nahikoak dira zeregin honetarako).

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

Horrek iradokitzen du entzulea dela komandoa inixserver, 20629 prozesu IDarekin exekutatzen. (Eta, kasualitatez, 3. fitxategi deskribatzailea erabiltzen du socket gisa.)

Informazio bera aurkitzeko bigarren tresna benetan erabilgarria deitzen zaio lsof. Sisteman irekitako fitxategi guztiak (edo fitxategi deskribatzaileak) zerrendatzen ditu. Edo fitxategi zehatz bati buruzko informazioa lor dezakezu:

# 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

Prozesua 20629 iraupen luzeko zerbitzaria da, beraz, erantsi dezakezu traza antzeko zerbait erabiliz strace -o /tmp/trace -p 20629. Beste terminal batean cron lan bat editatzen baduzu, errore batekin traza-irteera bat jasoko duzu. Eta hona hemen emaitza:

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

(Azken onartu () ez da osatuko trazatzean.) Berriz ere, zoritxarrez, emaitza honek ez du bilatzen ari garen errorea. Ez dugu ikusten bcrontag-ek socketera bidaltzen edo jasotzen duen mezurik. Horren ordez, prozesuen kontrol osoa (klonatu, itxaron4, SIGCHLD etab.) Prozesu honek haur prozesu bat sortzen du, eta horrek, asma dezakezun bezala, benetako lana egiten du. Eta haren arrastoa hartu behar baduzu, gehitu deiari traza -f. Hau da strace-rekin emaitza berrian errore-mezua bilatzen dugunean aurkituko duguna -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 +++

Orain, hori da zerbait. 21470 prozesuak "sarbidea ukatuta" errore bat jasotzen du fitxategi bat bidetik sortzen saiatzean tmp/spool.21470.1573692319.854640 (uneko lan-direktorioari dagokiona). Uneko lan-direktorioa ezagutuko bagenu, bide osoa ere ezagutuko genuke eta prozesuak zergatik ezin duen bere aldi baterako fitxategia bertan sortu jakingo genuke. Zoritxarrez, prozesua dagoeneko amaitu da, beraz, ezin duzu erabili lsof -p 21470 uneko direktorioa aurkitzeko, baina kontrako norabidean lan egin dezakezu - bilatu direktorioa aldatzen duten PID 21470 sistema-deiak. (Ez badaude, PID 21470-k bere gurasoengandik heredatu behar ditu, eta hau dagoeneko bidezkoa da lsof -p ezin da aurkitu.) Sistema-dei hau da chdir (erraz aurki daiteke sareko bilatzaile modernoen laguntzarekin). Eta hona hemen arrastoen emaitzetan oinarritutako alderantzizko bilaketen emaitza, PID 20629 zerbitzariraino:

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

(Galtzen bazara, baliteke nire aurreko mezua irakurri nahi izatea *nix prozesuen kudeaketari eta shellei buruz.) Beraz, PID 20629 zerbitzariak ez zuen bide horretan fitxategi bat sortzeko baimenik jaso /var/spool/cron/tmp/spool.21470.1573692319.854640. Seguruenik, honen arrazoia fitxategi-sistemaren baimen-ezarpen klasikoak dira. Egiaztatu dezagun:

# 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

Hantxe dago lurperatu txakurra! Zerbitzaria erabiltzaile-cron gisa exekutatzen da, baina root-ek bakarrik du direktorioan idazteko baimena /var/spool/cron/tmp/. Agindu sinplea chown cron /var/spool/cron/tmp/ behartuko du bcron behar bezala lan egin. (Arazoa hori ez balitz, hurrengo susmagarriena SELinux edo AppArmor bezalako nukleoaren segurtasun-modulu bat da, beraz nukleoaren mezuen erregistroa egiaztatuko nuke. dmesg.)

Guztira

Sistema-deien arrastoak erabatekoa izan daiteke hasiberri batentzat, baina espero dut inplementazio-arazo arrunten klase osoa arazteko modu azkar bat dela erakutsi izana. Imajinatu multiprozesu bat arazten saiatzen ari zarela bcronurratsez urrats arazte bat erabiliz.

Sistemaren deien katearen arrastoen emaitzak atzerantz analizatzeak trebetasuna eskatzen du, baina esan bezala, ia beti, erabiltzea traza, arrastoaren emaitza lortzen dut eta amaieratik hasita akatsak bilatzen ditut. Dena den, traza arazketan denbora asko aurrezten laguntzen dit. Zuretzat ere baliagarria izatea espero dut.

Iturria: www.habr.com

Gehitu iruzkin berria