গতকাল টানেলটি কাজ করছিল, আজ সকালে unit মৃত, জার্নালে রয়েছে Failed at step EXEC spawning /usr/local/bin/vpnclient। শংসাপত্র, রুট এবং অ্যাকাউন্ট কখনও ওই বাক্যে ঢোকে না। systemd ExecStart-কে একটি পাথে রূপান্তর করল, কার্নেলকে তা সম্পাদনের অনুরোধ করল, এবং কার্নেল তা প্রত্যাখ্যান করল — বেশিরভাগ ক্ষেত্রে কারণ ওই পাথে কিছুই নেই বা ফাইলটি সম্পাদনযোগ্য নয়। বিশ্লেষিত কমান্ড বিপরীতটা প্রমাণ না করা পর্যন্ত ত্রুটিটিকে ফাইল ও argv-এর সমস্যা হিসেবেই দেখুন।

কেন প্রমাণীকরণ শুরুর আগেই EXEC ব্যর্থ হয়

systemd ExecStart-কে কোনো শেল দিয়ে চালায় না। এটি fork করে, লাইন থেকে আর্গুমেন্ট ভেক্টর তৈরি করে এবং প্রথম উপাদানের ওপর execve ডাকে। সেই ডাক ব্যর্থ হলে পরিষেবাটি কখনও VPN ক্লায়েন্টের নিজস্ব কোডে পৌঁছায় না, তাই প্রোফাইল সম্পাদনা বা শংসাপত্র যাচাই কিছুই সাহায্য করতে পারে না।

স্টেটাস কোড এই শ্রেণিটিকে সাধারণ ক্র্যাশ থেকে আলাদা করে। status=203/EXEC নিয়ে বেরোনো unit কখনও প্রসেস শুরু করেনি; যে unit শুরু হয়ে পরে status=1 নিয়ে বেরোয়, সেটি হয়তো প্রমাণীকরণ, DNS বা রাউটিংয়ে ব্যর্থ হয়েছে। কোডটি আগে পড়ুন, তারপর ক্লায়েন্ট লগ — কারণ প্রথম ক্ষেত্রে ক্লায়েন্ট লগ খালি থাকবে।

জার্নালে যে পাথটি আছে সেটি systemd ব্যবহার করেছে, আপনি যেটি সম্পাদনা করেছেন সেটি নাও হতে পারে। Drop-in এবং জেনারেটরের আউটপুট ভেন্ডর ফাইলকে অগ্রাহ্য করতে পারে, আর পুরোনো daemon-reload মেমরিতে পুরোনো লাইনটি রেখে দেয়। তাই প্রথম ডায়াগনস্টিক হলো systemd-কে জিজ্ঞাসা করা সে কমান্ডটিকে কী ভাবছে, আপনি যে ফাইলটি বদলেছেন বলে মনে করছেন সেটি খোলা নয়।

বাইনারির পাথ যে তিন জায়গায় লেখা থাকে

ডিস্ট্রিবিউশন প্যাকেজ, ভেন্ডর স্ক্রিপ্ট এবং রিলিজ tarball থেকে ইনস্টল করা VPN ক্লায়েন্ট তিনটি ভিন্ন প্রিফিক্সে পড়তে পারে। unit, বিশেষাধিকার নিয়ম এবং ইনস্টলার — প্রত্যেকে ওই প্রিফিক্সগুলোর একটি করে লিখে রেখেছে, এবং তিনটির মধ্যে দুটি মিল না হলেই ত্রুটিটি দেখা যায়।

RecordCommon valueHow to read it
Unit or drop-in/usr/local/bin/vpnclientsystemctl cat vpnclient.service
Installed binary/usr/bin/vpnclientcommand -v vpnclient, then ls -l the result
Sudoers grant/opt/vpnclient/bin/vpnclientsudo grep -r vpnclient /etc/sudoers.d/

একটি নির্দিষ্ট অমিল এমন দেখতে: ভেন্ডর স্ক্রিপ্ট /usr/local/bin-এ ইনস্টল করে, tarball /opt-এর নিচে খোলা হয়েছে, আর unit এখনও আগের প্যাকেজের পুরোনো /usr/bin পাথের কথা বলছে। ওই ফাইলগুলোর মধ্যে কেবল একটি আছে, এবং সেটি খুব কমই ExecStart-এ থাকা ফাইল।

যে কোনো ফাইল বদলানোর আগে ঠিক করুন কোন পাথটি প্রামাণ্য। যদি ডিস্ট্রিবিউশন প্যাকেজ বাইনারির মালিক হয়, তবে প্যাকেজের পাথই প্রামাণ্য এবং unit তার অনুসরণ করবে। যদি ভেন্ডর স্ক্রিপ্ট মালিক হয়, একই নিয়ম ভেন্ডর প্রিফিক্সের ক্ষেত্রে প্রযোজ্য। প্রিফিক্সের মধ্যে বাইনারি কপি করলে দুটি কপি তৈরি হয়, যেগুলো পরের আপগ্রেডে আলাদা হয়ে যায়।

যখন উদ্ধৃত কমান্ড ফাইলের নাম হয়ে যায়

দ্বিতীয় ব্যর্থতার ধরন একই জার্নাল লাইনের পেছনে লুকিয়ে থাকে। কেউ এটি unit-এ লেখে এবং আশা করে ক্লায়েন্ট বুটের সময় সংযুক্ত হবে:

ExecStart=/usr/bin/"vpnclient connect office"

systemd মানটিকে শব্দে ভাগ করে, তাই প্রথম শব্দটি হয় /usr/bin/vpnclient connect office, আর উদ্ধৃতিগুলো গ্রুপিং সিনট্যাক্স হিসেবে সরে যায়। এরপর কার্নেল এমন ফাইল খোঁজে যার নামে স্পেস আছে, এবং তা নেই। বাইনারি ইনস্টল থাকা সত্ত্বেও ত্রুটিটি অনুপস্থিত বাইনারির মতোই।

সমর্থিত রূপ হলো প্রকৃত সম্পাদনযোগ্য ফাইল, তার পরে আলাদা আর্গুমেন্ট, যেমন ExecStart=/usr/bin/vpnclient connect office। যদি কর্মপ্রবাহের সত্যিই পাইপলাইন বা চেইন দরকার হয়, সেটি স্ক্রিপ্টে রাখুন এবং স্ক্রিপ্টটি ডাকুন, কারণ ExecStart-এ && নেই, পাইপ নেই এবং glob সম্প্রসারণ নেই।

ফাইলসিস্টেম নয়, unit ঠিক করুন

প্রলুব্ধকর মেরামত হলো প্রত্যাশিত পাথ থেকে আসল বাইনারিতে একটি সিম্বলিক লিংক। এটি ততদিন কাজ করে যতদিন প্যাকেজ আপডেট হয়ে লিংকটি মুছে ফেলা ফাইলের দিকে না যায়, বা SELinux লেবেল আর লক্ষ্যের সঙ্গে না মেলে। unit-কে drop-in দিয়ে সম্পাদনা করাই ভালো, যাতে ভেন্ডর ফাইল অক্ষত থাকে এবং আপগ্রেড পূর্বানুমেয় থাকে।

বিশেষাধিকার নিয়মকে একই পাথ ও একই উপকমান্ডের সঙ্গে মিলতে হবে। /usr/local/bin/vpnclient-এর জন্য sudoers এন্ট্রি /usr/bin/vpnclient-কে অনুমোদন করে না, আর যে এন্ট্রি প্রতিটি আর্গুমেন্ট অনুমোদন করে সেটি যেকোনো স্থানীয় প্রসেসকে টানেল পুনঃকনফিগার বা বন্ধ করার সুযোগ দেয়। unit-এর প্রয়োজনীয় দুটি ক্রিয়াকে অনুমতি দিন এবং সেবা বন্ধ করলেই ইন্টারফেস বন্ধ হয়ে গেলে teardown বাদ দিন।

এখানেই তুলনাটি লাভজনক: unit, প্যাকেজ ডেটাবেস এবং sudoers — সবগুলোর একই পাথ বলা উচিত। তা হলে রিবুট ছাড়াই এবং তৃতীয় জায়গায় বাইনারির কপি ছাড়াই EXEC ত্রুটি চলে যায়।

রিবুটের আগে বিশ্লেষিত কমান্ড প্রমাণ করুন

sudo systemctl daemon-reload
sudo systemctl cat vpnclient.service
systemctl show -p ExecStart vpnclient.service
systemd-analyze verify /etc/systemd/system/vpnclient.service
sudo systemctl restart vpnclient.service
systemctl status vpnclient.service --no-pager

systemctl show নির্ণায়ক আউটপুট, কারণ এটি দেখায় systemd আসলে যে argv বিশ্লেষণ করেছে, যেকোনো drop-in সহ। systemd-analyze verify রিস্টার্টের আগেই অনুপস্থিত বা অ-সম্পাদনযোগ্য পাথ ধরে ফেলে, আর রিস্টার্টের পরের status কমান্ড জানায় প্রসেসটি এখন আছে কি না।

unit শুরু হয়ে পরে ব্যর্থ হলে আপনি EXEC শ্রেণি ছেড়ে ক্লায়েন্টের নিজস্ব ত্রুটি ব্যবস্থাপনায় ঢুকে গেছেন। জার্নালে ক্লায়েন্টের বার্তা খুঁজুন, আরেকটি execve ব্যর্থতা নয়। unit-এর diff ও sudoers-এর diff একসঙ্গে পরিবর্তন রেকর্ডে রাখুন, যাতে পরের আপগ্রেড নীরবে বিভক্ত পাথটি আবার না আনে।

সম্পর্কিত নিবন্ধ