Strace ilə proqram təminatının yerləşdirilməsi

Strace ilə proqram təminatının yerləşdirilməsi

Mənim gündəlik işim əsasən proqram təminatının yerləşdirilməsidir, yəni mən suallara cavab verməyə çox vaxt sərf edirəm:

  • Bu proqram tərtibatçı üçün işləyir, amma mənim üçün deyil. Niyə?
  • Dünən bu proqram mənim üçün işlədi, amma bu gün işləmir. Niyə?

Bu, adi proqram təminatından bir qədər fərqli olan bir növ sazlamadır. Müntəzəm sazlama kodun məntiqi ilə bağlıdır, lakin yerləşdirmə üzrə sazlama kod və ətraf mühit arasında qarşılıqlı əlaqədir. Problemin kökü məntiqi xəta olsa belə, hər şeyin bir maşında işləməsi, başqa bir maşında işləməməsi problemin bir növ mühitdə olması deməkdir.

Belə ki, kimi adi ayıklama vasitələri yerinə gdb Yerləşdirməni sazlamaq üçün müxtəlif alətlər dəstim var. Və problemlə məşğul olmaq üçün ən çox sevdiyim alət "Bu proqram niyə mənim üçün işləmir?" çağırdı zolaq.

strace nədir?

zolaq “sistem zənglərinin izlənməsi” üçün bir vasitədir. Əvvəlcə Linux üçün yaradılmışdır, lakin eyni sazlama fəndləri digər sistemlər üçün alətlərlə edilə bilər (DTrace və ya ktrace).

Əsas tətbiq çox sadədir. Siz sadəcə olaraq hər hansı bir əmrlə strace-i işlətməlisiniz və o, bütün sistem zənglərini ləğv edəcək (baxmayaraq ki, əvvəlcə onu özünüz quraşdırmalı olacaqsınız. zolaq):

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

Bu sistem çağırışları nədir? Bu, əməliyyat sisteminin nüvəsi üçün API kimi bir şeydir. Bir zamanlar proqram təminatının işlədiyi aparatlara birbaşa çıxışı var idi. Məsələn, ekranda nəyisə göstərmək lazım idisə, o, video qurğular üçün portlar və ya yaddaşla əlaqəli registrlərlə oynayırdı. Çox tapşırıqlı kompüter sistemləri populyarlaşdıqda, müxtəlif proqramlar aparat üzərində mübarizə apararkən xaos hökm sürdü. Bir tətbiqdəki səhvlər bütün sistemi olmasa da, digərlərini sıradan çıxara bilər. Sonra CPU-da imtiyaz rejimləri (və ya "zəngin qorunması") göründü. Kernel ən imtiyazlı oldu: o, sistem zəngləri vasitəsilə aparatla qarşılıqlı əlaqədə olmaq üçün artıq nüvədən giriş tələb etməli olan daha az imtiyazlı proqramları meydana gətirərək, aparata tam giriş əldə etdi.

Binar səviyyədə sistem çağırışı sadə funksiya çağırışından bir qədər fərqlidir, lakin əksər proqramlar standart kitabxanada sarğıdan istifadə edir. Bunlar. POSIX C standart kitabxanasında funksiya çağırışı var yaz (), sistem çağırışı üçün bütün arxitekturaya aid kodu ehtiva edir yazmaq.

Strace ilə proqram təminatının yerləşdirilməsi

Bir sözlə, proqram və onun mühiti (kompüter sistemləri) arasında istənilən qarşılıqlı əlaqə sistem çağırışları vasitəsilə həyata keçirilir. Buna görə də, proqram bir maşında işləyərkən, digərində işləməyəndə, sistem zənglərinin izlənməsi nəticələrinə baxmaq yaxşı olardı. Daha dəqiq desək, burada sistem zəngi izi ilə təhlil edilə bilən tipik nöqtələrin siyahısı verilmişdir:

  • Konsol giriş/çıxışı
  • Şəbəkə I/O
  • Fayl sisteminə giriş və fayl I/O
  • Bir proses ipinin ömrünü idarə etmək
  • Aşağı səviyyəli yaddaş idarəetməsi
  • Xüsusi cihaz sürücülərinə giriş

strace nə vaxt istifadə edilməlidir?

Nəzəriyyədə, zolaq istifadəçi məkanında hər hansı bir proqramla istifadə olunur, çünki istifadəçi məkanında hər hansı bir proqram sistem zəngləri etməlidir. O, tərtib edilmiş, aşağı səviyyəli proqramlarla daha səmərəli işləyir, lakin iş vaxtından və tərcüməçidən əlavə səs-küyü kəsə bilsəniz, Python kimi yüksək səviyyəli dillərlə də işləyir.

Bütün əzəməti ilə zolaq bir maşında yaxşı işləyən proqram təminatının sazlanması zamanı özünü büruzə verir, lakin birdən-birə digərində işləməyi dayandırır, fayllar, icazələr haqqında qeyri-müəyyən mesajlar istehsal edir və ya bəzi əmrləri və ya başqa bir şeyi yerinə yetirmək üçün uğursuz cəhdlər edir... Çox təəssüf ki, amma yox. sertifikat yoxlama səhvləri kimi yüksək səviyyəli problemlərlə çox yaxşı birləşir. Adətən bu birləşməni tələb edir zolaqbəzən ltrace və daha yüksək səviyyəli alətlər (məsələn, komanda xətti aləti OpenSSL sertifikatı sazlamaq üçün).

Nümunə olaraq müstəqil serverdən istifadə edəcəyik, lakin sistem zənglərinin izlənməsi çox vaxt daha mürəkkəb yerləşdirmə platformalarında edilə bilər. Yalnız düzgün alətləri seçmək lazımdır.

Sadə sazlama nümunəsi

Deyək ki, siz heyrətamiz server tətbiqi foo-nu işə salmaq istəyirsiniz və nəticədə belə olur:

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

Görünür, yazdığınız konfiqurasiya faylını tapa bilmədi. Bu ona görə baş verir ki, bəzən paket menecerləri proqram tərtib edərkən gözlənilən fayl yerlərini üstələyirlər. Bir paylama üçün quraşdırma təlimatına əməl etsəniz, digərində gözlədiyiniz yerdən tamamilə fərqli fayllar tapacaqsınız. Səhv mesajı konfiqurasiya faylını harada axtarmaq lazım olduğunu söyləyərsə, problem bir neçə saniyə ərzində həll edilə bilər, lakin bu, yoxdur. Bəs hara baxmaq lazımdır?

Əgər mənbə koduna çıxışınız varsa, onu oxuyub hər şeyi öyrənə bilərsiniz. Yaxşı bir ehtiyat planı, lakin ən sürətli həll yolu deyil. kimi addım-addım sazlayıcıya müraciət edə bilərsiniz gdb və proqramın nə etdiyini görün, lakin ətraf mühitlə qarşılıqlı əlaqəni göstərmək üçün xüsusi olaraq hazırlanmış bir alətdən istifadə etmək daha effektivdir: zolaq.

Buraxılış zolaq lazımsız görünə bilər, amma yaxşı xəbər odur ki, onların əksəriyyətinə təhlükəsiz şəkildə məhəl qoyula bilməz. İz nəticələrini ayrıca faylda saxlamaq üçün -o operatorundan istifadə etmək çox vaxt faydalıdır:

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

Çıxışın təxminən bütün birinci səhifəsi zolaq - Bu, adətən, buraxılış üçün aşağı səviyyəli hazırlıqdır. (Çoxlu zənglər mmap, qoruyucu, tüy aşağı səviyyəli yaddaşın aşkarlanması və dinamik kitabxanaların göstərilməsi kimi şeylər üçün.) Əslində, çıxışı sazlama zamanı zolaq Sondan oxumaq daha yaxşıdır. Aşağıda bir problem olacaq yazmaq, səhv mesajı göstərən. Biz yuxarıya baxırıq və ilk səhv sistem çağırışını görürük - zəng , xəta atır ENOENT (“fayl və ya kataloq tapılmadı”) açmağa çalışır /etc/foo/config.json. Bu, konfiqurasiya faylının yerləşdiyi yerdir.

Bu sadəcə bir nümunə idi, amma istifadə etdiyim vaxtın 90%-ni deyərdim zolaq, bundan daha çətin bir iş yoxdur. Aşağıda tam addım-addım sazlama təlimatı verilmişdir:

  • Proqramdan sistem-y xətası haqqında qeyri-müəyyən mesaja görə əsəbləşin
  • ilə proqramı yenidən başladın zolaq
  • Səhv mesajını izləmə nəticələrində tapın
  • İlk uğursuz sistem zənginə çatana qədər yuxarı qalxın

Çox güman ki, 4-cü addımda sistem çağırışı nəyin səhv olduğunu aşkar edəcək.

Göstərişlər

Sizə daha mürəkkəb sazlama nümunəsini göstərməzdən əvvəl mən sizə effektiv istifadə üçün bir neçə fənd göstərəcəyəm zolaq:

insan sənin dostundur

Bir çox *nix sistemlərində nüvəyə sistem çağırışlarının tam siyahısını işə salmaqla əldə etmək olar adam sistit çağırır. kimi şeylər görəcəksiniz brk(2), yəni işləməklə daha çox məlumat əldə etmək olar adam 2 brk.

Kiçik dırmıq: adam 2 çəngəl mənə qabıq üçün səhifəni göstərir çəngəl () в GNU libc, belə çıxır ki, çağırmaqla həyata keçirilir klon(). Zəng semantikası yaba istifadə edərək proqram yazsanız eyni qalır çəngəl (), və izi işə salın - mən heç bir zəng tapa bilməyəcəyəm yaba, onların yerinə olacaq klon(). Mənbəni çıxışla müqayisə etməyə başlasanız, belə dırmıqlar sizi çaşdırır zolaq.

Çıxışı faylda saxlamaq üçün -o istifadə edin

zolaq geniş çıxış yarada bilər, ona görə də iz nəticələrini ayrı-ayrı fayllarda saxlamaq çox vaxt faydalıdır (yuxarıdakı nümunədə olduğu kimi). Bu, həmçinin proqramın çıxışı ilə çıxışı çaşdırmaqdan qaçmağa kömək edir zolaq konsolda.

Daha çox arqument datasına baxmaq üçün -s istifadə edin

Siz səhv mesajının ikinci yarısının yuxarıdakı nümunə izində göstərilmədiyini fərq etmiş ola bilərsiniz. Ona görədir zolaq default sətir arqumentinin yalnız ilk 32 baytını göstərir. Daha çox görmək istəyirsinizsə, kimi bir şey əlavə edin -128 zəngə zolaq.

-y faylları, yuvaları və s. izləməyi asanlaşdırır.

"Hamısı fayldır" o deməkdir ki, *nix sistemləri fayl deskriptorlarından istifadə edərək bütün I/O-nu yerinə yetirir, istər fayla, istər şəbəkəyə, istərsə də proseslərarası borulara aiddir. Bu proqramlaşdırma üçün əlverişlidir, lakin ümumi gördüyünüz zaman həqiqətən nə baş verdiyini izləməyi çətinləşdirir oxumaq и yazmaq sistem zəng izləmə nəticələrində.

Operator əlavə etməklə , məcbur edəcəksən zolaq Çıxışdakı hər bir fayl deskriptoruna onun nəyə işarə etdiyini qeyd etməklə qeyd edin.

-p** ilə artıq işləyən prosesə əlavə edin

Aşağıdakı nümunədən görəcəyiniz kimi, bəzən artıq işləyən proqramı izləmək lazımdır. 1337 prosesi kimi işlədiyi məlumdursa (məsələn, çıxışdan ps), onda siz bunu belə izləyə bilərsiniz:

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

Kök hüquqlarına ehtiyacınız ola bilər.

Uşaq proseslərini izləmək üçün -f istifadə edin

zolaq Varsayılan olaraq, yalnız bir prosesi izləyir. Əgər bu proses uşaq prosesləri yaradırsa, o zaman uşaq prosesin yaranması üçün sistem çağırışı görünə bilər, lakin uşaq prosesin sistem zəngləri göstərilməyəcək.

Əgər səhvin uşaq prosesində olduğunu düşünürsünüzsə, ifadədən istifadə edin -f, bu onun izlənməsinə imkan verəcək. Bunun mənfi tərəfi odur ki, çıxış sizi daha da çaşdıracaq. Nə vaxt zolaq bir prosesi və ya bir mövzunu izləyir, zəng hadisələrinin tək axını göstərir. O, eyni anda birdən çox prosesi izlədikdə, mesajla kəsilən zəngin başlanğıcını görə bilərsiniz , sonra - digər icra şöbələri üçün bir dəstə çağırış və yalnız bundan sonra - birincinin sonu . Və ya operatordan istifadə edərək bütün iz nəticələrini müxtəlif fayllara bölün -ff (ətraflı məlumat liderlik haqqında zolaq).

-e istifadə edərək izləri süzün

Gördüyünüz kimi, izin nəticəsi bütün mümkün sistem zənglərinin real yığınıdır. Bayraq -e Siz izi süzgəcdən keçirə bilərsiniz (bax bələdçi haqqında zolaq). Əsas üstünlüyü ondan ibarətdir ki, süzgəcdən keçirilmiş izi tam izləməkdən daha sürətli və sonra yerinə yetirməkdir grep`da. Düzünü desəm, demək olar ki, həmişə mənə əhəmiyyət vermir.

Bütün səhvlər pis deyil

Sadə və ümumi nümunə, eyni anda bir neçə yerdə fayl axtaran bir proqramdır, məsələn, icra edilə bilən faylı ehtiva edən kataloqu axtaran qabıq:

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

“Səhv barədə məlumat verməzdən əvvəl sonuncu uğursuz sorğu” kimi evristik üsullar müvafiq səhvləri tapmaqda yaxşıdır. Nə olursa olsun, ən sondan başlamaq məntiqlidir.

C proqramlaşdırma dərsləri sistem zənglərini başa düşməyə kömək edə bilər.

C kitabxanalarına standart zənglər sistem zəngləri deyil, yalnız nazik səth təbəqəsidir. Beləliklə, C-də necə və nə edəcəyinizi bir az da olsa başa düşsəniz, sistem çağırışı izinin nəticələrini başa düşmək sizin üçün daha asan olacaq. Məsələn, şəbəkə sistemlərinə edilən zəngləri aradan qaldırmaqda probleminiz var, eyni klassikaya baxın Bijanın Şəbəkə Proqramlaşdırma Bələdçisi.

Daha mürəkkəb sazlama nümunəsi

Artıq dedim ki, sadə sazlama nümunəsi işləyərkən ən çox qarşılaşmalı olduğum bir nümunədir zolaq. Bununla belə, bəzən real araşdırma tələb olunur, ona görə də burada daha təkmil sazlamanın real həyat nümunəsi var.

bcron - tapşırıqların işlənməsi planlayıcısı, *nix demonunun başqa bir tətbiqi cron. O, serverdə quraşdırılıb, lakin kimsə cədvəli redaktə etməyə çalışdıqda belə olur:

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

Tamam, o deməkdir ki bcron müəyyən bir fayl yazmağa çalışdı, amma alınmadı və bunun səbəbini etiraf etməyəcək. Açıqlama zolaq:

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

Sona yaxın bir səhv mesajı var yazmaq, amma bu dəfə bir şey fərqlidir. Birincisi, adətən bundan əvvəl baş verən müvafiq sistem çağırışı xətası yoxdur. İkincisi, aydındır ki, kimsə artıq səhv mesajını oxuyub. Deyəsən əsl problem başqa yerdədir və bcrontab sadəcə mesajı oxuyur.

Baxsanız adam 2 oxuyur, siz görə bilərsiniz ki, birinci arqument (3) fayl deskriptorudur və *nix bütün I/O emalları üçün istifadə edir. 3-cü fayl deskriptorunun hansı faylı təmsil etdiyini necə öyrənə bilərəm? Bu xüsusi vəziyyətdə qaça bilərsiniz zolaq operatorla (yuxarıya baxın) və o, avtomatik olaraq sizə xəbər verəcək, lakin bu kimi şeyləri anlamaq üçün izləmə nəticələrini necə oxumağı və təhlil etməyi bilmək faydalıdır.

Fayl deskriptorunun mənbəyi bir çox sistem çağırışlarından biri ola bilər (hamısı deskriptorun nə üçün olmasından asılıdır - konsol, şəbəkə rozetkası, faylın özü və ya başqa bir şey), lakin nə olursa olsun, biz axtarırıq 3 qaytarmaqla zənglər (yəni biz izləmə nəticələrində “= 3” axtarırıq). Bu nəticədə onlardan 2-si var: ən yuxarıda və yuva Ortasında. faylı açır amma yaxın(3) sonra yenidən bağlandığını göstərəcək. (Rake: fayl deskriptorları açıldıqda və bağlandıqda yenidən istifadə edilə bilər). Zəng edin rozetka() əvvəl sonuncu olduğu üçün uyğundur oxu (), və belə çıxır ki, bcrontab bir rozetka vasitəsilə bir şeylə işləyir. Növbəti sətir fayl deskriptorunun əlaqəli olduğunu göstərir unix domen yuvası yol boyunca /var/run/bcron-spool.

Beləliklə, əlaqəli prosesi tapmaq lazımdır unix yuvası Digər tərəfdə. Bu məqsədlə bir neçə səliqəli fənd var ki, bunların hər ikisi server yerləşdirmələrini aradan qaldırmaq üçün faydalıdır. Birincisi istifadə etməkdir netstat və ya daha yeni ss (rozetka statusu). Hər iki əmr sistemin aktiv şəbəkə əlaqələrini göstərir və bəyanatı qəbul edir -l dinləmə yuvalarını, eləcə də operatoru təsvir etmək üçün -p rozetkaya qoşulmuş proqramları müştəri kimi göstərmək üçün. (Daha çox faydalı variantlar var, lakin bu ikisi bu tapşırıq üçün kifayətdir.)

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

Bu, dinləyicinin əmr olduğunu göstərir inixserver, proses ID 20629 ilə işləyir. (Və təsadüfən o, yuva kimi fayl deskriptoru 3-dən istifadə edir.)

Eyni məlumatı tapmaq üçün ikinci həqiqətən faydalı vasitə deyilir lap. Sistemdəki bütün açıq faylları (və ya fayl deskriptorlarını) siyahıya alır. Və ya müəyyən bir fayl haqqında məlumat əldə edə bilərsiniz:

# 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

Proses 20629 uzunömürlü serverdir, ona görə də onu əlavə edə bilərsiniz zolaq kimi bir şey istifadə etmək strace -o /tmp/trace -p 20629. Başqa terminalda cron işini redaktə etsəniz, xəta ilə iz çıxışı alacaqsınız. Və nəticə budur:

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

(Sonuncu qəbul et() izləmə zamanı tamamlanmayacaq.) Yenə təəssüf ki, bu nəticədə axtardığımız xəta yoxdur. Biz bcrontag-ın rozetkaya göndərdiyi və ya ondan qəbul etdiyi heç bir mesaj görmürük. Bunun əvəzinə prosesə tam nəzarət (Clone, gözləyin 4, SIGCHLD və s.) Bu proses, təxmin etdiyiniz kimi, əsl işi görən uşaq prosesi yaradır. Və onun izini tutmaq lazımdırsa, zəngə əlavə edin strace -f. Strace ilə yeni nəticədə səhv mesajını axtardığımız zaman tapacağımız budur -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 +++

İndi bu bir şeydir. 21470 prosesi yolda fayl yaratmağa çalışarkən "giriş rədd edildi" xətası alır tmp/spool.21470.1573692319.854640 (cari iş kataloquna aiddir). Əgər biz indiki iş qovluğunu bilsəydik, tam yolu da bilərdik və prosesin niyə onun müvəqqəti faylını orada yarada bilmədiyini anlaya bilərdik. Təəssüf ki, proses artıq bitib, ona görə də sadəcə istifadə edə bilməzsiniz lsof -p 21470 cari kataloqu tapmaq üçün, lakin siz əks istiqamətdə işləyə bilərsiniz - kataloqu dəyişdirən PID 21470 sistem zənglərini axtarın. (Heç biri yoxdursa, PID 21470 onları valideynindən miras almalıdır və bu, artıq keçib. lsof -səh tapmaq mümkün deyil.) Bu sistem çağırışıdır chdir (müasir onlayn axtarış sistemlərinin köməyi ilə tapmaq asandır). Və burada PID 20629 serverinə qədər izləmə nəticələrinə əsaslanan tərs axtarışların nəticəsidir:

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

(Əgər itirmisinizsə, əvvəlki yazımı oxumaq istəyə bilərsiniz *nix prosesinin idarə edilməsi və qabıqlar haqqında.) Beləliklə, PID 20629 serveri yolda fayl yaratmaq üçün icazə almadı /var/spool/cron/tmp/spool.21470.1573692319.854640. Çox güman ki, bunun səbəbi klassik fayl sistemi icazə parametrləridir. yoxlayaq:

# 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

İtin basdırıldığı yer budur! Server istifadəçi cronu kimi işləyir, lakin yalnız kökün kataloqa yazmaq icazəsi var /var/spool/cron/tmp/. Sadə əmr chown cron /var/spool/cron/tmp/ məcbur edəcək bcron düzgün işləmək. (Əgər problem bu deyildisə, onda növbəti ən çox ehtimal olunan şübhəli SELinux və ya AppArmor kimi nüvə təhlükəsizlik moduludur, ona görə də nüvə mesajı jurnalını yoxlayardim. dmesg.)

Ümumi

Sistem zənglərinin izləri yeni başlayanlar üçün çətin ola bilər, lakin ümid edirəm ki, onların ümumi yerləşdirmə problemlərinin bütün sinfini aradan qaldırmağın sürətli yolu olduğunu göstərmişəm. Təsəvvür edin ki, çox prosesdə debug etməyə çalışırsınız bcronaddım-addım sazlayıcıdan istifadə etməklə.

Sistem zəng zənciri boyunca iz nəticələrini geriyə doğru təhlil etmək bacarıq tələb edir, lakin dediyim kimi, demək olar ki, həmişə istifadə edir zolaq, mən sadəcə iz nəticəsini alıram və sondan başlayaraq səhvləri axtarıram. Hər halda, zolaq sazlamaya çox vaxt qənaət etməyə kömək edir. Ümid edirəm sizin üçün də faydalı olar.

Mənbə: www.habr.com

Добавить комментарий