Мисалдар менен Linux файл дескриптору

Бир жолу интервью учурунда менден дискте орун калбай калгандыктан, кызмат иштебей калса эмне кыласыз?

Албетте, мен бул жерди эмнелер ээлегенин көрөм, мүмкүн болсо ошол жерди тазалайм деп жооп бердим.
Андан кийин интервьючу сурады, эгерде бөлүмдө бош орун жок болсо, бирок сиз бардык мейкиндикти ээлей турган файлдарды көрбөй жатсаңызчы?

Буга мен айттым, сиз ар дайым ачык файл дескрипторлорун, мисалы lsof буйругу менен карап, кайсы колдонмо бардык жеткиликтүү мейкиндикти ээлегенин түшүнсөңүз болот, андан кийин маалымат керекпи же жокпу, ошого жараша жагдайга жараша иш-аракет кыла аласыз. .

Интервьючу менин сөзүмдү токтотуп, анын суроосуна: "Бизге маалымат кереги жок дейли, бул жөн гана мүчүлүштүктөрдү оңдоо журналы, бирок колдонмо иштебейт, анткени ал мүчүлүштүктөрдү жаза албайт"?

"Макул" деп жооп бердим мен, "колдонмонун конфигурациясында мүчүлүштүктөрдү оңдоону өчүрүп, кайра иштетсек болот."
Интервьючу каршы чыкты: "Жок, биз тиркемени кайра иштете албайбыз, бизде дагы эле эстутумда сакталган маанилүү маалыматтар бар жана маанилүү кардарлар кызматтын өзүнө туташкан, биз аны кайра туташууга мажбурлай албайбыз."

"Макул" дедим мен, "эгер биз тиркемени кайра иштете албасак жана маалыматтар биз үчүн маанилүү болбосо, анда биз бул ачык файлды ls буйругунда көрбөсөк да, файлдын дескриптору аркылуу тазалай алабыз. файл системасында."

Маектешкен адам ыраазы болду, бирок мен жактырган жокмун.

Анан мен ойлодум, эмне үчүн менин билимимди сынап жаткан адам тереңирээк казбайт? Бирок, эгер маалыматтар маанилүү болсочу? Эгерде биз процессти кайра иштете албасак, жана процесс файл тутумуна бош орун жок бөлүмгө жазсачы? Эгер биз буга чейин жазылган маалыматтарды гана эмес, бул процесс жазган же жазууга аракет кылган маалыматтарды да жоготуп албасакчы?

Тузик

Карьерамдын башында мен колдонуучу маалыматын сактоо үчүн зарыл болгон кичинекей тиркемени түзүүгө аракет кылдым. Анан мен кантип колдонуучуну анын маалыматтарына дал келтирсем болот деп ойлодум. Маселен, менде Иванов Иван Иванович бар, анын бир аз маалыматы бар, бирок мен алар менен кантип достошо алам? Түз эле айта алам: “Тузик” деген ит дал ушул Иванга таандык. Ал эми атын өзгөртүп, Ивандын ордуна, мисалы, Оля болуп калсачы? Ошондо биздин Оля Ивановна Иванованын ити жок болуп калат, биздин Тузик дагы жок Ивандыкы болуп калат. Ар бир колдонуучуга уникалдуу идентификатор (ID) берген маалымат базасы бул көйгөйдү чечүүгө жардам берди жана менин Тузикем бул ID менен байланышкан, ал чындыгында жөн гана сериялык номер болчу. Ошентип, тузуктун ээсинин ID номери 2 болгон жана кайсы бир убакта Иван бул ID астында болгон, андан кийин Оля да дал ушул ID менен болгон. Адамзаттын жана мал чарбасынын проблемасы иш жузунде чечилди.

Файлдын дескриптору

Файлдын жана бул файл менен иштеген программанын көйгөйү болжол менен биздин ит менен адамдыкындай. Мен ivan.txt деген файлды ачып, ага tuzik деген сөздү жаза баштадым дейли, бирок файлга биринчи “t” тамгасын гана жаза алдым жана бул файлдын атын кимдир бирөө, мисалы, olya.txt деп өзгөрттү. Бирок файл ошол эле бойдон калууда, мен дагы ага өзүмдү жазгым келет. Файл системалык чакыруу аркылуу ачылган сайын ачык каалаган программалоо тилинде мен мени файлга көрсөткөн уникалдуу ID алам, бул ID файлдын дескриптору. Жана бул файл менен мындан ары эмне жана ким кылганы эч кандай мааниге ээ эмес, аны өчүрүп салса болот, атын өзгөртүүгө болот, ээсин өзгөртүүгө болот, же окуу жана жазуу укуктарын алып салууга болот, мен дагы эле кирүү мүмкүнчүлүгүм бар ага, анткени файлды ачуу учурунда мен аны окууга жана/же жазууга укугум бар болчу жана мен аны менен иштей баштадым, демек, мен мындан ары да иштешим керек.

Linuxда libc китепканасы ар бир иштеп жаткан тиркеме (процесс) үчүн 3 номерлүү 0,1,2 дескриптор файлын ачат. Кененирээк маалыматты шилтемелерден тапса болот man stdio и man stdout

  • Файлдын дескриптору 0 STDIN деп аталат жана колдонмо киргизүү менен байланышкан
  • Файлдын дескриптору 1 STDOUT деп аталат жана тиркемелер тарабынан басып чыгаруу буйруктары сыяктуу маалыматтарды чыгаруу үчүн колдонулат
  • Файлдын дескриптору 2 STDERR деп аталат жана ката билдирүүлөрүн чыгаруу үчүн колдонмолор тарабынан колдонулат.

Эгер программаңызда окуу же жазуу үчүн кандайдыр бир файлды ачсаңыз, анда сиз биринчи акысыз ID аласыз жана ал 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 дескриптор файлы псевдо терминалдык түзүлүш менен байланышкан /dev/pts, бирок биз дагы эле аларды башкара алабыз, мисалы, аларды экинчи консолдо иштете алабыз

[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

Андан кийин системалык чалуу аркылуу клон 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
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 менен биринчи бала баш процессинде системалык чалуу dup2, биздин STDOUT файл дескрипторун №1 түтүккө көрсөткөн файл дескрипторуна өзгөртөт, биздин учурда бул 3-сан. Ошентип, PID 9004 менен биринчи бала процесси STDOUTке жазгандын баары автоматтык түрдө түтүк буферинде аяктайт.

PID 9005 менен экинчи бала процессинде, bash STDIN саны 2 файл дескрипторун өзгөртүү үчүн dup0 колдонот. Эми PID 9005 менен экинчи башыбыз окуй турган нерселердин баары түтүктөн окулат.

Андан кийин 3 жана 4 номерлүү файл дескрипторлору дагы колдонулбай калгандыктан, бала процесстеринде жабылат.

Мен 255 файл дескрипторун атайылап этибарга албайм; ал bash тарабынан ички максаттар үчүн колдонулат жана ошондой эле бала процесстеринде жабылат.

Андан кийин, PID 9004 менен биринчи бала процессинде, bash тутумдук чакырууну колдоно баштайт Шмидт биз буйрук сабында көрсөткөн аткарылуучу файл, биздин учурда бул /usr/bin/cat.

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

Көрүнүп тургандай, файлдын көлөмү көбөйүп баратат жана биздин trunk иштебей калды. Келгиле, системалык чакыруу документтерин карап көрөлү ачык. Эгерде биз файлды ачууда O_APPEND желегин колдонсок, анда ар бир жазууда операциялык система файлдын өлчөмүн текшерип, файлдын эң аягына чейин маалыматтарды жазат жана муну атомдук түрдө аткарат. Бул бир эле файлга бир нече жиптерди же процесстерди жазууга мүмкүндүк берет. Бирок биздин кодубузда бул желекти колдонбойбуз. Эгерде биз файлды кошумча жазуу үчүн ачсак гана lsof файлынын башка өлчөмүн trunkтан кийин көрө алабыз, анын ордуна биздин кодубузда

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% ээлеген.

Биз тапшырманын шарттарына ылайык, биз жоголбой турган абдан маанилүү маалыматтарды жазууга аракет кылып жатканыбызды эстейбиз. Ошол эле учурда биз процессти кайра баштабастан кызматты оңдообуз керек.

Бизде дагы эле диск мейкиндиги бар дейли, бирок башка бөлүмдө, мисалы, /үйдө.

Келгиле, кодубузду "учуп жатканда кайра программалоого" аракет кылалы.

Бардык диск мейкиндигин жеп кеткен процессибиздин 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 подкасттарын угуңуз.

Баарына жакшылык.

Үй тапшырмасы катары, мен сизге төмөнкү буйрукту аткарсаңыз, кош жана уйку процессинин дескрипторлорунда эмне болору жөнүндө ойлонууну сунуштайм:

[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000

Source: www.habr.com

Комментарий кошуу