এর ব্যবহার /proc/self/exe
অ-বহনযোগ্য এবং অবিশ্বস্ত। আমার উবুন্টু 12.04 সিস্টেমে, সিমলিংকটি পড়তে / অনুসরণ করতে আপনাকে অবশ্যই মূল হতে হবে। এটি বুস্টের উদাহরণ তৈরি করবে এবং সম্ভবত whereami()
পোস্ট হওয়া সমাধানগুলি ব্যর্থ হবে।
এই পোস্টটি খুব দীর্ঘ তবে প্রকৃত সমস্যাগুলি নিয়ে আলোচনা করে এবং কোডটি উপস্থাপন করে যা আসলে কোনও পরীক্ষার স্যুটের বিরুদ্ধে বৈধতার সাথে কাজ করে।
আপনার প্রোগ্রামটি সন্ধান করার সর্বোত্তম উপায় হ'ল সিস্টেমটি যে পদক্ষেপগুলি ব্যবহার করে একই পদক্ষেপগুলি পুনরায় সন্ধান করা। এই ব্যবহার করে সম্পন্ন করা হয় argv[0]
ফাইল সিস্টেম রুট, PWD পথ পরিবেশ ও বিবেচনা করা symlinks এবং পথনাম ক্যাননিকাল করার বিরুদ্ধে সমাধান। এটি স্মৃতি থেকে তবে আমি অতীতে এটি সফলভাবে করেছি এবং বিভিন্ন পরিস্থিতিতে এটি পরীক্ষা করেছি। এটি কাজ করার গ্যারান্টিযুক্ত নয় তবে এটি যদি না হয় তবে সম্ভবত আপনার আরও অনেক বড় সমস্যা রয়েছে এবং এটি আলোচিত অন্যান্য পদ্ধতির তুলনায় এটি সামগ্রিকভাবে নির্ভরযোগ্য। ইউনিক্স সামঞ্জস্যপূর্ণ সিস্টেমে এমন পরিস্থিতি রয়েছে যাতে সঠিক পরিচালনা করা হয়argv[0]
আপনাকে আপনার প্রোগ্রামে পাবেন না তবে আপনি একটি প্রত্যয়যুক্ত ভাঙ্গা পরিবেশে চালাচ্ছেন। এটি ১৯ 1970০ সালের পর থেকে সমস্ত ইউনিক্স উদ্ভূত সিস্টেমে এবং এমনকি কিছু নন-ইউনিক্স উত্পন্ন সিস্টেমের কাছে মোটামুটি বহনযোগ্য কারণ এটি মূলত libc () স্ট্যান্ডার্ড কার্যকারিতা এবং স্ট্যান্ডার্ড কমান্ড লাইন কার্যকারিতা উপর নির্ভর করে। এটি লিনাক্স (সমস্ত সংস্করণ), অ্যান্ড্রয়েড, ক্রোম ওএস, মিনিক্স, মূল বেল ল্যাবস ইউনিক্স, ফ্রিবিএসডি, নেটবিএসডি, ওপেনবিএসডি, বিএসডি এক্সএক্স, সানোস, সোলারিস, এসওয়াইএসভি, এইচপিইউএক্স, কনসেন্ট্রিক্স, এসসিও, ডারউইন, এআইএক্স, ওএস এক্স, নেক্সটস্টেপ ইত্যাদি And এবং সামান্য সংশোধন করে সম্ভবত ভিএমএস, ভিএম / সিএমএস, ডস / উইন্ডোজ, রিঅ্যাকটস, ওএস / ২, ইত্যাদি If যদি কোনও জিইউআই পরিবেশ থেকে সরাসরি কোনও প্রোগ্রাম চালু করা হয় তবে এটি অবশ্যই argv[0]
একটি চূড়ান্ত পথে চলে যেতে হবে।
বুঝতে হবে যে প্রতিটি ইউনিক্স সামঞ্জস্যপূর্ণ অপারেটিং সিস্টেমের প্রায় প্রতিটি শেল যা মূলত প্রকাশিত হয়েছিল সেগুলি একইভাবে প্রোগ্রামগুলি আবিষ্কার করে এবং অপারেটিং পরিবেশকে প্রায় একইভাবে সেট করে (কিছু alচ্ছিক অতিরিক্ত দিয়ে)। এবং অন্য যে কোনও প্রোগ্রাম যা একটি প্রোগ্রাম চালু করে সেই প্রোগ্রামটির জন্য একই পরিবেশ (আরজিভি, পরিবেশের স্ট্রিং ইত্যাদি) তৈরি করা আশা করা হয় যেন এটি কোনও শেল থেকে চালিত হয়েছিল, কিছু alচ্ছিক অতিরিক্ত রয়েছে with কোনও প্রোগ্রাম বা ব্যবহারকারী এমন পরিবেশ স্থাপন করতে পারে যা এটি চালু করা অন্যান্য অধস্তন প্রোগ্রামগুলির জন্য এই সম্মেলন থেকে বিচ্যুত হয় তবে যদি এটি হয় তবে এটি একটি বাগ এবং প্রোগ্রামটির অধীনস্থ প্রোগ্রাম বা এর অধীনস্থরা সঠিকভাবে কাজ করবে এমন কোনও যুক্তিসঙ্গত প্রত্যাশা নেই।
এর সম্ভাব্য মানগুলি argv[0]
অন্তর্ভুক্ত:
/path/to/executable
- পরম পাথ
../bin/executable
- পিডাব্লুডির সাথে সম্পর্কিত
bin/executable
- পিডাব্লুডির সাথে সম্পর্কিত
./foo
- পিডাব্লুডির সাথে সম্পর্কিত
executable
- বেসনাম, পথে সন্ধান করুন
bin//executable
- পিডাব্লুডির সাথে সম্পর্কিত, নন-ক্যানোনিকাল
src/../bin/executable
- পিডাব্লুডির সাথে সম্পর্কিত, নন-ক্যানোনিকাল, ব্যাকট্র্যাকিং
bin/./echoargc
- পিডাব্লুডির সাথে সম্পর্কিত, নন-ক্যানোনিকাল
মানগুলি যা আপনার দেখা উচিত নয়:
~/bin/executable
- আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন।
~user/bin/executable
- আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন
alias
- আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন
$shellvariable
- আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন
*foo*
- ওয়াইল্ডকার্ড, আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন, খুব কার্যকর নয়
?foo?
- ওয়াইল্ডকার্ড, আপনার প্রোগ্রামটি চলার আগে আবারও লিখেছেন, খুব কার্যকর নয়
এছাড়াও, এগুলিতে অ-ক্যানোনিকাল পাথের নাম এবং প্রতীকী লিঙ্কগুলির একাধিক স্তর থাকতে পারে। কিছু ক্ষেত্রে একই প্রোগ্রামে একাধিক হার্ড লিঙ্ক থাকতে পারে। উদাহরণস্বরূপ, /bin/ls
, /bin/ps
, /bin/chmod
, /bin/rm
, ইত্যাদি কঠিন লিঙ্ক হতে পারে /bin/busybox
।
নিজেকে খুঁজে পেতে নীচের পদক্ষেপগুলি অনুসরণ করুন:
আপনার প্রোগ্রামে প্রবেশের সময় pwd, PATH, এবং argv [0] সংরক্ষণ করুন (বা আপনার গ্রন্থাগারের সূচনা) কারণ তারা পরে পরিবর্তন করতে পারে।
Alচ্ছিক: বিশেষত অ-ইউনিক্স সিস্টেমের জন্য আলাদা করুন তবে উপস্থিত থাকলে পথের নাম হোস্ট / ব্যবহারকারী / ড্রাইভ উপসর্গ অংশটি বাতিল করবেন না; যে অংশটি প্রায়শই কোলনের আগে বা প্রাথমিক "//" অনুসরণ করে।
যদি argv[0]
কোনও পরম পথ হয় তবে এটি একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করুন। একটি নিখুঁত পাথ সম্ভবত "/" দিয়ে শুরু হয় তবে কিছু অ-ইউনিক্স সিস্টেমে এটি "\" বা একটি ড্রাইভ চিঠি বা নাম উপসর্গের পরে শুরু হয় কোলন।
অন্যথায় যদি argv[0]
আপেক্ষিক পথ হয় ("/" বা "\" থাকে তবে এটি দিয়ে শুরু হয় না, যেমন "../../bin/foo", তারপরে pwd + "/" + argv [0] একত্রিত করুন (ব্যবহার করুন যখন প্রোগ্রাম শুরু হয়েছে তখন থেকে বর্তমানের ডিরেক্টরি পরিচালনা করুন, বর্তমান নয়)।
অন্যথায় যদি আরগভি [0] একটি সরল বেসনাম হয় (কোনও স্ল্যাশ নেই), তবে এটি প্রতিটি PATH এনভায়রনমেন্ট ভেরিয়েবলের প্রতিটি এন্ট্রির সাথে একত্রিত করুন এবং সেগুলি চেষ্টা করুন এবং সফল হওয়া প্রথমটি ব্যবহার করুন।
Alচ্ছিক: অন্যটি খুব প্ল্যাটফর্ম নির্দিষ্ট /proc/self/exe
, /proc/curproc/file
(BSD) (char *)getauxval(AT_EXECFN)
, এবং dlgetname(...)
যদি উপস্থিত থাকে তবে চেষ্টা করুন। এমনকি এগুলি আগে argv[0]
ভিত্তিক পদ্ধতিগুলি ব্যবহার করে দেখতে পারেন, যদি সেগুলি উপলব্ধ থাকে এবং আপনার যদি অনুমতি সংক্রান্ত সমস্যার মুখোমুখি না হয়। কিছুটা অপ্রত্যাশিত ইভেন্টে (যখন আপনি সমস্ত সিস্টেমের সমস্ত সংস্করণ বিবেচনা করেন) যেগুলি উপস্থিত থাকে এবং ব্যর্থ হয় না, তারা আরও প্রামাণিক হতে পারে।
.চ্ছিক: কমান্ড লাইন প্যারামিটার ব্যবহার করে পাস করা পথের জন্য পরীক্ষা করুন।
.চ্ছিক: আপনার মোড়ক স্ক্রিপ্ট দ্বারা পরিবেশগতভাবে কোনও পথের নাম স্পষ্টভাবে দেওয়া হয়েছে কিনা তা পরীক্ষা করুন।
Alচ্ছিক: একটি সর্বশেষ অবলম্বন হিসাবে পরিবেশের পরিবর্তনশীল "_" চেষ্টা করুন। এটি সম্পূর্ণ আলাদা আলাদা প্রোগ্রামের দিকে ইঙ্গিত করতে পারে যেমন ব্যবহারকারীদের শেল।
সিমলিংকগুলি সমাধান করুন, একাধিক স্তর থাকতে পারে। অসীম লুপ হওয়ার সম্ভাবনা রয়েছে, যদিও সেগুলি উপস্থিত থাকলে সম্ভবত আপনার প্রোগ্রামটি ডাকা হবে না।
"/Foo/../bar/" "" / বার / "এর মতো সাবস্ট্রিংগুলি সমাধান করে ফাইলের নামটি ক্যানোনিকালাইজ করুন। মনে রাখবেন আপনি যদি কোনও নেটওয়ার্ক মাউন্ট পয়েন্ট অতিক্রম করেন তবে এটি সম্ভাব্যভাবে অর্থ পরিবর্তন করতে পারে, তাই ক্যানোনাইজেশন সবসময় ভাল জিনিস হয় না। একটি নেটওয়ার্ক সার্ভারে, ".." সিমলিংকটি ক্লায়েন্টের পরিবর্তে সার্ভারের প্রসঙ্গে অন্য কোনও ফাইলের পথে যেতে পারে। এই ক্ষেত্রে, আপনি সম্ভবত ক্লায়েন্টের প্রসঙ্গটি চান তাই ক্যানোনিকালাইজেশন ঠিক আছে। এছাড়াও "/./" "/" তে "/" এবং "//" তে "/" তে রূপান্তর করুন। শেল ইন, readlink --canonicalize
একাধিক প্রতিলিঙ্ক সমাধান করবে এবং নাম ক্যানোনিকালাইজ। চেজ একই কাজ করতে পারে তবে ইনস্টল করা হয়নি। realpath()
বা canonicalize_file_name()
উপস্থিত থাকলে সহায়তা করতে পারে।
যদি realpath()
কম্পাইল সময়ে বিদ্যমান নয়, আপনি একটি permissively লাইসেন্সকৃত গ্রন্থাগার বন্টন থেকে একটি কপি ধার, এবং নিজের বরং চাকা reinventing তুলনায় এটি কম্পাইল পারে। আপনি যদি PATH_MAX এর চেয়ে কম বাফার ব্যবহার করছেন তবে সম্ভাব্য বাফার ওভারফ্লো (আকারের আউটপুট বাফারে পাস করুন, স্ট্রান্সকিপি () বনাম স্ট্রিপিপি () মনে করুন। নামমাত্র বেসরকারী অনুলিপিটি উপস্থিত থাকলে তা পরীক্ষা না করে ব্যবহার করা সহজ হতে পারে। অ্যান্ড্রয়েড / ডারউইন / বিএসডি থেকে অনুমতিপ্রাপ্ত লাইসেন্সের অনুলিপি:
https://android.googlesource.com/platfor/bionic/+/f077784/libc/upstream-freebsd/lib/libc/stdlib/relpath.c
সচেতন থাকুন যে একাধিক প্রচেষ্টা সফল বা আংশিকভাবে সফল হতে পারে এবং তারা সকলে একই নির্বাহী হিসাবে নির্দেশ করতে পারে না, তাই আপনার নির্বাহযোগ্যকে যাচাই করার বিষয়টি বিবেচনা করুন; তবে আপনার পড়ার অনুমতি নাও থাকতে পারে - আপনি যদি এটি পড়তে না পারেন তবে এটিকে ব্যর্থতা হিসাবে গণ্য করবেন না। বা আপনার নির্বাহযোগ্য যেমন "../lib/" ডিরেক্টরি হিসাবে আপনি সন্ধানের চেষ্টা করছেন তার কাছাকাছি কিছু যাচাই করুন। আপনার একাধিক সংস্করণ, প্যাকেজড এবং স্থানীয়ভাবে সংকলিত সংস্করণগুলি, স্থানীয় এবং নেটওয়ার্ক সংস্করণগুলি এবং স্থানীয় এবং ইউএসবি-ড্রাইভের পোর্টেবল সংস্করণ ইত্যাদি থাকতে পারে এবং আপনার স্থানীয় অবস্থানের বিভিন্ন পদ্ধতি থেকে দুটি অসম্পূর্ণ ফলাফল পেতে পারে এমন একটি ছোট্ট সম্ভাবনা রয়েছে। এবং "_" সহজেই ভুল প্রোগ্রামটির দিকে ইঙ্গিত করতে পারে।
একটি প্রোগ্রাম ব্যবহার করে execve
ইচ্ছাকৃতভাবে argv[0]
প্রোগ্রামটি লোড করতে ব্যবহৃত প্রকৃত পাথের সাথে বেমানান হয়ে যেতে পারে এবং PATH, "_", pwd, ইত্যাদির ক্ষতি করতে পারে যদিও এর বেশি কারণ নেই; তবে এটির নিরাপত্তাজনিত প্রভাব থাকতে পারে যদি আপনার যদি ঝুঁকিপূর্ণ কোড থাকে যা আপনার মৃত্যুদন্ড পরিবেশকে বিভিন্নভাবে পরিবর্তিত করা যেতে পারে তবে এই সীমাবদ্ধ নয়, এটিকে (ক্রোট, ফিউজ ফাইল সিস্টেম, হার্ড লিঙ্কস ইত্যাদি) সম্ভব হয় It শেল কমান্ডগুলির জন্য PATH সেট করার জন্য তবে এটি রফতানি করতে ব্যর্থ।
অ-ইউনিক্স সিস্টেমগুলির জন্য আপনার অগত্যা কোডিং করার দরকার নেই তবে কিছু বিশেষত্ব সম্পর্কে অবগত হওয়া ভাল ধারণা হবে যাতে আপনি কোডটি এমনভাবে লিখতে পারেন যে কারওর পরে পোর্ট করা এত কঠিন নয় isn't । সচেতন থাকুন যে কয়েকটি সিস্টেমে (ডিসি ভিএমএস, ডস, ইউআরএল, ইত্যাদি) ড্রাইভের নাম বা অন্যান্য উপসর্গ থাকতে পারে যা "সি: \", "সিএস $ ড্রাইভ: [foo] বার", এবং "ফাইলের মতো কোলন দিয়ে শেষ হয়" : /// foo বিন্যাস / বার / বায "। পুরাতন ডিইসি ভিএমএস সিস্টেমগুলি "[" এবং "]" ব্যবহার করে পাথের ডিরেক্টরি অংশটি বন্ধ করে দেয় যদিও আপনার প্রোগ্রামটি পসিক্স পরিবেশে সংকলিত থাকলে এটির পরিবর্তন হতে পারে। কিছু সিস্টেম, যেমন ভিএমএসের একটি ফাইল সংস্করণ থাকতে পারে (শেষে একটি সেমিকোলন দ্বারা পৃথক)। কিছু সিস্টেমে "// ড্রাইভ / পাথ / টু / ফাইল" বা "ব্যবহারকারী @ হোস্ট: / পাথ / টু / ফাইল" (scp কমান্ড) বা "ফাইল:" হিসাবে টানা দুটি স্ল্যাশ ব্যবহার করে: (স্পেস দিয়ে সীমাবদ্ধ) এবং "পাঠ" কোলন দিয়ে সীমাবদ্ধ তবে আপনার প্রোগ্রামটি PATH গ্রহণ করা উচিত যাতে আপনাকে পথের বিষয়ে চিন্তা করার দরকার নেই। ডস এবং অন্যান্য কিছু সিস্টেমে আপেক্ষিক পাথ থাকতে পারে যা ড্রাইভ উপসর্গ দিয়ে শুরু হয়। সি: foo.exe ড্রাইভ সিতে বর্তমান ডিরেক্টরিতে foo.exe বোঝায়, সুতরাং আপনার সিটিতে বর্তমান ডিরেক্টরিটি অনুসন্ধান করতে হবে: এবং এটি পিডব্লুডির জন্য ব্যবহার করুন। (স্পেস দিয়ে সীমাবদ্ধ) এবং "পাঠ" কোলন দিয়ে সীমাবদ্ধ তবে আপনার প্রোগ্রামটি PATH গ্রহণ করা উচিত যাতে আপনাকে পথের বিষয়ে চিন্তা করার দরকার নেই। ডস এবং অন্যান্য কিছু সিস্টেমে আপেক্ষিক পাথ থাকতে পারে যা ড্রাইভ উপসর্গ দিয়ে শুরু হয়। সি: foo.exe ড্রাইভ সিতে বর্তমান ডিরেক্টরিতে foo.exe বোঝায়, সুতরাং আপনার সিটিতে বর্তমান ডিরেক্টরিটি অনুসন্ধান করতে হবে: এবং এটি পিডব্লুডির জন্য ব্যবহার করুন।
আমার সিস্টেমে সিমলিংক এবং মোড়কের উদাহরণ:
/usr/bin/google-chrome is symlink to
/etc/alternatives/google-chrome which is symlink to
/usr/bin/google-chrome-stable which is symlink to
/opt/google/chrome/google-chrome which is a bash script which runs
/opt/google/chome/chrome
নোট করুন যে ব্যবহারকারী বিলে এইচপিতে একটি প্রোগ্রামের উপরে একটি লিঙ্ক পোস্ট করেছে যা এর তিনটি বেসিক কেস পরিচালনা করে argv[0]
। এটির জন্য কিছু পরিবর্তন দরকার, যদিও:
- এটি সমস্ত পুনর্লিখন
strcat()
এবং strcpy()
ব্যবহার strncat()
এবং ব্যবহার করা প্রয়োজন strncpy()
। যদিও ভেরিয়েবলগুলি PATHMAX দৈর্ঘ্যের হিসাবে ঘোষিত করা হয়েছে, PATHMAX-1 এর দৈর্ঘ্যের একটি ইনপুট মান> PATHMAX এবং PATHMAX দৈর্ঘ্যের একটি ইনপুট মান নির্বিঘ্নিত হবে।
- এটি কেবল ফল ছাপানোর পরিবর্তে একটি লাইব্রেরি ফাংশন হিসাবে আবার লিখতে হবে।
- এটি নামগুলি ক্যানোনিকালাইজ করতে ব্যর্থ হয়েছে (উপরে উল্লিখিত রিয়েলপথ কোডটি ব্যবহার করুন)
- এটি প্রতীকী লিঙ্কগুলি সমাধান করতে ব্যর্থ হয়েছে (রিয়েলপথ কোডটি ব্যবহার করুন)
সুতরাং, যদি আপনি এইচপি কোড এবং রিয়েলপথ কোড উভয়কে একত্রিত করেন এবং উভয়কে বাফার ওভারফ্লো প্রতিরোধী হিসাবে সংশোধন করেন তবে আপনার এমন কিছু হওয়া উচিত যা সঠিকভাবে ব্যাখ্যা করতে পারে argv[0]
।
নীচে argv[0]
উবুন্টু 12.04 এ একই প্রোগ্রামটি চালনার বিভিন্ন উপায়ে বাস্তবের মানগুলি চিত্রিত করে। এবং হ্যাঁ, প্রোগ্রামটি দুর্ঘটনাক্রমে ইকোআরজিভির পরিবর্তে ইকোআরজিসি নামকরণ করা হয়েছিল। এটি পরিষ্কার অনুলিপি করার জন্য একটি স্ক্রিপ্ট ব্যবহার করে করা হয়েছিল তবে শেলটিতে এটি ম্যানুয়ালি করলে একই ফলাফল পাওয়া যায় (আপনি যদি এগুলি স্পষ্টভাবে সক্ষম না করেন তবে এলিয়াসগুলি স্ক্রিপ্টে কাজ করবে না)।
cat ~/src/echoargc.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
main(int argc, char **argv)
{
printf(" argv[0]=\"%s\"\n", argv[0]);
sleep(1); /* in case run from desktop */
}
tcc -o ~/bin/echoargc ~/src/echoargc.c
cd ~
/home/whitis/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
echoargc
argv[0]="echoargc"
bin/echoargc
argv[0]="bin/echoargc"
bin//echoargc
argv[0]="bin//echoargc"
bin/./echoargc
argv[0]="bin/./echoargc"
src/../bin/echoargc
argv[0]="src/../bin/echoargc"
cd ~/bin
*echo*
argv[0]="echoargc"
e?hoargc
argv[0]="echoargc"
./echoargc
argv[0]="./echoargc"
cd ~/src
../bin/echoargc
argv[0]="../bin/echoargc"
cd ~/junk
~/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
~whitis/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
alias echoit=~/bin/echoargc
echoit
argv[0]="/home/whitis/bin/echoargc"
echoarg=~/bin/echoargc
$echoarg
argv[0]="/home/whitis/bin/echoargc"
ln -s ~/bin/echoargc junk1
./junk1
argv[0]="./junk1"
ln -s /home/whitis/bin/echoargc junk2
./junk2
argv[0]="./junk2"
ln -s junk1 junk3
./junk3
argv[0]="./junk3"
gnome-desktop-item-edit --create-new ~/Desktop
# interactive, create desktop link, then click on it
argv[0]="/home/whitis/bin/echoargc"
# interactive, right click on gnome application menu, pick edit menus
# add menu item for echoargc, then run it from gnome menu
argv[0]="/home/whitis/bin/echoargc"
cat ./testargcscript 2>&1 | sed -e 's/^/ /g'
#!/bin/bash
# echoargc is in ~/bin/echoargc
# bin is in path
shopt -s expand_aliases
set -v
cat ~/src/echoargc.c
tcc -o ~/bin/echoargc ~/src/echoargc.c
cd ~
/home/whitis/bin/echoargc
echoargc
bin/echoargc
bin//echoargc
bin/./echoargc
src/../bin/echoargc
cd ~/bin
*echo*
e?hoargc
./echoargc
cd ~/src
../bin/echoargc
cd ~/junk
~/bin/echoargc
~whitis/bin/echoargc
alias echoit=~/bin/echoargc
echoit
echoarg=~/bin/echoargc
$echoarg
ln -s ~/bin/echoargc junk1
./junk1
ln -s /home/whitis/bin/echoargc junk2
./junk2
ln -s junk1 junk3
./junk3
এই উদাহরণগুলি ব্যাখ্যা করে যে এই পোস্টে বর্ণিত কৌশলগুলি বিভিন্ন পরিস্থিতিতে কাজ করা উচিত এবং কেন কয়েকটি পদক্ষেপ প্রয়োজনীয়।
সম্পাদনা: এখন, প্রোগ্রামটি যেটি আরগভি [0] প্রিন্ট করে তা আসলে নিজেকে আবিষ্কার করার জন্য আপডেট করা হয়েছে।
// Copyright 2015 by Mark Whitis. License=MIT style
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
// "look deep into yourself, Clarice" -- Hanibal Lector
char findyourself_save_pwd[PATH_MAX];
char findyourself_save_argv0[PATH_MAX];
char findyourself_save_path[PATH_MAX];
char findyourself_path_separator='/';
char findyourself_path_separator_as_string[2]="/";
char findyourself_path_list_separator[8]=":"; // could be ":; "
char findyourself_debug=0;
int findyourself_initialized=0;
void findyourself_init(char *argv0)
{
getcwd(findyourself_save_pwd, sizeof(findyourself_save_pwd));
strncpy(findyourself_save_argv0, argv0, sizeof(findyourself_save_argv0));
findyourself_save_argv0[sizeof(findyourself_save_argv0)-1]=0;
strncpy(findyourself_save_path, getenv("PATH"), sizeof(findyourself_save_path));
findyourself_save_path[sizeof(findyourself_save_path)-1]=0;
findyourself_initialized=1;
}
int find_yourself(char *result, size_t size_of_result)
{
char newpath[PATH_MAX+256];
char newpath2[PATH_MAX+256];
assert(findyourself_initialized);
result[0]=0;
if(findyourself_save_argv0[0]==findyourself_path_separator) {
if(findyourself_debug) printf(" absolute path\n");
realpath(findyourself_save_argv0, newpath);
if(findyourself_debug) printf(" newpath=\"%s\"\n", newpath);
if(!access(newpath, F_OK)) {
strncpy(result, newpath, size_of_result);
result[size_of_result-1]=0;
return(0);
} else {
perror("access failed 1");
}
} else if( strchr(findyourself_save_argv0, findyourself_path_separator )) {
if(findyourself_debug) printf(" relative path to pwd\n");
strncpy(newpath2, findyourself_save_pwd, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
strncat(newpath2, findyourself_path_separator_as_string, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
strncat(newpath2, findyourself_save_argv0, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
realpath(newpath2, newpath);
if(findyourself_debug) printf(" newpath=\"%s\"\n", newpath);
if(!access(newpath, F_OK)) {
strncpy(result, newpath, size_of_result);
result[size_of_result-1]=0;
return(0);
} else {
perror("access failed 2");
}
} else {
if(findyourself_debug) printf(" searching $PATH\n");
char *saveptr;
char *pathitem;
for(pathitem=strtok_r(findyourself_save_path, findyourself_path_list_separator, &saveptr); pathitem; pathitem=strtok_r(NULL, findyourself_path_list_separator, &saveptr) ) {
if(findyourself_debug>=2) printf("pathitem=\"%s\"\n", pathitem);
strncpy(newpath2, pathitem, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
strncat(newpath2, findyourself_path_separator_as_string, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
strncat(newpath2, findyourself_save_argv0, sizeof(newpath2));
newpath2[sizeof(newpath2)-1]=0;
realpath(newpath2, newpath);
if(findyourself_debug) printf(" newpath=\"%s\"\n", newpath);
if(!access(newpath, F_OK)) {
strncpy(result, newpath, size_of_result);
result[size_of_result-1]=0;
return(0);
}
} // end for
perror("access failed 3");
} // end else
// if we get here, we have tried all three methods on argv[0] and still haven't succeeded. Include fallback methods here.
return(1);
}
main(int argc, char **argv)
{
findyourself_init(argv[0]);
char newpath[PATH_MAX];
printf(" argv[0]=\"%s\"\n", argv[0]);
realpath(argv[0], newpath);
if(strcmp(argv[0],newpath)) { printf(" realpath=\"%s\"\n", newpath); }
find_yourself(newpath, sizeof(newpath));
if(1 || strcmp(argv[0],newpath)) { printf(" findyourself=\"%s\"\n", newpath); }
sleep(1); /* in case run from desktop */
}
এবং এখানে আউটপুট যা দেখায় যে পূর্ববর্তী প্রতিটি পরীক্ষায় এটি আসলে খুঁজে পেয়েছিল।
tcc -o ~/bin/echoargc ~/src/echoargc.c
cd ~
/home/whitis/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
echoargc
argv[0]="echoargc"
realpath="/home/whitis/echoargc"
findyourself="/home/whitis/bin/echoargc"
bin/echoargc
argv[0]="bin/echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
bin//echoargc
argv[0]="bin//echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
bin/./echoargc
argv[0]="bin/./echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
src/../bin/echoargc
argv[0]="src/../bin/echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
cd ~/bin
*echo*
argv[0]="echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
e?hoargc
argv[0]="echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
./echoargc
argv[0]="./echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
cd ~/src
../bin/echoargc
argv[0]="../bin/echoargc"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
cd ~/junk
~/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
~whitis/bin/echoargc
argv[0]="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
alias echoit=~/bin/echoargc
echoit
argv[0]="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
echoarg=~/bin/echoargc
$echoarg
argv[0]="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
rm junk1 junk2 junk3
ln -s ~/bin/echoargc junk1
./junk1
argv[0]="./junk1"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
ln -s /home/whitis/bin/echoargc junk2
./junk2
argv[0]="./junk2"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
ln -s junk1 junk3
./junk3
argv[0]="./junk3"
realpath="/home/whitis/bin/echoargc"
findyourself="/home/whitis/bin/echoargc"
উপরে বর্ণিত দুটি জিইউআই লঞ্চগুলিও সঠিকভাবে প্রোগ্রামটি আবিষ্কার করে।
একটি সম্ভাব্য ক্ষতি আছে। access()
ফাংশন অনুমতি ড্রপ যদি প্রোগ্রাম পরীক্ষামূলক আগে setuid করা হয়। যদি এমন কোনও পরিস্থিতি হয় যেখানে প্রোগ্রামটি একজন এলিভেটেড ব্যবহারকারী হিসাবে পাওয়া যায় তবে নিয়মিত ব্যবহারকারী হিসাবে দেখা যায় না, তবে এমন পরিস্থিতি থাকতে পারে যেখানে এই পরীক্ষাগুলি ব্যর্থ হবে, যদিও এই পরিস্থিতিতে এই প্রোগ্রামটি বাস্তবায়িত হওয়ার সম্ভাবনা কম। এর পরিবর্তে কেউ euidaccess () ব্যবহার করতে পারে। তবে এটি সম্ভব, এটি প্রকৃত ব্যবহারকারীর চেয়ে আগে কোনও অ্যাক্সেসযোগ্য প্রোগ্রাম খুঁজে পেতে পারে।