Sencimiga programaro deplojo kun strace

Sencimiga programaro deplojo kun strace

Mia taga laboro estas plejparte programara deplojo, kio signifas, ke mi pasigas multan tempon provante respondi demandojn kiel:

  • Ĉi tiu programaro funkcias por la programisto, sed ne por mi. Kial?
  • Hieraŭ ĉi tiu programaro funkciis por mi, sed hodiaŭ ĝi ne funkcias. Kial?

Ĉi tio estas speco de senararigado, kiu estas iomete diferenca de regula programara senararigado. Regula senararigado temas pri la logiko de la kodo, sed disfalda sencimigo temas pri la interago inter la kodo kaj la medio. Eĉ se la radiko de la problemo estas logika eraro, la fakto ke ĉio funkcias sur unu maŝino kaj ne sur alia signifas, ke la problemo estas iel en la medio.

Do anstataŭ la kutimaj sencimigaj iloj kiel gdb Mi havas malsaman aron da iloj por sencimiga deplojo. Kaj mia plej ŝatata ilo por trakti la problemon kiel "Kial ĉi tiu programaro ne funkcias por mi?" vokis strace.

Kio estas strace?

strace estas ilo por "sistema voka spurado". Ĝi estis origine kreita por Linukso, sed la samaj sencimigaj lertaĵoj povas esti faritaj per iloj por aliaj sistemoj (DTracektrace).

La baza aplikaĵo estas tre simpla. Vi nur bezonas ruli Strace per iu ajn komando kaj ĝi forĵetos ĉiujn sistemajn vokojn (kvankam unue vi verŝajne devos instali ĝin mem). 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 +++

Kio estas ĉi tiuj sistemvokoj? Ĉi tio estas io kiel API por la operaciuma kerno. Iam, programaro havis rektan aliron al la aparataro, per kiu ĝi funkciis. Se, ekzemple, ĝi bezonis montri ion sur la ekrano, ĝi ludis per havenoj aŭ memor-mapitaj registroj por video-aparatoj. Kiam plurtaskaj komputilsistemoj populariĝis, kaoso regis dum diversaj aplikaĵoj batalis pri la aparataro. Eraroj en unu aplikaĵo povus faligi aliajn, se ne la tutan sistemon. Tiam privilegiaj reĝimoj (aŭ "ringa protekto") aperis en la CPU. La kerno iĝis la plej privilegiita: ĝi ricevis plenan aliron al la aparataro, generi malpli privilegiitajn aplikojn, kiuj jam devis peti aliron de la kerno por interagi kun la aparataro per sistemaj vokoj.

Je la binara nivelo, sistemvoko estas iomete diferenca de simpla funkciovoko, sed la plej multaj programoj uzas envolvaĵon en la norma biblioteko. Tiuj. la POSIX C-norma biblioteko enhavas funkciovokon skribi (), kiu enhavas la tutan arkitektur-specifan kodon por la sistemvoko skribi.

Sencimiga programaro deplojo kun strace

Resume, ajna interago inter aplikaĵo kaj ĝia medio (komputilaj sistemoj) estas efektivigita per sistemaj vokoj. Sekve, kiam programaro funkcias sur unu maŝino sed ne sur alia, estus bone rigardi la sistemajn vokatajn rezultojn. Pli specife, jen listo de tipaj punktoj, kiuj povas esti analizitaj per sistema voka spuro:

  • Konzolo I/O
  • Reto I/O
  • Dosiersistema aliro kaj dosiero I/O
  • Administri la vivdaŭron de proceza fadeno
  • Malaltnivela memoradministrado
  • Aliro al specifaj aparataj ŝoforoj

Kiam uzi strace?

En teorio, strace uzata kun iu ajn programo en uzantspaco, ĉar ĉiu programo en uzantspaco devas fari sistemajn vokojn. Ĝi funkcias pli efike kun kompilitaj, malaltnivelaj programoj, sed ĝi ankaŭ funkcias kun altnivelaj lingvoj kiel Python se vi povas tranĉi la aldonan bruon de la rultempo kaj interpretisto.

En sia tuta gloro strace manifestiĝas dum senararigado de programaro, kiu bone funkcias ĉe unu maŝino, sed subite ĉesas labori ĉe alia, produktante neklarajn mesaĝojn pri dosieroj, permesoj aŭ malsukcesaj provoj plenumi iujn ordonojn aŭ ion alian... Domaĝe, sed ĝi ne faras. kombinas tiel bone kun altnivelaj problemoj kiel ekzemple atestilkontrolaj eraroj. Kutime ĉi tio postulas kombinaĵon straceiafoje lspuro kaj pli altnivelaj iloj (kiel la komandlinia ilo openssl por sencimigi la atestilon).

Ni uzos memstaran servilon kiel ekzemplon, sed sistema voka spurado ofte povas esti farita sur pli kompleksaj deplojplatformoj. Vi nur bezonas elekti la ĝustajn ilojn.

Simpla elpuriga ekzemplo

Ni diru, ke vi volas ruli la mirindan servilan aplikaĵon foo, kaj jen kio vi finas:

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

Ŝajne ĝi ne trovis la agordan dosieron, kiun vi skribis. Ĉi tio okazas ĉar foje kiam pakaĵadministrantoj kompilas aplikaĵon, ili superregas la atendatajn dosierlokojn. Kaj se vi sekvas la instalan gvidilon por unu distribuo, en alia vi trovas dosierojn tute malsamajn ol kie vi atendis. La problemo povus esti solvita en kelkaj sekundoj se la erarmesaĝo dirus kie serĉi la agordan dosieron, sed ĝi ne faras. Do kie rigardi?

Se vi havas aliron al la fontkodo, vi povas legi ĝin kaj ekscii ĉion. Bona rezerva plano, sed ne la plej rapida solvo. Vi povas recurri al paŝo post paŝo erarserĉilo kiel gdb kaj vidu kion faras la programo, sed estas multe pli efika uzi ilon kiu estas specife desegnita por montri interagadon kun la medio: strace.

konkludo strace eble ŝajnas superflua, sed la bona novaĵo estas, ke la plej granda parto de ĝi povas esti sekure ignorita. Ofte estas utile uzi la operatoron -o por konservi spurrezultojn al aparta dosiero:

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

Proksimume la tuta unua paĝo de eligo strace - Ĉi tio estas kutime malaltnivela preparo por lanĉo. (Multaj vokoj mmap, mprotekti, plumo por aferoj kiel detekti malaltnivelan memoron kaj montri dinamikajn bibliotekojn.) Efektive, dum senararigado de la eligo strace Pli bone legi de la fino mem. Estos defio sube skribi, kiu montras erarmesaĝon. Ni rigardas supre kaj vidas la unuan eraran sistemvokon - la vokon openat, kiu ĵetas eraron ENOENT ("dosiero aŭ dosierujo ne trovita") provante malfermi /etc/foo/config.json. Ĉi tie devus esti la agorda dosiero.

Ĉi tio estis nur ekzemplo, sed mi dirus 90% de la tempo, kiun mi uzas strace, estas nenio pli malfacila por fari ol ĉi tio. Malsupre estas kompleta paŝo-post-paŝa sencimiga gvidilo:

  • Ĉagreniĝu pro neklara mesaĝo pri sistema-y-eraro de programo
  • Rekomencu la programon per strace
  • Trovu la erarmesaĝon en la spurrezultoj
  • Iru pli alte ĝis vi trafos la unuan malsukcesan sistemvokon

Estas tre verŝajne, ke la sistemvoko en paŝo 4 rivelos kio misfunkciis.

Konsiloj

Antaŭ ol montri al vi ekzemplon de pli kompleksa senararigado, mi montros al vi kelkajn lertaĵojn por efika uzo strace:

viro estas via amiko

Sur multaj *nix-sistemoj, kompleta listo de sistemvokoj al la kerno povas esti akirita per funkciado man syscalls. Vi vidos aferojn kiel brk (2), kio signifas ke pli da informoj povas esti akiritaj per kurado viro 2 brk.

Malgranda rastilo: viro 2 forko montras al mi la paĝon por la ŝelo forko () в GNU-libc, kiu, ĝi rezultas, estas efektivigita per vokado kloni(). Voku semantiko forkon restas la sama se vi skribas programon uzante forko (), kaj rulu spuron - mi ne trovos vokojn forkon, anstataŭ ili estos kloni(). Tiaj rastiloj nur konfuzas vin se vi komencas kompari la fonton kun la eligo strace.

Uzu -o por konservi la eligon al dosiero

strace povas generi ampleksan produktaĵon, do ofte utilas konservi spurrezultojn en apartaj dosieroj (kiel en la supra ekzemplo). Ĉi tio ankaŭ helpas eviti konfuzi program-produktaĵon kun eligo strace en la konzolo.

Uzu -s por vidi pliajn argumentajn datumojn

Vi eble rimarkis, ke la dua duono de la erarmesaĝo ne estas montrita en la ekzempla spuro supre. Estas ĉar strace defaŭlte montras nur la unuajn 32 bajtojn de la ĉenargumento. Se vi volas vidi pli, aldonu ion similan -s 128 al la voko strace.

-y faciligas spuri dosierojn, ingojn, ktp.

"Ĉio estas dosiero" signifas, ke *nix-sistemoj faras ĉiujn I/O uzante dosierpriskribilojn, ĉu tio validas por dosiero aŭ reto aŭ interprocezaj tuboj. Ĉi tio estas oportuna por programado, sed malfaciligas konservi trakon de kio vere okazas kiam vi vidas komunan legi и skribi en la sistemvoka spurrezultoj.

Aldonante operatoron Jes, vi devigos strace komentu ĉiun dosierpriskribilon en la eligo kun noto pri tio, al kio ĝi montras.

Alligiĝu al jam funkcianta procezo per -p**

Kiel vi vidos el la ekzemplo sube, foje vi devas spuri programon, kiu jam funkcias. Se oni scias, ke ĝi funkcias kiel procezo 1337 (diru, de la eligo ps), tiam vi povas spuri ĝin jene:

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

Vi eble bezonas radikrajtojn.

Uzu -f por monitori infanajn procezojn

strace Defaŭlte, ĝi spuras nur unu procezon. Se ĉi tiu procezo generas infanprocezojn, tiam la sistemvoko por generi la infanprocezon povas esti vidita, sed la sistemvokoj de la infanprocezo ne estos montrataj.

Se vi pensas, ke la eraro estas en infana procezo, uzu la deklaron -f, ĉi tio ebligos ĝian spuradon. La malavantaĝo de ĉi tio estas, ke la eligo eĉ pli konfuzos vin. Kiam strace spuras unu procezon aŭ unu fadenon, ĝi montras ununuran fluon de vokaj eventoj. Kiam ĝi spuras plurajn procezojn samtempe, vi povas vidi la komencon de voko interrompita de mesaĝo , tiam - aro da vokoj por aliaj ekzekutbranĉoj, kaj nur tiam - la fino de la unua <...foocall rekomencis>. Aŭ dividi ĉiujn spurrezultojn en malsamajn dosierojn, ankaŭ uzante la funkciigiston -ff (detaloj en gvidado sur strace).

Filtri spurojn uzante -e

Kiel vi povas vidi, la rezulto de la spuro estas vera amaso de ĉiuj eblaj sistemvokoj. Flago -e Vi povas filtri la spuron (vidu gvidado sur strace). La ĉefa avantaĝo estas, ke estas pli rapide ruli filtritan spuron ol fari plenan spuron kaj poste grep`je. Verdire, mi preskaŭ ĉiam ne zorgas.

Ne ĉiuj eraroj estas malbonaj

Simpla kaj ofta ekzemplo estas programo serĉanta dosieron en pluraj lokoj samtempe, kiel ŝelo serĉanta dosierujon kiu enhavas ruleblan dosieron:

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

Heŭristiko kiel "lasta malsukcesa peto antaŭ raporti eraron" kapablas trovi koncernajn erarojn. Estu kiel ajn, estas logike komenci de la fino mem.

C programaj lerniloj povas helpi vin kompreni sistemajn vokojn.

Normaj vokoj al C-bibliotekoj ne estas sistemvokoj, sed nur maldika surfactavolo. Do, se vi komprenas almenaŭ iomete kiel kaj kion fari en C, estos pli facile por vi kompreni la rezultojn de la sistema voka spuro. Ekzemple, vi havas problemojn pri senararvokoj al retaj sistemoj, rigardu la saman klasikaĵon La Gvidilo de Bija pri Reta Programado.

Pli kompleksa sencimiga ekzemplo

Mi jam diris, ke la ekzemplo de simpla sencimigo estas ekzemplo de tio, pri kio mi plejparte devas trakti kiam mi laboras strace. Tamen foje necesas reala esploro, do jen realviva ekzemplo de pli altnivela senararigado.

bcron - tasko-pretiga planilo, alia efektivigo de la *nix-demono cron. Ĝi estas instalita sur la servilo, sed kiam iu provas redakti la horaron, jen kio okazas:

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

Bone, tio signifas bcron provis skribi certan dosieron, sed ĝi ne sukcesis, kaj li ne konfesos kial. Malkovrante 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 +++

Estas erarmesaĝo proksime de la fino skribi, sed ĉi-foje io estas alia. Unue, ne ekzistas grava sistema alvoka eraro, kiu kutime okazas antaŭ ĉi tio. Due, estas klare, ke ie iu jam legis la erarmesaĝon. Ŝajnas, ke la vera problemo estas aliloke, kaj bcrontab simple reludas la mesaĝon.

Se vi rigardas viro 2 legi, vi povas vidi ke la unua argumento (3) estas dosierpriskribilo, kiun *nix uzas por ĉiu I/O-pretigo. Kiel mi ekscias, kian dosierpriskribilon 3 reprezentas? En ĉi tiu aparta kazo, vi povas kuri strace kun funkciigisto Jes (vidu supre) kaj ĝi aŭtomate diros al vi, sed por eltrovi tiajn aferojn, estas utile scii kiel legi kaj analizi spurrezultojn.

La fonto de dosierpriskribilo povas esti unu el multaj sistemvokoj (ĉio dependas de por kio la priskribilo estas - konzolo, retkonekto, la dosiero mem aŭ io alia), sed estu kiel ajn, ni serĉas vokas resendante 3 (t.e. ni serĉas "= 3" en la spurrezultoj). En ĉi tiu rezulto estas 2 el ili: openat ĉe la plej supro kaj socket Meze. openat malfermas la dosieron sed proksimaj(3) tiam montros, ke ĝi denove fermiĝas. (Rake: dosierpriskribiloj povas esti reuzitaj kiam ili estas malfermitaj kaj fermitaj). Voku ingo () taŭga ĉar ĝi estas la lasta antaŭe legi (), kaj rezultas, ke bcrontab funkcias kun io per ingo. La sekva linio montras, ke la dosierpriskribilo estas asociita kun Unikso-domajna ingo survoje /var/run/bcron-spool.

Do, ni devas trovi la procezon asociita kun uniksa ingo sur la alia flanko. Estas kelkaj bonegaj lertaĵoj por ĉi tiu celo, kiuj ambaŭ estas utilaj por sencimigi servildeplojojn. La unua estas uzi netstat aŭ pli nova ss (statuso de ingo). Ambaŭ komandoj montras la aktivajn retajn konektojn de la sistemo kaj prenas la deklaron -l priskribi aŭskultantajn ingojn, same kiel la funkciigiston -p por montri programojn konektitajn al la ingo kiel kliento. (Estas multaj pli utilaj opcioj, sed ĉi tiuj du sufiĉas por ĉi tiu tasko.)

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

Ĉi tio sugestas, ke la aŭskultanto estas la komando inixserver, funkcianta kun proceza ID 20629. (Kaj, hazarde, ĝi uzas dosierpriskribilon 3 kiel la ingon.)

La dua vere utila ilo por trovi la saman informon nomiĝas lsof. Ĝi listigas ĉiujn malfermitajn dosierojn (aŭ dosierpriskribilojn) en la sistemo. Aŭ vi povas ricevi informojn pri unu specifa dosiero:

# 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

Procezo 20629 estas longdaŭra servilo, do vi povas alligi ĝin strace uzante ion kiel strace -o /tmp/trace -p 20629. Se vi redaktas cron-laboron en alia terminalo, vi ricevos spuron kun eraro. Kaj jen la rezulto:

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

(Lasta akcepti () ne estos kompletigita dum spurado.) Denove, bedaŭrinde, ĉi tiu rezulto ne enhavas la eraron, kiun ni serĉas. Ni ne vidas mesaĝojn, kiujn bcrontag sendas aŭ ricevas de la ingo. Anstataŭe, kompleta proceza kontrolo (klono, atendu4, SIGCHLD ktp.) Ĉi tiu procezo generas infanan procezon, kiu, kiel vi povas supozi, faras la veran laboron. Kaj se vi bezonas kapti ŝian spuron, aldonu al la voko strace -f. Jen kion ni trovos kiam ni serĉos la erarmesaĝon en la nova rezulto kun 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 +++

Nun, tio estas io. Procezo 21470 ricevas eraron de "aliro rifuzita" kiam li provas krei dosieron ĉe la vojo tmp/spool.21470.1573692319.854640 (rilate al la nuna labordosierujo). Se ni nur scius la nunan labordosierujon, ni ankaŭ konus la plenan vojon kaj povus eltrovi kial la procezo ne povas krei sian provizoran dosieron en ĝi. Bedaŭrinde, la procezo jam eliris, do vi ne povas simple uzi lsof -p 21470 por trovi la nunan dosierujon, sed vi povas labori en la kontraŭa direkto - serĉu PID 21470 sistemvokojn kiuj ŝanĝas la dosierujon. (Se ne ekzistas, PID 21470 certe heredis ilin de sia gepatro, kaj ĉi tio jam estas tra lsof -p ne povas esti eltrovita.) Ĉi tiu sistemvoko estas chdir (kiu estas facile eltrovebla helpe de modernaj retaj serĉiloj). Kaj jen la rezulto de inversaj serĉoj bazitaj sur la spurrezultoj, ĝis la servilo 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 +++

(Se vi estas perdita, vi eble volas legi mian antaŭan afiŝon pri *nix-proceza administrado kaj ŝeloj.) Do, la servilo PID 20629 ne ricevis permeson krei dosieron ĉe la vojo /var/spool/cron/tmp/spool.21470.1573692319.854640. Plej verŝajne, la kialo de ĉi tio estas la klasikaj dosiersistemaj permesaj agordoj. Ni kontrolu:

# 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

Tie estas enterigita la hundo! La servilo funkcias kiel uzanta cron, sed nur root havas permeson skribi al la dosierujo /var/spool/cron/tmp/. Simpla komando chown cron /var/spool/cron/tmp/ devigos bcron funkcii ĝuste. (Se tio ne estis la problemo, tiam la sekva plej verŝajna suspektato estas kerna sekureca modulo kiel SELinux aŭ AppArmor, do mi kontrolus la kernan mesaĝan protokolon per dmesg.)

Tuta

Sistemvokospuroj povas esti superfortaj por komencanto, sed mi esperas, ke mi montris, ke ili estas rapida maniero sencimigi tutan klason de oftaj deplojproblemoj. Imagu provi sencimigi multprocezon bcronuzante paŝon post paŝo erarserĉilon.

Analizi spurrezultojn malantaŭen laŭ la sistema voka ĉeno postulas lertecon, sed kiel mi diris, preskaŭ ĉiam, uzi strace, mi nur ricevas la spurrezulton kaj serĉas erarojn ekde la fino. Ĉiuokaze, strace helpas min ŝpari multe da tempo pri senararigado. Mi esperas, ke ĝi estos utila ankaŭ al vi.

fonto: www.habr.com

Aldoni komenton