/ প্রোকে / স্ব / এক্সাই ছাড়াই চলমান নির্বাহী পথের সন্ধান করা


190

আমার কাছে মনে হয় লিনাক্সের / proc / self / exe দিয়ে এটি সহজ easy তবে আমি জানতে চাই যে ক্রস-প্ল্যাটফর্ম ইন্টারফেস সহ সি / সি ++ তে বর্তমান অ্যাপ্লিকেশনটির ডিরেক্টরি খুঁজে পাওয়ার কোনও সুবিধাজনক উপায় আছে কিনা। আমি কিছু প্রকল্প দেখেছি আরগভ [0] এর সাথে ঘুরে বেড়াচ্ছি, তবে এটি সম্পূর্ণ নির্ভরযোগ্য বলে মনে হয় না।

আপনার যদি কখনও সমর্থন করতে হয়, বলুন, ম্যাক ওএস এক্স, যা / প্রো / / নেই, আপনি কি করতেন? প্ল্যাটফর্ম-নির্দিষ্ট কোডটি বিচ্ছিন্ন করতে #ifdefs ব্যবহার করবেন (উদাহরণস্বরূপ, এনএসবান্ডেল)? অথবা আরজিভি [0], AT পাথ এবং কী নয়, প্রান্তের ক্ষেত্রে ত্রুটিগুলি খুঁজে পাওয়ার ঝুঁকি নিয়ে এক্সিকিউটেবলের পথটি কেটে নেওয়ার চেষ্টা করবেন?



আমি গুগল করলাম: আমার ps -o comm। আমাকে এখানে কী নিয়ে এসেছিল তা হ'ল: "/ প্রপোক / পিডি /পাথ / এ.আউট"
বেসিন

আইএমএইচও গর্বিতের উত্তর শীর্ষে থাকা উপযুক্ত, কারণ এটি "ক্রস-প্ল্যাটফর্ম ইন্টারফেস" প্রয়োজনীয়তার সঠিকভাবে সম্বোধন করে এবং সংহত করা খুব সহজ।
স্টাফেন গৌরিচন

উত্তর:


348

কিছু ওএস-নির্দিষ্ট ইন্টারফেস:

বহনযোগ্য (তবে কম নির্ভরযোগ্য) পদ্ধতিটি ব্যবহার করা হয় argv[0]। যদিও এটি কলিং প্রোগ্রামের মাধ্যমে কোনও কিছুর কাছে সেট করা যেতে পারে, তবে কনভেনশন দ্বারা এটি কার্যকর হয় এমন একটি পথের নাম বা ব্যবহার করে পাওয়া যায় এমন একটি নামকে সেট করে $PATH

বাশ ও কেএস সহ কয়েকটি শেল পরিবেশের পরিবর্তনশীলকে_ কার্যকর করার পূর্বে নির্বাহের সম্পূর্ণ পথে " " সেট করে । সেক্ষেত্রে আপনি getenv("_")এটি পেতে ব্যবহার করতে পারেন । তবে এটি বিশ্বাসযোগ্য নয় কারণ সমস্ত শেল এটি করে না এবং এটি কোনও কিছুতে সেট করা যেতে পারে বা কোনও পিতামাতার প্রক্রিয়া থেকে ছেড়ে দেওয়া যেতে পারে যা আপনার প্রোগ্রামটি কার্যকর করার আগে এটি পরিবর্তন করে না।


3
এবং আরও মনে রাখবেন যে _NSGetExecutablePath () সিমলিংকগুলি অনুসরণ করে না।
অনুমান করুন

1
নেটবিএসডি: রিডলিংক / প্রোক / কার্পোক / এক্সি ড্রাগন ফ্লাই বিএসডি: রিডলিংক / প্রোক / কারপ্রোক / ফাইল

6
সোলারিস: char exepath[MAXPATHLEN]; sprintf(exepath, "/proc/%d/path/a.out", getpid()); readlink(exepath, exepath, sizeof(exepath));; এটি এর থেকে পৃথক getexecname()- যা সমান pargs -x <PID> | grep AT_SUN_EXECNAME...
ফ্র্যাঙ্কএইচ does

4
"কিউডেস্কটপ সার্ভিসেস :: স্টোরেজলোকেশন (কিউডেস্কটপ সার্ভিস :: ডেটা লোকেশন)" এটি এক্সিকিউটেবলের পথ নয়, এটি প্রতি ব্যবহারকারী ডিরেক্টরিতে পথের নাম যেখানে ডেটা সংরক্ষণ করা উচিত।

2
ওপেনবিএসডি হ'ল একমাত্র যেখানে আপনি এখনও 2017 সালে পারবেন না You আপনাকে PATH এবং আরজিভি [0]
লথার

27

এর ব্যবহার /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 () ব্যবহার করতে পারে। তবে এটি সম্ভব, এটি প্রকৃত ব্যবহারকারীর চেয়ে আগে কোনও অ্যাক্সেসযোগ্য প্রোগ্রাম খুঁজে পেতে পারে।


1
আপনি এতে প্রচুর পরিশ্রম করেছেন - ভাল করেছেন। দুর্ভাগ্যক্রমে, কোনওটিই strncpy()(বিশেষত) strncat()কোডটিতে নিরাপদে ব্যবহার করা হয়নি। strncpy()নাল সমাপ্তির গ্যারান্টি দেয় না; যদি উত্সের স্ট্রিংটি লক্ষ্য জায়গার চেয়ে দীর্ঘ হয় তবে স্ট্রিংটি বাতিল হয় না। strncat()ব্যবহার করা খুব কঠিন; যদি লক্ষ্যটির চেয়ে দীর্ঘ হয় তবে strncat(target, source, sizeof(target))এটি ভুল ( targetশুরু করার জন্য খালি স্ট্রিং হলেও ) sourceis দৈর্ঘ্যটি হ'ল অক্ষরের সংখ্যা যা নিরাপদে লক্ষ্যবস্তুতে পেছনের শূন্যটি বাদ দিয়ে যুক্ত করা যায়, তাই sizeof(target)-1সর্বোচ্চ।
জোনাথন লেফলার

4
আপনার নির্দেশিত পদ্ধতিটি আমার ব্যবহার করা উচিত নয় তার বিপরীতে আরআরএনপিপি কোডটি সঠিক। আমি আপনাকে কোডটি আরও মনোযোগ সহকারে পড়ার পরামর্শ দিচ্ছি। এটি বাফারগুলিকে উপচে ফেলে না বা নির্বিঘ্নে ছেড়ে দেয়। স্ট্রান্সপি () / স্টেনক্যাট () এর প্রতিটি ব্যবহার সাইজেরফ (বাফার) অনুলিপি করে সীমাবদ্ধ, যা বৈধ, এবং তারপরে বাফারের শেষ অক্ষরটি বাফরের শেষ অক্ষরকে শূন্যের ওভাররাইট করে পূরণ করা হয়। স্ট্রিংক্যাট () তবে আকার হিসাবে প্যারামিটারকে একটি গণনা হিসাবে ভুলভাবে ব্যবহার করে এবং এটি বাফার ওভারফ্লো আক্রমণগুলির পূর্বেকার হওয়ার কারণে প্রবাহিত হতে পারে।
হোয়াইটিস

"sudo apt-get install libbsd0 libbsd-dev", তারপরে এস / স্ট্রিংক্যাট / স্ট্রলক্যাট /
হোয়াইটিস ২itis

1
PATH_MAX ব্যবহার করবেন না। এটি 30 বছর আগে কাজ করা বন্ধ করে দিয়েছিল, সর্বদা malloc ব্যবহার করুন।
লোথার

এছাড়াও আপনি যদি কোনও কল কল ব্যবহার করেন। কেবলমাত্র একটি অংশ নয়, কেবল এক্সের দিকে যাত্রাপথটি পুরোপুরি সমাধান করুন এবং তারপরে কল করুন। আপনি যদি সমাধানে রিয়েলপথ ব্যবহার করেন তবে এখানে কোনও অলস মূল্যায়ন সম্ভব নয় possible অন্যান্য এরারগুলির সাথে একত্রে সবচেয়ে দীর্ঘতম কোড যা আমি দীর্ঘ উত্তরে স্ট্যাকওভারফ্লোতে দেখেছি।
লোথার

13

পরীক্ষা করে দেখুন whereami গ্রেগরি Pakosz (যা কেবলমাত্র একটি সি ফাইল আছে) লাইব্রেরি থেকে; এটি আপনাকে বিভিন্ন প্ল্যাটফর্মগুলিতে বর্তমান এক্সিকিউটেবলের পুরো পথটি পেতে দেয়। বর্তমানে, এটি গিথুবের রেপো হিসাবে এখানে উপলব্ধ


8

ELF দোভাষী দ্বারা পাস করা তথ্য ব্যবহার করে /proc/self/exeবা ব্যবহার করা লিনাক্সের একটি বিকল্প, argv[0]যেমন গ্লিবসি দ্বারা উপলব্ধ করা হয়েছে:

#include <stdio.h>
#include <sys/auxv.h>

int main(int argc, char **argv)
{
    printf("%s\n", (char *)getauxval(AT_EXECFN));
    return(0);
}

দ্রষ্টব্য এটি getauxvalএকটি গ্লাবসি এক্সটেনশন, এবং দৃ be় হতে আপনার পরীক্ষা করা উচিত যাতে এটি ফিরে না আসে NULL(ইএলএফ ইন্টারপ্রেটার AT_EXECFNপ্যারামিটারটি সরবরাহ করে না তা বোঝায় ) তবে লিনাক্সে আসলে এটি কখনও সমস্যা বলে আমি মনে করি না।


আমি এটি পছন্দ করি কারণ এটি সহজ এবং গ্লিবসিটি যাইহোক Gtk + এর সাথে অন্তর্ভুক্ত করা হয়েছে (যা আমি ব্যবহার করছি)।
কলিন কেইনান

4

আপনার যদি কখনও সমর্থন করতে হয়, বলুন, ম্যাক ওএস এক্স, যা / প্রো / / নেই, আপনি কি করতেন? প্ল্যাটফর্ম-নির্দিষ্ট কোডটি বিচ্ছিন্ন করতে #ifdefs ব্যবহার করবেন (উদাহরণস্বরূপ, এনএসবান্ডেল)?

হ্যাঁ প্ল্যাটফর্মের নির্দিষ্ট কোডটি বিচ্ছিন্ন #ifdefsকরা এটি প্রচলিত পদ্ধতি।

আরেকটি পদ্ধতির মধ্যে পরিষ্কার- #ifdefবিহীন শিরোনাম রয়েছে যাতে ফাংশন সংক্রান্ত ঘোষণা রয়েছে এবং প্রয়োগগুলি প্ল্যাটফর্মের নির্দিষ্ট উত্স ফাইলগুলিতে রাখে। উদাহরণস্বরূপ, পোকো সি ++ গ্রন্থাগার কীভাবে তাদের পরিবেশ বর্গের জন্য একই রকম কিছু করে তা দেখুন ।


4

প্ল্যাটফর্ম জুড়ে নির্ভরযোগ্যভাবে এই কাজটি করার জন্য # আইফডিএফ স্টেটমেন্ট ব্যবহার করা দরকার।

নীচের কোডটি উইন্ডোজ, লিনাক্স, ম্যাকস, সোলারিস বা ফ্রিবিএসডি (যদিও ফ্রিবিএসডি অচিহ্নিত) the কোডটি সহজ করার জন্য এটি বুস্ট > = 1.55.0 ব্যবহার করে তবে আপনি চাইলে এটি সরানো যথেষ্ট সহজ easy ওএস এবং সংকলকটি প্রয়োজনীয় হিসাবে কেবল _MSC_VER এবং __linux এর মতো সংজ্ঞা ব্যবহার করুন।

#include <string>
#include <boost/predef/os.h>

#if (BOOST_OS_WINDOWS)
#  include <stdlib.h>
#elif (BOOST_OS_SOLARIS)
#  include <stdlib.h>
#  include <limits.h>
#elif (BOOST_OS_LINUX)
#  include <unistd.h>
#  include <limits.h>
#elif (BOOST_OS_MACOS)
#  include <mach-o/dyld.h>
#elif (BOOST_OS_BSD_FREE)
#  include <sys/types.h>
#  include <sys/sysctl.h>
#endif

/*
 * Returns the full path to the currently running executable,
 * or an empty string in case of failure.
 */
std::string getExecutablePath() {
#if (BOOST_OS_WINDOWS)
    char *exePath;
    if (_get_pgmptr(&exePath) != 0)
        exePath = "";
#elif (BOOST_OS_SOLARIS)
    char exePath[PATH_MAX];
    if (realpath(getexecname(), exePath) == NULL)
        exePath[0] = '\0';
#elif (BOOST_OS_LINUX)
    char exePath[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", exePath, sizeof(exePath));
    if (len == -1 || len == sizeof(exePath))
        len = 0;
    exePath[len] = '\0';
#elif (BOOST_OS_MACOS)
    char exePath[PATH_MAX];
    uint32_t len = sizeof(exePath);
    if (_NSGetExecutablePath(exePath, &len) != 0) {
        exePath[0] = '\0'; // buffer too small (!)
    } else {
        // resolve symlinks, ., .. if possible
        char *canonicalPath = realpath(exePath, NULL);
        if (canonicalPath != NULL) {
            strncpy(exePath,canonicalPath,len);
            free(canonicalPath);
        }
    }
#elif (BOOST_OS_BSD_FREE)
    char exePath[2048];
    int mib[4];  mib[0] = CTL_KERN;  mib[1] = KERN_PROC;  mib[2] = KERN_PROC_PATHNAME;  mib[3] = -1;
    size_t len = sizeof(exePath);
    if (sysctl(mib, 4, exePath, &len, NULL, 0) != 0)
        exePath[0] = '\0';
#endif
    return std::string(exePath);
}

উপরের সংস্করণে এক্সিকিউটেবল নাম সহ পুরো পাথ ফেরত দেয়। পরিবর্তে যদি আপনি এক্সিকিউটেবল নাম ছাড়াই পথটি চান #include boost/filesystem.hpp>এবং রিটার্নের বিবৃতিটি এখানে পরিবর্তন করুন:

return strlen(exePath)>0 ? boost::filesystem::path(exePath).remove_filename().make_preferred().string() : std::string();

@ ফ্র্যাঙ্ক, আপনি কেন এমনটি নিশ্চিত তা নিশ্চিত হন না। আমার জন্য কাজ কর. আমি অন্য প্রতিক্রিয়া দাবী করে দেখেছি যে আপনার কাছে / প্রো / স্ব / এক্সে অ্যাক্সেসের জন্য রুট দরকার তবে আমি খুঁজে পাইনি যে আমি যে কোনও লিনাক্স সিস্টেমে চেষ্টা করেছি (সেন্টোস বা মিন্ট)।
jtbr

2

কিউএনএক্স নিউট্রিনো সংস্করণের উপর নির্ভর করে চলমান প্রক্রিয়া শুরু করতে ব্যবহৃত এক্সিকিউটেবল ফাইলের পুরো পথ এবং নাম খুঁজে বের করার বিভিন্ন উপায় রয়েছে। আমি প্রক্রিয়া শনাক্তকারী হিসাবে চিহ্নিত করি <PID>। নিম্নলিখিত চেষ্টা করুন:

  1. যদি ফাইলটি /proc/self/exefileবিদ্যমান থাকে তবে এর বিষয়বস্তু হ'ল অনুরোধ করা তথ্য।
  2. যদি ফাইলটি /proc/<PID>/exefileবিদ্যমান থাকে তবে এর বিষয়বস্তু হ'ল অনুরোধ করা তথ্য।
  3. যদি ফাইলটি /proc/self/asবিদ্যমান থাকে, তবে:
    1. open() ফাইল.
    2. কমপক্ষে, এর একটি বাফার বরাদ্দ করুন sizeof(procfs_debuginfo) + _POSIX_PATH_MAX
    3. ইনফুট হিসাবে সেই বাফারটি দিন devctl(fd, DCMD_PROC_MAPDEBUG_BASE,...
    4. এটিকে বাফারটি কাস্ট করুন procfs_debuginfo*
    5. অনুরোধ করা তথ্য কাঠামোর pathক্ষেত্রে at সতর্কতা : কিছু কারণে, কখনও কখনও, QNX ফাইল পাথের প্রথম স্ল্যাশ বাদ দেয় । শুরুতে যোগ যে যখন প্রয়োজন।procfs_debuginfo//
    6. পরিষ্কার করুন (ফাইলটি বন্ধ করুন, বাফার মুক্ত করুন ইত্যাদি)।
  4. 3.ফাইলটি সহ পদ্ধতিটি ব্যবহার করে দেখুন /proc/<PID>/as
  5. এমন একটি কাঠামো dladdr(dlsym(RTLD_DEFAULT, "main"), &dlinfo)যেখানে রয়েছে যাতে অনুরোধ করা তথ্য থাকতে পারে চেষ্টা করুন।dlinfoDl_infodli_fname

আশা করি এটা কাজে লাগবে.


1

আফাইক, এরকম কোনও উপায় নেই। এবং একটি অস্পষ্টতাও রয়েছে: যদি একই এক্সিকিউটেবলের কাছে একাধিক হার্ড-লিঙ্কগুলি "পয়েন্টিং" করে থাকে তবে আপনি উত্তর হিসাবে কী পেতে চান? (হার্ড-লিঙ্ক না আসলে "নির্দেশ", তারা হয় একবার execve শুধু ফাঃ অনুক্রমের অন্য স্থানে একই ফাইল,।) () সফলভাবে একটি নতুন বাইনারি executes, তার আর্গুমেন্ট সম্পর্কে সব তথ্য হারিয়ে গেছে।


1
"একবার কার্যকর () একবার সফলভাবে একটি নতুন বাইনারি কার্যকর করে, এর আর্গুমেন্ট সম্পর্কিত সমস্ত তথ্য নষ্ট হয়ে যায়।" প্রকৃতপক্ষে, আরগপি এবং এনভিভিপি আর্গুমেন্টগুলি হারিয়ে যায় না, তারা আরজিভি [পরিবেশ] এবং পরিবেশ হিসাবে পাস হয় এবং কিছু ইউএন * জেসে, পথের নাম যুক্তি বা এটি থেকে নির্মিত কিছু হয় হয় আরগপি এবং এনভিভিপি (OS X) সহ পাশ করা হয় / আইওএস, সোলারিস) বা মার্ক4-এর উত্তরে তালিকাভুক্ত একটি পদ্ধতির মাধ্যমে উপলব্ধ করা হয়েছে। তবে, হ্যাঁ, এটি একের বেশি সংখ্যক রয়েছে যদি আপনাকে একটি শক্ত লিঙ্ক দেয়।

1

আপনি আরজিভি [0] ব্যবহার করতে পারেন এবং PATH পরিবেশ পরিবর্তনশীল বিশ্লেষণ করতে পারেন। দেখুন: একটি প্রোগ্রামের একটি নমুনা যা নিজেকে খুঁজে পেতে পারে


7
এটি আসলে নির্ভরযোগ্য নয় (যদিও এটি সাধারণত execvargv
শেলস

9
এটি একটি ভুল উত্তর। এটি আপনাকে বলতে পারে যেখানে আপনি একই নামের সাথে একটি প্রোগ্রাম কোথায় পেতে পারেন । তবে বর্তমানে চলমান এক্সিকিউটেবল আসলে কোথায় থাকে সে সম্পর্কে এটি আপনাকে কিছুই বলে না।
ল্যারি গ্রিটজ

0

এক্সিকিউটেবল ইমেজের পাথের নাম পাওয়ার আরও বহনযোগ্য উপায়:

আপনার প্রসেস আইডি দিলে পিএস আপনাকে এক্সিকিউটেবলের পথ দিতে পারে। এছাড়াও পিএস একটি পসিক্স ইউটিলিটি তাই এটি পোর্টেবল হওয়া উচিত

সুতরাং যদি প্রক্রিয়া আইডি 249297 হয় তবে এই আদেশটি আপনাকে কেবলমাত্র পথের নাম দেয়।

    ps -p 24297 -o comm --no-heading

যুক্তি ব্যাখ্যা

-p - প্রদত্ত প্রক্রিয়া নির্বাচন করে

-o কম - কমান্ডের নাম প্রদর্শন করে (-o cmd পুরো কমান্ড লাইনটি নির্বাচন করে)

- কোন শিরোনাম - একটি শিরোনাম লাইন প্রদর্শন করবেন না, কেবলমাত্র আউটপুট।

এসি প্রোগ্রাম পপেনের মাধ্যমে এটি চালাতে পারে।


এটি প্যারামগুলির সাথে পূর্ণ লঞ্চের স্ট্রিং দেয়।
ইটেক

- কোনও শিরোনামটি বহনযোগ্য নয়
ভাল ব্যক্তি

1
এক্সিকিউটে প্রথম যুক্তি যদি পরম পথ না হয় তবে কাজ করে না।
hroptatyr

-4

আপনি সি ব্যবহার করেন, আপনি getwd ফাংশন ব্যবহার করতে পারেন:

int main()
{       
 char buf[4096];
 getwd(buf);
 printf(buf);
}

এটি স্ট্যান্ডার্ড আউটপুট, এক্সিকিউটেবলের বর্তমান ডিরেক্টরিতে মুদ্রণ করবে।


3
কমপক্ষে উইন্ডোজে, চলমান এক্সিকিউটেবলের সাথে বর্তমান ওয়ার্কিং ডিরেক্টরিটির কোনও বিশেষ সম্পর্ক নেই। উদাহরণস্বরূপ, ক্রিয়েটপ্রসেস একটি .exe আরম্ভ করতে পারে এবং সম্পূর্ণরূপে স্বতঃসংশ্লিষ্ট ডিরেক্টরিটি সেট করে।
স্পাইক0xff

পরিস্থিতি প্রতিটি অন্যান্য ওএসের ক্ষেত্রে একই রকম: বর্তমান ডিরেক্টরিটি কখনও কখনও ঘটনাক্রমে এক্সিকিউটেবল ডিরেক্টরি হিসাবে একই হয় তবে এটি সম্পূর্ণ আলাদা হতে পারে।
লাসি

-10

কোনও প্রোগ্রামের পরম মান পাথটি আপনার মূল ফাংশনের এনভিপির পিডাব্লুডিতে থাকে, সেখানে জেন্তেভ নামে একটি ফাংশনও রয়েছে, তাই আছে that

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.