কম্পিউটার টিউটোরিয়াল

রুবি দিয়ে নিজস্ব লিনাক্স টুলস তৈরি করুন: একটি ব্যবহারিক গাইড

আমরা একসাথে একটি প্রজেক্ট তৈরি করি!

ps, top এবং netstat এর মতো লিনাক্স টুলস খুবই কাজের।

এগুলো আপনার সিস্টেমে কী হচ্ছে তার সম্পর্কে অনেক তথ্য দেয়।

  • কিন্তু এগুলো কীভাবে কাজ করে?
  • তারা সব তথ্য কোথা থেকে পায়?
  • আমরা কীভাবে এগুলো ব্যবহার করে নিজস্ব টুলস তৈরি করতে পারি?

এই পোস্টে আমরা মিলে তিনটি জনপ্রিয় লিনাক্স টুল পুনর্নির্মাণ করব।

আপনি একটি ২-ইন-১ অফার পাচ্ছেন: রুবির কিছু ট্রিক শিখবেন এবং একই সাথে ব্যবহারিক লিনাক্স জ্ঞানও অর্জন করবেন! 🙂

স্ট্যাটাস তথ্য খুঁজে বের করা

চলুন দেখি এই সব টুলগুলো তাদের তথ্য কোথা থেকে পায়।

উত্তরটি প্রোক ফাইলসিস্টেমে রয়েছে!

/proc ডিরেক্টরির ভেতর তাকালে আপনি দেখবেন এটা আপনার কম্পিউটারের অন্য যেকোনো ডিরেক্টরির মতো কিছু ডিরেক্টরি এবং ফাইল দেখাচ্ছে।

এগুলো আসল ফাইল নয়, বরং লিনাক্স কার্নেল ব্যবহারকারীদের কাছে ডেটা প্রকাশ করার একটি পদ্ধতি।

এটি খুব সুবিধাজনক কারণ এগুলো সাধারণ ফাইলগুলোর মতো ব্যবহার করা যায়, অর্থাৎ আপনি কোনো স্পেশাল টুল ছাড়াই এগুলো পড়তে পারেন।

লিনাক্স জগতে অনেক জিনিস এভাবে কাজ করে।

আপনি যদি অন্য একটি উদাহরণ দেখতে চান তবে /dev ডিরেক্টরিতে এক নজর দিন।

এখন আমরা বুঝতে পারলাম আমরা কী সাথে কাজ করছি, চলুন /proc ডিরেক্টরির কন্টেন্ট দেখি…

1 10 104 105 11 11015 11469 11474 11552 11655 

এটি শুধু একটি ছোট নমুনা, কিন্তু আপনি দ্রুত একটি প্যাটার্ন লক্ষ্য করতে পারবেন।

এই সব নম্বরগুলো কী?

দेखুন, এগুলো আসলে পিআইডি (PID - Process IDs)।

প্রতিটি এন্ট্রি একটি নির্দিষ্ট প্রসেসের তথ্য ধারণ করে।

আপনি যদি ps রান করেন তবে দেখবেন প্রতিটি প্রসেসের সাথে একটি পিআইডি যুক্ত থাকে:

PID TTY TIME CMD 15952 pts/5 00:00:00 ps 22698 pts/5 00:00:01 bash 

এ থেকে আমরা অনুমান করতে পারি যে ps কী করছে: এটি শুধু /proc ডিরেক্টরির ওপর ইটারেট করে এবং সেখানে পাওয়া তথ্যগুলো প্রিন্ট করে।

চলুন দেখা যাক সেই নম্বরवाले ডিরেক্টরিগুলোর ভেতর কী আছে:

attr autogroup auxv cgroup clear_refs cmdline comm cpuset cwd environ exe fd 

স্থান বাঁচাতে শুধু একটি নমুনা দেওয়া হয়েছে, কিন্তু আমি আপনাকে পুরো লিস্ট দেখার পরামর্শ দিচ্ছি।

এখানে কিছু গুরুত্বপূর্ণ এন্ট্রি:

এন্ট্রি বিবরণ
comm প্রোগ্রামের নাম
cmdline এই প্রসেস চালু করার জন্য ব্যবহৃত কমান্ড
environ এই প্রসেস শুরু করার সময়ের এনভায়রনমেন্ট ভেরিয়েবলগুলো
status প্রসেসের স্ট্যাটাস (রানিং, স্লিপিং…) এবং মেমরি ব্যবহার
fd ফাইল ডেসক্রিপ্টর ধারণকারী ডিরেক্টরি (ওপেন ফাইল, সকেট…)

এখন আমরা এটা জানতে পেরেছি, সুতরাং আমরা আমাদের নিজস্ব টুলস লিখতে শুরু করতে পারি!

চলমান প্রোগ্রামের লিস্ট কীভাবে বানাতে হয়

চলুন শুধু /proc এর অধীনে থাকা সকল ডিরেক্টরির একটি লিস্ট বানাতে পারি।

এটা আমরা Dir ক্লাস ব্যবহার করে করতে পারি।

উদাহরণ:

Dir.glob("/proc/[0-9]*") 

লক্ষ্য করুন আমি কীভাবে একটি নম্বর রেঞ্জ ব্যবহার করলাম, কারণ /proc এর অধীনে আরও অনেক ফাইল রয়েছে যেগুলো আমাদের अभी দরকার নেই, আমাদের শুধু নম্বরवाले ডিরেক্টরিগুলো দরকার।

এখন আমরা এই লিস্টের ওপর ইটারেট করে دوটি কলাম প্রিন্ট করতে পারি, একটা পিআইডির জন্য আরেকটা প্রোগ্রামের নামের জন্য।

উদাহরণ:

pids = Dir.glob("/proc/[0-9]*") puts "PID\tCMD" puts "-" * 15 pids.each do |pid| cmd = File.read(pid + "/comm") pid = pid.scan(/\d+/).first puts "#{pid}\t#{cmd}" end 

এই আউটপুটটি হবে:

PID CMD --------------- 1 systemd 2 kthreadd 3 ksoftirqd/0 5 kworker/0 7 migration/0 8 rcu_preempt 9 rcu_bh 10 rcu_sched 

হে, দেখতে পাচ্ছি আমরা ps বানাতে পেরেছি! হ্যাঁ, এতে মূল টুলের সকল ফ্যান্সি অপশন নেই, কিন্তু আমরা কিছু ফাংশনাল বানাতে পেরেছি।

কौন শুনছে? (পোর্ট মনিটরিং)

চলুন এবার netstat এর অনুলিপি তৈরি করি, এর আউটপুট -ant ফ্ল্যাগসহ এমন দেখায়।

Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN tcp 0 0 192.168.1.82:39530 182.14.172.159:22 ESTABLISHED 

এই তথ্য কোথায় পাওয়া যায়? আপনি যদি বলেন /proc এর ভেতর, তবে আপনি সঠিক! আরও স্পষ্টভাবে বললে /proc/net/tcp এ।

“하지만 একটা সমস্যা আছে, এটি netstat আউটপুটের মতো কিছুই দেখাচ্ছে না!

0: 0100007F:1538 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 9216 1: 2E58A8C0:9A6A 9FBB0EB9:0016 01 00000000:00000000 00:00000000 00000000 1000 0 258603 

অর্থাৎ আমাদের রেগুলার এক্সপ্রেশন ব্যবহার করে কিছু পার্সিং করতে হবে। ফিলহাল শুধু লোকাল অ্যাড্রেস এবং স্ট্যাটাস নিয়ে চিন্তা করি।

এখানে আমার তৈরি করা রেগেক্স:

LINE_REGEX = /\s+\d+: (?<local_addr>\w+):(?<local_port>\w+) \w+:\w+ (?<status>\w+)/ 

এটি আমাদের কিছু হেক্সাডেসিমেল ভ্যালু দেবে যেগুলো ডেসিমেলে কনভার্ট করতে হবে। চলুন একটি ক্লাস বানাই যা এই কাজটি করবে।

class TCPInfo def initialize(line) @data = parse(line) end def parse(line) line.match(LINE_REGEX) end def local_port @data["local_port"].to_i(16) end # হেক্স থেকে রेगুলার আইপি নোটেশনে কনভার্ট def local_addr decimal_to_ip(@data["local_addr"].to_i(16)) end STATUSES = { "0A" => "LISTENING", "01" => "ESTABLISHED", "06" => "TIME_WAIT", "08" => "CLOSE_WAIT" } def status code = @data["status"] STATUSES.fetch(code, "UNKNOWN") end # এই বাইনারি ম্যাথ নিয়ে চিন্তা করবেন না। def decimal_to_ip(decimal) ip = [] ip << (decimal >> 24 & 0xFF) ip << (decimal >> 16 & 0xFF) ip << (decimal >> 8 & 0xFF) ip << (decimal & 0xFF) ip.join(".") end end 

বাকি আছে রেজাল্টগুলো একটি সুন্দর টেবিল ফরম্যাটে প্রিন্ট করা।

require 'table_print' tp connections 

উদাহরণ আউটপুট:

STATUS | LOCAL_PORT | LOCAL_ADDR ------------|------------|-------------- LISTENING | 5432 | 127.0.0.1 ESTABLISHED | 39530 | 192.168.88.46 

হ্যাঁ, এই জেমটি দারুণ!

আমি এখন খুঁজে পেলাম আর ljust / rjust দিয়ে হাতপা ফুলাতে হবে না 🙂

আমার পোর্ট ব্যবহার করছো না!

আপনি কি কখনো এই মেসেজটি দেখেছেন?

Address already in use - bind(2) for "localhost" port 5000 

উम्म…

আমি চিন্তা করছি কোন প্রোগ্রামই সেই পোর্টটি ব্যবহার করছে।

চলুন খুঁজে বের করি:

fuser -n tcp -v 5000 PORT USER PID ACCESS CMD 5000/tcp rubyguides 30893 F.... nc 

আহা, вот পেলাম কলprits!

এখন আমরা এই প্রোগ্রামটি বন্ধ করতে পারি যদি আমরা চাই না এটি চলুক, এবং এতে আমাদের পোর্ট মুক্ত হয়ে যাবে। fuser প্রোগ্রামটি কীভাবে বুঝলো কে এই পোর্টটি ব্যবহার করছে?

আপনি حدس করলেন!

আবার /proc ফাইলসিস্টেম।

দ্রষ্টব্য, এটি দুটি বিষয় কম্বাইন করেছে যেগুলো আমরা ইতিমধ্যে আলোচনা করেছি: প্রসেস লিস্টের মাধ্যমে ঘুরে বেড়ানো এবং /proc/net/tcp থেকে একটিভ কানেকশন পড়া।

আমাদের শুধু একটি এক্সট্রা ধাপ দরকার:

ওপেন পোর্টের ইনফরমেশন পিআইডির সাথে মিলিয়ে দেওয়া।

আমরা যদি /proc/net/tcp থেকে পাওয়া TCP ডেটা দেখি, তবে সেখানে পিআইডি নেই। কিন্তু আমরা ইনোড নম্বর ব্যবহার করতে পারি।

“ইনোড হল একটি ডেটা স্ট্রাকচার যা ফাইলসিস্টেম অবজেক্টকে রিপ্রেজেন্ট করে।” — উইকিপিডিয়া

ইনোড ব্যবহার করে ম্যাচিং প্রসেস কীভাবে খুঁজে বের করব? যদি আমরা একটি প্রসেসের fd ডিরেক্টরিতে তাকائ যাক যেটির একটি ওপেন পোর্ট আছে, তবে আমরা এমন একটি লাইন পাব:

/proc/3295/fd/5 -> socket:[12345] 

ব্র্যাকেটের মাঝখানের নম্বরটিই ইনোড নম্বর। তাহলে এখন আমাদের শুধু সব ফাইলগুলো ওপর ইটারেট করতে হবে এবং আমরা ম্যাচিং প্রসেসটি পেয়ে যাব।

এখানে একটি পদ্ধতি:

x = Dir.glob("/proc/[0-9]*/fd/*").find do |fd| File.readlink(fd).include? "socket:[#{socket_inode}]" rescue nil end pid = x.scan(/\d+/).first name = File.readlink("/proc/#{pid}/exe") puts "Port #{hex_port.to_i(16)} in use by #{name} (#{pid})" 

উদাহরণ আউটপুট:

Port 5432 in use by /usr/bin/postgres (474) 

দ্রষ্টব্য: এই কোডটি আপনাকে রুট হিসেবে বা প্রসেসের মালিক হিসেবে রান করতে হবে।

অন্যথায় আপনি /proc এর ভেতরের প্রসেস ডিটেইলস পড়তে পারবেন না।

উপসংহার

এই পোস্টে আপনি শিখেছেন যে লিনাক্স ভার্চুয়াল /proc ফাইলসিস্টেমের মাধ্যমে প্রচুর ডেটা প্রকাশ করে। আপনি শিখেছেন কীভাবে /proc এর অধীনে থাকা ডেটা ব্যবহার করে ps, netstat এবং fuser মতো জনপ্রিয় লিনাক্স টুলস পুনর্নির্মাণ করা যায়।

নিউজলেটার সাবস্ক্রাইব করা ভুলবেন না যাতে পরবর্তী পোস্ট মিস না হয়। 🙂


  1. নিজেই লিনাক্স টেক সাপোর্ট হওয়ার পদ্ধতি

  2. নিজে বাসার জীবন ব্যয় হিসাব করার টেক টুলস

  3. রুবি মেথড ব্যাখ্যা: কাস্টম ফাংশন সহজে তৈরি করুন

  4. SUSE Studio: নিজের কাস্টম লিনাক্স ডিস্ট্রিবিউশন বানান