การใช้งาน/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 () แทนได้ อย่างไรก็ตามเป็นไปได้ว่าอาจพบโปรแกรมที่ไม่สามารถเข้าถึงได้ก่อนหน้านี้บนเส้นทางที่ผู้ใช้จริงสามารถทำได้