Dabeşkirina nermalavê bi strace

Dabeşkirina nermalavê bi strace

Karê min ê rojane bi piranî bicîhkirina nermalavê ye, ku tê vê wateyê ku ez gelek wext derbas dikim ku ez bersiv bidim pirsên wekî:

  • Ev nermalavê ji bo pêşdebirker dixebite, lê ne ji bo min. Çima?
  • Duh vê nermalavê ji min re dixebitî, lê îro nake. Çima?

Ev celebek xeletkirinê ye ku ji xeletkirina nermalava birêkûpêk hinekî cûda ye. Debugkirina birêkûpêk li ser mantiqa kodê ye, lê debuggkirina bicîhkirinê li ser danûstendina di navbera kod û hawîrdorê de ye. Her çend koka pirsgirêkê xeletiyek mentiqî be jî, rastiya ku her tişt li ser makîneyek û ne li ser makîneyek din dixebite tê vê wateyê ku pirsgirêk bi rengek di hawîrdorê de ye.

Ji ber vê yekê li şûna amûrên xeletkirinê yên adetî yên mîna gdb Ji bo sazkirina debugkirinê komek amûrek cûda ya min heye. Û amûra min a bijare ji bo mijûlbûna bi pirsgirêka mîna "Çima ev nermalavê ji min re naxebite?" gazî kirin strace.

Strace çi ye?

strace amûrek ji bo "şopandina banga pergalê" ye. Ew bi eslê xwe ji bo Linux-ê hate afirandin, lê heman hîleyên xeletkirinê dikarin bi amûrên pergalên din re bêne kirin (DTrace an ktrace).

Serîlêdana bingehîn pir hêsan e. Hûn tenê hewce ne ku bi her fermanê re strace bimeşînin û ew ê hemî bangên pergalê bavêje (tevî ku pêşî hûn ê neçar bin ku wê bixwe saz bikin 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 +++

Ev bangên sîstemê çi ne? Ev tiştek mîna API-ê ji bo kernelê pergala xebitandinê ye. Carekê, nermalavê rasterast gihîştina hardware ya ku li ser dixebitî bû. Mînakî, heke hewce bû ku tiştek li ser ekranê nîşan bide, ew ji bo cîhazên vîdyoyê bi portan an tomarên nexşeya bîranînê lîstin. Dema ku pergalên komputerê yên pirzimanî populer bûn, kaos serdest bû ji ber ku sepanên cihêreng li ser hardware şer kirin. Çewtiyên di yek serîlêdanê de dikarin yên din hilweşînin, heke ne tevahiya pergalê. Dûv re modên îmtiyazê (an "parastina ring") di CPU de xuya bûn. Kernel bû ya herî bi îmtiyaz: ew gihîştina tam a hardware wergirt, serîlêdanên kêmtir îmtiyaz derxist holê ku berê neçar mabû ku ji kernelê bigihîje da ku bi navgîniya bangên pergalê re bi hardware re têkilî daynin.

Di asta binary de, bangek pergalê ji bangek fonksiyonek hêsan hinekî cûda ye, lê pir bername di pirtûkxaneya standard de pêçekek bikar tînin. Ewan. pirtûkxaneya standard POSIX C bangek fonksiyonê dihewîne nivîsîn(), ku ji bo banga pergalê hemî koda mîmarî-taybetî dihewîne nivîsîn.

Dabeşkirina nermalavê bi strace

Bi kurtasî, her têkiliyek di navbera serîlêdanek û hawîrdora wê (pergalên komputerê) de bi bangên pergalê ve tête kirin. Ji ber vê yekê, gava ku nermalavê li ser makîneyek lê ne li ser yekî din dixebite, dê baş be ku meriv li encamên şopandina banga pergalê binêre. Bi taybetî, li vir navnîşek xalên tîpîk ên ku bi karanîna şopek banga pergalê têne analîz kirin heye:

  • Konsolê I/O
  • Tora I/O
  • Gihîştina pergala pelê û pelê I/O
  • Birêvebirina jiyana pêvajoyek pêvajoyek
  • Rêveberiya bîra-asta kêm
  • Gihîştina ajokarên cîhaza taybetî

Kengê strace bikar bînin?

Di teoriyê de, strace bi her bernameyekê di cîhê bikarhêner de tê bikar anîn, ji ber ku her bernameyek di cîhê bikarhêner de divê bangên pergalê bike. Ew bi bernameyên berhevkirî,-asta nizm re bi bandortir dixebite, lê di heman demê de bi zimanên astek bilind ên mîna Python re jî dixebite heke hûn dikarin dengê zêde ji dema xebitandinê û wergêrê qut bikin.

Di hemû rûmeta xwe de strace di dema debugkirina nermalava ku li ser makîneyek baş dixebite, xwe nîşan dide, lê ji nişka ve li ser makîneyek din dixebite, peyamên nezelal der barê pelan, destûran de, an hewildanên neserkeftî yên pêkanîna hin fermanan an tiştek din çêdike... Heyf e, lê na bi pirsgirêkên asta bilind ên wekî xeletiyên verastkirina sertîfîkayê re ew qas baş tevbigerin. Bi gelemperî ev yek bi hev re hewce dike stracecarna ltrace û amûrên asta bilind (wek amûra rêzika fermanê openssl ji bo rastkirina sertîfîkayê).

Em ê wekî mînakek serverek serbixwe bikar bînin, lê şopandina banga pergalê bi gelemperî li ser platformên bicîhkirina tevlihevtir dikare were kirin. Hûn tenê hewce ne ku amûrên rast hilbijêrin.

Mînaka debugkirina hêsan

Ka em bibêjin ku hûn dixwazin serîlêdana servera ecêb bimeşînin, û tiştê ku hûn bi dawî dibin ev e:

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

Xuya ye ku wê nikarî pela veavakirinê ya ku we nivîsî bibîne. Ev diqewime ji ber ku carinan gava ku rêvebirên pakêtê serîlêdanek berhev dikin, ew cîhên pelê yên hêvîdar derbas dikin. Û heke hûn rêbernameya sazkirinê ji bo yek belavkirinê bişopînin, di ya din de hûn pelan bi tevahî ji cihê ku we hêvî dikir cûda dibînin. Pirsgirêk dikare di nav çend saniyan de were çareser kirin heke peyama xeletiyê bêje ku hûn li pelê veavakirinê li ku bigerin, lê ew nabe. Ji ber vê yekê li ku derê binêrin?

Heke hûn gihîştina koda çavkaniyê heye, hûn dikarin wê bixwînin û her tiştî fêr bibin. Planek paşvekêşana baş, lê ne çareseriya herî bilez. Hûn dikarin serî li debugerek gav-bi-gav bidin mîna gdb û bibînin ka bername çi dike, lê pir bi bandortir e ku meriv amûrek bikar bîne ku bi taybetî hatî çêkirin da ku têkiliya bi jîngehê re nîşan bide: strace.

encamê strace dibe ku bêkêmasî xuya bike, lê nûçeya baş ev e ku piraniya wê dikare bi ewlehî were paşguh kirin. Pir caran kêrhatî ye ku meriv operator -o bikar bîne da ku encamên şopandinê li pelek cûda hilîne:

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

Nêzîkî tevahiya rûpela yekem a hilberê strace - Ev bi gelemperî ji bo destpêkirinê amadekariya asta nizm e. (Gelek bang mmap, mprotect, quill ji bo tiştên wekî tesbîtkirina bîra kêm-asta û nîşandana pirtûkxaneyên dînamîkî.) Bi rastî, di dema verastkirina derketinê de strace Çêtir e ku meriv ji dawiyê bixwîne. Dê dijwariyek li jêr hebe nivîsîn, ku peyamek çewtiyê nîşan dide. Em li jor dinêrin û yekem banga pergala çewt - bang openat, ku xeletiyek derdixe ENOENT ("pel an pelrêça nehat dîtin") hewl dide veke /etc/foo/config.json. Li vir divê pelê veavakirinê lê be.

Ev tenê mînakek bû, lê ez ê bibêjim 90% ji dema ku ez bikar tînim strace, tiştekî ji vê dijwartir nîne. Li jêr rêbernameyek bêkêmasî ya gav-bi-gav heye:

  • Ji ber peyamek nezelal di derbarê xeletiyek pergalê-y ji bernameyekê aciz bibin
  • Bernameyê ji nû ve bidin destpêkirin strace
  • Di encamên şopandinê de peyama xeletiyê bibînin
  • Herin bilindtir heya ku hûn yekem banga pergala têkçûyî bixin

Pir îhtîmal e ku banga pergalê ya di gava 4-an de dê eşkere bike ka çi xelet derket.

Hîretan

Berî ku ez mînakek xeletkirina tevlihevtir nîşanî we bidim, ez ê ji bo karanîna bi bandor çend hîleyan nîşanî we bidim strace:

mêr hevalê te ye

Li ser gelek pergalên *nix, navnîşek bêkêmasî ya bangên pergalê ji kernelê re dikare bi xebitandinê were bidestxistin mêr sîscalls. Hûn ê tiştên mîna bibînin brk(2), ku tê vê wateyê ku bêtir agahdarî dikare bi xebitandinê were bidestxistin mêr 2 brk.

Rafa piçûk: mêr 2 qalik rûpela şêlê nîşanî min dide milêvdanî() в GNU libc, ya ku derket holê, bi bangkirinê tê pêkanîn klon (). Banga semantîk milêvdanî Heke hûn bernameyek bikar bînin binivîsin heman dimîne milêvdanî(), û şopek bimeşîne - Ez ê tu bangan nabînim milêvdanî, li şûna wan dê hebin klon (). Ger hûn dest bi berhevkirina çavkaniyê bi derketinê re bikin, rakêşên wusa tenê we tevlihev dikin strace.

-o-ê bikar bînin ku encam li pelek tomar bike

strace dikare encamek berfireh çêbike, ji ber vê yekê pir caran bikêr e ku encamên şopandinê di pelên cûda de hilînin (wek mînaka li jor). Ev jî dibe alîkar ku hûn hilberîna bernameyê bi encam re tevlihev nekin strace di konsolê de.

-s bikar bînin da ku bêtir daneyên argumanan bibînin

Dibe ku we ferq kiriye ku nîvê duyemîn ê peyama xeletiyê di şopa mînaka li jor de nayê xuyang kirin. Ji ber ku strace default tenê 32 baytên pêşîn ên argumana rêzê nîşan dide. Heke hûn dixwazin bêtir bibînin, tiştek mîna zêde bikin -s 128 ji bo bangê strace.

-y şopandina pelan, soketan, hwd hêsantir dike.

"Hemû pel e" tê vê wateyê ku * pergalên nix hemî I/O bi karanîna ravekerên pelan dikin, çi ew ji bo pelek an torgilokek an lûleyên navpêvajoyê derbas dibe. Ev ji bo bernamekirinê rehet e, lê dema ku hûn hevpar dibînin şopandina tiştê ku bi rastî diqewime dijwar dike xwendin и nivîsîn di pergalê de bang encamên şopê dikin.

Bi zêdekirina operatorek y, hûn ê zor bikin strace her ravekerê pelê di encam de bi têbînîyek ku ew çi nîşan dide binivîsin.

Bi -p** pêvajoyek jixwe dimeşe ve girêdin

Wekî ku hûn ê ji mînaka jêrîn bibînin, carinan hûn hewce ne ku bernameyek ku jixwe tê xebitandin bişopînin. Ger tê zanîn ku ew wekî pêvajoya 1337 dimeşîne (dibêjin, ji derketinê ps), wê hingê hûn dikarin bi vî rengî bişopînin:

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

Dibe ku hûn hewceyê mafên root bin.

Ji bo şopandina pêvajoyên zarokan -f bikar bînin

strace Bi xwerû, ew tenê pêvajoyek dişopîne. Ger ev pêvajo pêvajoyên zarokan çêdike, wê hingê banga pergalê ya ji bo hilanîna pêvajoya zarok dikare were dîtin, lê bangên pergalê yên pêvajoya zarokê nayên xuyang kirin.

Heke hûn difikirin ku xeletî di pêvajoyek zarokê de ye, daxuyaniyê bikar bînin -f, ev ê şopandina wê bike. Nerazîbûna vê ev e ku encam dê we hîn bêtir tevlihev bike. Heke strace yek pêvajoyek an yek xêzek dişopîne, ew yek rûkalek bûyerên bangê nîşan dide. Gava ku ew bi yekcarî gelek pêvajoyan dişopîne, dibe ku hûn destpêka bangek ku ji hêla peyamek ve hatî qut kirin bibînin , paşê - komek bangên ji bo şaxên darvekirinê yên din, û tenê hingê - dawiya yekem <…çavkaniyê ji nû ve dest pê kir>. An jî hemî encamên şopandinê li pelên cûda dabeş bikin, di heman demê de operator jî bikar bînin -ff (hûrgilî di birêvebirî li ser strace).

Parzûna şopên bi bikaranîna -e

Wekî ku hûn dikarin bibînin, encama şopê pileyek rastîn a hemî bangên pergalê yên gengaz e. Al -e Hûn dikarin şopê fîlter bikin (binêre birêvebirî li ser strace). Feydeya sereke ev e ku meriv şopek fîlterkirî ji kirina şopek tevahî û dûv re zûtir e grep`li. Bi rastî, ez hema her gav ne xema min e.

Hemî xeletî ne xirab in

Nimûneyek hêsan û gelemperî bernameyek e ku di yek carî de li pelek li çend deveran digere, mîna şêlek ku li pelrêçekek ku pelek îcrakar tê de ye digere:

$ 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 mîna "daxwaza paşîn a têkçûyî berî raporkirina xeletiyek" di dîtina xeletiyên têkildar de baş in. Welê ku dibe bila bibe, mentiqî ye ku meriv ji dawiyê dest pê bike.

Dersên bernamesaziya C dikarin ji we re bibin alîkar ku hûn bangên pergalê fam bikin.

Bangên standard ji pirtûkxaneyên C re ne bangên pergalê ne, lê tenê tebeqeyek rûkalek zirav e. Ji ber vê yekê, heke hûn bi kêmanî piçek fêm bikin ka meriv çawa û çi di C-yê de bike, dê ji we re hêsantir be ku hûn encamên şopa banga pergalê fam bikin. Mînakî, hûn di rakirina bangên pergalên torê de pirsgirêk hene, li heman klasîk binêrin Bija's Guide to Programming Network.

Nimûneyek jihevdebirina tevlihevtir

Min berê jî got ku mînaka xeletkirina hêsan mînakek e ya ku ez bi piranî dema ku pê re dixebitim pê re mijûl dibim strace. Lêbelê, carinan vekolînek rastîn hewce ye, ji ber vê yekê li vir mînakek rast-jiyana debugkirina pêşkeftî heye.

bcron - Plansazkera pêvajoyek peywirê, pêkanîna din a *nix daemon cron. Ew li ser serverê hatî saz kirin, lê gava ku kesek hewl dide ku bernameyê biguherîne, ev tişt dibe:

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

Okay, ev tê wê wateyê bcron hewl da ku pelek diyar binivîse, lê ew bi ser neket, û ew ê qebûl neke çima. Vekirin 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 +++

Peyamek çewtiyek nêzîkê dawiyê heye nivîsîn, lê vê carê tiştek cûda ye. Pêşîn, xeletiyek banga pergalê ya têkildar tune, ku bi gelemperî berî vê yekê çêdibe. Ya duyemîn, diyar e ku li cîhek kesek berê peyama xeletiyê xwendiye. Wusa dixuye ku pirsgirêka rastîn li cîhek din e, û bcrontab bi tenê peyamê vedigerîne.

Ger hûn lê binêrin mêr 2 xwendin, hûn dikarin bibînin ku argumana yekem (3) ravekerek pelê ye, ku *nix ji bo hemî pêvajoyên I/O bikar tîne. Ez çawa dikarim bibînim ka ravekera pelê 3 çi temsîl dike? Di vê rewşa taybetî de, hûn dikarin birevin strace bi operator y (li jor binêre) û ew ê bixweber ji we re vebêje, lê ji bo ku hûn tiştên bi vî rengî fam bikin, kêrhatî ye ku hûn zanibin meriv çawa encamên şopandinê bixwîne û pars bike.

Çavkaniya ravekerek pelê dikare yek ji gelek bangên pergalê be (ew hemî bi wê ve girêdayî ye ku diyarker ji bo çi ye - konsolek, soketek torê, pel bixwe, an tiştek din), lê wusa be, em lê digerin. bi vegerandina 3 re bang dike (ango em di encamên şopandinê de li "= 3" digerin). Di vê encamê de 2 ji wan hene: openat di serî de pir û çarçowe Di navîn. openat pelê lê vedike nêzîkî(3) wê hingê dê nîşan bide ku ew dîsa girtî ye. (Rake: Danasîna pelan dema ku têne vekirin û girtin dikarin ji nû ve werin bikar anîn). Bang çarçowe() minasib ji ber ku ew ya paşîn a berê ye xwendin(), û derket holê ku bcrontab bi tiştek bi riya soketê re dixebite. Rêza paşîn nîşan dide ku ravekera pelê pê re têkildar e soketa domaina unix wizeya erênî /var/run/bcron-spool.

Ji ber vê yekê, pêdivî ye ku em pêvajoyek ku pê ve girêdayî ye bibînin soketa unix li aliyê din. Ji bo vê mebestê çend hîleyên xweş hene, ku her du jî ji bo rakirina rêgezên serverê bikêr in. Ya yekem ew e ku bikar bînin netstat an nûtir ss (rewşa soketê). Her du ferman girêdanên torê yên çalak ên pergalê destnîşan dikin û daxuyaniyê digirin -l ji bo danasîna soketên guhdarîkirinê, û hem jî operator -p ji bo nîşandana bernameyên girêdayî soketê wek muwekîlê. (Gelek vebijarkên bikêrtir hene, lê ev her du ji bo vî karî bes in.)

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

Ev pêşniyar dike ku guhdar emir e inixserver, bi ID-ya pêvajoyê 20629 dixebite. (Û, bi tesadufî, ew ravekera pelê 3 wekî soket bikar tîne.)

Amûra duyemîn a bi rastî kêrhatî ji bo dîtina heman agahiyê tê gotin lsof. Ew hemî pelên vekirî (an ravekerên pelan) li ser pergalê navnîş dike. An jî hûn dikarin li ser pelek taybetî agahdarî bistînin:

# 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

Pêvajoya 20629 serverek demdirêj e, ji ber vê yekê hûn dikarin pê ve girêbidin strace bikaranîna tiştekî wek strace -o /tmp/trace -p 20629. Ger hûn di termînalek din de karek kronê biguherînin, hûn ê encamek şopek bi xeletiyek bistînin. Û li vir encam e:

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

(Dawîn baweranîn() dema şopandinê temam nabe.) Dîsa, mixabin, ev encam xeletiya ku em lê digerin tune ye. Em ti peyamên ku bcrontag ji soketê dişîne an distîne nabînin. Di şûna wê de, kontrolkirina pêvajoyê bi tevahî (clone, bisekinin4, SIGCHLD hwd.) Ev pêvajo pêvajoyek zarokê çêdike, ku, wekî ku hûn texmîn dikin, karê rastîn dike. Û heke hûn hewce ne ku şopa wê bigirin, li bangê zêde bikin strace -f. Ya ku em ê gava ku em di encama nû de bi strace li peyama xeletiyê bigerin ev e -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 +++

Niha, ew tiştek e. Pêvajoya 21470 dema ku hewl dide ku pelek di rê de biafirîne xeletiyek "gihiştinê red kir" distîne tmp/spool.21470.1573692319.854640 (girêdayî pelrêça xebatê ya heyî). Ger me tenê pelrêça xebatê ya heyî bizanibûya, em ê rêça tevahî jî zanibin û karibin fam bikin ka çima pêvajo nikare pelê xweya demkî tê de biafirîne. Mixabin, pêvajo jixwe derketiye, ji ber vê yekê hûn nekarin tenê bikar bînin lsof -p 21470 ji bo ku pelrêça heyî bibînin, lê hûn dikarin berevajî vê yekê bixebitin - li bangên pergala PID 21470 ku pelrêçê diguhezîne bigerin. (Heke tune be, divê PID 21470 wan ji dêûbavê xwe mîras girtibe, û ev jixwe derbas dibe lsof -p nayê dîtin.) Ev banga sîstemê ye chdir (ku bi alîkariya motorên lêgerînê yên serhêl ên nûjen têne fêr kirin hêsan e). Û li vir encama lêgerînên berevajî yên li ser bingeha encamên şopandinê, heya heya servera PID 20629 heye:

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

(Heke hûn winda bûne, dibe ku hûn bixwazin nivîsa min a berê bixwînin li ser * rêveberiya pêvajoya nix û şêlên.) Ji ber vê yekê, servera PID 20629 destûr negirt ku pelek li ser rê çêbike /var/spool/cron/tmp/spool.21470.1573692319.854640. Bi îhtîmalek mezin, sedema vê yekê mîhengên destûra pergala pelê ya klasîk e. Ka em kontrol bikin:

# 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

Li wê derê kûçik tê veşartin! Pêşkêşkar wekî kronek bikarhêner dimeşe, lê tenê root destûr heye ku li pelrêçê binivîse /var/spool/cron/tmp/. Fermana hêsan chown cron /var/spool/cron/tmp/ dê zorê bike bcron rast dixebitin. (Heke ew ne pirsgirêk bû, wê hingê gumanbarê paşîn modulek ewlehiya kernelê ya mîna SELinux an AppArmor e, ji ber vê yekê ez ê têketina peyama kernelê bi kontrol bikim dmesg.)

Tevahî

Şopên bangewaziya pergalê dikare ji bo destpêkek pir giran be, lê ez hêvî dikim ku min destnîşan kir ku ew rêyek bilez in ku hûn çînek tevahî pirsgirêkên bicîhkirina hevpar derxînin. Bifikirin ku hewl didin ku pirpêvajoyek debug bikin bcronbikaranîna debugger-gav-gav.

Parzûnkirina şopa encamên paşverû li ser zincîra bangê ya pergalê jêhatîbûnê hewce dike, lê wekî ku min got, hema hema her gav, karanîna strace, Ez tenê encama şopandinê distînim û ji dawiyê dest pê dike li xeletiyan digerim. Herçi jî, strace ji min re dibe alîkar ku gelek dem li ser debuggkirinê xilas bikim. Ez hêvî dikim ku ew ê ji we re jî bikêr be.

Source: www.habr.com

Add a comment