การค้นหาเส้นทางของไฟล์เรียกทำงานปัจจุบันโดยไม่มี / proc / self / exe


190

สำหรับฉันแล้วดูเหมือนว่า Linux สามารถใช้งานได้ง่ายกับ / proc / self / exe แต่ฉันต้องการทราบว่ามีวิธีที่สะดวกในการค้นหาไดเรกทอรีของแอปพลิเคชันปัจจุบันใน C / C ++ พร้อมอินเทอร์เฟซข้ามแพลตฟอร์มหรือไม่ ฉันเคยเห็นบางโครงการล้อเล่นกับ argv [0] แต่ดูเหมือนจะไม่น่าเชื่อถือทั้งหมด

หากคุณเคยให้การสนับสนุนพูดว่า Mac OS X ซึ่งไม่มี / proc / คุณจะทำอะไร ใช้ #ifdefs เพื่อแยกรหัสเฉพาะแพลตฟอร์ม (ตัวอย่างเช่น NSBundle) หรือไม่ หรือพยายามที่จะอนุมานเส้นทางของปฏิบัติการจาก argv [0], $ PATH และอะไรก็ตามที่เสี่ยงต่อการหาข้อบกพร่องในกรณีขอบ



ฉัน googled: ps -o commได้รับของฉัน สิ่งที่นำฉันมาที่นี่คือ: "/proc/pid/path/a.out"
อ่าง

IMHO ภูมิใจที่คำตอบของคุณควรจะอยู่ด้านบนเพราะมันตอบสนองความต้องการ "อินเตอร์เฟซข้ามแพลตฟอร์ม" อย่างถูกต้องและง่ายต่อการรวมเข้าด้วยกัน
Stéphane Gourichon

คำตอบ:


348

อินเทอร์เฟซเฉพาะสำหรับระบบปฏิบัติการบางตัว:

แบบพกพา ( แต่มีความน่าเชื่อถือน้อยกว่า) argv[0]วิธีการคือการใช้งาน $PATHแม้ว่ามันอาจจะตั้งเพื่ออะไรโดยโปรแกรมเรียกโดยการประชุมมีการตั้งค่าทั้งชื่อเส้นทางของการปฏิบัติการหรือชื่อที่พบโดยใช้

เชลล์บางตัวรวมถึง bash และ ksh ตั้งค่าตัวแปรสภาพแวดล้อม " _"เป็นพา ธ เต็มของไฟล์สั่งการก่อนที่จะถูกเรียกใช้งาน ในกรณีนี้คุณสามารถใช้getenv("_")เพื่อรับมัน อย่างไรก็ตามสิ่งนี้ไม่น่าเชื่อถือเพราะเชลล์บางตัวทำสิ่งนี้ได้และมันสามารถตั้งค่าเป็นอะไรก็ได้หรือเหลือจากกระบวนการพาเรนต์ซึ่งไม่ได้เปลี่ยนก่อนที่จะรันโปรแกรมของคุณ


3
และโปรดทราบว่า _NSGetExecutablePath () จะไม่ติดตาม symlinks
naruse

1
NetBSD: readlink / proc / curproc / exe DragonFly BSD: readlink / proc / curproc / ไฟล์
naruse

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...
FrankH

4
"QDesktopServices :: storageLocation (QDesktopServices :: DataLocation)" นั่นไม่ใช่เส้นทางของไฟล์เรียกทำงานนั่นคือชื่อพา ธ ของไดเรกทอรีต่อผู้ใช้ที่ควรจัดเก็บข้อมูล

2
OpenBSD เป็นสิ่งเดียวที่คุณยังไม่สามารถทำได้ในปี 2560 คุณต้องใช้ PATH และ argv [0] วิธี
Lothar

27

การใช้งาน/proc/self/exeไม่ใช่แบบพกพาและไม่น่าเชื่อถือ ในระบบ Ubuntu 12.04 ของฉันคุณต้องรูทเพื่ออ่าน / ติดตาม symlink นี่จะทำให้ตัวอย่าง Boost และอาจเป็นไปได้ว่าwhereami()โซลูชันที่โพสต์ล้มเหลว

โพสต์นี้ยาวมาก แต่พูดถึงปัญหาที่เกิดขึ้นจริงและนำเสนอรหัสที่ใช้งานได้จริงพร้อมกับการตรวจสอบกับชุดทดสอบ

วิธีที่ดีที่สุดในการค้นหาโปรแกรมของคุณคือการทำตามขั้นตอนเดิมที่ระบบใช้ สิ่งนี้ทำได้โดยใช้การargv[0]แก้ไขกับรูทระบบไฟล์, pwd, สภาพแวดล้อมของพา ธ และการพิจารณา symlink และการกำหนดชื่อพา ธ นี่เป็นความทรงจำ แต่ฉันเคยทำมาแล้วในอดีตและทดสอบในสถานการณ์ที่แตกต่างหลากหลาย มันไม่ได้รับประกันว่าจะทำงาน แต่ถ้ามันไม่ได้คุณอาจมีปัญหาที่ใหญ่กว่าและมีความน่าเชื่อถือโดยรวมมากกว่าวิธีอื่น ๆ ที่กล่าวถึง มีสถานการณ์ในระบบที่เข้ากันได้กับ Unix ซึ่งจัดการได้อย่างเหมาะสมargv[0]จะไม่นำคุณไปสู่โปรแกรมของคุณ แต่คุณกำลังดำเนินการในสภาพแวดล้อมที่แตกหักอย่างแน่นอน นอกจากนี้ยังสามารถพกพาไปยังระบบที่ได้รับ Unix ได้ทั้งหมดตั้งแต่ปี 1970 และแม้กระทั่งระบบที่ไม่ได้มาจาก Unix บางระบบเนื่องจากอาศัยการทำงานมาตรฐาน libc () และฟังก์ชั่นบรรทัดคำสั่งมาตรฐาน มันควรทำงานบน Linux (ทุกรุ่น), Android, Chrome OS, Minix, Bell Labs Unix ดั้งเดิม, FreeBSD, NetBSD, OpenBSD, BSD xx, SunOS, Solaris, SYSV, HPUX, Concentrix, SCO, ดาร์วิน, AIX, OS X, ขั้นตอนต่อไปเป็นต้นและด้วยการปรับเปลี่ยนเล็กน้อยอาจเป็น VMS, VM / CMS, DOS / Windows, ReactOS, OS / 2 เป็นต้นหากโปรแกรมถูกเปิดใช้งานโดยตรงจากสภาพแวดล้อม GUI คุณควรกำหนดargv[0]เส้นทางที่แน่นอน

เข้าใจว่าเกือบทุกเชลล์ในระบบปฏิบัติการที่รองรับ Unix ทุกตัวที่เคยปล่อยออกมาโดยทั่วไปจะค้นหาโปรแกรมในลักษณะเดียวกันและตั้งค่าสภาพแวดล้อมการทำงานเกือบจะเหมือนกัน (พร้อมอุปกรณ์เสริมพิเศษ) และโปรแกรมอื่น ๆ ที่เปิดตัวโปรแกรมนั้นคาดว่าจะสร้างสภาพแวดล้อมเดียวกัน (argv, สตริงสภาพแวดล้อม, ฯลฯ ) สำหรับโปรแกรมนั้นราวกับว่ามันถูกเรียกใช้จากเชลล์ด้วยตัวเลือกพิเศษบางอย่าง โปรแกรมหรือผู้ใช้สามารถตั้งค่าสภาพแวดล้อมที่เบี่ยงเบนจากการประชุมนี้สำหรับโปรแกรมรองอื่น ๆ ที่เปิดตัว แต่ถ้าเป็นเช่นนั้นนี่เป็นข้อผิดพลาดและโปรแกรมไม่มีความคาดหวังที่สมเหตุสมผลว่าโปรแกรมรองหรือผู้ใต้บังคับบัญชาจะทำงานได้อย่างถูกต้อง

ค่าที่เป็นไปได้ของการargv[0]รวม:

  • /path/to/executable - เส้นทางที่แน่นอน
  • ../bin/executable - สัมพันธ์กับ pwd
  • bin/executable - สัมพันธ์กับ pwd
  • ./foo - สัมพันธ์กับ pwd
  • executable - ชื่อฐานค้นหาในเส้นทาง
  • bin//executable - สัมพันธ์กับ pwd ไม่ใช่แบบบัญญัติ
  • src/../bin/executable - สัมพันธ์กับ pwd, ไม่ใช่แบบบัญญัติ, การย้อนรอย
  • bin/./echoargc - สัมพันธ์กับ pwd ไม่ใช่แบบบัญญัติ

ค่าที่คุณไม่ควรเห็น:

  • ~/bin/executable - เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงาน
  • ~user/bin/executable - เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงาน
  • alias - เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงาน
  • $shellvariable - เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงาน
  • *foo* - wildcard เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงานไม่มีประโยชน์มาก
  • ?foo? - wildcard เขียนใหม่ก่อนที่โปรแกรมของคุณจะทำงานไม่มีประโยชน์มาก

นอกจากนี้สิ่งเหล่านี้อาจมีชื่อพา ธ ที่ไม่เป็นที่ยอมรับและการเชื่อมโยงสัญลักษณ์หลายเลเยอร์ ในบางกรณีอาจมีฮาร์ดลิงก์หลายตัวในโปรแกรมเดียวกัน ตัวอย่างเช่น/bin/ls, /bin/ps, /bin/chmod, /bin/rmและอื่น ๆ /bin/busyboxอาจจะมีการเชื่อมโยงอย่างหนักเพื่อ

ในการค้นหาตัวเองให้ทำตามขั้นตอนด้านล่าง:

  • บันทึก pwd, PATH และ argv [0] เมื่อเข้าสู่โปรแกรมของคุณ (หรือการเริ่มต้นไลบรารีของคุณ) เนื่องจากอาจเปลี่ยนแปลงในภายหลัง

  • ทางเลือก: โดยเฉพาะอย่างยิ่งสำหรับระบบที่ไม่ใช่ระบบ Unix แยกออก แต่อย่าทิ้งส่วนนำหน้าชื่อโฮสต์ / ผู้ใช้ / ไดรฟ์หากมี; ส่วนที่มักนำหน้าโคลอนหรือตามด้วย "//" เริ่มต้น

  • ถ้าargv[0]เป็นพา ธ สัมบูรณ์ใช้เป็นจุดเริ่มต้น เส้นทางที่แน่นอนอาจเริ่มต้นด้วย "/" แต่ในระบบที่ไม่ใช่ Unix บางระบบอาจเริ่มต้นด้วย "\" หรือตัวอักษรชื่อไดรฟ์หรือคำนำหน้าชื่อตามด้วยเครื่องหมายจุดคู่

  • ถ้าargv[0]เป็นเส้นทางแบบสัมพัทธ์ (มี "/" หรือ "\" แต่ไม่ได้ขึ้นต้นด้วยเช่น "../../bin/foo" จากนั้นรวม pwd + "/" + argv [0] (ใช้ นำเสนอไดเรกทอรีการทำงานจากเมื่อเริ่มต้นโปรแกรมไม่ใช่ปัจจุบัน)

  • มิฉะนั้นถ้า argv [0] เป็น basename ธรรมดา (ไม่มีเครื่องหมายทับ) จากนั้นรวมกับแต่ละรายการในตัวแปรสภาพแวดล้อม PATH ในทางกลับกันแล้วลองใช้และใช้อันแรกและประสบความสำเร็จ

  • ตัวเลือก: อื่นลองเฉพาะแพลตฟอร์มมาก/proc/self/exe, /proc/curproc/file(BSD) และ(char *)getauxval(AT_EXECFN)และdlgetname(...)ถ้ามี คุณอาจลองargv[0]วิธีการเหล่านี้ก่อน- ตามหากมีและคุณไม่พบปัญหาสิทธิ์ ในเหตุการณ์ที่ค่อนข้างไม่น่าจะเกิดขึ้น (เมื่อคุณพิจารณาทุกระบบทุกเวอร์ชัน) ว่ามีอยู่และไม่ล้มเหลวก็อาจมีสิทธิ์มากกว่า

  • ทางเลือก: ตรวจสอบชื่อพา ธ ที่ส่งผ่านโดยใช้พารามิเตอร์บรรทัดคำสั่ง

  • ทางเลือก: ตรวจสอบชื่อพา ธ ในสภาพแวดล้อมที่ส่งผ่านโดยสคริปต์ wrapper ของคุณหากมี

  • ทางเลือก: ในฐานะทางเลือกสุดท้ายลองตัวแปรสภาพแวดล้อม "_" มันอาจชี้ไปที่โปรแกรมอื่นทั้งหมดเช่นเชลล์ผู้ใช้

  • แก้ไข symlink อาจมีหลายเลเยอร์ มีความเป็นไปได้ของการวนซ้ำไม่ จำกัด แม้ว่าหากมีอยู่โปรแกรมของคุณอาจไม่ถูกเรียกใช้

  • กำหนดชื่อไฟล์ให้เป็นมาตรฐานโดยการแก้ไขสตริงย่อยเช่น "/foo/../bar/" เป็น "/ bar /" โปรดทราบว่าสิ่งนี้อาจเปลี่ยนความหมายได้หากคุณข้ามจุดเชื่อมต่อเครือข่ายดังนั้นการทำให้เป็น Canonization อาจไม่ใช่สิ่งที่ดีเสมอไป บนเซิร์ฟเวอร์เครือข่าย ".. " ใน symlink อาจถูกใช้เพื่อสำรวจเส้นทางไปยังไฟล์อื่นในบริบทของเซิร์ฟเวอร์แทนบนไคลเอนต์ ในกรณีนี้คุณอาจต้องการบริบทของไคลเอนต์ แปลงรูปแบบเช่น "/./" เป็น "/" และ "//" เป็น "/" ด้วย ในเปลือกreadlink --canonicalizeจะแก้ปัญหาหลาย symlink และชื่อบัญญัติ Chase อาจทำคล้ายกัน แต่ไม่ได้ติดตั้ง realpath()หรือcanonicalize_file_name()ถ้ามีอาจช่วยได้

หากrealpath()ไม่มีอยู่ในเวลารวบรวมคุณอาจยืมสำเนาจากการแจกจ่ายไลเซนส์ที่ได้รับอนุญาตและรวบรวมไว้ในตัวคุณแทนที่จะรวบรวมล้อ แก้ไขบัฟเฟอร์ที่อาจเกิดการโอเวอร์โฟลว์ (ส่งผ่านขนาดบัฟเฟอร์เอาต์พุตคิดว่า strncpy () vs strcpy ()) หากคุณจะใช้บัฟเฟอร์น้อยกว่า PATH_MAX อาจเป็นการง่ายกว่าที่จะใช้สำเนาส่วนตัวที่ถูกเปลี่ยนชื่อแทนที่จะทำการทดสอบหากมีอยู่ สำเนาใบอนุญาตที่อนุญาตจาก android / darwin / bsd: https://android.googlesource.com/platform/bionic/+/f077784/libc/upstream-freebsd/lib/libc/stdlib/realpath.c

โปรดทราบว่าความพยายามหลายครั้งอาจประสบความสำเร็จหรือประสบความสำเร็จบางส่วนและพวกเขาอาจไม่ชี้ไปที่ปฏิบัติการเดียวกันดังนั้นให้พิจารณาการตรวจสอบปฏิบัติการของคุณ อย่างไรก็ตามคุณอาจไม่ได้รับอนุญาตให้อ่าน - หากคุณไม่สามารถอ่านได้อย่าถือเป็นความล้มเหลว หรือตรวจสอบบางสิ่งที่ใกล้เคียงกับไฟล์ที่เรียกใช้งานได้ของคุณเช่นไดเรกทอรี "../lib/" ที่คุณพยายามค้นหา คุณอาจมีหลายรุ่นรุ่นที่บรรจุและที่คอมไพล์ในประเทศรุ่นในท้องถิ่นและเครือข่ายและรุ่นพกพาในท้องถิ่นและไดรฟ์ USB ฯลฯ และมีความเป็นไปได้เล็กน้อยที่คุณอาจได้รับผลลัพธ์ที่เข้ากันไม่ได้สองวิธีจากวิธีการค้นหาต่างๆ และ "_" อาจชี้ไปที่โปรแกรมผิด

โปรแกรมที่ใช้execveสามารถตั้งค่าโดยเจตนาargv[0]ให้เข้ากันไม่ได้กับเส้นทางจริงที่ใช้ในการโหลดโปรแกรมและ PATH ที่เสียหาย "_", pwd ฯลฯ แม้ว่าจะไม่มีเหตุผลมากนักที่จะทำเช่นนั้น แต่นี่อาจมีผลกระทบด้านความปลอดภัยหากคุณมีรหัสที่มีช่องโหว่ซึ่งไม่สนใจความจริงที่ว่าสภาพแวดล้อมในการดำเนินการของคุณสามารถเปลี่ยนแปลงได้หลายวิธีรวมถึง แต่ไม่ จำกัด เพียงการกระทำนี้ (chroot, ฟิวส์ระบบไฟล์ลิงก์ถาวร ฯลฯ ) สำหรับคำสั่งเชลล์เพื่อตั้งค่า PATH แต่ไม่สามารถส่งออกได้

คุณไม่จำเป็นต้องเขียนโค้ดสำหรับระบบที่ไม่ใช่ระบบปฏิบัติการยูนิกซ์ แต่เป็นความคิดที่ดีที่จะต้องตระหนักถึงคุณสมบัติบางอย่างเพื่อให้คุณสามารถเขียนโค้ดในลักษณะที่ไม่ยากสำหรับบางคนที่จะย้ายพอร์ตในภายหลัง . โปรดทราบว่าระบบบางระบบ (DEC VMS, DOS, URL ฯลฯ ) อาจมีชื่อไดรฟ์หรือคำนำหน้าอื่น ๆ ที่ลงท้ายด้วยโคลอนเช่น "C: \", "sys $ drive: [foo] bar" และ "file : /// foo / บาร์ / baz" ระบบ DEC VMS เก่าใช้ "[" และ "]" เพื่อล้อมรอบส่วนไดเรกทอรีของเส้นทางแม้ว่าอาจมีการเปลี่ยนแปลงหากโปรแกรมของคุณรวบรวมในสภาพแวดล้อม POSIX ระบบบางระบบเช่น VMS อาจมีรุ่นของไฟล์ (คั่นด้วยเครื่องหมายอัฒภาคตอนท้าย) ระบบบางระบบใช้เครื่องหมายทับสองตัวติดกันเช่นใน "// drive / path / to / file" หรือ "user @ host: / path / to / file" (คำสั่ง scp) หรือ "file: (คั่นด้วยช่องว่าง) และ "เส้นทาง" คั่นด้วยเครื่องหมายโคลอน แต่โปรแกรมของคุณควรได้รับ PATH ดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับเส้นทาง DOS และระบบอื่น ๆ สามารถมีเส้นทางสัมพันธ์ที่ขึ้นต้นด้วยคำนำหน้าไดรฟ์ C: foo.exe อ้างถึง foo.exe ในไดเรกทอรีปัจจุบันบนไดรฟ์ C ดังนั้นคุณไม่จำเป็นต้องค้นหาไดเรกทอรีปัจจุบันบน C: และใช้สำหรับ pwd (คั่นด้วยช่องว่าง) และ "เส้นทาง" คั่นด้วยเครื่องหมายโคลอน แต่โปรแกรมของคุณควรได้รับ PATH ดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับเส้นทาง DOS และระบบอื่น ๆ สามารถมีเส้นทางสัมพันธ์ที่ขึ้นต้นด้วยคำนำหน้าไดรฟ์ C: foo.exe อ้างถึง foo.exe ในไดเรกทอรีปัจจุบันบนไดรฟ์ C ดังนั้นคุณไม่จำเป็นต้องค้นหาไดเรกทอรีปัจจุบันบน C: และใช้สำหรับ pwd

ตัวอย่างของ symlinks และ wrappers ในระบบของฉัน:

/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 จะไม่ถูกทำลาย
  • จำเป็นต้องเขียนใหม่เป็นฟังก์ชันไลบรารีแทนที่จะพิมพ์ผลลัพธ์ออกมา
    • มันไม่สามารถตั้งชื่อให้เป็นมาตรฐานได้ (ใช้รหัสเรียลพา ธ ที่ฉันลิงก์ไว้ด้านบน)
    • มันไม่สามารถแก้ไขลิงก์สัญลักษณ์ (ใช้รหัส realpath)

ดังนั้นถ้าคุณรวมทั้งรหัส HP และรหัส realpath argv[0]และแก้ไขทั้งที่จะทนต่อการบัฟเฟอร์ล้นแล้วคุณควรจะมีอะไรบางอย่างที่ถูกต้องสามารถแปลความหมาย

ต่อไปนี้แสดงให้เห็นถึงคุณค่าที่แท้จริงของargv[0]วิธีการต่าง ๆ ของการเรียกใช้โปรแกรมเดียวกันบน Ubuntu 12.04 และใช่โปรแกรมนั้นชื่อ echoargc โดยบังเอิญแทนที่จะเป็น echoargv สิ่งนี้ทำโดยใช้สคริปต์สำหรับการคัดลอกที่สะอาด แต่การทำด้วยตนเองในเชลล์จะได้ผลลัพธ์เดียวกัน (ยกเว้นชื่อแทนจะไม่ทำงานในสคริปต์เว้นแต่คุณจะเปิดใช้งานอย่างชัดเจน)

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

ตัวอย่างเหล่านี้แสดงให้เห็นว่าเทคนิคที่อธิบายไว้ในโพสต์นี้ควรทำงานในสถานการณ์ที่หลากหลายและสาเหตุที่ขั้นตอนบางอย่างจำเป็น

แก้ไข: ตอนนี้โปรแกรมที่พิมพ์ argv [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"

การเปิดตัว GUI สองรายการที่อธิบายไว้ข้างต้นยังสามารถค้นหาโปรแกรมได้อย่างถูกต้อง

มีข้อผิดพลาดที่อาจเกิดขึ้นได้ access()ฟังก์ชั่นลดลงสิทธิ์ถ้าโปรแกรมจะ setuid ก่อนการทดสอบ หากมีสถานการณ์ที่โปรแกรมสามารถพบได้ในฐานะผู้ใช้ที่ยกระดับ แต่ไม่ได้เป็นผู้ใช้ปกติอาจมีสถานการณ์ที่การทดสอบเหล่านี้จะล้มเหลวแม้ว่าจะไม่น่าเป็นไปได้ที่โปรแกรมจะถูกดำเนินการภายใต้สถานการณ์เหล่านั้น สามารถใช้ euidaccess () แทนได้ อย่างไรก็ตามเป็นไปได้ว่าอาจพบโปรแกรมที่ไม่สามารถเข้าถึงได้ก่อนหน้านี้บนเส้นทางที่ผู้ใช้จริงสามารถทำได้


1
คุณใช้ความพยายามอย่างมากในเรื่องนั้น - ทำได้ดีมาก น่าเสียดายที่ไม่มีการใช้strncpy()(โดยเฉพาะ) strncat()อย่างปลอดภัยในรหัส strncpy()ไม่รับประกันการยกเลิก null หากสตริงต้นทางยาวกว่าพื้นที่เป้าหมายสตริงนั้นจะไม่ถูกยกเลิก strncat()ใช้งานยากมาก strncat(target, source, sizeof(target))ผิด (แม้ว่าtargetจะเป็นสตริงว่างเปล่าที่จะเริ่มต้นด้วย) หากsourceยาวกว่าเป้าหมาย ความยาวคือจำนวนอักขระที่สามารถต่อท้ายเป้าหมายได้อย่างปลอดภัยโดยไม่รวมค่า null ต่อท้ายดังนั้นsizeof(target)-1สูงสุด
Jonathan Leffler

4
รหัส strncpy ถูกต้องไม่เหมือนกับวิธีที่คุณบอกเป็นนัยว่าฉันควรใช้ ฉันขอแนะนำให้คุณอ่านรหัสอย่างระมัดระวังมากขึ้น มันไม่ได้บัฟเฟอร์ล้นและไม่ทิ้งพวกมันไว้ การใช้ strncpy () / stncat () แต่ละครั้งจะถูก จำกัด โดยการคัดลอก sizeof (buffer) ซึ่งใช้ได้แล้วอักขระตัวสุดท้ายของบัฟเฟอร์จะถูกเติมด้วยการเขียนทับศูนย์อักขระตัวสุดท้ายของบัฟเฟอร์ อย่างไรก็ตาม strncat () ใช้พารามิเตอร์ขนาดไม่ถูกต้องเป็นจำนวนและอาจล้นเนื่องจากข้อเท็จจริงที่ว่ามันมาก่อนการโจมตีบัฟเฟอร์ล้น
whitis

"sudo apt-get install libbsd0 libbsd-dev" จากนั้น s / strncat / strlcat /
whitis

1
อย่าใช้ PATH_MAX สิ่งนี้หยุดทำงานเมื่อ 30 ปีที่แล้วใช้ malloc เสมอ
Lothar

นอกจากนี้หากคุณใช้การโทรเริ่มต้น แก้ไขเส้นทางไปยัง exe อย่างสมบูรณ์โดยเริ่มต้นและไม่ใช่เพียงแค่ส่วนหนึ่งจากนั้นทำการโทรออกภายหลัง ไม่มีการประเมินผลแบบขี้เกียจที่นี่หากคุณใช้ realpath ในตัวแก้ไข เมื่อรวมกับข้อผิดพลาดอื่น ๆ เพียงแค่รหัสที่แย่ที่สุดที่ฉันเคยเห็นใน stackoverflow ในเวลานาน
Lothar

13

ตรวจสอบห้องสมุดwhereamiจาก Gregory Pakosz (ซึ่งมีไฟล์ C เพียงไฟล์เดียว); ช่วยให้คุณได้รับเส้นทางแบบเต็มไปยังปฏิบัติการในปัจจุบันบนแพลตฟอร์มที่หลากหลาย ปัจจุบันก็มีอยู่เป็น repo บน GitHub ที่นี่


8

อีกทางเลือกหนึ่งในการใช้งาน Linux /proc/self/exeหรือargv[0]ใช้ข้อมูลที่ส่งผ่านล่าม ELF จัดทำโดย glibc เช่น:

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

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

โปรดทราบว่าgetauxvalนี่เป็นส่วนขยาย glibc และเพื่อความเสถียรคุณควรตรวจสอบเพื่อไม่ให้ส่งคืนNULL(ระบุว่าล่าม ELF ไม่ได้ให้AT_EXECFNพารามิเตอร์) แต่ฉันไม่คิดว่านี่เป็นปัญหาจริงบน Linux


ฉันชอบสิ่งนี้เพราะมันเรียบง่ายและ glibc รวมอยู่ใน Gtk + ต่อไป (ซึ่งฉันใช้)
โคลินคีแนนส์มี. ค.

4

หากคุณเคยให้การสนับสนุนพูดว่า Mac OS X ซึ่งไม่มี / proc / คุณจะทำอะไร ใช้ #ifdefs เพื่อแยกรหัสเฉพาะแพลตฟอร์ม (ตัวอย่างเช่น NSBundle) หรือไม่

ใช่การแยกรหัสเฉพาะแพล็ตฟอร์มด้วย#ifdefsเป็นวิธีดั้งเดิมที่ทำได้

อีกวิธีหนึ่งก็คือการมี#ifdefส่วนหัวแบบไม่มีเลเยอร์ที่สะอาดซึ่งมีฟังก์ชั่นการประกาศและวางการประยุกต์ใช้ในซอร์สไฟล์เฉพาะของแพลตฟอร์ม ตัวอย่างเช่นลองดูวิธีที่ไลบรารี Poco C ++ ทำสิ่งที่คล้ายกับคลาสEnvironmentของพวกเขา


4

การทำให้งานนี้ผ่านแพลตฟอร์มได้อย่างน่าเชื่อถือต้องใช้คำสั่ง #ifdef

รหัสด้านล่างค้นหาเส้นทางของไฟล์ปฏิบัติการใน Windows, Linux, MacOS, Solaris หรือ FreeBSD (แม้ว่า FreeBSD จะไม่ได้ทดสอบ) มันใช้เพิ่ม > = 1.55.0 เพื่อลดความซับซ้อนของรหัส แต่มันง่ายพอที่จะลบถ้าคุณต้องการ เพียงใช้กำหนดเช่น _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 เป็น:

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

@ Frank ไม่แน่ใจว่าทำไมคุณพูดอย่างนั้น ได้ผลสำหรับฉัน ฉันเห็นคำตอบอื่นอ้างว่าคุณต้องการรูทเพื่อเข้าถึง / proc / self / exe แต่ฉันไม่พบว่าในระบบ Linux ใด ๆ ที่ฉันได้ลอง (CentOS หรือ Mint)
jtbr

2

ขึ้นอยู่กับรุ่นของQNX Neutrinoมีหลายวิธีในการค้นหาพา ธ เต็มและชื่อของไฟล์เรียกทำงานที่ใช้เพื่อเริ่มกระบวนการทำงาน <PID>ฉันหมายถึงรหัสกระบวนการเป็น ลองทำสิ่งต่อไปนี้:

  1. หากไฟล์/proc/self/exefileมีอยู่แล้วเนื้อหาของมันเป็นข้อมูลที่ร้องขอ
  2. หากไฟล์/proc/<PID>/exefileมีอยู่แล้วเนื้อหาของมันเป็นข้อมูลที่ร้องขอ
  3. หากไฟล์/proc/self/asมีอยู่แล้ว:
    1. open() ไฟล์
    2. sizeof(procfs_debuginfo) + _POSIX_PATH_MAXจัดสรรกันชนของเป็นอย่างน้อย
    3. ให้บัฟเฟอร์ที่เป็น input devctl(fd, DCMD_PROC_MAPDEBUG_BASE,...เพื่อ
    4. procfs_debuginfo*โพลล์บัฟเฟอร์ไป
    5. ข้อมูลที่ร้องขออยู่ที่pathฟิลด์ของprocfs_debuginfoโครงสร้าง คำเตือน : ด้วยเหตุผลบางอย่างในบางครั้ง QNX จะไม่ใส่เครื่องหมายสแลชแรก/ของพา ธ ไฟล์ แสดงว่า/เมื่อจำเป็น
    6. ล้างข้อมูล (ปิดไฟล์, เพิ่มบัฟเฟอร์, ฯลฯ )
  4. ลองขั้นตอนในกับไฟล์3./proc/<PID>/as
  5. ลองdladdr(dlsym(RTLD_DEFAULT, "main"), &dlinfo)ที่dlinfoเป็นDl_infoโครงสร้างที่dli_fnameอาจมีข้อมูลที่ร้องขอ

ฉันหวังว่านี่จะช่วยได้.


1

AFAIK ไม่มีทางเช่นนั้น และยังมีความแปลกใหม่: คุณต้องการคำตอบอย่างไรถ้าไฟล์ปฏิบัติการเดียวกันนั้นมีฮาร์ดลิงก์หลายตัว "ชี้" ไปที่มัน? (ฮาร์ดลิงค์ไม่จริง "ชี้" พวกเขาเป็นไฟล์เดียวกันเพียงแค่ที่อื่นในลำดับชั้นของ FS) เมื่อ execve () ประสบความสำเร็จในการดำเนินการไบนารีใหม่ข้อมูลทั้งหมดเกี่ยวกับข้อโต้แย้งของมันจะหายไป


1
"เมื่อเอ็กซีคิวต์ () ประสบความสำเร็จในการดำเนินการไบนารี่ใหม่ข้อมูลทั้งหมดเกี่ยวกับการโต้แย้งจะหายไป" ที่จริงแล้วอาร์กิวเมนต์ argp และ envp จะไม่หายไปพวกเขาจะถูกส่งผ่านเป็น argv [] และสภาพแวดล้อมและในบาง UN * Xes อาร์กิวเมนต์ชื่อพา ธ หรือสิ่งที่สร้างขึ้นจากมันจะถูกส่งผ่านพร้อมกับ argp และ envp (OS X / iOS, Solaris) หรือจัดทำผ่านหนึ่งในกลไกที่ระบุไว้ในคำตอบของ mark4o แต่ใช่ว่าจะช่วยให้คุณเชื่อมโยงอย่างใดอย่างหนึ่งหากมีมากกว่าหนึ่ง

1

คุณสามารถใช้ argv [0] และวิเคราะห์ตัวแปรสภาพแวดล้อม PATH ดูที่: ตัวอย่างของโปรแกรมที่สามารถค้นหาได้


7
สิ่งนี้ไม่น่าเชื่อถือจริง ๆ (แม้ว่าโดยทั่วไปจะทำงานกับโปรแกรมที่เปิดตัวโดยเชลล์ทั่วไป) เพราะexecvและญาตินำพา ธ ไปยังปฏิบัติการที่แยกได้จากargv
dmckee --- อดีตผู้ดูแลลูกแมว

9
นี่เป็นคำตอบที่ไม่ถูกต้อง มันอาจจะบอกคุณที่คุณสามารถหาโปรแกรมที่มีชื่อเดียวกัน แต่มันไม่ได้บอกอะไรคุณเกี่ยวกับตำแหน่งที่โปรแกรมปฏิบัติการที่ใช้งานอยู่มีอยู่จริง
Larry Gritz

0

วิธีพกพาเพิ่มเติมเพื่อรับชื่อพา ธ ของอิมเมจที่ปฏิบัติการได้:

ps สามารถให้เส้นทางของการปฏิบัติการให้คุณมี ID กระบวนการ ps เป็นยูทิลิตี้ POSIX ด้วยดังนั้นจึงควรพกพาได้

ดังนั้นหาก id กระบวนการคือ 249297 คำสั่งนี้จะให้ชื่อพา ธ เท่านั้น

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

คำอธิบายของข้อโต้แย้ง

-p - เลือกกระบวนการที่กำหนด

-o comm - แสดงชื่อคำสั่ง (-o cmd เลือกบรรทัดคำสั่งทั้งหมด)

- ไม่มีส่วนหัว - อย่าแสดงบรรทัดหัวเรื่องเพียงแค่เอาต์พุต

โปรแกรม AC สามารถเรียกใช้ผ่าน popen


มันให้สตริงการเปิดตัวเต็มรูปแบบกับ params
ETech

- ไม่มีส่วนหัวเป็นแบบพกพา
คนดี

1
ไม่ทำงานหากอาร์กิวเมนต์แรกของ execv ไม่ใช่เส้นทางที่สมบูรณ์
hroptatyr

-4

หากคุณใช้ C คุณสามารถใช้ฟังก์ชัน getwd:

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

สิ่งนี้คุณจะพิมพ์บนเอาต์พุตมาตรฐานซึ่งเป็นไดเร็กทอรีปัจจุบันของไฟล์เรียกทำงาน


3
อย่างน้อยบน Windows ไดเร็กทอรีการทำงานปัจจุบันไม่มีความสัมพันธ์เฉพาะกับไฟล์เรียกทำงานที่รันได้ ตัวอย่างเช่นCreateProcessสามารถเรียกใช้. exe และตั้งค่าไดเรกทอรีทำงานได้อย่างอิสระโดยสมบูรณ์
Spike0xff

สถานการณ์นั้นเหมือนกันในทุก ๆ OS: ไดเรกทอรีปัจจุบันบางครั้งก็เหมือนกับไดเร็กทอรีที่เรียกใช้งานได้โดยเกิดขึ้น แต่อาจแตกต่างกันโดยสิ้นเชิง
Lassi

-10

เส้นทางค่าสัมบูรณ์ของโปรแกรมอยู่ใน PWD ของ envp ของฟังก์ชั่นหลักของคุณนอกจากนี้ยังมีฟังก์ชั่นใน C ที่เรียกว่า getenv ดังนั้นจึงมี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.