اسٹریس کے ساتھ ڈیبگنگ سافٹ ویئر کی تعیناتی

اسٹریس کے ساتھ ڈیبگنگ سافٹ ویئر کی تعیناتی

میرا دن کا کام زیادہ تر سافٹ ویئر کی تعیناتی ہے، جس کا مطلب ہے کہ میں سوالات کے جوابات دینے کی کوشش میں کافی وقت صرف کرتا ہوں جیسے:

  • یہ سافٹ ویئر ڈویلپر کے لیے کام کرتا ہے، لیکن میرے لیے نہیں۔ کیوں؟
  • کل اس سافٹ ویئر نے میرے لیے کام کیا، لیکن آج ایسا نہیں ہوتا۔ کیوں؟

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

تو بجائے عام ڈیبگنگ ٹولز جیسے جی ڈی بی میرے پاس ڈیبگنگ تعیناتی کے لیے ٹولز کا ایک مختلف سیٹ ہے۔ اور اس مسئلے سے نمٹنے کے لیے میرا پسندیدہ ٹول جیسے "یہ سافٹ ویئر میرے لیے کام کیوں نہیں کرتا؟" بلایا سٹرس.

سٹریس کیا ہے؟

سٹرس "سسٹم کال ٹریسنگ" کے لیے ایک ٹول ہے۔ یہ اصل میں لینکس کے لیے بنایا گیا تھا، لیکن وہی ڈیبگنگ ٹرکس دوسرے سسٹمز کے لیے ٹولز کے ساتھ کی جا سکتی ہیں (Drace یا ktrace).

بنیادی درخواست بہت آسان ہے۔ آپ کو صرف کسی بھی کمانڈ کے ساتھ اسٹریس چلانے کی ضرورت ہے اور یہ تمام سسٹم کالز کو ڈمپ کر دے گا (حالانکہ پہلے آپ کو اسے خود انسٹال کرنا پڑے گا سٹرس):

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

یہ سسٹم کالز کیا ہیں؟ یہ آپریٹنگ سسٹم کرنل کے لیے API کی طرح کچھ ہے۔ ایک زمانے میں، سافٹ ویئر کو اس ہارڈ ویئر تک براہ راست رسائی حاصل تھی جس پر وہ چل رہا تھا۔ اگر، مثال کے طور پر، اسے اسکرین پر کچھ ظاہر کرنے کی ضرورت ہے، تو یہ ویڈیو ڈیوائسز کے لیے بندرگاہوں یا میموری میپ شدہ رجسٹروں کے ساتھ چلتی ہے۔ جب ملٹی ٹاسکنگ کمپیوٹر سسٹمز مقبول ہوئے تو افراتفری کا راج ہو گیا کیونکہ ہارڈ ویئر پر مختلف ایپلی کیشنز کا مقابلہ ہوا۔ ایک ایپلیکیشن میں خرابیاں دوسرے کو نیچے لا سکتی ہیں، اگر نہیں تو پورے سسٹم کو۔ پھر استحقاق کے طریقے (یا "رنگ پروٹیکشن") CPU میں نمودار ہوئے۔ دانا سب سے زیادہ مراعات یافتہ بن گیا: اس نے ہارڈ ویئر تک مکمل رسائی حاصل کی، کم مراعات یافتہ ایپلی کیشنز کو جنم دیا جن کو پہلے ہی سسٹم کالز کے ذریعے ہارڈ ویئر کے ساتھ بات چیت کرنے کے لیے دانا سے رسائی کی درخواست کرنی پڑتی تھی۔

بائنری سطح پر، سسٹم کال ایک سادہ فنکشن کال سے قدرے مختلف ہوتی ہے، لیکن زیادہ تر پروگرام معیاری لائبریری میں ریپر استعمال کرتے ہیں۔ وہ. POSIX C معیاری لائبریری ایک فنکشن کال پر مشتمل ہے۔ لکھیں ()، جس میں سسٹم کال کے لیے تمام فن تعمیر کے مخصوص کوڈ شامل ہیں۔ لکھنا.

اسٹریس کے ساتھ ڈیبگنگ سافٹ ویئر کی تعیناتی

مختصراً، ایپلیکیشن اور اس کے ماحول (کمپیوٹر سسٹم) کے درمیان کوئی بھی تعامل سسٹم کالز کے ذریعے کیا جاتا ہے۔ لہذا، جب سافٹ ویئر ایک مشین پر کام کرتا ہے لیکن دوسری پر نہیں، تو سسٹم کال ٹریسنگ کے نتائج کو دیکھنا اچھا ہوگا۔ مزید خاص طور پر، یہاں عام پوائنٹس کی ایک فہرست ہے جن کا تجزیہ سسٹم کال ٹریس کے ذریعے کیا جا سکتا ہے:

  • کنسول I/O
  • نیٹ ورک I/O
  • فائل سسٹم تک رسائی اور فائل I/O
  • پروسیس تھریڈ کی زندگی بھر کا انتظام کرنا
  • کم سطحی میموری کا انتظام
  • مخصوص ڈیوائس ڈرائیورز تک رسائی

اسٹریس کب استعمال کریں؟

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

اس کی ساری شان و شوکت میں سٹرس سافٹ ویئر کی ڈیبگنگ کے دوران خود کو ظاہر کرتا ہے جو ایک مشین پر اچھی طرح کام کرتا ہے، لیکن اچانک دوسری مشین پر کام کرنا بند کر دیتا ہے، فائلوں، اجازتوں، یا کچھ کمانڈز یا کسی اور چیز پر عمل کرنے کی ناکام کوششوں کے بارے میں مبہم پیغامات پیدا کرتا ہے... یہ افسوس کی بات ہے، لیکن ایسا نہیں ہوتا ہے۔ سرٹیفکیٹ کی توثیق کی خرابیوں جیسے اعلی سطحی مسائل کے ساتھ اچھی طرح سے یکجا کریں۔ عام طور پر یہ ایک مجموعہ کی ضرورت ہے سٹرسکبھی کبھی ltrace اور اعلی سطحی ٹولز (جیسے کمانڈ لائن ٹول کھولیں سرٹیفکیٹ کو ڈیبگ کرنے کے لیے)۔

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

ڈیبگنگ کی سادہ مثال

ہم کہتے ہیں کہ آپ حیرت انگیز سرور ایپلی کیشن foo چلانا چاہتے ہیں، اور یہ وہی ہے جس کے ساتھ آپ ختم ہوتے ہیں:

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

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

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

آؤٹ پٹ سٹرس بے کار لگ سکتا ہے، لیکن اچھی خبر یہ ہے کہ اس میں سے زیادہ تر کو محفوظ طریقے سے نظر انداز کیا جا سکتا ہے۔ ٹریس کے نتائج کو علیحدہ فائل میں محفوظ کرنے کے لیے -o آپریٹر کا استعمال کرنا اکثر مفید ہوتا ہے۔

$ strace -o /tmp/trace foo
Error opening configuration file: No such file or directory
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0
brk(NULL)                               = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0
mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 > 1 260A2 "..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000
mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0
mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000
mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000
mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000
mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0
mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0
mprotect(0x56363b08b000, 4096, PROT_READ) = 0
mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0
munmap(0x7f2f12cf1000, 25186)           = 0
openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
brk(NULL)                               = 0x56363b3fb000
brk(0x56363b41c000)                     = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Error opening configuration file"..., 60) = 60
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

آؤٹ پٹ کا تقریباً پورا پہلا صفحہ سٹرس - یہ عام طور پر لانچ کے لیے کم سطح کی تیاری ہے۔ (بہت ساری کالیں۔ mmap, ایمپروٹیکٹ, quill نچلی سطح کی میموری کا پتہ لگانے اور متحرک لائبریریوں کو ظاہر کرنے جیسی چیزوں کے لیے۔) دراصل، آؤٹ پٹ کو ڈیبگ کرنے کے دوران سٹرس آخر سے پڑھنا بہتر ہے۔ نیچے ایک چیلنج ہوگا۔ لکھنا، جو ایک غلطی کا پیغام دکھاتا ہے۔ ہم اوپر دیکھتے ہیں اور پہلی غلط نظام کال - کال دیکھتے ہیں۔ کھلنا، جو ایک غلطی پھینکتا ہے۔ ENOENT ("فائل یا ڈائریکٹری نہیں ملی") کھولنے کی کوشش کر رہا ہے۔ /etc/foo/config.json. یہ وہ جگہ ہے جہاں کنفیگریشن فائل ہونی چاہئے۔

یہ صرف ایک مثال تھی، لیکن میں اس وقت کا 90% کہوں گا جو میں استعمال کرتا ہوں۔ سٹرساس سے زیادہ مشکل کام کچھ نہیں ہے۔ ذیل میں ایک مکمل مرحلہ وار ڈیبگنگ گائیڈ ہے:

  • کسی پروگرام سے سسٹم وائی کی خرابی کے بارے میں مبہم پیغام کی وجہ سے پریشان ہوں۔
  • کے ساتھ پروگرام کو دوبارہ شروع کریں۔ سٹرس
  • ٹریس کے نتائج میں غلطی کا پیغام تلاش کریں۔
  • اس وقت تک اوپر جائیں جب تک کہ آپ پہلی ناکام سسٹم کال کو نہ ماریں۔

یہ بہت ممکن ہے کہ مرحلہ 4 میں سسٹم کال سے پتہ چل جائے گا کہ کیا غلط ہوا ہے۔

اشارے

آپ کو زیادہ پیچیدہ ڈیبگنگ کی ایک مثال دکھانے سے پہلے، میں آپ کو مؤثر استعمال کے لیے چند ترکیبیں دکھاؤں گا۔ سٹرس:

آدمی تمہارا دوست ہے

بہت سے *نکس سسٹمز پر، کرنل کو سسٹم کالز کی مکمل فہرست چلا کر حاصل کی جا سکتی ہے۔ آدمی syscalls. آپ کو ایسی چیزیں نظر آئیں گی۔ brk(2)جس کا مطلب ہے کہ چلانے سے مزید معلومات حاصل کی جا سکتی ہیں۔ آدمی 2 brk.

چھوٹا ریک: آدمی 2 کانٹا مجھے شیل کا صفحہ دکھاتا ہے۔ کانٹا () в GNU libc، جو، پتہ چلتا ہے، کال کرکے لاگو کیا جاتا ہے۔ کلون (). سیمنٹکس کو کال کریں۔ کانٹا اگر آپ استعمال کرتے ہوئے ایک پروگرام لکھتے ہیں تو وہی رہتا ہے۔ کانٹا ()، اور ایک ٹریس چلائیں - مجھے کوئی کال نہیں ملے گی۔ کانٹا، ان کے بجائے وہاں ہو جائے گا کلون (). اس طرح کے ریک آپ کو صرف اس صورت میں الجھا دیتے ہیں جب آپ ماخذ کا موازنہ آؤٹ پٹ سے کرنا شروع کر دیں۔ سٹرس.

آؤٹ پٹ کو فائل میں محفوظ کرنے کے لیے -o کا استعمال کریں۔

سٹرس وسیع آؤٹ پٹ پیدا کر سکتا ہے، اس لیے ٹریس کے نتائج کو الگ فائلوں میں محفوظ کرنا اکثر مفید ہوتا ہے (جیسا کہ اوپر کی مثال میں)۔ یہ آؤٹ پٹ کے ساتھ مبہم پروگرام آؤٹ پٹ سے بچنے میں بھی مدد کرتا ہے۔ سٹرس کنسول میں

مزید دلیل کا ڈیٹا دیکھنے کے لیے -s کا استعمال کریں۔

آپ نے محسوس کیا ہوگا کہ غلطی کے پیغام کا دوسرا نصف اوپر کی مثال ٹریس میں نہیں دکھایا گیا ہے۔ یہ اس لئے کیوں کے سٹرس ڈیفالٹ سٹرنگ آرگومنٹ کے صرف پہلے 32 بائٹس دکھاتا ہے۔ اگر آپ مزید دیکھنا چاہتے ہیں تو کچھ شامل کریں۔ - ایکس 128 کال پر سٹرس.

-y فائلوں، ساکٹ وغیرہ کو ٹریک کرنا آسان بناتا ہے۔

"سب فائل ہے" کا مطلب ہے کہ *نکس سسٹم تمام I/O فائل ڈسکرپٹرز کا استعمال کرتے ہوئے کرتے ہیں، چاہے وہ فائل یا نیٹ ورک یا انٹر پروسیس پائپ پر لاگو ہو۔ یہ پروگرامنگ کے لیے آسان ہے، لیکن جب آپ عام دیکھتے ہیں تو واقعی کیا ہو رہا ہے اس پر نظر رکھنا مشکل بنا دیتا ہے۔ پڑھیں и لکھنا سسٹم کال ٹریس کے نتائج میں۔

آپریٹر کو شامل کرکے -y، آپ مجبور کریں گے۔ سٹرس آؤٹ پٹ میں ہر فائل ڈسکرپٹر کو اس نوٹ کے ساتھ تشریح کریں کہ یہ کس چیز کی طرف اشارہ کرتا ہے۔

-p** کے ساتھ پہلے سے چل رہے عمل سے منسلک کریں

جیسا کہ آپ نیچے دی گئی مثال سے دیکھیں گے، بعض اوقات آپ کو پہلے سے چلنے والے پروگرام کو ٹریس کرنے کی ضرورت ہوتی ہے۔ اگر یہ معلوم ہے کہ یہ عمل 1337 کے طور پر چل رہا ہے (کہیں، آؤٹ پٹ سے ps)، پھر آپ اسے اس طرح ٹریس کر سکتے ہیں:

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

آپ کو جڑ کے حقوق کی ضرورت ہوسکتی ہے۔

بچوں کے عمل کی نگرانی کے لیے -f کا استعمال کریں۔

سٹرس پہلے سے طے شدہ طور پر، یہ صرف ایک عمل کو ٹریس کرتا ہے۔ اگر یہ عمل چائلڈ پروسیس کو جنم دیتا ہے، تو چائلڈ پروسیس کو اسپن کرنے کے لیے سسٹم کال کو دیکھا جا سکتا ہے، لیکن چائلڈ پروسیس کی سسٹم کالز ظاہر نہیں ہوں گی۔

اگر آپ کو لگتا ہے کہ غلطی بچوں کے عمل میں ہے تو بیان کا استعمال کریں۔ -f، یہ اس کی ٹریسنگ کو قابل بنائے گا۔ اس کا منفی پہلو یہ ہے کہ آؤٹ پٹ آپ کو اور بھی الجھائے گا۔ کب سٹرس ایک عمل یا ایک دھاگے کا پتہ لگاتا ہے، یہ کال کے واقعات کا ایک سلسلہ دکھاتا ہے۔ جب یہ ایک ہی وقت میں متعدد عملوں کو ٹریس کرتا ہے، تو آپ کو کال کا آغاز ایک پیغام کے ذریعے روکا ہوا دیکھ سکتا ہے۔ , پھر - دیگر پھانسی کی شاخوں کے لئے کالوں کا ایک گروپ، اور تب ہی - پہلی کا اختتام <…foocal resumed>. یا آپریٹر کا استعمال کرتے ہوئے تمام ٹریس نتائج کو مختلف فائلوں میں تقسیم کریں۔ -ff (تفصیلات قیادت پر سٹرس).

-e کا استعمال کرتے ہوئے نشانات کو فلٹر کریں۔

جیسا کہ آپ دیکھ سکتے ہیں، ٹریس کا نتیجہ تمام ممکنہ نظام کالوں کا ایک حقیقی ڈھیر ہے۔ جھنڈا۔ -e آپ ٹریس کو فلٹر کرسکتے ہیں (دیکھیں۔ رہنما پر سٹرس)۔ اہم فائدہ یہ ہے کہ فلٹر شدہ ٹریس کو مکمل ٹریس کرنے اور پھر چلانے سے زیادہ تیز ہے۔ grep`پر. ایماندار ہونے کے لئے، مجھے تقریبا ہمیشہ پرواہ نہیں ہے.

تمام غلطیاں بری نہیں ہوتیں۔

ایک سادہ اور عام مثال ایک پروگرام ہے جس میں ایک ساتھ کئی جگہوں پر فائل کی تلاش ہوتی ہے، جیسے ایک شیل کسی ڈائریکٹری کی تلاش کرتا ہے جس میں ایک قابل عمل فائل ہوتی ہے۔

$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...

"خرابی کی اطلاع دینے سے پہلے آخری ناکام درخواست" جیسے ہیورسٹکس متعلقہ غلطیوں کو تلاش کرنے میں اچھے ہیں۔ جیسا کہ یہ ہو سکتا ہے، یہ بالکل آخر سے شروع کرنا منطقی ہے.

سی پروگرامنگ ٹیوٹوریلز سسٹم کالز کو سمجھنے میں آپ کی مدد کر سکتے ہیں۔

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

ڈیبگنگ کی ایک زیادہ پیچیدہ مثال

میں نے پہلے ہی کہا ہے کہ سادہ ڈیبگنگ کی مثال اس کی ایک مثال ہے جس کے ساتھ کام کرتے وقت مجھے زیادہ تر نمٹنا پڑتا ہے۔ سٹرس. تاہم، کبھی کبھی ایک حقیقی تحقیقات کی ضرورت ہوتی ہے، لہذا یہاں زیادہ جدید ڈیبگنگ کی ایک حقیقی زندگی کی مثال ہے۔

bcron - ٹاسک پروسیسنگ شیڈیولر، *نکس ڈیمون کا ایک اور نفاذ کرون. یہ سرور پر انسٹال ہے، لیکن جب کوئی شخص شیڈول میں ترمیم کرنے کی کوشش کرتا ہے، تو ایسا ہوتا ہے:

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

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

# strace -o /tmp/trace crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
# cat /tmp/trace
...
openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
read(3, "#Ansible: logsaggn20 14 * * * lo"..., 8192) = 150
read(3, "", 8192)                       = 0
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
socket(AF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
write(3, "156:Slogs #Ansible: logsaggn20 1"..., 161) = 161
read(3, "32:ZCould not create temporary f"..., 8192) = 36
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49
unlink("bcrontab.14779.1573691864.847933") = 0
exit_group(111)                         = ?
+++ exited with 111 +++

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

اگر آپ دیکھیں آدمی 2 پڑھیں، آپ دیکھ سکتے ہیں کہ پہلی دلیل (3) ایک فائل ڈسکرپٹر ہے، جو *nix تمام I/O پروسیسنگ کے لیے استعمال کرتا ہے۔ میں کیسے جان سکتا ہوں کہ فائل ڈسکرپٹر 3 کس چیز کی نمائندگی کرتا ہے؟ اس خاص معاملے میں، آپ چلا سکتے ہیں۔ سٹرس آپریٹر کے ساتھ -y (اوپر دیکھیں) اور یہ خود بخود آپ کو بتائے گا، لیکن اس طرح کی چیزوں کا پتہ لگانے کے لیے، یہ جاننا مفید ہے کہ ٹریس کے نتائج کو کیسے پڑھنا اور پارس کرنا ہے۔

فائل ڈسکرپٹر کا ماخذ بہت سی سسٹم کالز میں سے ایک ہو سکتا ہے (یہ سب اس بات پر منحصر ہے کہ ڈسکرپٹر کس چیز کے لیے ہے - کنسول، نیٹ ورک ساکٹ، فائل خود، یا کچھ اور)، لیکن جیسا بھی ہو، ہم اسے تلاش کرتے ہیں۔ 3 واپس کر کے کالز (یعنی ہم ٹریسنگ کے نتائج میں "= 3" تلاش کرتے ہیں)۔ اس نتیجے میں ان میں سے 2 ہیں: کھلنا سب سے اوپر اور ساکٹ درمیان میں. کھلنا فائل کھولتا ہے لیکن بند کریں(3) پھر دکھائے گا کہ یہ دوبارہ بند ہوجاتا ہے۔ (ریک: فائل ڈسکرپٹرز کو کھولنے اور بند ہونے پر دوبارہ استعمال کیا جا سکتا ہے)۔ کال کریں۔ ساکٹ () مناسب ہے کیونکہ یہ اس سے پہلے آخری ہے۔ پڑھیں ()، اور یہ پتہ چلتا ہے کہ bcrontab ساکٹ کے ذریعے کسی چیز کے ساتھ کام کرتا ہے۔ اگلی لائن سے پتہ چلتا ہے کہ فائل ڈسکرپٹر سے وابستہ ہے۔ یونکس ڈومین ساکٹ راستے میں /var/run/bcron-spool.

لہذا، ہمیں اس سے منسلک عمل کو تلاش کرنے کی ضرورت ہے یونکس ساکٹ دوسری طرف. اس مقصد کے لیے کچھ صاف ستھری چالیں ہیں، جو دونوں سرور کی تعیناتیوں کو ڈیبگ کرنے کے لیے مفید ہیں۔ سب سے پہلے استعمال کرنا ہے۔ netstat یا نیا؟ ss (ساکٹ کی حیثیت)۔ دونوں کمانڈز سسٹم کے فعال نیٹ ورک کنکشن کو ظاہر کرتے ہیں اور بیان لیتے ہیں۔ -l سننے کے ساکٹ کے ساتھ ساتھ آپریٹر کی وضاحت کرنے کے لیے -p ساکٹ سے منسلک پروگراموں کو بطور کلائنٹ ظاہر کرنے کے لیے۔ (اور بھی بہت سے مفید آپشنز ہیں، لیکن یہ دونوں اس کام کے لیے کافی ہیں۔)

# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0   128   /var/run/bcron-spool 1466637   * 0   users:(("unixserver",pid=20629,fd=3))

اس سے پتہ چلتا ہے کہ سننے والا حکم ہے۔ inixserverپروسیس ID 20629 کے ساتھ چل رہا ہے۔

اسی معلومات کو تلاش کرنے کے لیے دوسرا واقعی مفید ٹول کہا جاتا ہے۔ lsof. یہ سسٹم پر تمام کھلی فائلوں (یا فائل ڈسکرپٹرز) کی فہرست دیتا ہے۔ یا آپ ایک مخصوص فائل کے بارے میں معلومات حاصل کر سکتے ہیں:

# lsof /var/run/bcron-spool
COMMAND   PID   USER  FD  TYPE  DEVICE              SIZE/OFF  NODE    NAME
unixserve 20629 cron  3u  unix  0x000000005ac4bd83  0t0       1466637 /var/run/bcron-spool type=STREAM

پروسیس 20629 ایک طویل المدت سرور ہے، لہذا آپ اسے منسلک کر سکتے ہیں۔ سٹرس کچھ اس طرح کا استعمال کرتے ہوئے strace -o /tmp/trace -p 20629. اگر آپ کسی دوسرے ٹرمینل میں کرون جاب میں ترمیم کرتے ہیں، تو آپ کو غلطی کے ساتھ ٹریس آؤٹ پٹ ملے گا۔ اور یہاں نتیجہ ہے:

accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL

(آخری قبول کریں () ٹریس کرتے وقت مکمل نہیں کیا جائے گا۔) ایک بار پھر، بدقسمتی سے، اس نتیجے میں وہ غلطی نہیں ہے جس کی ہم تلاش کر رہے ہیں۔ ہمیں کوئی پیغامات نظر نہیں آتے جو bcrontag ساکٹ کو بھیجتا یا وصول کرتا ہے۔ اس کے بجائے، مکمل عمل کنٹرول (کلون, انتظار 4, SIGCHLD وغیرہ) یہ عمل بچوں کے عمل کو جنم دیتا ہے، جو کہ جیسا کہ آپ اندازہ لگا سکتے ہیں، اصل کام کرتا ہے۔ اور اگر آپ کو اس کی پگڈنڈی پکڑنے کی ضرورت ہے تو کال میں شامل کریں۔ strace -f. یہ وہی ہے جو ہمیں اس وقت ملے گا جب ہم اسٹریس کے ساتھ نئے نتیجے میں ایرر میسج تلاش کریں گے۔ -f -o /tmp/trace -p 20629:

21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

اب، یہ کچھ ہے. راستے پر فائل بنانے کی کوشش کرتے وقت پروسیس 21470 کو "رسائی سے انکار" کی غلطی موصول ہوتی ہے۔ tmp/spool.21470.1573692319.854640 (موجودہ ورکنگ ڈائرکٹری سے متعلق)۔ اگر ہم صرف موجودہ ورکنگ ڈائرکٹری کو جانتے ہیں، تو ہمیں مکمل راستہ بھی معلوم ہوگا اور یہ معلوم کرنے کے قابل ہو جائیں گے کہ عمل اس میں اپنی عارضی فائل کیوں نہیں بنا سکتا۔ بدقسمتی سے، عمل پہلے ہی ختم ہو چکا ہے، لہذا آپ صرف استعمال نہیں کر سکتے lsof -p 21470 موجودہ ڈائرکٹری کو تلاش کرنے کے لیے، لیکن آپ مخالف سمت میں کام کر سکتے ہیں - PID 21470 سسٹم کالز تلاش کریں جو ڈائریکٹری کو تبدیل کرتی ہیں۔ (اگر کوئی نہیں ہے تو، PID 21470 نے انہیں اپنے والدین سے وراثت میں حاصل کیا ہوگا، اور یہ پہلے سے ہی ہو چکا ہے۔ lsof -p پتہ نہیں چلا۔) یہ سسٹم کال ہے۔ chdir (جسے جدید آن لائن سرچ انجنوں کی مدد سے تلاش کرنا آسان ہے)۔ اور سرور PID 20629 تک تمام راستے ٹریس کے نتائج کی بنیاد پر ریورس سرچز کا نتیجہ یہ ہے:

20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470
...
21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0
...
21470 chdir("/var/spool/cron")          = 0
...
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

(اگر آپ کھو گئے ہیں، تو آپ میری پچھلی پوسٹ پڑھنا چاہیں گے۔ * نکس پروسیس مینجمنٹ اور شیلز کے بارے میںلہذا، سرور PID 20629 کو راستے پر فائل بنانے کی اجازت نہیں ملی۔ /var/spool/cron/tmp/spool.21470.1573692319.854640. زیادہ تر امکان ہے، اس کی وجہ کلاسک فائل سسٹم کی اجازت کی ترتیبات ہیں۔ آؤ دیکھیں:

# ls -ld /var/spool/cron/tmp/
drwxr-xr-x 2 root root 4096 Nov  6 05:33 /var/spool/cron/tmp/
# ps u -p 20629
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
cron     20629  0.0  0.0   2276   752 ?        Ss   Nov14   0:00 unixserver -U /var/run/bcron-spool -- bcron-spool

وہیں کتا دفن ہے! سرور صارف کرون کے طور پر چلتا ہے، لیکن صرف روٹ کو ڈائریکٹری میں لکھنے کی اجازت ہے۔ /var/spool/cron/tmp/. سادہ حکم chown cron /var/spool/cron/tmp/ دباو ڈالا گیا bcron صحیح طریقے سے کام کریں. (اگر یہ مسئلہ نہیں تھا، تو اگلا ممکنہ مشتبہ ایک کرنل سیکیورٹی ماڈیول ہے جیسے SELinux یا AppArmor، لہذا میں اس کے ساتھ کرنل میسج لاگ کو چیک کروں گا dmesg.)

مجموعی طور پر

سسٹم کال کے نشانات ایک ابتدائی کے لیے بہت زیادہ ہو سکتے ہیں، لیکن مجھے امید ہے کہ میں نے دکھایا ہے کہ وہ عام تعیناتی کے مسائل کی پوری کلاس کو ڈیبگ کرنے کا ایک تیز طریقہ ہیں۔ ایک ملٹی پروسیس کو ڈیبگ کرنے کی کوشش کا تصور کریں۔ bcronمرحلہ وار ڈیبگر کا استعمال کرتے ہوئے

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

ماخذ: www.habr.com

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