Feilsøking av programvaredistribusjon med strace

Feilsøking av programvaredistribusjon med strace

Dagsjobben min er for det meste programvaredistribusjon, noe som betyr at jeg bruker mye tid på å prøve å svare på spørsmål som:

  • Denne programvaren fungerer for utvikleren, men ikke for meg. Hvorfor?
  • I går fungerte denne programvaren for meg, men i dag gjør den det ikke. Hvorfor?

Dette er en slags feilsøking som er litt forskjellig fra vanlig programvarefeilsøking. Vanlig feilsøking handler om logikken i koden, men distribusjonsfeilsøking handler om samspillet mellom koden og miljøet. Selv om roten til problemet er en logisk feil, betyr det at alt fungerer på en maskin og ikke på en annen at problemet på en eller annen måte er i miljøet.

Så i stedet for de vanlige feilsøkingsverktøyene som gdb Jeg har et annet sett med verktøy for å feilsøke distribusjon. Og mitt favorittverktøy for å håndtere problemet som "Hvorfor fungerer ikke denne programvaren for meg?" kalt strace.

Hva er strace?

strace er et verktøy for "systemanropssporing". Det ble opprinnelig laget for Linux, men de samme feilsøkingstriksene kan gjøres med verktøy for andre systemer (DTrace eller ktrace).

Den grunnleggende applikasjonen er veldig enkel. Du trenger bare å kjøre strace med hvilken som helst kommando, og den vil dumpe alle systemanrop (selv om du sannsynligvis må installere den selv først 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 +++

Hva er disse systemanropene? Dette er noe sånt som et API for operativsystemkjernen. En gang i tiden hadde programvare direkte tilgang til maskinvaren den kjørte på. Hvis den for eksempel trengte å vise noe på skjermen, spilte den med porter eller minnetilordnede registre for videoenheter. Da multitasking-datasystemer ble populære, hersket kaos da ulike applikasjoner kjempet om maskinvaren. Feil i ett program kan ødelegge andre, hvis ikke hele systemet. Deretter dukket privilegiemoduser (eller "ringbeskyttelse") opp i CPU'en. Kjernen ble den mest privilegerte: den fikk full tilgang til maskinvaren, og skapte mindre privilegerte applikasjoner som allerede måtte be om tilgang fra kjernen for å samhandle med maskinvaren gjennom systemanrop.

På binært nivå er et systemkall litt forskjellig fra et enkelt funksjonskall, men de fleste programmer bruker en innpakning i standardbiblioteket. De. POSIX C standardbiblioteket inneholder et funksjonskall skrive(), som inneholder all den arkitekturspesifikke koden for systemkallet skrive.

Feilsøking av programvaredistribusjon med strace

Kort sagt, enhver interaksjon mellom en applikasjon og dens miljø (datasystemer) utføres gjennom systemanrop. Derfor, når programvare fungerer på én maskin, men ikke på en annen, ville det være greit å se på resultatene for systemanropssporing. Mer spesifikt, her er en liste over typiske punkter som kan analyseres ved hjelp av en systemanropssporing:

  • Konsoll I/O
  • Nettverk I/U
  • Filsystemtilgang og fil I/O
  • Administrere levetiden til en prosesstråd
  • Minneadministrasjon på lavt nivå
  • Tilgang til spesifikke enhetsdrivere

Når skal man bruke strace?

I teorien, strace brukes med et hvilket som helst program i brukerrommet, fordi ethvert program i brukerrommet må foreta systemanrop. Det fungerer mer effektivt med kompilerte programmer på lavt nivå, men det fungerer også med høynivåspråk som Python hvis du kan kutte gjennom ekstra støy fra kjøretiden og tolken.

I all sin prakt strace manifesterer seg under feilsøking av programvare som fungerer bra på en maskin, men som plutselig slutter å fungere på en annen, produserer vage meldinger om filer, tillatelser eller mislykkede forsøk på å utføre noen kommandoer eller noe annet... Det er synd, men det gjør det ikke kombineres så godt med problemer på høyt nivå som sertifikatverifiseringsfeil. Vanligvis krever dette en kombinasjon strace, noen ganger spore og verktøy på høyere nivå (som kommandolinjeverktøyet openssl for å feilsøke sertifikatet).

Vi vil bruke en frittstående server som et eksempel, men systemanropssporing kan ofte gjøres på mer komplekse distribusjonsplattformer. Du trenger bare å velge de riktige verktøyene.

Enkelt feilsøkingseksempel

La oss si at du vil kjøre den fantastiske serverapplikasjonen foo, og dette er hva du ender opp med:

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

Tilsynelatende kunne den ikke finne konfigurasjonsfilen du skrev. Dette skjer fordi noen ganger når pakkebehandlere kompilerer et program, overstyrer de de forventede filplasseringene. Og hvis du følger installasjonsveiledningen for en distribusjon, i en annen finner du filer helt andre enn du forventet. Problemet kan løses i løpet av et par sekunder hvis feilmeldingen fortalte hvor du skal lete etter konfigurasjonsfilen, men det gjør den ikke. Så hvor skal du se?

Hvis du har tilgang til kildekoden, kan du lese den og finne ut alt. En god backup-plan, men ikke den raskeste løsningen. Du kan ty til en trinnvis debugger som gdb og se hva programmet gjør, men det er mye mer effektivt å bruke et verktøy som er spesielt utviklet for å vise interaksjon med miljøet: strace.

Utgang strace kan virke overflødig, men den gode nyheten er at det meste trygt kan ignoreres. Det er ofte nyttig å bruke -o-operatoren for å lagre sporingsresultater i en egen fil:

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

Omtrent hele første side med utdata strace – Dette er vanligvis lavnivå forberedelser til lansering. (Mange samtaler mmap, beskytte, fjærpenn for ting som å oppdage lavnivåminne og vise dynamiske biblioteker.) Faktisk under feilsøking av utdata strace Det er bedre å lese helt fra slutten. Det kommer en utfordring nedenfor skrive, som viser en feilmelding. Vi ser ovenfor og ser det første feilaktige systemanropet - anropet åpnet, som gir en feil ENOENT ("fil eller katalog ikke funnet") prøver å åpne /etc/foo/config.json. Det er her konfigurasjonsfilen skal være.

Dette var bare et eksempel, men jeg vil si at 90% av tiden jeg bruker strace, det er ikke noe mye vanskeligere å gjøre enn dette. Nedenfor er en komplett trinn-for-trinn feilsøkingsveiledning:

  • Bli opprørt på grunn av en vag melding om en system-y-feil fra et program
  • Start programmet på nytt med strace
  • Finn feilmeldingen i sporingsresultatene
  • Gå høyere til du treffer det første mislykkede systemanropet

Det er svært sannsynlig at systemanropet i trinn 4 vil avsløre hva som gikk galt.

tips

Før jeg viser deg et eksempel på mer kompleks feilsøking, vil jeg vise deg noen triks for effektiv bruk strace:

mann er din venn

På mange *nix-systemer kan en komplett liste over systemkall til kjernen fås ved å kjøre mann syscaller. Du vil se ting som brk(2), noe som betyr at mer informasjon kan fås ved å kjøre mann 2 brk.

Liten rake: mann 2 gaffel viser meg siden for skallet gaffel() в GNU libc, som, det viser seg, implementeres ved å ringe klone(). Ring semantikk gaffel forblir den samme hvis du skriver et program med gaffel(), og kjør et spor - jeg finner ingen anrop gaffel, i stedet for dem vil det være klone(). Slike raker forvirrer deg bare hvis du begynner å sammenligne kilden med utgangen strace.

Bruk -o for å lagre utdataene til en fil

strace kan generere omfattende utdata, så det er ofte nyttig å lagre sporingsresultater i separate filer (som i eksempelet ovenfor). Dette bidrar også til å unngå å forveksle programutdata med utdata strace i konsollen.

Bruk -s for å vise flere argumentdata

Du har kanskje lagt merke til at andre halvdel av feilmeldingen ikke vises i eksempelsporet ovenfor. Det er fordi strace standard viser bare de første 32 bytene av strengargumentet. Hvis du vil se mer, legg til noe som -s 128 til samtalen strace.

-y gjør det enklere å spore filer, stikkontakter, etc.

"All is file" betyr at *nix-systemer gjør all I/O ved å bruke filbeskrivelser, enten det gjelder en fil eller et nettverk eller interprosess-rør. Dette er praktisk for programmering, men gjør det vanskelig å holde styr på hva som egentlig skjer når du ser vanlig lese и skrive i systemanropssporingsresultatene.

Ved å legge til en operatør -y, vil du tvinge strace merk hver filbeskrivelse i utdataene med en merknad om hva den peker på.

Koble til en allerede kjørende prosess med -p**

Som du vil se fra eksemplet nedenfor, må du noen ganger spore et program som allerede kjører. Hvis det er kjent at det kjører som prosess 1337 (f.eks. fra utgangen ps), så kan du spore det slik:

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

Du trenger kanskje root-rettigheter.

Bruk -f for å overvåke underordnede prosesser

strace Som standard sporer den bare én prosess. Hvis denne prosessen skaper underordnede prosesser, kan systemkallet for å gyte underprosessen sees, men underordnet prosessens systemanrop vil ikke bli vist.

Hvis du tror feilen er i en underordnet prosess, bruk setningen -f, vil dette aktivere sporingen. Ulempen med dette er at utgangen vil forvirre deg enda mer. Når strace sporer én prosess eller én tråd, den viser en enkelt strøm av samtalehendelser. Når den sporer flere prosesser samtidig, kan du se starten på en samtale avbrutt av en melding , deretter - en haug med oppfordringer til andre henrettelsesgrener, og først da - slutten av den første <...foocall gjenopptatt>. Eller del opp alle sporingsresultater i forskjellige filer, også ved å bruke operatøren -ff (detaljer i ledelsestrace).

Filtrer spor ved å bruke -e

Som du kan se, er resultatet av sporingen en reell haug med alle mulige systemanrop. Flagg -e Du kan filtrere sporet (se lederskapstrace). Den største fordelen er at det er raskere å kjøre en filtrert trace enn å gjøre en full trace og deretter grep`kl. For å være ærlig bryr jeg meg nesten alltid.

Ikke alle feil er dårlige

Et enkelt og vanlig eksempel er et program som leter etter en fil flere steder samtidig, som et skall som leter etter en katalog som inneholder en kjørbar fil:

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

Heuristikk som «siste mislykkede forespørsel før feilrapportering» er gode til å finne relevante feil. Uansett er det logisk å starte helt fra slutten.

C-programmeringsveiledninger kan hjelpe deg å forstå systemanrop.

Standardanrop til C-biblioteker er ikke systemanrop, men kun et tynt overflatelag. Så hvis du i det minste forstår litt hvordan og hva du skal gjøre i C, vil det være lettere for deg å forstå resultatene av systemanropssporingen. For eksempel har du problemer med å feilsøke anrop til nettverkssystemer, se på den samme klassikeren Bijas guide til nettverksprogrammering.

Et mer komplekst feilsøkingseksempel

Jeg har allerede sagt at eksemplet med enkel feilsøking er et eksempel på hva jeg stort sett må forholde meg til når jeg jobber med strace. Noen ganger kreves det imidlertid en reell undersøkelse, så her er et virkelighetseksempel på mer avansert feilsøking.

bcron - oppgavebehandlingsplanlegger, en annen implementering av *nix-demonen cron. Det er installert på serveren, men når noen prøver å redigere tidsplanen, skjer dette:

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

Ok, det betyr bcron prøvde å skrive en bestemt fil, men det gikk ikke, og han vil ikke innrømme hvorfor. Avdekke 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 +++

Det er en feilmelding helt på slutten skrive, men denne gangen er noe annerledes. For det første er det ingen relevant systemanropsfeil, som vanligvis oppstår før dette. For det andre er det tydelig at noen allerede har lest feilmeldingen et sted. Det ser ut som det virkelige problemet er et annet sted, og bcrontab bare spiller av meldingen.

Hvis du ser på mann 2 lest, kan du se at det første argumentet (3) er en filbeskrivelse, som *nix bruker for all I/O-behandling. Hvordan finner jeg ut hva filbeskrivelse 3 representerer? I dette spesielle tilfellet kan du løpe strace med operatør -y (se ovenfor), og det vil automatisk fortelle deg det, men for å finne ut ting som dette, er det nyttig å vite hvordan du leser og analyserer sporingsresultater.

Kilden til en filbeskrivelse kan være en av mange systemanrop (alt avhenger av hva beskrivelsen er for - en konsoll, en nettverkskontakt, selve filen eller noe annet), men uansett hvor det er, ser vi etter anrop ved å returnere 3 (dvs. vi ser etter "= 3" i sporingsresultatene). I dette resultatet er det 2 av dem: åpnet helt på toppen og stikkontakt I midten. åpnet åpner filen men nær(3) vil da vise at den lukkes igjen. (Rake: filbeskrivelser kan gjenbrukes når de åpnes og lukkes). Anrop stikkontakt() egnet fordi det er den siste før lese(), og det viser seg at bcrontab fungerer med noe gjennom en socket. Den neste linjen viser at filbeskrivelsen er knyttet til unix domene socket er på vei /var/run/bcron-spool.

Så vi må finne prosessen knyttet til unix-kontakt på den andre siden. Det er et par fine triks for dette formålet, som begge er nyttige for feilsøking av serverdistribusjoner. Den første er å bruke netstat eller nyere ss (kontaktstatus). Begge kommandoene viser systemets aktive nettverksforbindelser og tar setningen -l for å beskrive lyttekontakter, samt operatøren -p for å vise programmer koblet til stikkontakten som en klient. (Det er mange flere nyttige alternativer, men disse to er tilstrekkelige for denne oppgaven.)

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

Dette antyder at lytteren er kommandoen inixserver, kjører med prosess-ID 20629. (Og tilfeldigvis bruker den filbeskrivelse 3 som socket.)

Det andre virkelig nyttige verktøyet for å finne den samme informasjonen kalles lsof. Den viser alle åpne filer (eller filbeskrivelser) på systemet. Eller du kan få informasjon om én bestemt fil:

# 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 en langvarig server, så du kan koble den til strace bruker noe sånt som strace -o /tmp/trace -p 20629. Hvis du redigerer en cron-jobb i en annen terminal, vil du motta en sporingsutgang med en feil. Og her er resultatet:

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

(Siste aksepterer() vil ikke bli fullført ved sporing.) Igjen, dessverre, dette resultatet inneholder ikke feilen vi ser etter. Vi ser ingen meldinger som bcrontag sender til eller mottar fra kontakten. I stedet fullfør prosesskontroll (klone, vent4, SIGCHLD osv.) Denne prosessen skaper en barneprosess, som, som du kanskje gjetter, gjør det virkelige arbeidet. Og hvis du trenger å fange sporet hennes, legg til i samtalen strace -f. Dette er hva vi finner når vi søker etter feilmeldingen i det nye resultatet med 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å, det er noe. Prosess 21470 mottar en "tilgang nektet"-feil når du prøver å opprette en fil på banen tmp/spool.21470.1573692319.854640 (relatert til gjeldende arbeidskatalog). Hvis vi bare kjente den gjeldende arbeidskatalogen, ville vi også vite hele banen og kunne finne ut hvorfor prosessen ikke kan opprette den midlertidige filen i den. Dessverre har prosessen allerede avsluttet, så du kan ikke bare bruke lsof -p 21470 for å finne gjeldende katalog, men du kan jobbe i motsatt retning - se etter PID 21470-systemanrop som endrer katalogen. (Hvis det ikke er noen, må PID 21470 ha arvet dem fra overordnet, og dette er allerede gjennom lsof -s kan ikke bli funnet ut.) Dette systemanropet er chdir (som er lett å finne ut ved hjelp av moderne nettsøkemotorer). Og her er resultatet av omvendte søk basert på sporingsresultatene, helt til server 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 +++

(Hvis du er borte, kan det være lurt å lese mitt forrige innlegg om *nix prosessstyring og skjell.) Så serveren PID 20629 fikk ikke tillatelse til å opprette en fil på banen /var/spool/cron/tmp/spool.21470.1573692319.854640. Mest sannsynlig er årsaken til dette de klassiske tillatelsesinnstillingene for filsystemet. La oss sjekke:

# 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

Det er der hunden ligger begravet! Serveren kjører som en bruker-cron, men bare root har tillatelse til å skrive til katalogen /var/spool/cron/tmp/. Enkel kommando chown cron /var/spool/cron/tmp/ vil tvinge bcron fungere riktig. (Hvis det ikke var problemet, så er den nest mest sannsynlige mistenkte en kjernesikkerhetsmodul som SELinux eller AppArmor, så jeg ville sjekket kjernemeldingsloggen med dmesg.)

Totalt

Systemanropssporing kan være overveldende for en nybegynner, men jeg håper jeg har vist at de er en rask måte å feilsøke en hel klasse med vanlige distribusjonsproblemer. Tenk deg å prøve å feilsøke en multiprosess bcronved hjelp av en trinn-for-trinn debugger.

Å analysere sporingsresultater bakover langs systemanropskjeden krever ferdigheter, men som jeg sa, nesten alltid, ved å bruke strace, jeg får bare sporingsresultatet og ser etter feil fra slutten. Uansett, strace hjelper meg å spare mye tid på feilsøking. Jeg håper det vil være nyttig for deg også.

Kilde: www.habr.com

Legg til en kommentar