strace көмегімен бағдарламалық құралды қолдануды жөндеу

strace көмегімен бағдарламалық құралды қолдануды жөндеу

Менің күнделікті жұмысым негізінен бағдарламалық жасақтаманы орналастыру болып табылады, яғни мен келесі сұрақтарға жауап беруге көп уақыт жұмсаймын:

  • Бұл бағдарламалық құрал әзірлеуші ​​үшін жұмыс істейді, бірақ мен үшін емес. Неліктен?
  • Кеше бұл бағдарламалық жасақтама мен үшін жұмыс істеді, бірақ бүгін ол жұмыс істемейді. Неліктен?

Бұл кәдімгі бағдарламалық құралды жөндеуден біршама ерекшеленетін жөндеудің бір түрі. Тұрақты жөндеу кодтың логикасына қатысты, бірақ орналастыруды түзету код пен орта арасындағы өзара әрекеттесу туралы. Мәселенің түбірі логикалық қате болса да, бәрі бір машинада емес, басқа машинада жұмыс істейтіндігі мәселенің қандай да бір түрде қоршаған ортада екенін білдіреді.

Сондықтан әдеттегі жөндеу құралдарының орнына gdb Менде орналастыруды жөндеуге арналған басқа құралдар жиынтығы бар. «Неге бұл бағдарламалық құрал мен үшін жұмыс істемейді?» сияқты мәселені шешуге арналған менің сүйікті құралым. шақырды стресс.

Стрейс дегеніміз не?

стресс «жүйелік қоңырауларды қадағалау» құралы болып табылады. Бастапқыда ол Linux үшін жасалған, бірақ дәл осындай жөндеу амалдарын басқа жүйелерге арналған құралдармен жасауға болады (DTrace немесе ktrace).

Негізгі қолданба өте қарапайым. Сізге кез келген пәрменмен 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 сияқты нәрсе. Бір кездері бағдарламалық жасақтама өзі жұмыс істейтін аппараттық құралға тікелей қол жеткізе алды. Егер, мысалы, экранда бірдеңені көрсету қажет болса, ол порттармен немесе бейне құрылғылар үшін жадпен салыстырылған регистрлермен ойнады. Көптапсырмалы компьютерлік жүйелер танымал болған кезде, әртүрлі қолданбалар аппараттық құралдар үшін күрескен кезде хаос билік етті. Бір қолданбадағы қателер бүкіл жүйені болмаса, басқаларын бұзуы мүмкін. Содан кейін процессорда артықшылық режимдері (немесе «сақинадан қорғау») пайда болды. Ядро ең артықшылықты болды: ол жүйелік қоңыраулар арқылы аппараттық құралмен өзара әрекеттесу үшін ядродан кіруді сұрауға мәжбүр болған азырақ артықшылықты қолданбаларды шығара отырып, аппараттық құралға толық рұқсат алды.

Екілік деңгейде жүйелік шақыру қарапайым функциялық шақырудан аздап ерекшеленеді, бірақ көптеген бағдарламалар стандартты кітапханадағы қаптаманы пайдаланады. Анау. POSIX C стандартты кітапханасында функция шақыруы бар жазу (), ол жүйелік шақыруға арналған барлық архитектураға тән кодты қамтиды жазу.

strace көмегімен бағдарламалық құралды қолдануды жөндеу

Қысқаша айтқанда, қолданба мен оның ортасы (компьютерлік жүйелер) арасындағы кез келген әрекеттестік жүйелік шақырулар арқылы жүзеге асады. Сондықтан, бағдарламалық жасақтама бір құрылғыда жұмыс істеп, басқа құрылғыда жұмыс істемейтін болса, жүйенің қоңырауды бақылау нәтижелерін қарау жақсы болар еді. Нақтырақ айтқанда, мұнда жүйелік қоңырау ізі арқылы талдауға болатын типтік нүктелердің тізімі берілген:

  • Консоль енгізу/шығару
  • Желілік енгізу/шығару
  • Файлдық жүйеге қол жеткізу және файл енгізу/шығару
  • Процесс ағынының қызмет ету мерзімін басқару
  • Төмен деңгейлі жадты басқару
  • Арнайы құрылғы драйверлеріне қол жеткізу

strace қашан қолданылады?

Теориялық тұрғыдан, стресс пайдаланушы кеңістігіндегі кез келген бағдарламамен пайдаланылады, себебі пайдаланушы кеңістігіндегі кез келген бағдарлама жүйелік қоңырауларды жасауы керек. Ол құрастырылған, төмен деңгейлі бағдарламалармен тиімдірек жұмыс істейді, бірақ жұмыс уақыты мен аудармашыдан қосымша шуды азайта алсаңыз, Python сияқты жоғары деңгейлі тілдермен де жұмыс істейді.

Оның барлық салтанатында стресс бір машинада жақсы жұмыс істейтін бағдарламалық жасақтаманы жөндеу кезінде көрінеді, бірақ кенеттен екіншісінде жұмысын тоқтатады, файлдар, рұқсаттар туралы анық емес хабарламалар шығарады немесе кейбір пәрмендерді немесе басқа нәрсені орындаудың сәтсіз әрекеттері... Өкінішті, бірақ олай емес. сертификатты тексеру қателері сияқты жоғары деңгейлі мәселелермен жақсы үйлеседі. Әдетте бұл комбинацияны қажет етеді стресскейде ltrace және жоғары деңгейлі құралдар (мысалы, пәрмен жолы құралы ашылады сертификатты жөндеу үшін).

Мысал ретінде біз оқшау серверді қолданамыз, бірақ жүйелік қоңырауларды бақылауды көбінесе күрделірек орналастыру платформаларында жасауға болады. Сізге тек дұрыс құралдарды таңдау керек.

Қарапайым жөндеу мысалы

Сіз foo серверінің таңғажайып қолданбасын іске қосқыңыз келеді делік, және сіз мынаны орындайсыз:

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

Шығарылымның шамамен бірінші беті стресс - Бұл әдетте ұшыруға дайындық деңгейі төмен. (Қоңыраулар көп ммап, қорғау, брк төмен деңгейлі жадты анықтау және динамикалық кітапханаларды көрсету сияқты нәрселер үшін.) Шын мәнінде, шығысты жөндеу кезінде стресс Соңынан бастап оқыған дұрыс. Төменде сынақ болады жазу, ол қате туралы хабарды көрсетеді. Біз жоғарыдан қарап, бірінші қате жүйелік қоңырауды көреміз - қоңырау ашу, ол қате жібереді ENOENT («файл немесе каталог табылмады») ашуға тырысады /etc/foo/config.json. Бұл жерде конфигурация файлы болуы керек.

Бұл жай ғана мысал, бірақ мен пайдаланатын уақыттың 90% дер едім стресс, мұны істеуден әлдеқайда қиын ештеңе жоқ. Төменде толық қадамдық жөндеу нұсқаулығы берілген:

  • Бағдарламадан жүйелік қате туралы түсініксіз хабарға байланысты ашуланыңыз
  • арқылы бағдарламаны қайта іске қосыңыз стресс
  • Бақылау нәтижелерінен қате туралы хабарды табыңыз
  • Бірінші сәтсіз жүйелік қоңырауға жеткенше жоғары көтеріліңіз

4-қадамдағы жүйелік қоңырау ненің дұрыс емес екенін анықтауы әбден мүмкін.

Кеңестер мен амалдар

Сізге күрделірек жөндеудің мысалын көрсетпес бұрын, мен сізге тиімді пайдалану үшін бірнеше амалдарды көрсетемін стресс:

адам сенің досың

Көптеген *nix жүйелерінде ядроға жүйелік шақырулардың толық тізімін іске қосу арқылы алуға болады адам жүйесі шақырады. сияқты нәрселерді көресіз brk(2), яғни іске қосу арқылы қосымша ақпаратты алуға болады адам 2 брк.

Шағын тырма: адам 2 шанышқы маған қабықтың бетін көрсетеді шанышқы () в GNU libc, ол шақыру арқылы жүзеге асады клон(). Қоңырау семантикасы Шанышқы пайдаланып бағдарламаны жазсаңыз, өзгеріссіз қалады шанышқы (), және ізді іске қосыңыз - мен ешқандай қоңырау таппаймын Шанышқы, олардың орнына болады клон(). Мұндай тырмалар, егер сіз көзді шығыспен салыстыра бастасаңыз, сізді шатастырады стресс.

Шығаруды файлға сақтау үшін -o пайдаланыңыз

стресс ауқымды нәтижелерді жасай алады, сондықтан бақылау нәтижелерін бөлек файлдарда сақтау жиі пайдалы (жоғарыдағы мысалдағыдай). Бұл сонымен қатар бағдарламаның шығысын шығыспен шатастырмауға көмектеседі стресс консольде.

Қосымша аргумент деректерін көру үшін -s пайдаланыңыз

Сіз қате туралы хабардың екінші жартысы жоғарыдағы мысал ізінде көрсетілмегенін байқаған боларсыз. Себебі стресс әдепкі жол аргументінің тек алғашқы 32 байтты көрсетеді. Көбірек көргіңіз келсе, келесідей нәрсені қосыңыз -s 128 қоңырауға стресс.

-y файлдарды, розеткаларды және т.б. бақылауды жеңілдетеді.

«Барлығы файл» *nix жүйелері файлға немесе желіге немесе процессаралық құбырларға қатысты болсын, файл дескрипторлары арқылы барлық енгізу/шығаруды орындайтынын білдіреді. Бұл бағдарламалау үшін ыңғайлы, бірақ жалпыны көргенде шынымен не болып жатқанын бақылауды қиындатады оқу и жазу Жүйедегі қоңырауды бақылау нәтижелерінде.

Операторды қосу арқылы , сіз мәжбүрлейсіз стресс шығарудағы әрбір файл дескрипторына оның нені көрсететіні туралы жазбамен түсініктеме беріңіз.

Жұмыс істеп тұрған процеске -p** арқылы тіркеңіз

Төмендегі мысалдан көріп отырғаныңыздай, кейде іске қосылған бағдарламаны қадағалау керек. Егер оның 1337 процесі ретінде жұмыс істейтіні белгілі болса (мысалы, шығыстан ps), содан кейін оны келесідей қадағалауға болады:

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

Сізге түбірлік құқықтар қажет болуы мүмкін.

еншілес процестерді бақылау үшін -f пайдаланыңыз

стресс Әдепкі бойынша ол тек бір процесті қадағалайды. Егер бұл процесс еншілес процестерді тудырса, еншілес процесті тудыратын жүйелік шақыруды көруге болады, бірақ еншілес процестің жүйелік қоңыраулары көрсетілмейді.

Қатені еншілес процесте деп ойласаңыз, мәлімдемені пайдаланыңыз -f, бұл оны қадағалауға мүмкіндік береді. Мұның кемшілігі - шығу сізді одан сайын шатастырады. Қашан стресс бір процесті немесе бір ағынды қадағалайды, ол қоңырау оқиғаларының бір ағынын көрсетеді. Ол бірден бірнеше процестерді қадағалағанда, хабармен үзілген қоңыраудың басталуын көре аласыз , содан кейін - басқа орындау тармақтары үшін қоңыраулар тобы, содан кейін ғана - біріншісінің соңы <…анықтамалық қоңырау қайта жалғасты>. Немесе барлық бақылау нәтижелерін операторды пайдаланып әртүрлі файлдарға бөліңіз -ff (толығырақ бағыттаушы туралы стресс).

-e көмегімен жолдарды сүзіңіз

Көріп отырғаныңыздай, іздің нәтижесі барлық ықтимал жүйелік қоңыраулардың нақты үйіндісі болып табылады. Жалау -e Сіз ізді сүзуге болады (қараңыз көшбасшылық туралы стресс). Негізгі артықшылығы - толық ізді орындағаннан кейін сүзгіленген жолды орындау жылдамырақ grep` сағ. Шынымды айтсам, мен әрқашан дерлік маңызды емеспін.

Барлық қателер жаман емес

Қарапайым және кең таралған мысал - файлды бірден бірнеше жерден іздейтін бағдарлама, мысалы, орындалатын файлы бар каталогты іздейтін қабық:

$ 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 бағдарламалау оқулықтары жүйелік қоңырауларды түсінуге көмектеседі.

Си кітапханаларына стандартты қоңыраулар жүйелік қоңыраулар емес, тек жұқа беттік қабат. Сонымен, егер сіз C тілінде қалай және не істеу керектігін аздап түсінсеңіз, жүйелік қоңырау ізінің нәтижелерін түсіну оңайырақ болады. Мысалы, сізде желілік жүйелерге қоңырауларды жөндеу кезінде қиындықтар туындады, сол классиканы қараңыз Bija желілік бағдарламалауға арналған нұсқаулық.

Күрделі жөндеу мысалы

Қарапайым отладка үлгісі жұмыс істеген кезде мен жиі айналысатын нәрсенің мысалы екенін айттым стресс. Дегенмен, кейде нақты тергеу қажет, сондықтан мұнда жетілдірілген жөндеудің нақты өмірлік мысалы келтірілген.

бкрон - тапсырмаларды өңдеуді жоспарлаушы, *nix демонының басқа іске асуы Cron. Ол серверде орнатылған, бірақ біреу кестені өңдеуге тырысқанда, келесідей болады:

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

Жарайды, бұл дегеніміз бкрон белгілі бір файлды жазуға тырысты, бірақ ол нәтиже бермеді және ол неге екенін мойындамайды. Ашу стресс:

# 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 барлық енгізу/шығару өңдеуі үшін пайдаланады. 3 файл дескрипторы қандай екенін қалай білуге ​​болады? Бұл нақты жағдайда сіз жүгіре аласыз стресс операторымен (жоғарыдан қараңыз) және ол сізге автоматты түрде хабарлайды, бірақ осы сияқты нәрселерді анықтау үшін бақылау нәтижелерін оқу және талдауды білу пайдалы.

Файл дескрипторының көзі көптеген жүйелік шақырулардың бірі болуы мүмкін (бәрі дескриптордың не үшін арналғанына байланысты – консоль, желілік ұяшық, файлдың өзі немесе басқа нәрсе), бірақ қалай болса да, біз іздейміз. 3 қайтару арқылы шақырады (яғни, біз бақылау нәтижелерінен «= 3» іздейміз). Бұл нәтижеде олардың 2-і бар: ашу ең жоғарғы жағында және розеткаға қосыңыз ортасында. ашу файлды ашады, бірақ жақын(3) қайта жабылатынын көрсетеді. (Rake: файл дескрипторларын ашу және жабу кезінде қайта пайдалануға болады). Қоңырау розетка () қолайлы, себебі ол бұрынғы соңғысы оқу (), және 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 процесс идентификаторымен жұмыс істейді. (Және кездейсоқ ол ұяшық ретінде 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 розеткаға жіберетін немесе розеткадан алатын хабарларды көрмейміз. Оның орнына процесті басқаруды аяқтаңыз (Clone, күтіңіз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 ретінде жұмыс істейді, бірақ тек түбірде каталогқа жазу рұқсаты бар /var/spool/cron/tmp/. Қарапайым команда chown cron /var/spool/cron/tmp/ мәжбүрлейді бкрон дұрыс жұмыс істеу. (Егер мәселе бұл болмаса, келесі ең ықтимал күдікті SELinux немесе AppArmor сияқты ядролық қауіпсіздік модулі болып табылады, сондықтан мен ядро ​​туралы хабар журналын тексеретін едім dmesg.)

Барлығы

Жүйелік қоңыраулардың іздері жаңадан бастағандар үшін өте қиын болуы мүмкін, бірақ мен олардың жалпы орналастыру мәселелерінің бүкіл класын түзетудің жылдам жолы екенін көрсеттім деп үміттенемін. Көп процесті жөндеуге тырысып көріңіз бкронқадамдық жөндеу құралын пайдалану.

Жүйелік қоңыраулар тізбегі бойынша кері нәтижелерді талдау шеберлікті талап етеді, бірақ мен айтқанымдай, әрқашан дерлік пайдалану стресс, Мен жай ғана бақылау нәтижесін аламын және соңынан бастап қателерді іздеймін. Бәрібір, стресс түзетуге көп уақытты үнемдеуге көмектеседі. Сізге де пайдалы болады деп үміттенемін.

Ақпарат көзі: www.habr.com

пікір қалдыру