مثالوں کے ساتھ لینکس میں فائل ڈسکرپٹر

ایک بار ایک انٹرویو کے دوران مجھ سے پوچھا گیا کہ اگر آپ کو ڈسک میں جگہ ختم ہونے کی وجہ سے کوئی سروس کام نہیں کر رہی تو آپ کیا کریں گے؟

البتہ میں نے جواب دیا کہ میں دیکھوں گا کہ اس جگہ پر کیا قبضہ ہے اور اگر ممکن ہوا تو اس جگہ کو صاف کر دوں گا۔
پھر انٹرویو لینے والے نے پوچھا، اگر پارٹیشن پر خالی جگہ نہ ہو، لیکن آپ کو کوئی فائل بھی نظر نہیں آتی جو ساری جگہ لے لے؟

اس پر میں نے کہا کہ آپ ہمیشہ اوپن فائل ڈسکرپٹرز کو دیکھ سکتے ہیں، مثال کے طور پر lsof کمانڈ کے ساتھ، اور سمجھ سکتے ہیں کہ کونسی ایپلیکیشن نے تمام دستیاب جگہ لی ہے، اور پھر آپ حالات کے مطابق کام کر سکتے ہیں، اس پر منحصر ہے کہ آیا ڈیٹا کی ضرورت ہے۔ .

انٹرویو لینے والے نے مجھے آخری لفظ پر روکا، اپنے سوال میں اضافہ کیا: "فرض کریں کہ ہمیں ڈیٹا کی ضرورت نہیں ہے، یہ صرف ایک ڈیبگ لاگ ہے، لیکن ایپلیکیشن کام نہیں کرتی کیونکہ یہ ڈیبگ نہیں لکھ سکتی"؟

"ٹھیک ہے،" میں نے جواب دیا، "ہم ایپلیکیشن کی تشکیل میں ڈیبگ کو بند کر کے اسے دوبارہ شروع کر سکتے ہیں۔"
انٹرویو لینے والے نے اعتراض کیا: "نہیں، ہم ایپلیکیشن کو دوبارہ شروع نہیں کر سکتے، ہمارے پاس اب بھی اہم ڈیٹا میموری میں محفوظ ہے، اور اہم کلائنٹس خود سروس سے جڑے ہوئے ہیں، جنہیں ہم دوبارہ جوڑنے پر مجبور نہیں کر سکتے۔"

"ٹھیک ہے،" میں نے کہا، "اگر ہم ایپلیکیشن کو دوبارہ شروع نہیں کر سکتے اور ڈیٹا ہمارے لیے اہم نہیں ہے، تو ہم اس کھلی فائل کو فائل ڈسکرپٹر کے ذریعے صاف کر سکتے ہیں، چاہے ہم اسے ls کمانڈ میں نہ دیکھیں۔ فائل سسٹم پر۔"

انٹرویو لینے والا خوش تھا، لیکن میں نہیں تھا۔

پھر میں نے سوچا، میرے علم کی جانچ کرنے والا شخص گہرا کیوں نہیں کرتا؟ لیکن کیا ہوگا اگر ڈیٹا سب کے بعد اہم ہے؟ کیا ہوگا اگر ہم کسی عمل کو دوبارہ شروع نہیں کرسکتے ہیں، اور یہ عمل ایک پارٹیشن پر فائل سسٹم کو لکھتا ہے جس میں خالی جگہ نہیں ہے؟ کیا ہوگا اگر ہم نہ صرف اس ڈیٹا کو کھو سکتے ہیں جو پہلے سے لکھا جا چکا ہے، بلکہ وہ ڈیٹا بھی جسے یہ عمل لکھتا ہے یا لکھنے کی کوشش کرتا ہے؟

تزک

اپنے کیریئر کے شروع میں، میں نے ایک چھوٹی ایپلی کیشن بنانے کی کوشش کی جس میں صارف کی معلومات کو ذخیرہ کرنے کی ضرورت تھی۔ اور پھر میں نے سوچا، میں صارف کو اس کے ڈیٹا سے کیسے ملا سکتا ہوں۔ مثال کے طور پر، میرے پاس Ivanov Ivan Ivanovich ہے، اور اس کے پاس کچھ معلومات ہیں، لیکن میں ان سے دوستی کیسے کر سکتا ہوں؟ میں براہ راست اشارہ کر سکتا ہوں کہ "Tuzik" نامی کتا اسی آئیوان کا ہے۔ لیکن کیا ہوگا اگر وہ اپنا نام بدل لے اور آئیون کی بجائے اولیا بن جائے؟ تب یہ پتہ چلے گا کہ ہمارے اولیا ایوانوانا ایوانوا کے پاس اب کتا نہیں رہے گا، اور ہمارا توزک اب بھی غیر موجود ایوان سے تعلق رکھتا ہے۔ ایک ڈیٹابیس جس نے ہر صارف کو ایک منفرد شناخت کنندہ (ID) دیا اس نے اس مسئلے کو حل کرنے میں مدد کی، اور میرا Tuzik اس ID سے منسلک تھا، جو درحقیقت صرف ایک سیریل نمبر تھا۔ اس طرح، اس کے مالک کے پاس ID نمبر 2 تھا، اور کسی وقت آئیون اس ID کے تحت تھا، اور پھر اولیا اسی ID کے تحت ہو گیا۔ انسانیت اور حیوانات کا مسئلہ عملی طور پر حل ہو گیا۔

فائل ڈسکرپٹر

اس فائل کے ساتھ کام کرنے والے فائل اور پروگرام کا مسئلہ تقریباً ہمارے کتے اور انسان کا مسئلہ ہے۔ فرض کریں کہ میں نے ivan.txt نامی ایک فائل کھولی اور اس میں لفظ tuzik لکھنا شروع کیا، لیکن فائل میں صرف پہلا حرف "t" لکھنے میں کامیاب ہوا، اور اس فائل کا نام کسی نے بدل کر، مثال کے طور پر olya.txt رکھ دیا۔ لیکن فائل وہی ہے، اور میں اب بھی اس میں اپنا اککا ریکارڈ کرنا چاہتا ہوں۔ ہر بار سسٹم کال کے ذریعے فائل کھولی جاتی ہے۔ کھول کسی بھی پروگرامنگ زبان میں مجھے ایک منفرد ID موصول ہوتی ہے جو مجھے کسی فائل کی طرف اشارہ کرتی ہے، یہ ID فائل ڈسکرپٹر ہے۔ اور اس سے کوئی فرق نہیں پڑتا کہ اس فائل کے ساتھ آگے کیا اور کون کرتا ہے، اسے ڈیلیٹ کیا جا سکتا ہے، اس کا نام تبدیل کیا جا سکتا ہے، مالک تبدیل کیا جا سکتا ہے، یا پڑھنے لکھنے کے حقوق چھین لیے جا سکتے ہیں، مجھے پھر بھی رسائی حاصل رہے گی۔ اس پر، کیونکہ فائل کو کھولنے کے وقت، مجھے اسے پڑھنے اور/یا لکھنے کے حقوق حاصل تھے اور میں اس کے ساتھ کام شروع کرنے میں کامیاب ہو گیا، جس کا مطلب ہے کہ مجھے ایسا کرنا جاری رکھنا چاہیے۔

لینکس میں، libc لائبریری ہر چلنے والی ایپلیکیشن (عمل) کے لیے 3 ڈسکرپٹر فائلیں کھولتی ہے، جن کی تعداد 0,1,2 ہے۔ مزید معلومات لنکس پر مل سکتی ہیں۔ آدمی stdio и آدمی stdout

  • فائل ڈسکرپٹر 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 ڈسکرپٹر فائلیں سیوڈو ٹرمینل ڈیوائس سے وابستہ ہیں۔ /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 کو 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 کے ساتھ ہمارا دوسرا bash جو بھی پڑھے گا وہ پائپ سے پڑھا جائے گا۔

اس کے بعد، 3 اور 4 نمبر والے فائل ڈسکرپٹرز بھی چائلڈ پروسیس میں بند ہو جاتے ہیں، کیونکہ وہ مزید استعمال نہیں ہوتے۔

میں جان بوجھ کر فائل ڈسکرپٹر 255 کو نظر انداز کرتا ہوں؛ یہ اندرونی مقاصد کے لیے خود bash کے ذریعے استعمال ہوتا ہے اور اسے چائلڈ پروسیس میں بھی بند کر دیا جائے گا۔

اگلا، PID 9004 کے ساتھ پہلے چائلڈ پروسیس میں، bash سسٹم کال کا استعمال شروع کرتا ہے۔ عملدرآمد قابل عمل فائل جس کی ہم نے کمانڈ لائن پر وضاحت کی ہے، ہمارے معاملے میں یہ ہے /usr/bin/cat۔

PID 9005 کے ساتھ دوسرے چائلڈ پروسیس میں، bash ہمارے کیس /usr/bin/sleep میں، ہم نے بیان کردہ دوسرا قابل عمل چلاتا ہے۔

ایگزیک سسٹم کال فائل ہینڈلز کو بند نہیں کرتی جب تک کہ اوپن کال کے وقت انہیں 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 -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

جیسا کہ آپ دیکھ سکتے ہیں، فائل کا سائز صرف بڑھ رہا ہے اور ہمارے ٹرنک نے کام نہیں کیا۔ آئیے سسٹم کال دستاویزات کو دیکھتے ہیں۔ کھول. اگر ہم کسی فائل کو کھولتے وقت O_APPEND جھنڈا استعمال کرتے ہیں، تو ہر تحریر کے ساتھ، آپریٹنگ سسٹم فائل کے سائز کو چیک کرتا ہے اور فائل کے بالکل آخر تک ڈیٹا لکھتا ہے، اور یہ جوہری طور پر کرتا ہے۔ یہ ایک سے زیادہ تھریڈز یا عمل کو ایک ہی فائل میں لکھنے کی اجازت دیتا ہے۔ لیکن ہمارے کوڈ میں ہم اس جھنڈے کا استعمال نہیں کرتے ہیں۔ ہم lsof کے بعد ٹرنک میں صرف اس صورت میں ایک مختلف فائل کا سائز دیکھ سکتے ہیں جب ہم فائل کو اضافی تحریر کے لیے کھولیں، جس کا مطلب ہے کہ ہمارے کوڈ میں

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

اور "a" پرچم کے ساتھ

[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) یا ایپلی کیشن میں لاگنگ کی مختلف سطحوں کا استعمال کرتے ہیں۔ لینکس دراصل پہلے سے چل رہے پروگرام کو لکھنے اور تبدیل کرنے کی صلاحیت فراہم کرتا ہے، مثال کے طور پر متغیرات کی قدروں کو تبدیل کرنا، بریک پوائنٹ سیٹ کرنا، وغیرہ۔

فائل لکھنے کے لیے ڈسک کی کافی جگہ نہ ہونے کے بارے میں اصل سوال کی طرف لوٹتے ہوئے، آئیے اس مسئلے کو حل کرنے کی کوشش کرتے ہیں۔

آئیے اپنے پارٹیشن کے لیے ایک فائل بنائیں، جسے ہم الگ ڈسک کے طور پر نصب کریں گے۔

[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 میں۔

آئیے اپنے کوڈ کو "مکھی پر دوبارہ پروگرام" کرنے کی کوشش کریں۔

آئیے اپنے عمل کے پی آئی ڈی کو دیکھتے ہیں، جس نے ڈسک کی تمام جگہ کھا لی ہے۔

[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 کیا سسٹم کال کرتا ہے (اوپر دیکھیں کہ ہم نے اسٹریس کہاں سے چلائی اور اوپن کال کہاں ملی)، فائل کو کھولنے کے لیے اپنے کوڈ پر کارروائی کرتے وقت، ہم اپنے عمل کی جانب سے خود بھی ایسا ہی کرتے ہیں، لیکن ہمیں O_WRONLY|O_CREAT| O_TRUNC بٹس عددی قدر سے بدلتے ہیں۔ ایسا کرنے کے لیے، مثال کے طور پر دانا کے ذرائع کھولیں۔ یہاں اور دیکھیں کہ کون سے جھنڈے کس کے ذمہ دار ہیں۔

#O_WRONLY 00000001 کی وضاحت کریں۔
#O_CREAT 00000100 کی وضاحت کریں۔
#O_TRUNC 00001000 کی وضاحت کریں۔

ہم تمام اقدار کو یکجا کرتے ہیں، ہمیں 00001101 ملتا ہے۔

ہم اپنی کال کو جی ڈی بی سے چلاتے ہیں۔

(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) 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

کوئی ڈیٹا ضائع نہیں ہوتا، ایپلیکیشن کام کرتی ہے، نوشتہ جات نئے مقام پر لکھے جاتے ہیں۔

آئیے کام کو تھوڑا سا پیچیدہ کریں۔

آئیے تصور کریں کہ ڈیٹا ہمارے لیے اہم ہے، لیکن ہمارے پاس کسی بھی پارٹیشن میں ڈسک کی جگہ نہیں ہے اور ہم ڈسک کو جوڑ نہیں سکتے۔

ہم جو کر سکتے ہیں وہ یہ ہے کہ اپنے ڈیٹا کو کہیں ری ڈائریکٹ کریں، مثال کے طور پر پائپ پر، اور بدلے میں کسی پروگرام کے ذریعے ڈیٹا کو پائپ سے نیٹ ورک پر ری ڈائریکٹ کریں، مثال کے طور پر نیٹ کیٹ۔
ہم 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

اب ہمیں کسی نہ کسی طرح اس پائپ میں جانے والے تمام ڈیٹا کو نیٹ ورک کے ذریعے دوسرے سرور پر لپیٹنا ہوگا؛ وہی نیٹ کیٹ اس کے لیے موزوں ہے۔

سرور 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

ڈیٹا محفوظ ہو گیا، مسئلہ حل ہو گیا۔

میں ڈیگیرو سے اپنے ساتھیوں کو ہیلو کہنے کا یہ موقع لیتا ہوں۔
ریڈیو-T پوڈکاسٹ سنیں۔

سب اچھا.

ہوم ورک کے طور پر، میرا مشورہ ہے کہ آپ اس بارے میں سوچیں کہ اگر آپ مندرجہ ذیل کمانڈ کو چلاتے ہیں تو پروسیس فائل ڈسکرپٹرز cat and sleep میں کیا ہوگا:

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

ماخذ: www.habr.com

نیا تبصرہ شامل کریں