Отклањање грешака у примени софтвера са страце

Отклањање грешака у примени софтвера са страце

Мој дневни посао је углавном постављање софтвера, што значи да проводим доста времена покушавајући да одговорим на питања као што су:

  • Овај софтвер ради за програмера, али не и за мене. Зашто?
  • Јуче је овај софтвер радио за мене, али данас није. Зашто?

Ово је врста отклањања грешака која се мало разликује од обичног софтверског отклањања грешака. Редовно отклањање грешака се односи на логику кода, али отклањање грешака при примени се односи на интеракцију између кода и окружења. Чак и ако је корен проблема логичка грешка, чињеница да све ради на једној машини, а не на другој значи да је проблем некако у окружењу.

Дакле, уместо уобичајених алата за отклањање грешака као што су гдб Имам другачији скуп алата за отклањање грешака у примени. И мој омиљени алат за решавање проблема попут „Зашто овај софтвер не ради за мене?“ позвани страце.

Шта је страце?

страце је алат за „праћење системских позива“. Првобитно је креиран за Линук, али се исти трикови за отклањање грешака могу урадити са алатима за друге системе (ДТраце или ктраце).

Основна апликација је врло једноставна. Само треба да покренете страце са било којом командом и она ће избацити све системске позиве (иако ћете прво вероватно морати сами да је инсталирате страце):

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

Шта су ови системски позиви? Ово је нешто попут АПИ-ја за језгро оперативног система. Некада је софтвер имао директан приступ хардверу на којем је радио. Ако је, на пример, требало да прикаже нешто на екрану, играо се са портовима или меморијским мапираним регистрима за видео уређаје. Када су рачунарски системи са више задатака постали популарни, завладао је хаос док су се разне апликације бориле око хардвера. Грешке у једној апликацији могу срушити друге, ако не и цео систем. Затим су се у ЦПУ-у појавили режими привилегија (или „заштита прстена“). Кернел је постао најпривилегованији: добио је пун приступ хардверу, стварајући мање привилеговане апликације које су већ морале да захтевају приступ од језгра да би комуницирале са хардвером путем системских позива.

На бинарном нивоу, системски позив се мало разликује од једноставног позива функције, али већина програма користи омотач у стандардној библиотеци. Оне. стандардна библиотека ПОСИКС Ц садржи позив функције напиши (), који садржи сав код за системски позив специфичан за архитектуру write (писати).

Отклањање грешака у примени софтвера са страце

Укратко, свака интеракција између апликације и њеног окружења (рачунарских система) се врши путем системских позива. Стога, када софтвер ради на једној машини, али не и на другој, било би добро погледати резултате праћења системских позива. Тачније, ево листе типичних тачака које се могу анализирати коришћењем праћења системског позива:

  • Конзола И/О
  • Мрежни И/О
  • Приступ систему датотека и улаз/излаз датотека
  • Управљање животним веком нити процеса
  • Управљање меморијом ниског нивоа
  • Приступ одређеним драјверима уређаја

Када користити страце?

Теоретски, страце користи се са било којим програмом у корисничком простору, јер сваки програм у корисничком простору мора да врши системске позиве. Ефикасније ради са компајлираним програмима ниског нивоа, али такође ради и са језицима високог нивоа као што је Питхон ако можете да пресечете додатну буку из времена извршавања и тумача.

У свој својој раскоши страце манифестује се током отклањања грешака у софтверу који добро ради на једној машини, али изненада престаје да ради на другој, производећи нејасне поруке о фајловима, дозволама или неуспелим покушајима да се изврше неке команде или нешто друго... Штета, али не комбинују тако добро са проблемима високог нивоа као што су грешке у верификацији сертификата. Обично ово захтева комбинацију страцепонекад лтраце и алати вишег нивоа (попут алата командне линије опенссл за отклањање грешака у сертификату).

Користићемо самостални сервер као пример, али праћење системских позива се често може обавити на сложенијим платформама за примену. Само треба да изаберете праве алате.

Једноставан пример отклањања грешака

Рецимо да желите да покренете невероватну серверску апликацију фоо, а ово је оно што ћете добити:

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

Очигледно није могао да пронађе конфигурациону датотеку коју сте написали. Ово се дешава зато што понекад, када менаџери пакета компајлирају апликацију, замењују очекиване локације датотека. А ако пратите водич за инсталацију за једну дистрибуцију, у другој ћете пронаћи датотеке потпуно другачије од оних које сте очекивали. Проблем би се могао решити за неколико секунди ако би порука о грешци рекла где да потражим конфигурациону датотеку, али не. Па где да гледам?

Ако имате приступ изворном коду, можете га прочитати и сазнати све. Добар резервни план, али не и најбрже решење. Можете да прибегнете дебагеру корак по корак као што је гдб и видите шта програм ради, али је много ефикасније користити алат који је посебно дизајниран да прикаже интеракцију са окружењем: страце.

Излаз страце може изгледати сувишно, али добра вест је да се већина тога може безбедно занемарити. Често је корисно користити -о оператор да сачувате резултате праћења у засебној датотеци:

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

Отприлике цела прва страница излаза страце - Ово је обично припрема на ниском нивоу за лансирање. (Много позива ммап, мппротецт, брк за ствари попут откривања меморије ниског нивоа и приказивања динамичких библиотека.) Заправо, током отклањања грешака у излазу страце Боље је читати од самог краја. У наставку ће бити изазов write (писати), који приказује поруку о грешци. Погледамо изнад и видимо први погрешан системски позив - позив опенат, што даје грешку ЕНОЕНТ („датотека или директоријум није пронађен“) покушава да се отвори /етц/фоо/цонфиг.јсон. Овде треба да се налази конфигурациона датотека.

Ово је био само пример, али рекао бих 90% времена које користим страце, не постоји ништа много теже од овога. Испод је комплетан водич за отклањање грешака корак по корак:

  • Узнемирите се због нејасне поруке о системској грешци из програма
  • Поново покрените програм са страце
  • Пронађите поруку о грешци у резултатима праћења
  • Идите више док не погодите први неуспели системски позив

Врло је вероватно да ће системски позив у кораку 4 открити шта је пошло наопако.

Савети

Пре него што вам покажем пример сложенијег отклањања грешака, показаћу вам неколико трикова за ефикасну употребу страце:

човек је твој пријатељ

На многим *ник системима, комплетна листа системских позива кернелу се може добити покретањем ман сисцаллс. Видећете ствари као што су брк(2), што значи да се више информација може добити покретањем човек 2 брк.

Мале грабуље: човек 2 виљушка показује ми страницу за шкољку виљушка () в ГНУ либц, који се, испоставило се, спроводи позивањем клон (). Семантика позива виљушка остаје исти ако пишете програм користећи виљушка (), и покрените праћење - нећу пронаћи позиве виљушка, уместо њих биће клон (). Такве грабуље вас само збуне ако почнете да упоређујете извор са излазом страце.

Користите -о да сачувате излаз у датотеку

страце може да генерише обиман излаз, тако да је често корисно чувати резултате праћења у одвојеним датотекама (као у примеру изнад). Ово такође помаже да се избегне мешање излаза програма са излазом страце у конзоли.

Користите -с да видите више података о аргументима

Можда сте приметили да друга половина поруке о грешци није приказана у горњем примеру трага. Зато што страце подразумевано приказује само прва 32 бајта аргумента стринг. Ако желите да видите више, додајте нешто попут -с 128 на позив страце.

-и олакшава праћење датотека, утичница итд.

„Све је датотека“ значи да *ник системи раде све И/О користећи дескрипторе датотека, било да се то односи на датотеку или мрежу или међупроцесне цеви. Ово је згодно за програмирање, али отежава праћење шта се заиста дешава када видите уобичајено читати и write (писати) у резултатима праћења системског позива.

Додавањем оператора , присилићете страце означите сваки дескриптор датотеке у излазу напоменом на шта указује.

Повежите са већ покренутим процесом помоћу -п**

Као што ћете видети из примера у наставку, понекад морате да пратите програм који је већ покренут. Ако је познато да се покреће као процес 1337 (рецимо, из излаза ps), онда га можете пратити овако:

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

Можда ће вам требати роот права.

Користите -ф за надгледање подређених процеса

страце Подразумевано, прати само један процес. Ако овај процес покреће подређене процесе, онда се системски позив за покретање подређеног процеса може видети, али системски позиви подређеног процеса неће бити приказани.

Ако мислите да је грешка у подређеном процесу, користите изјаву -f, ово ће омогућити његово праћење. Лоша страна овога је што ће вас излаз још више збунити. Када страце прати један процес или једну нит, приказује један ток догађаја позива. Када прати више процеса одједном, можете видети да је почетак позива прекинут поруком , затим - гомила позива за друге гране извршења, па тек онда - крај прве <…фооцалл ресумед>. Или поделите све резултате праћења у различите датотеке, такође користећи оператор -фф (детаљи у вођство на страце).

Филтрирајте трагове помоћу -е

Као што видите, резултат праћења је права гомила свих могућих системских позива. Застава -e Можете филтрирати траг (погледајте вођство на страце). Главна предност је у томе што је брже покренути филтрирано праћење него извршити пуно праћење и затим греп`ат. Да будем искрен, скоро увек ме није брига.

Нису све грешке лоше

Једноставан и уобичајен пример је програм који тражи датотеку на неколико места одједном, попут љуске која тражи директоријум који садржи извршну датотеку:

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

Хеуристика као што је „последњи неуспели захтев пре пријављивања грешке“ је добра у проналажењу релевантних грешака. Како год било, логично је кренути од самог краја.

Упутства за Ц програмирање могу вам помоћи да разумете системске позиве.

Стандардни позиви Ц библиотекама нису системски позиви, већ само танак површински слој. Дакле, ако бар мало разумете како и шта да радите у Ц-у, биће вам лакше да разумете резултате праћења системског позива. На пример, имате проблема са отклањањем грешака у позивима мрежним системима, погледајте исти класик Бијин водич за мрежно програмирање.

Сложенији пример отклањања грешака

Већ сам рекао да је пример једноставног отклањања грешака пример онога чиме се углавном морам бавити при раду страце. Међутим, понекад је потребна права истрага, па ево примера из стварног живота напреднијег отклањања грешака.

бцрон - планер обраде задатака, друга имплементација *ник демона црон. Инсталиран је на серверу, али када неко покуша да измени распоред, дешава се следеће:

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

Постоји порука о грешци при самом крају write (писати), али овај пут је нешто другачије. Прво, не постоји релевантна грешка системског позива, која се обично јавља пре тога. Друго, јасно је да је негде неко већ прочитао поруку о грешци. Изгледа да је прави проблем негде другде, и бцронтаб једноставно репродукује поруку.

Ако погледате човек 2 чита, можете видети да је први аргумент (3) дескриптор датотеке, који *ник користи за сву И/О обраду. Како да сазнам шта представља дескриптор датотеке 3? У овом конкретном случају, можете трчати страце са оператером (види горе) и аутоматски ће вам рећи, али да бисте схватили овакве ствари, корисно је знати како да читате и анализирате резултате праћења.

Извор дескриптора датотеке може бити један од многих системских позива (све зависи од тога чему дескриптор служи - конзоли, мрежној утичници, сам фајл или нешто друго), али како год било, ми тражимо позива враћањем 3 (тј. тражимо „= 3“ у резултатима праћења). У овом резултату постоје 2 од њих: опенат на самом врху и утичница У средини. опенат отвара датотеку али близу(3) ће тада показати да се поново затвара. (Раке: дескриптори датотека се могу поново користити када се отворе и затворе). Цалл соцкет () погодан јер је последњи пре читати(), и испоставило се да бцронтаб ради са нечим преко утичнице. Следећи ред показује да је дескриптор датотеке повезан са уник доменска утичница успут /вар/рун/бцрон-споол.

Дакле, морамо пронаћи процес повезан са уникс соцкет с друге стране. Постоји неколико згодних трикова за ову сврху, од којих су оба корисна за отклањање грешака при постављању сервера. Прва је употреба нетстат или новијег 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))

Ово сугерише да је слушалац команда иниксервер, који ради са ИД-ом процеса 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 је дуговечни сервер, тако да га можете прикључити страце користећи нешто попут страце -о /тмп/траце -п 20629. Ако уредите црон посао у другом терминалу, добићете излаз праћења са грешком. И ево резултата:

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

(последњи прихвати () неће бити завршен приликом праћења.) Опет, нажалост, овај резултат не садржи грешку коју тражимо. Не видимо ниједну поруку коју бцронтаг шаље или прима са сокета. Уместо тога, потпуна контрола процеса (клонирати, чекај4, СИГЦХЛД итд.) Овај процес ствара подређени процес, који, као што можете претпоставити, ради прави посао. А ако треба да ухватите њен траг, додајте позиву страце -ф. Ово је оно што ћемо пронаћи када тражимо поруку о грешци у новом резултату са страце -ф -о /тмп/траце -п 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 добија грешку „приступ одбијен“ када покушава да креира датотеку на путањи тмп/споол.21470.1573692319.854640 (који се односи на тренутни радни именик). Када бисмо само знали тренутни радни директоријум, знали бисмо и пуну путању и могли бисмо да схватимо зашто процес не може да креира своју привремену датотеку у њему. Нажалост, процес је већ изашао, тако да не можете само да га користите лсоф -п 21470 да бисте пронашли тренутни директоријум, али можете радити у супротном смеру - потражите ПИД 21470 системске позиве који мењају директоријум. (Ако их нема, ПИД 21470 мора да их је наследио од свог родитеља, а ово је већ лсоф -п не може се сазнати.) Овај системски позив је цхдир (што је лако сазнати уз помоћ савремених онлајн претраживача). А ево и резултата обрнутих претрага заснованих на резултатима праћења, све до сервера ПИД 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 +++

(Ако сте се изгубили, можда бисте желели да прочитате мој претходни пост о *ник управљању процесима и шкољкама.) Дакле, сервер ПИД 20629 није добио дозволу да креира датотеку на путањи /вар/споол/црон/тмп/споол.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

Ту је пас закопан! Сервер ради као корисник црон, али само роот има дозволу за писање у директоријум /вар/споол/црон/тмп/. Једноставна команда цховн црон /вар/споол/црон/тмп/ ће приморати бцрон раде исправно. (Ако то није проблем, онда је следећи највероватније сумњиви модул за безбедност кернела као што је СЕЛинук или АппАрмор, тако да бих проверио дневник порука језгра са дмесг.)

Укупно

Праћење системских позива може бити неодољиво за почетнике, али надам се да сам показао да су они брз начин за отклањање грешака у читавој класи уобичајених проблема са применом. Замислите да покушавате да отклоните грешке у вишепроцесу бцронкористећи дебагер корак по корак.

Рашчлањивање резултата праћења уназад дуж ланца системских позива захтева вештину, али као што сам рекао, скоро увек, коришћење страце, само добијам резултат праћења и тражим грешке почевши од краја. У сваком случају, страце помаже ми да уштедим много времена на отклањању грешака. Надам се да ће и вама бити од користи.

Извор: ввв.хабр.цом

Додај коментар