Програм хангамжийн байршуулалтыг strace ашиглан дибаг хийх

Програм хангамжийн байршуулалтыг strace ашиглан дибаг хийх

Миний өдөр тутмын ажил бол ихэвчлэн програм хангамжийн байршуулалт бөгөөд энэ нь би дараах асуултуудад хариулахын тулд маш их цаг зарцуулдаг гэсэн үг юм.

  • Энэ програм хангамж нь хөгжүүлэгчийн хувьд ажилладаг боловч надад тохирохгүй. Яагаад?
  • Өчигдөр энэ програм хангамж надад ажилласан, гэхдээ өнөөдөр тийм биш. Яагаад?

Энэ нь ердийн програм хангамжийн дибаг хийхээс арай өөр төрлийн дибаг хийх явдал юм. Тогтмол дибаг хийх нь кодын логиктой холбоотой боловч байршуулах дибаг нь код болон хүрээлэн буй орчны харилцан үйлчлэлийн тухай юм. Асуудлын үндэс нь логик алдаа байсан ч бүх зүйл нэг машин дээр ажиллахгүй, нөгөө машин дээр ажиллахгүй байгаа нь асуудал ямар нэгэн байдлаар орчинд байна гэсэн үг юм.

Тиймээс ердийн дибаг хийх хэрэгслийн оронд гэх мэт gdb Би байршуулалтыг дибаг хийх өөр хэрэгслүүдтэй. Асуудлыг шийдвэрлэх хамгийн дуртай хэрэгсэл бол "Яагаад энэ програм хангамж надад тохирохгүй байна вэ?" дуудсан мөр.

Strace гэж юу вэ?

мөр нь "системийн дуудлагыг хянах" хэрэгсэл юм. Энэ нь анх Linux-д зориулж бүтээгдсэн боловч бусад системийн хэрэгслүүдийн тусламжтайгаар алдаа засах аргыг ашиглаж болно (DTrace буюу ктраце).

Үндсэн програм нь маш энгийн. Та зүгээр л 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 +++

Эдгээр системийн дуудлага юу вэ? Энэ нь үйлдлийн системийн цөмд зориулсан API шиг зүйл юм. Нэгэн цагт програм хангамж нь ажиллаж байсан техник хангамжид шууд ханддаг байсан. Жишээлбэл, дэлгэцэн дээр ямар нэг зүйлийг харуулах шаардлагатай бол портууд эсвэл видео төхөөрөмжүүдийн санах ойн зураглал бүхий регистрүүдээр тоглодог. Олон үйлдэлт компьютерийн системүүд түгээмэл болоход янз бүрийн программууд техник хангамжийн төлөө тэмцэлдэж эмх замбараагүй байдал ноёрхож байв. Нэг програмын алдаа нь бүхэл бүтэн системийг биш юмаа гэхэд бусдыг нь сүйрүүлж болзошгүй. Дараа нь CPU-д давуу эрхийн горимууд (эсвэл "бөгжний хамгаалалт") гарч ирэв. Цөм нь хамгийн давуу эрхтэй болсон: энэ нь техник хангамжид бүрэн хандалт авч, системийн дуудлагуудаар дамжуулан техник хангамжтай харилцахын тулд цөмөөс хандах хүсэлт гаргах шаардлагатай байсан бага давуу эрхтэй програмуудыг төрүүлсэн.

Хоёртын түвшинд системийн дуудлага нь энгийн функцийн дуудлагаас ялимгүй ялгаатай боловч ихэнх программууд стандарт номын санд боодол ашигладаг. Тэдгээр. POSIX C стандарт номын сан нь функцийн дуудлагыг агуулдаг бичих (), энэ нь системийн дуудлагын архитектурт хамаарах бүх кодыг агуулдаг бичих.

Програм хангамжийн байршуулалтыг strace ашиглан дибаг хийх

Товчхондоо, програм болон түүний орчин (компьютерийн систем) хоорондын аливаа харилцан үйлчлэл нь системийн дуудлагаар явагддаг. Тиймээс, програм хангамж нь нэг машин дээр ажилладаг боловч нөгөө машин дээр ажилладаггүй бол системийн дуудлагын хяналтын үр дүнг харах нь зүйтэй юм. Бүр тодруулбал, системийн дуудлагын мөрийг ашиглан дүн шинжилгээ хийж болох ердийн цэгүүдийн жагсаалтыг энд оруулав.

  • Консолын I/O
  • Сүлжээний I/O
  • Файлын системийн хандалт ба файлын I/O
  • Процессын хэлхээний ашиглалтын хугацааг удирдах
  • Доод түвшний санах ойн менежмент
  • Тодорхой төхөөрөмжийн драйверуудад хандах

Хэзээ strace ашиглах вэ?

Онолын хувьд, мөр Хэрэглэгчийн орон зайд байгаа аливаа програм нь системийн дуудлага хийх ёстой тул хэрэглэгчийн орон зайд байгаа ямар ч программтай хамт ашиглагддаг. Энэ нь эмхэтгэсэн, доод түвшний программууд дээр илүү үр дүнтэй ажилладаг боловч хэрэв та ажиллах хугацаа болон орчуулагчийн нэмэлт дуу чимээг багасгаж чадвал Python зэрэг өндөр түвшний хэлтэй ажилладаг.

Бүх сүр жавхлангаараа мөр Нэг машин дээр сайн ажилладаг программ хангамжийг дибаг хийх явцад илэрдэг, гэвч гэнэт нөгөө машин дээр ажиллахаа больж, файл, зөвшөөрлийн талаар тодорхойгүй мэдээллүүд гаргах, эсвэл зарим команд болон өөр ямар нэг зүйлийг гүйцэтгэх оролдлого амжилтгүй болох нь харамсалтай, гэхдээ тийм биш. гэрчилгээ баталгаажуулалтын алдаа зэрэг өндөр түвшний асуудлуудтай маш сайн хослуулах. Энэ нь ихэвчлэн хослолыг шаарддаг мөрзаримдаа ltrace болон дээд түвшний хэрэгслүүд (тушаалын мөрийн хэрэгсэл гэх мэт openssl гэрчилгээг дибаг хийх).

Бид жишээ болгон бие даасан сервер ашиглах болно, гэхдээ системийн дуудлагыг хянах нь ихэвчлэн илүү төвөгтэй байршуулах платформ дээр хийгддэг. Та зүгээр л зөв хэрэгслийг сонгох хэрэгтэй.

Дибаг хийх энгийн жишээ

Та гайхалтай серверийн програмыг ажиллуулахыг хүсч байна гэж бодъё, тэгвэл та дараах зүйлийг хийв.

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

Таны бичсэн тохиргооны файлыг олж чадаагүй бололтой. Энэ нь заримдаа багц менежерүүд програмыг эмхэтгэх үед хүлээгдэж буй файлын байршлыг дарж бичдэгтэй холбоотой юм. Хэрэв та нэг түгээлтийн суулгах гарын авлагыг дагаж мөрдвөл нөгөөд та бодож байснаас тэс өөр файлуудыг олох болно. Хэрэв алдааны мэдэгдэл нь тохиргооны файлыг хаанаас хайхыг зааж өгсөн бол асуудлыг хэдхэн секундын дотор шийдэж болох боловч тийм биш юм. Тэгэхээр хаана хайх вэ?

Хэрэв та эх кодыг ашиглах боломжтой бол үүнийг уншиж, бүх зүйлийг олж мэдэх боломжтой. Сайн нөөц төлөвлөгөө, гэхдээ хамгийн хурдан шийдэл биш. Та алхам алхмаар дибаглагч руу хандаж болно gdb мөн програм нь юу хийж байгааг хараарай, гэхдээ хүрээлэн буй орчинтой харилцах харилцааг харуулах зорилгоор тусгайлан боловсруулсан хэрэгслийг ашиглах нь илүү үр дүнтэй байдаг. мөр.

дүгнэлт мөр шаардлагагүй мэт санагдаж болох ч сайн мэдээ гэвэл ихэнхийг нь үл тоомсорлож болно. Үр дүнг тусдаа файлд хадгалахын тулд -o операторыг ашиглах нь ихэвчлэн ашигтай байдаг:

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

Гаралтын эхний хуудас бараг бүхэлдээ мөр - Энэ нь ихэвчлэн хөөргөх бэлтгэлийн доод түвшин юм. (Маш олон дуудлага mmap, хамгаалах, brk доод түвшний санах ойг илрүүлэх, динамик сангуудыг харуулах гэх мэт зүйлсийн хувьд.) Үнэндээ гаралтыг дибаг хийх явцад. мөр Эцсээс нь уншсан нь дээр. Доор сорилтой байх болно бичих, энэ нь алдааны мессежийг харуулдаг. Бид дээрээс харвал системийн анхны алдаатай дуудлага - дуудлага нээх, энэ нь алдаа гаргадаг ENOENT (“файл эсвэл лавлах олдсонгүй”) нээх гэж байна /etc/foo/config.json. Энэ нь тохиргооны файл байх ёстой газар юм.

Энэ бол зүгээр л жишээ байсан, гэхдээ би ашигладаг цаг хугацааныхаа 90% -ийг хэлэх болно мөр, үүнээс илүү хийхэд хэцүү зүйл байхгүй. Алхам алхмаар дибаг хийх бүрэн гарын авлагыг доор харуулав.

  • Програмын системийн алдааны тухай тодорхойгүй мессежээс болж бухимдаарай
  • -ээр програмыг дахин эхлүүлнэ үү мөр
  • Мөрийн үр дүнгээс алдааны мэдэгдлийг олоорой
  • Эхний бүтэлгүйтсэн системийн дуудлагад хүрэх хүртлээ дээш яв

4-р алхам дахь системийн дуудлага нь юу буруу болсныг илчлэх магадлал өндөр байна.

Зөвлөмжүүд

Илүү төвөгтэй дибаг хийх жишээг харуулахын өмнө би танд үр дүнтэй ашиглах хэд хэдэн заль мэхийг үзүүлэх болно мөр:

хүн бол чиний найз

Олон *nix системүүд дээр цөм рүү залгасан системийн дуудлагын бүрэн жагсаалтыг ажиллуулснаар авч болно хүн систем дууддаг. гэх мэт зүйлсийг та харах болно brk(2), энэ нь ажиллуулснаар илүү их мэдээлэл авах боломжтой гэсэн үг юм хүн 2 brk.

Жижиг тармуур: хүн 2 сэрээ надад бүрхүүлийн хуудсыг харуулж байна сэрээ () в GNU libc, энэ нь дуудлагаар хэрэгждэг нь харагдаж байна клон(). Дуудлага семантик Салаа ашиглан програм бичвэл ижил хэвээр байна сэрээ (), мөн ул мөр ажиллуулах - Би ямар ч дуудлага олохгүй Салаа, тэдний оронд байх болно клон(). Хэрэв та эх сурвалжийг гаралттай харьцуулж эхэлбэл ийм тармуурууд таныг төөрөлдүүлдэг мөр.

Гаралтыг файлд хадгалахын тулд -o ашиглана уу

мөр өргөн цар хүрээтэй гаралт үүсгэж чаддаг тул ул мөрийн үр дүнг тусдаа файлд хадгалах нь ихэвчлэн ашигтай байдаг (дээрх жишээн дээрх шиг). Энэ нь програмын гаралтыг гаралттай андуурахаас зайлсхийхэд тусалдаг мөр консол дээр.

Бусад аргументын өгөгдлийг харахын тулд -s-г ашиглана уу

Дээрх жишээн дээр алдааны мэдэгдлийн хоёр дахь тал харагдахгүй байгааг та анзаарсан байх. Учир нь мөр анхдагч нь мөр аргументын зөвхөн эхний 32 байтыг харуулдаг. Хэрэв та илүү ихийг үзэхийг хүсвэл иймэрхүү зүйлийг нэмээрэй -s 128 дуудлага руу мөр.

-y нь файл, залгуур гэх мэтийг хянахад хялбар болгодог.

"Бүх зүйл файл" гэдэг нь *nix систем нь файл эсвэл сүлжээ эсвэл процесс хоорондын хоолойд хамаарахаас үл хамааран файлын тодорхойлогчийг ашиглан бүх оролт/гаралтыг гүйцэтгэдэг гэсэн үг юм. Энэ нь програмчлалын хувьд тохиромжтой боловч нийтлэг зүйлийг харахад юу болж байгааг хянахад хэцүү болгодог унш и бичих систем дэх дуудлагын мөрөөр үр дүн.

Оператор нэмэх замаар y, та хүчлэх болно мөр гаралт дахь файлын тодорхойлогч бүрийг юуг зааж байгааг тэмдэглэж бичнэ үү.

-p** ашиглан аль хэдийн ажиллаж байгаа процесст хавсаргана уу

Доорх жишээнээс харахад заримдаа та аль хэдийн ажиллаж байгаа програмыг мөрдөх шаардлагатай болдог. Хэрэв энэ нь 1337 процессоор ажиллаж байгаа нь мэдэгдэж байгаа бол (гаралтаас ps), тэгвэл та үүнийг дараах байдлаар мөрдөж болно:

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

Танд root эрх хэрэгтэй байж магадгүй.

Хүүхдийн үйл явцыг хянахын тулд -f ашиглана уу

мөр Анхдагч байдлаар, энэ нь зөвхөн нэг процессыг мөрддөг. Хэрэв энэ үйл явц нь хүүхэд процессыг үүсгэдэг бол хүүхдийн процессыг үүсгэх системийн дуудлага харагдах боловч хүүхдийн процессын системийн дуудлагууд харагдахгүй.

Хэрэв та алдаа нь хүүхдийн процесст байна гэж бодож байвал мэдэгдлийг ашиглана уу -f, энэ нь түүнийг мөрдөх боломжийг олгоно. Үүний сул тал нь гаралт нь таныг улам төөрөгдүүлэх болно. Хэзээ мөр нэг процесс эсвэл нэг урсгалыг мөрддөг бөгөөд энэ нь дуудлагын үйл явдлын нэг урсгалыг харуулдаг. Энэ нь нэгэн зэрэг олон процессыг хянах үед та мессежээр тасалдсан дуудлагын эхлэлийг харж болно , дараа нь - бусад гүйцэтгэлийн салбаруудад зориулсан олон тооны дуудлага, зөвхөн дараа нь - эхнийх нь төгсгөл <…foocald дахин эхэлсэн>. Эсвэл бүх ул мөрийн үр дүнг өөр өөр файл болгон хуваах, мөн оператор ашиглан -ff (дэлгэрэнгүйг дотор гарын авлага дээр мөр).

-e ашиглан ул мөрийг шүүнэ

Таны харж байгаагаар ул мөрийн үр дүн нь системийн бүх боломжит дуудлагын бодит овоо юм. туг -e Та ул мөрийг шүүж болно (харна уу гарын авлага дээр мөр). Гол давуу тал нь шүүсэн мөрийг гүйцэтгээд дараа нь хийхээс илүү хурдан ажиллуулдаг grep` at. Үнэнийг хэлэхэд би бараг үргэлж тоодоггүй.

Алдаа бүхэн муу биш

Энгийн бөгөөд нийтлэг жишээ бол гүйцэтгэгдэх файл агуулсан лавлахыг хайж буй бүрхүүл гэх мэт хэд хэдэн газраас файл хайж буй програм юм.

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

"Алдаа мэдээлэхээс өмнө хамгийн сүүлд амжилтгүй болсон хүсэлт" гэх мэт эвристик нь холбогдох алдааг олоход сайн байдаг. Ямар ч байсан эцсээс нь эхлэх нь логик юм.

Си програмчлалын хичээлүүд нь системийн дуудлагыг ойлгоход тусална.

Си номын сангуудын стандарт дуудлага нь системийн дуудлага биш, зөвхөн нимгэн гадаргуугийн давхарга юм. Тиймээс, хэрэв та C хэл дээр яаж, юу хийхээ бага ч гэсэн ойлгосон бол системийн дуудлагын ул мөрийн үр дүнг ойлгоход хялбар байх болно. Жишээлбэл, та сүлжээний систем рүү залгасан дуудлагыг дибаг хийхэд асуудалтай тул ижил сонгодог хувилбарыг хараарай Сүлжээний програмчлалын талаар Bija гарын авлага.

Илүү төвөгтэй дибаг хийх жишээ

Энгийн дибаг хийх жишээ бол миний ажиллахад ихэвчлэн тулгардаг зүйлийн жишээ гэдгийг би аль хэдийн хэлсэн мөр. Гэсэн хэдий ч заримдаа жинхэнэ судалгаа хийх шаардлагатай байдаг тул илүү дэвшилтэт дибаг хийх бодит жишээг энд үзүүлэв.

bcron - даалгавар боловсруулах хуваарьлагч, *nix дэмоны өөр нэг хэрэглүүр cron. Энэ нь сервер дээр суулгасан боловч хэн нэгэн хуваарийг засах гэж оролдох үед дараах зүйл тохиолддог.

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

За, энэ нь гэсэн үг bcron тодорхой файл бичих гэж оролдсон боловч бүтсэнгүй, яагаад гэдгийг нь хүлээн зөвшөөрөхгүй. Илчлэх мөр:

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

Төгсгөлд нь алдааны мэдэгдэл байна бичих, гэхдээ энэ удаад нэг зүйл өөр байна. Нэгдүгээрт, үүнээс өмнө ихэвчлэн тохиолддог системийн дуудлагын алдаа байхгүй. Хоёрдугаарт, хаа нэгтээ хэн нэгэн алдааны мэдэгдлийг аль хэдийн уншсан нь тодорхой байна. Жинхэнэ асуудал өөр газар байгаа юм шиг харагдаж байна, мөн bcrontab зүгээр л мессежийг дахин тоглуулдаг.

Хэрэв та харвал хүн 2 уншсан, та эхний аргумент (3) нь файлын тодорхойлогч гэдгийг харж болно, үүнийг *nix бүх I/O боловсруулалтад ашигладаг. 3-р файлын тодорхойлогч ямар байгааг хэрхэн олж мэдэх вэ? Энэ тохиолдолд та гүйж болно мөр оператортой y (дээрээс харна уу) бөгөөд энэ нь танд автоматаар хэлэх болно, гэхдээ үүнтэй төстэй зүйлийг олж мэдэхийн тулд ул мөрийн үр дүнг хэрхэн уншиж, задлан шинжлэхийг мэдэх нь ашигтай.

Файлын тодорхойлогчийн эх сурвалж нь олон системийн дуудлагын нэг байж болно (энэ нь тодорхойлогч нь юунд зориулагдсан - консол, сүлжээний залгуур, файл өөрөө эсвэл өөр зүйлээс хамаарна) байж болно, гэхдээ бид хайж байна. 3-ыг буцаах замаар дуудна (жишээ нь бид мөрдөх үр дүнгээс "= 3" гэж хайдаг). Үүний үр дүнд тэдгээрийн 2 нь байна: нээх хамгийн дээд хэсэгт болон Сокет Дунд нь. нээх файлыг нээх боловч нууц(3) дараа нь дахин хаагдахыг харуулах болно. (Тармуур: файлын тодорхойлогчийг нээх, хаах үед дахин ашиглах боломжтой). Дуудлага хийх сокет () Энэ нь өмнөх сүүлчийнх учраас тохиромжтой унших (), тэгээд bcrontab нь залгуураар ямар нэгэн зүйлтэй ажилладаг болох нь харагдаж байна. Дараагийн мөр нь файлын тодорхойлогчтой холбоотой болохыг харуулж байна unix домэйн залгуур замдаа /var/run/bcron-spool.

Тиймээс бид үүнтэй холбоотой үйл явцыг олох хэрэгтэй unix залгуур нөгөө талаар. Энэ зорилгоор хэд хэдэн цэвэрхэн заль мэх байдаг бөгөөд эдгээр нь хоёулаа серверийн байршуулалтыг дибаг хийхэд тустай. Эхнийх нь ашиглах явдал юм netstat эсвэл шинэ ss (сокетийн төлөв). Хоёр тушаал хоёулаа системийн идэвхтэй сүлжээний холболтыг харуулж, мэдэгдлийг авна -l сонсох залгууруудыг тайлбарлах, түүнчлэн оператор -p залгуурт холбогдсон програмуудыг үйлчлүүлэгчээр харуулах. (Илүү олон хэрэгтэй сонголтууд байгаа ч энэ хоёр нь энэ ажилд хангалттай.)

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

Энэ нь сонсогч бол тушаал гэдгийг харуулж байна inix сервер, 20629 процессийн ID-тай ажиллаж байна. (Тэгээд санамсаргүй байдлаар энэ нь файлын тодорхойлогч 3-ыг залгуур болгон ашигладаг.)

Ижил мэдээллийг олох хоёр дахь үнэхээр хэрэгтэй хэрэгсэл гэж нэрлэдэг тийм. Энэ нь систем дээрх бүх нээлттэй файлуудыг (эсвэл файлын тодорхойлогчдыг) жагсаадаг. Эсвэл та тодорхой нэг файлын талаар мэдээлэл авч болно:

# 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

Процесс 20629 нь урт хугацааны сервер тул та үүнийг хавсаргаж болно мөр гэх мэт зүйлийг ашиглах strace -o /tmp/trace -p 20629. Хэрэв та өөр терминал дахь cron ажлыг засвал алдаатай ул мөрийн гаралтыг хүлээн авах болно. Тэгээд үр дүн нь энд байна:

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

(Сүүлийн хүлээн авах () мөшгих үед дуусахгүй.) Дахин хэлэхэд харамсалтай нь энэ үр дүн бидний хайж буй алдааг агуулаагүй байна. Бид bcrontag нь залгуур руу илгээдэг эсвэл хүлээн авдаг мессежийг харахгүй байна. Үүний оронд үйл явцыг бүрэн хянах (хуулбар, 4 он, SIGCHLD гэх мэт) Энэ үйл явц нь хүүхдийн процессыг бий болгодог бөгөөд энэ нь таны таамаглаж байгаагаар жинхэнэ ажлыг гүйцэтгэдэг. Хэрэв та түүний мөрийг олох шаардлагатай бол дуудлагад нэмнэ үү strace -f. Шинэ үр дүнгийн алдааны мессежийг 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 +++

Одоо энэ бол ямар нэгэн зүйл. 21470 процесс нь зам дээр файл үүсгэхийг оролдох үед "хандах боломжгүй" алдааг хүлээн авдаг tmp/дамар.21470.1573692319.854640 (одоогийн ажлын лавлахтай холбоотой). Хэрэв бид одоогийн ажиллаж буй лавлахыг мэддэг байсан бол бүрэн замыг мэдэж, процесс яагаад түр зуурын файлаа үүсгэж чадахгүй байгааг олж мэдэх боломжтой болно. Харамсалтай нь процесс аль хэдийн дууссан тул та зүгээр л ашиглах боломжгүй lsof -p 21470 Одоогийн лавлахыг олохын тулд та эсрэг чиглэлд ажиллах боломжтой - лавлахыг өөрчилдөг PID 21470 системийн дуудлагуудыг хайж олоорой. (Хэрэв байхгүй бол PID 21470 нь тэдгээрийг эцэг эхээсээ өвлөн авсан байх ёстой бөгөөд энэ нь аль хэдийн дууссан. lsof -х олж чадахгүй байна.) Энэ системийн дуудлага юм чдир (орчин үеийн онлайн хайлтын системийн тусламжтайгаар үүнийг олоход хялбар байдаг). Мөн 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 +++

(Хэрэв та төөрсөн бол миний өмнөх нийтлэлийг уншина уу тухай *nix процессын удирдлага болон бүрхүүлүүд.) Тиймээс PID 20629 сервер зам дээр файл үүсгэх зөвшөөрөл аваагүй байна /var/spool/cron/tmp/spool.21470.1573692319.854640. Үүний шалтгаан нь сонгодог файлын системийн зөвшөөрлийн тохиргоо юм. Шалгацгаая:

# 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

Энэ бол нохойг оршуулсан газар юм! Сервер нь хэрэглэгчийн cron хэлбэрээр ажилладаг боловч зөвхөн root нь директор руу бичих эрхтэй /var/spool/cron/tmp/. Энгийн тушаал chown cron /var/spool/cron/tmp/ хүчлэх болно bcron зөв ажиллах. (Хэрэв энэ нь асуудал биш байсан бол дараагийн сэжигтэй зүйл бол SELinux эсвэл AppArmor гэх мэт цөмийн хамгаалалтын модуль байх тул би цөмийн мессежийн бүртгэлийг шалгах болно. dmesg.)

Нийт

Системийн дуудлагын ул мөр нь эхлэгчдэд маш хэцүү байж болох ч эдгээр нь нийтлэг байршуулалтын асуудлуудыг бүхэлд нь дибаг хийх хурдан арга гэдгийг харуулсан гэж найдаж байна. Олон процессыг дибаг хийх гэж байна гэж төсөөлөөд үз дээ bcronалхам алхмаар дибаг ашиглан.

Системийн дуудлагын гинжин хэлхээний дагуу ул мөрийн үр дүнг задлан шинжлэх нь ур чадвар шаарддаг боловч миний хэлсэнчлэн бараг үргэлж мөр, Би зүгээр л ул мөрийн үр дүнг авч, төгсгөлөөс эхлэн алдааг хайж байна. Ямар ч байсан, мөр дибаг хийхэд маш их цаг хэмнэхэд тусалдаг. Танд ч бас хэрэг болно гэж найдаж байна.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх