Бірде сұхбат кезінде маған дискіде бос орын таусылғандықтан қызмет жұмыс істемей қалса, не істейсіз?
Әрине, мен бұл жердің не жатқанын көремін, мүмкін болса, сол жерді тазалаймын деп жауап бердім.
Содан кейін сұхбат алушы бөлімде бос орын болмаса, бірақ сіз барлық орынды алатын файлдарды көрмесеңіз ше?
Бұған мен әрқашан ашық файл дескрипторларын, мысалы, lsof пәрменімен қарауға болатынын және қандай қолданбаның барлық бос орынды алғанын түсінуге болатынын айттым, содан кейін деректер қажет пе, соған байланысты жағдайларға сәйкес әрекет ете аласыз. .
Интервьюер соңғы сөзімде мені тоқтатып, оның сұрағына қосты: «Бізге деректер қажет емес делік, бұл жай ғана жөндеу журналы, бірақ қолданба жұмыс істемейді, себебі ол жөндеуді жаза алмайды»?
«Жарайды, - деп жауап бердім мен, «біз қолданба конфигурациясында жөндеуді өшіріп, оны қайта іске қоса аламыз».
Сұхбат алушы қарсылық білдірді: «Жоқ, біз қолданбаны қайта іске қоса алмаймыз, бізде әлі де жадта сақталған маңызды деректер бар және маңызды клиенттер қызметтің өзіне қосылған, біз оны қайта қосуға мәжбүрлей алмаймыз».
«Жарайды» дедім мен, «егер біз қолданбаны қайта іске қоса алмасақ және деректер біз үшін маңызды болмаса, ls пәрменінде көрмесек те, бұл ашық файлды файл дескрипторы арқылы жай ғана тазалай аламыз. файлдық жүйеде».
Сұхбат беруші риза болды, бірақ мен емес.
Сонда мен ойладым, неге менің білімімді сынайтын адам тереңірек зерттемейді? Бірақ егер деректер өте маңызды болса ше? Егер процесті қайта іске қоса алмасақ және процесс бос орыны жоқ бөлімде файлдық жүйеге жазылса ше? Жазылған деректерді ғана емес, сонымен бірге осы процесс жазатын немесе жазуға тырысатын деректерді де жоғалта алмасақ ше?
Тузик
Мансаптың басында мен пайдаланушы ақпаратын сақтауға қажет шағын қосымшаны жасауға тырыстым. Содан кейін мен пайдаланушыны оның деректеріне қалай сәйкестендіруге болады деп ойладым. Мысалы, менде Иванов Иван Иванович бар, оның біраз ақпараты бар, бірақ мен олармен қалай достасамын? Мен «Тузик» деген иттің дәл осы Ивандікі екенін айта аламын. Бірақ ол атын өзгертіп, Иванның орнына, мысалы, Оля болса ше? Сонда біздің Оля Ивановна Иванованың иті болмайды, ал біздің Тузик әлі жоқ Ивандікі болып шығады. Әрбір пайдаланушыға бірегей идентификатор (ID) беретін дерекқор бұл мәселені шешуге көмектесті және менің Tuzik осы идентификаторға байланысты болды, бұл шын мәнінде жай сериялық нөмір болды. Осылайша, эйс иесінің жеке куәлігі 2 болды, ал бір уақытта Иван осы жеке куәліктің астында болды, содан кейін Оля сол жеке куәлікке ие болды. Адамгершілік пен мал шаруашылығының мәселесі іс жүзінде шешілді.
Файл дескрипторы
Файлдың және осы файлмен жұмыс істейтін бағдарламаның мәселесі шамамен біздің ит пен адамның проблемасымен бірдей. Мен ivan.txt деп аталатын файлды ашып, оған tuzik сөзін жаза бастадым делік, бірақ файлдағы бірінші «t» әрпін ғана жаза алдым және бұл файлдың атын біреу өзгертті, мысалы, olya.txt деп. Бірақ файл сол күйінде қалады, мен оған әлі де өзімнің эйсімді жазғым келеді. Файл жүйелік қоңырау арқылы ашылған сайын
Linux жүйесінде libc кітапханасы әрбір іске қосылған қолданба (процесс) үшін 3 нөмірленген 0,1,2 дескриптор файлын ашады. Қосымша ақпаратты сілтемелерден табуға болады
- 0 файл дескрипторы STDIN деп аталады және қолданба енгізуімен байланысты
- 1-файл дескрипторы STDOUT деп аталады және оны қолданбалар басып шығару пәрмендері сияқты деректерді шығару үшін пайдаланады
- Файл дескрипторы 2 STDERR деп аталады және оны қолданбалар қате туралы хабарларды шығару үшін пайдаланады.
Егер сіздің бағдарламаңызда оқу немесе жазу үшін кез келген файлды ашсаңыз, онда сіз бірінші тегін идентификаторды аласыз және ол 3-ші нөмірге ие болады.
Файл дескрипторларының тізімін оның PID білсеңіз, кез келген процесс үшін көруге болады.
Мысалы, bash консолін ашып, процессіміздің PID-ін қарастырайық
[user@localhost ]$ echo $$
15771
Екінші консольде жүгірейік
[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user 0 Oct 7 15:42 .
dr-xr-xr-x 9 user user 0 Oct 7 15:42 ..
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Осы мақаланың мақсаттары үшін №255 файл дескрипторын елемеуге болады; ол байланысты кітапхана арқылы емес, bash өзі арқылы ашылған.
Енді барлық 3 дескрипторлық файл псевдотерминал құрылғысымен байланысты
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
Ал бірінші консольде біз көреміз
[user@localhost ]$ hello world
Қайта бағыттау және құбыр
Сіз бұл 3 дескриптор файлын кез келген процесте, соның ішінде bash бағдарламасында, мысалы, екі процесті байланыстыратын құбыр арқылы оңай ауыстыра аласыз, қараңыз.
[user@localhost ]$ cat /dev/zero | sleep 10000
Бұл пәрменді өзіңіз орындай аласыз strace -f және ішінде не болып жатқанын қараңыз, бірақ мен сізге қысқаша айтып беремін.
PID 15771 бар ата-аналық bash процесі біздің команданы талдайды және қанша пәрменді іске қосқымыз келетінін нақты түсінеді, біздің жағдайда олардың екеуі бар: мысық және ұйқы. Bash екі еншілес процесті жасау және оларды бір құбырға біріктіру қажет екенін біледі. Жалпы, bash-қа 2 еншілес процесс және бір құбыр қажет болады.
Bash еншілес процестерді жасамас бұрын жүйелік қоңырауды іске қосады
Ата-аналық процесс үшін құбыр бар сияқты, бірақ әлі еншілес процестер жоқ:
PID command
15771 bash
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Содан кейін жүйелік қоңырауды пайдаланыңыз
PID command
15771 bash
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
PID command
9004 bash
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21
PID command
9005 bash
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21
Клондау процесті барлық файл дескрипторларымен бірге клондайтынын ұмытпаңыз, сондықтан олар ата-аналық және еншілес процесстерде бірдей болады. PID 15771 бар ата-ана процесінің міндеті еншілес процестерді бақылау болып табылады, сондықтан ол балалардан жауап күтеді.
Сондықтан оған құбыр қажет емес және ол 3 және 4 нөмірлі файл дескрипторларын жабады.
PID 9004 бар бірінші еншілес bash процесінде жүйелік қоңырау
PID 9005 бар екінші еншілес процесте bash STDIN нөмірі 2 файл дескрипторын өзгерту үшін dup0 пайдаланады. Енді PID 9005 бар екінші bash оқылатын барлық нәрсе құбырдан оқылады.
Осыдан кейін 3 және 4 нөмірлі файл дескрипторлары да еншілес процестерде жабылады, өйткені олар енді пайдаланылмайды.
Мен 255 файл дескрипторын әдейі елемеймін; ол bash арқылы ішкі мақсаттар үшін пайдаланылады және сонымен қатар еншілес процестерде жабылады.
Содан кейін, PID 9004 бар бірінші еншілес процесте bash жүйелік қоңырауды пайдалана бастайды
PID 9005 бар екінші еншілес процесте bash біз көрсеткен екінші орындалатын файлды іске қосады, біздің жағдайда /usr/bin/sleep.
Exec жүйелік шақыруы файл дескрипторларын жабылмайды, егер олар ашық қоңырау жасалған уақытта O_CLOEXEC жалаушасымен ашылмаса. Біздің жағдайда орындалатын файлдарды іске қосқаннан кейін барлық ағымдағы файл дескрипторлары сақталады.
Консольде тексеріңіз:
[user@localhost ]$ pgrep -P 15771
9004
9005
[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user 0 Oct 7 15:42 .
dr-xr-xr-x 9 user user 0 Oct 7 15:42 ..
lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
[user@localhost ]$ ls -lah /proc/9004/fd
total 0
dr-x------ 2 user user 0 Oct 7 15:57 .
dr-xr-xr-x 9 user user 0 Oct 7 15:57 ..
lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21
l-wx------ 1 user user 64 Oct 7 15:57 1 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
lr-x------ 1 user user 64 Oct 7 15:57 3 -> /dev/zero
[user@localhost ]$ ls -lah /proc/9005/fd
total 0
dr-x------ 2 user user 0 Oct 7 15:57 .
dr-xr-xr-x 9 user user 0 Oct 7 15:57 ..
lr-x------ 1 user user 64 Oct 7 15:57 0 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21
[user@localhost ]$ ps -up 9004
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
user 9004 0.0 0.0 107972 620 pts/21 S+ 15:57 0:00 cat /dev/zero
[user@localhost ]$ ps -up 9005
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
user 9005 0.0 0.0 107952 360 pts/21 S+ 15:57 0:00 sleep 10000
Көріп отырғаныңыздай, біздің құбырдың бірегей саны екі процесте де бірдей. Осылайша, бізде бір ата-анасы бар екі түрлі процесс арасында байланыс бар.
Bash пайдаланатын жүйелік қоңыраулармен таныс емес адамдар үшін командаларды strace арқылы іске қосуды және ішкі не болып жатқанын көруді ұсынамын, мысалы:
strace -s 1024 -f bash -c "ls | grep hello"
Дискідегі бос орын аз және деректерді процесті қайта іске қоспай-ақ сақтауға тырысатын мәселемізге оралайық. Дискіге секундына шамамен 1 мегабайт жазатын шағын программа жазайық. Сонымен қатар, егер қандай да бір себептермен дискіге деректерді жаза алмасақ, біз оны елемейміз және деректерді бір секундта қайта жазуға тырысамыз. Мен Python қолданатын мысалда сіз кез келген басқа бағдарламалау тілін пайдалана аласыз.
[user@localhost ]$ cat openforwrite.py
import datetime
import time
mystr="a"*1024*1024+"n"
with open("123.txt", "w") as f:
while True:
try:
f.write(str(datetime.datetime.now()))
f.write(mystr)
f.flush()
time.sleep(1)
except:
pass
Бағдарламаны іске қосып, файл дескрипторларын қарастырайық
[user@localhost ]$ python openforwrite.py &
[1] 3762
[user@localhost ]$ ps axuf | grep [o]penforwrite
user 3762 0.0 0.0 128600 5744 pts/22 S+ 16:28 0:00 | _ python openforwrite.py
[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user 0 Oct 7 16:29 .
dr-xr-xr-x 9 user user 0 Oct 7 16:29 ..
lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt
Көріп отырғаныңыздай, бізде 3 стандартты файл дескрипторы және біз ашқан тағы біреуі бар. Файл өлшемін тексерейік:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
Деректер жазылуда, біз файлдағы рұқсаттарды өзгертуге тырысамыз:
[user@localhost ]$ sudo chown root: 123.txt
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 root root 168M Oct 7 16:31 123.txt
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 root root 172M Oct 7 16:31 123.txt
Біздің пайдаланушының файлға жазуға рұқсаты болмаса да, деректер әлі де жазылып жатқанын көреміз. Оны жоюға тырысайық:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Деректер қайда жазылған? Және олар мүлдем жазылған ба? Біз тексереміз:
[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user 0 Oct 7 16:29 .
dr-xr-xr-x 9 user user 0 Oct 7 16:29 ..
lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt (deleted)
Иә, біздің файл дескрипторымыз әлі де бар және біз бұл файл дескрипторын ескі файлымыз сияқты өңдей аламыз, оны оқи аламыз, тазалай аламыз және көшіре аламыз.
Файл өлшемін қарастырайық:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Файл өлшемі 19923457. Файлды тазалап көрейік:
[user@localhost ]$ truncate -s 0 /proc/31083/fd/3
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 136318390 2621522 /home/user/123.txt
Көріп отырғаныңыздай, файл өлшемі тек ұлғаюда және біздің магистраль жұмыс істемеді. Жүйелік шақыру құжаттамасын қарастырайық
with open("123.txt", "w") as f:
қоюымыз керек
with open("123.txt", "a") as f:
«w» жалаушасымен тексеру
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
және «а» жалауымен
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
Жұмыс істеп тұрған процесті бағдарламалау
Көбінесе бағдарламашылар бағдарламаларды жасау және тестілеу кезінде отладчиктерді (мысалы, GDB) немесе қолданбада тіркеудің әртүрлі деңгейлерін пайдаланады. Linux жұмыс істеп тұрған бағдарламаны нақты жазуға және өзгертуге мүмкіндік береді, мысалы, айнымалы мәндерді өзгерту, тоқтау нүктесін орнату және т.б..
Файлды жазу үшін дискілік кеңістіктің жеткіліксіздігі туралы бастапқы сұраққа оралсақ, мәселені модельдеуге тырысайық.
Бөлімге файл жасайық, оны бөлек диск ретінде орнатамыз:
[user@localhost ~]$ dd if=/dev/zero of=~/tempfile_for_article.dd bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.00525929 s, 2.0 GB/s
[user@localhost ~]$
Файлдық жүйені құрайық:
[user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd
mke2fs 1.42.9 (28-Dec-2013)
/home/user/tempfile_for_article.dd is not a block special device.
Proceed anyway? (y,n) y
...
Writing superblocks and filesystem accounting information: done
[user@localhost ~]$
Файлдық жүйені орнату:
[user@localhost ~]$ sudo mount ~/tempfile_for_article.dd /mnt/
[sudo] password for user:
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 172K 7.9M 3% /mnt
Біз иесімен каталог жасаймыз:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Файлды тек өз бағдарламамызда жазу үшін ашайық:
with open("/mnt/logs/123.txt", "w") as f:
Іске қосу
[user@localhost ]$ python openforwrite.py
Біз бірнеше секунд күтеміз
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Сонымен, бізде осы мақаланың басында сипатталған мәселе бар. Бос орын 0, 100% бос.
Тапсырманың шарттарына сәйкес біз жоғалуға болмайтын өте маңызды деректерді жазуға тырысамыз. Сонымен қатар, біз процесті қайта іске қоспай, қызметті түзетуіміз керек.
Бізде әлі де дискілік кеңістік бар делік, бірақ басқа бөлімде, мысалы, /home.
Біздің кодты «жылу кезінде қайта бағдарламалауға» тырысайық.
Барлық дискілік кеңістікті жеп қойған процессіміздің PID-ін қарастырайық:
[user@localhost ~]$ ps axuf | grep [o]penfor
user 10078 27.2 0.0 128600 5744 pts/22 R+ 11:06 0:02 | _ python openforwrite.py
Процесске gdb арқылы қосылыңыз
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Ашық файл дескрипторларын қарастырайық:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt
Бізді қызықтыратын №3 файл дескрипторы туралы ақпаратты қарастырамыз
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Python қандай жүйелік шақыруды жасайтынын есте сақтай отырып (жоғарыдан біз strace орындаған және ашық қоңырауды тапқан жерді қараңыз), файлды ашу үшін кодты өңдеген кезде, процесс атынан өзіміз де солай істейміз, бірақ бізге O_WRONLY|O_CREAT| қажет. O_TRUNC биттері сандық мәнмен ауыстырылады. Мұны істеу үшін, мысалы, ядро көздерін ашыңыз
#ТЕК 00000001 анықтау
#O_CREAT 00000100 анықтаңыз
#O_TRUNC 00001000 анықтаңыз
Біз барлық мәндерді бір мәнге біріктіреміз, біз 00001101 аламыз
Біз қоңырауды gdb-ден орындаймыз
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Сонымен, бізде 4 нөмірі бар жаңа файл дескрипторы және басқа бөлімде жаңа ашық файл алдық, біз тексереміз:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Біз құбырмен мысалды есте сақтаймыз - bash файл дескрипторларын қалай өзгертеді және біз dup2 жүйелік шақыруын үйрендік.
Біз бір файл дескрипторын екіншісімен ауыстыруға тырысамыз
(gdb) call dup2(4,3)
$2 = 3
Тексеру:
(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user 0 Oct 8 11:06 .
dr-xr-xr-x 9 user user 0 Oct 8 11:06 ..
lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:09 3 -> /home/user/123.txt
l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Біз 4 файл дескрипторын жабамыз, өйткені ол бізге қажет емес:
(gdb) call close (4)
$1 = 0
Және gdb шығыңыз
(gdb) quit
A debugging session is active.
Inferior 1 [process 10078] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 10078
Жаңа файлды тексеру:
[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 5.1M Oct 8 11:18 /home/user/123.txt
[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 7.1M Oct 8 11:18 /home/user/123.txt
Көріп отырғаныңыздай, деректер жаңа файлға жазылған, ескісін тексерейік:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Ешқандай деректер жоғалмайды, қолданба жұмыс істейді, журналдар жаңа орынға жазылады.
Тапсырманы сәл қиындатып көрейік
Деректер біз үшін маңызды деп елестетіп көрейік, бірақ бөлімдердің ешқайсысында дискілік бос орын жоқ және біз дискіні қоса алмаймыз.
Біз жасай алатын нәрсе - деректерді бір жерге, мысалы, құбырға қайта бағыттау және өз кезегінде деректерді құбырдан желіге қандай да бір бағдарлама арқылы, мысалы, netcat арқылы қайта бағыттау.
Біз mkfifo командасы арқылы атаулы құбыр жасай аламыз. Ол бос орын болмаса да, файлдық жүйеде псевдофайл жасайды.
Қолданбаны қайта іске қосыңыз және тексеріңіз:
[user@localhost ]$ python openforwrite.py
[user@localhost ~]$ ps axuf | grep [o]pen
user 5946 72.9 0.0 128600 5744 pts/22 R+ 11:27 0:20 | _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Дискіде бос орын жоқ, бірақ біз онда аталған құбырды сәтті жасаймыз:
[user@localhost ~]$ mkfifo /mnt/logs/megapipe
[user@localhost ~]$ ls -lah /mnt/logs/megapipe
prw-rw-r-- 1 user user 0 Oct 8 11:28 /mnt/logs/megapipe
Енді бізге осы құбырға түсетін барлық деректерді желі арқылы басқа серверге орау керек; бұл үшін дәл сол netcat қолайлы.
remote-server.example.com серверінде біз іске қосамыз
[user@localhost ~]$ nc -l 7777 > 123.txt
Біздің проблемалық серверде біз бөлек терминалда іске қосамыз
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Енді құбырда аяқталатын барлық деректер автоматты түрде netcat ішіндегі stdin-ге өтеді, ол оны 7777 портындағы желіге жібереді.
Бізге тек осы аталған құбырға деректерімізді жазуды бастау керек.
Қолданба бізде қазірдің өзінде жұмыс істеп тұр:
[user@localhost ~]$ ps axuf | grep [o]pen
user 5946 99.8 0.0 128600 5744 pts/22 R+ 11:27 169:27 | _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
Барлық жалаушалардың ішінен бізге тек O_WRONLY қажет, себебі файл бұрыннан бар және оны тазалаудың қажеті жоқ.
[user@localhost ~]$ gdb -p 5946
...
(gdb) call open("/mnt/logs/megapipe", 00000001,0666)
$1 = 4
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe
(gdb) call dup2(4,3)
$2 = 3
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe
l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe
(gdb) call close(4)
$3 = 0
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 ..
lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe
(gdb) quit
A debugging session is active.
Inferior 1 [process 5946] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 5946
remote-server.example.com қашықтағы серверін тексеру
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Деректер келіп жатыр, біз проблемалық серверді тексереміз
[user@localhost ~]$ ls -lah /mnt/logs/
total 7.9M
drwxr-xr-x 2 user user 1.0K Oct 8 11:28 .
drwxr-xr-x 4 root root 1.0K Oct 8 10:55 ..
-rw-rw-r-- 1 user user 7.9M Oct 8 14:17 123.txt
prw-rw-r-- 1 user user 0 Oct 8 14:22 megapipe
Деректер сақталады, мәселе шешілді.
Осы мүмкіндікті пайдаланып, Дегиродағы әріптестеріме сәлем жолдаймын.
Radio-T подкасттарын тыңдаңыз.
Бәріне жақсылық.
Үй тапсырмасы ретінде, егер сіз келесі пәрменді орындасаңыз, cat және sleep процессінің дескрипторлары файлында не болатыны туралы ойлануды ұсынамын:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Ақпарат көзі: www.habr.com