tìm kiếm PATH bao gồm các liên kết tượng trưng?


9

Tiêu chuẩn vỏ POSIX cho biết trên trang web này

http://pub.opengroup.org/onlinepub/9699919799/

về cách shell sử dụng PATHđể tìm kiếm các tệp thực thi:

"Danh sách sẽ được tìm kiếm từ đầu đến cuối, áp dụng tên tệp cho từng tiền tố, cho đến khi tìm thấy tệp thực thi có tên được chỉ định và quyền thực thi phù hợp."

Chà, đây không phải là cách nó hoạt động trong triển khai POSIX thực sự:

man which nói:

"trả về tên đường dẫn của các tệp (hoặc liên kết) sẽ được thực thi trong môi trường hiện tại, các đối số của nó được đưa ra dưới dạng các lệnh trong trình bao tuân thủ POSIX nghiêm ngặt. Nó thực hiện điều này bằng cách tìm kiếm PATH để tìm các tệp thực thi khớp với tên của tệp đối số. Nó không theo các liên kết tượng trưng. "

OK, chúng ta hãy xem xét tình huống này:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar

OK, đây là một liên kết tượng trưng PATHvới tên chính xác và nó được báo cáo lslà có thể thực thi được.

which không nhìn vào nó chút nào, mà chỉ quan tâm đến những gì nó chỉ vào.

Điều đó mặc dù thực tế là cả hai đều man whichnói rõ ràng rằng nó không tuân theo các liên kết tượng trưng (và thực tế chúng ta thấy nó không, bởi vì which foobarkhông in foobar1), và tài liệu shell POSIX được trích dẫn ở trên, không bao giờ đề cập đến các liên kết tượng trưng trong PATHthuật toán.

Vì vậy, là whichvà các shell hiện có sai, hoặc tôi không hiểu tài liệu?

LÀM RÕ:

Tôi biết và có thể giải thích các hành vi hiện có. Câu hỏi của tôi không phải là "làm thế nào để làm việc này?". Điều đó tôi biết.

Câu hỏi của tôi là về tài liệu: lỗi của tôi ở đâu trong việc làm theo tài liệu mà tôi đã trích dẫn. Hoặc là tài liệu sai?

ĐỘNG LỰC: Tại sao tôi quan tâm?

Vâng, tôi là một người thực hiện. Người thực hiện khác nhau có yêu cầu khác nhau. Đối với tôi, yêu cầu là từ của tiêu chuẩn POSIX hiện tại PHẢI được tuân theo CHÍNH XÁC (hay chính xác hơn là tốt nhất có thể, bởi vì, bản thân tiêu chuẩn có phần lỗi). Giống như đó là lời của Thiên Chúa.

Bây giờ, từ ngữ tiêu chuẩn là khá rõ ràng - sau đây các liên kết tượng trưng không được đề cập, trong đó ở nhiều nơi khác, nó được đề cập đến nơi cần phải được thực hiện. Vì vậy, trong trường hợp này, không.

Tuy nhiên, tôi luôn kiểm tra lại cách cư xử dashbashhành xử, chỉ để đảm bảo. Bây giờ tất nhiên, có một vấn đề nhỏ ở đây, dashmặc dù nó được lập hóa đơn là POSIX, có rất nhiều lỗi nhỏ phù hợp với POSIX. bash, Tôi vẫn chưa tìm thấy bất kỳ lỗi nào với POSIX, nhưng ... bash không thực sự là POSIX, nó còn hơn thế nữa.

Vì vậy, có bạn có nó. Đó là lý do tại sao tôi quan tâm.


Bạn không hiểu: không theo liên kết tượng trưng trên tệp . $PATHcó thể chứa liên kết tượng trưng. Hãy thử which sh.
Ipor Sircer

OK, nhưng trong trường hợp của tôi $PATHkhông có bất kỳ liên kết tượng trưng nào.
322908

Trong hầu hết tất cả các tình huống, symlink được theo dõi một cách minh bạch. Các trường hợp chúng thường không được đề cập rõ ràng (ví dụ như các cuộc gọi hệ thống lstat(2)), theo sau chúng thường không được nêu. Ví dụ, mô tả open(2)chỉ đề cập đến các liên kết tượng trưng khi nói về hành vi của O_CREAT | O_EXCL. Không cần phải nói rằng tệp mục tiêu sẽ được mở.
Barmar

Câu trả lời:


10

Các quyền của symlink là không liên quan. Bạn thậm chí không thể thay đổi chúng nếu bạn đã cố gắng.

Vấn đề là quyền của tập tin cơ bản.

Sẽ rất tốt nếu có các thư mục trong PATH của bạn bao gồm các liên kết tượng trưng đến các tệp thực thi. Trên thực tế, có khả năng nhiều tệp thực thi trong PATH của bạn là các liên kết tượng trưng. Ví dụ: trên các hệ thống giống như debian / ubfox:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash

Tài liệu

Từ man chmod:

chmod không bao giờ thay đổi quyền của các liên kết tượng trưng; cuộc gọi hệ thống chmod không thể thay đổi quyền của họ. Đây không phải là một vấn đề vì quyền của các liên kết tượng trưng không bao giờ được sử dụng. Tuy nhiên, đối với mỗi liên kết tượng trưng được liệt kê trên dòng lệnh, chmod thay đổi quyền của tệp được trỏ. Ngược lại, chmod bỏ qua các liên kết tượng trưng gặp phải trong quá trình duyệt thư mục đệ quy. [Nhấn mạnh thêm.]

Thí dụ

Shell có một bài kiểm tra -x, để xác định xem một tập tin có thể thực thi được không. Hãy thử xem:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable

Vì vậy, giống như bạn đã tìm thấy which, shell không xem xét một liên kết mềm có thể thực thi được trừ khi tệp bên dưới có thể thực thi được.

Cách thức hoạt động

Trên hệ thống Debian, whichlà tập lệnh shell. Phần có liên quan của mã là:

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac

Như bạn có thể thấy, nó sử dụng -xthử nghiệm để xác định một tệp có thể thực thi được không.

POSIX chỉ định -xthử nghiệm như sau:

Tên đường dẫn -x
Đúng nếu tên đường dẫn phân giải thành một mục nhập thư mục hiện có cho một tệp cho phép thực thi tệp (hoặc tìm kiếm nó, nếu đó là một thư mục) sẽ được cấp, như được định nghĩa trong Đọc, ghi và tạo tệp. Sai nếu tên đường dẫn không thể được giải quyết hoặc nếu tên đường dẫn phân giải thành mục nhập thư mục hiện có cho một tệp cho phép thực thi (hoặc tìm kiếm) thì tệp sẽ không được cấp. [Nhấn mạnh thêm.]

Vì vậy, POSIX kiểm tra tên đường dẫn giải quyết . Nói cách khác, nó chấp nhận liên kết tượng trưng.

Chức năng thực thi POSIX

Hàm thực thi POSIX theo các liên kết tượng trưng. Thông số POSIX tiếp tục kéo dài để chỉ định các điều kiện lỗi mà nó có thể báo cáo nếu các liên kết tượng trưng là hình tròn hoặc quá sâu, chẳng hạn như:

[ELOOP]
Một vòng lặp tồn tại trong các liên kết tượng trưng gặp phải trong quá trình giải quyết đối số đường dẫn hoặc tệp.

[ELOOP] Đã gặp
hơn nhiều liên kết tượng trưng {SYMLOOP_MAX} trong quá trình giải quyết đường dẫn hoặc đối số tệp.
[ENAMETOOLONG]
Do gặp phải một liên kết tượng trưng để giải quyết đối số đường dẫn, độ dài của chuỗi tên đường dẫn được thay thế đã vượt quá {PATH_MAX}.


Tôi BIẾT tất cả những gì bạn viết trong câu trả lời của bạn. Tôi biết mọi thứ "hoạt động" như thế nào. Đó không phải là câu hỏi của tôi. Câu hỏi của tôi là về tài liệu. Chỉ cho tôi nơi tôi không hiểu tài liệu. Hoặc cho tôi biết rằng các tài liệu là không chính xác.
322908

@ user322908 Trên hầu hết các hệ thống, whichlà tập lệnh shell. Vì vậy, nó có khả năng chỉ sử dụng -xthử nghiệm mà tôi đã cho thấy. Theo POSIX, -xkiểm tra xem một tệp "giải quyết" thành tệp thực thi hay không. Nếu bạn đang nhìn thấy một cái gì đó khác nhau, bạn đang tìm kiếm ở đâu?
John1024

Cảm ơn bạn và tôi xin lỗi vì đã là một nỗi đau như vậy ... Tôi nhận ra rằng câu hỏi của tôi khác với 99% câu hỏi nên thật khó để hiểu tôi là gì sau đó. Một lần nữa, tôi không quan tâm đến "cách thức" whichhoạt động, hoặc liệu nó là -xhay cái gì khác. Tôi quan tâm để biết nơi tôi không theo dõi chính xác các tài liệu mà tôi trích dẫn.
322908

4
@ user322908 Các POSIX execchức năng sau liên kết tượng trưng. Điều đó dường như làm rõ rằng các tệp được liên kết có thể được thực thi trong POSIX.
John1024

2
Tôi cũng đã kiểm tra Ubuntu 17.10 man which có nội dung "Nó không hợp quy hóa tên đường dẫn." Điều đó không có nghĩa là nó không theo các liên kết. Điều đó chỉ có nghĩa, như bạn đã quan sát, rằng nó không "hợp quy hóa" tên.
John1024

3

Trong trường hợp này, các liên kết tượng trưng được theo dõi trong suốt, mà không cần chuẩn hóa đường dẫn cuối cùng. Nói cách khác, whichkhông quan tâm đến việc có phải /home/mark/binlà một liên kết tượng trưng hay không. Những gì nó quan tâm là liệu các tập tin /home/mark/bin/foobartồn tại hay không. Không cần phải làm phẳng các liên kết tượng trưng theo cách thủ công - HĐH có thể tự làm điều đó tốt.

Và thực tế, khi whichhỏi về thông tin tệp /home/mark/bin/foobar, HĐH thông báo /home/mark/binlà một liên kết tượng trưng, ​​theo dõi nó và tìm thấy thành công foobartrong thư mục đích.

Đây là hành vi mặc định trừ khi chương trình sử dụng open(…, O_NOFOLLOW)hoặc fstatat(…, AT_SYMLINK_NOFOLLOW)truy cập tệp.

[ý kiến ​​hợp nhất trong]

Mặc dù bạn nói rằng các tiện ích shell thực hiện trên cơ sở từng trường hợp cụ thể, nhưng nó không giống với các tòa nhà hạt nhân: tất cả các cuộc gọi liên quan đến tệp đều theo các liên kết theo mặc định, trừ khi cờ "nofollow" được đưa ra. (Ngay cả lstat cũng theo các liên kết tượng trưng trong tất cả các thành phần đường dẫn ngoại trừ thành phần cuối cùng.)

Khi đặc tả không đề cập rõ ràng phải làm gì với symlink, nó ngụ ý hành vi mặc định sẽ được sử dụng. Đó là, một shell theo thuật toán đường dẫn neithers giải quyết các liên kết tượng trưng theo cách thủ công cũng như không rõ ràng từ chối hệ điều hành làm điều tương tự. (Nó chỉ ghép từng thành phần $ PATH với tên thực thi.)

Khi trang hướng dẫn (1) nói rằng nó không tuân theo các liên kết tượng trưng, ​​nó có thể có nghĩa là một số điều, nhưng phiên bản GNU coreutils nói theo cách này:

Điều này sẽ coi hai thư mục tương đương là khác nhau khi một trong số chúng chứa một đường dẫn có liên kết tượng trưng.

Đó là phạm vi hẹp hơn nhiều - điều đó chỉ có nghĩa là whichsẽ không cố gắng chuẩn hóa thủ công tất cả các đường dẫn để loại bỏ các bản sao, nhưng điều đó không có nghĩa là công cụ sẽ từ chối hệ thống symlink theo hệ điều hành nói chung. Ví dụ: nếu /binlà một liên kết tượng trưng /usr/bin, chạy which -a shsẽ trả về cả hai /bin/sh/usr/bin/sh.


Vâng cảm ơn bạn, tôi biết tất cả những điều này. Câu hỏi của tôi không phải là cách mọi thứ "hoạt động". Tôi biết làm thế nào họ làm việc. Đó không phải là quan điểm của tôi. Quan điểm của tôi là về tài liệu. Tôi đang theo dõi tài liệu không chính xác ở đâu. Hoặc là tài liệu không chính xác.
322908

2
Bạn đang hiểu tài liệu không chính xác - nếu nó không đề cập đến các liên kết sau, điều đó có nghĩa là nó không giải quyết thủ công các liên kết tượng trưng, ​​nhưng hành vi hệ điều hành thông thường vẫn được áp dụng. whichTrang hướng dẫn GNU nêu nó khác nhau: "Điều này sẽ coi hai thư mục tương đương là khác nhau khi một trong số chúng chứa một đường dẫn có liên kết tượng trưng."
grawity

OK, đó là tốt hơn cảm ơn bạn! Tôi đang cố gắng để hiểu ... Nhưng ... xin lỗi vì tôi là một kẻ đau cổ: "hành vi hệ điều hành thông thường" KHÔNG phải luôn luôn tuân theo các liên kết tượng trưng. Có rất nhiều tiện ích không. Đó là trên cơ sở từng trường hợp.
322908

1
Tất cả các lệnh gọi kernel - chdir, open, chmod, execve ... - sẽ theo các liên kết tượng trưng cả trong đường dẫn và đuôi, trừ khi bạn chỉ định AT_SYMLINK_NOFOLLOW hoặc tương tự. (lstat là người duy nhất không có các liên kết tượng trưng ở đuôi, nhưng vẫn làm như vậy đối với đường dẫn còn lại.) Do đó, hành vi mặc định là tuân theo các liên kết tượng trưng. Ví dụ, khi shell gọi execve("/home/mark/bin/foobar", …)nó sẽ dẫn đến tất cả các liên kết tượng trưng được theo dõi.
grawity

OK Tôi nghĩ rằng tôi đang mua execveđối số, thực sự, trong quá trình thực hiện của tôi execl(), điều tương tự. Xin vui lòng nếu bạn bao gồm điều này trong câu trả lời của bạn, tôi sẽ chấp nhận.
322908

1

Shell phù hợp với tài liệu của nó ở chỗ nó tuân theo các quy tắc cho độ phân giải tên đường dẫn. whichphù hợp với tài liệu của nó. Hai người làm những việc hơi khác nhau.

Đầu ra của whichlà tên tệp và đường dẫn của liên kết, không phải là đường dẫn đến những gì liên kết tượng trưng trỏ đến. Điều này được đánh vần trong trang người đàn ông.

Khi một lệnh được thực thi, liên kết được "theo dõi" theo Phần 4.13 Độ phân giải tên đường dẫn trong cùng . Điều khoản liên quan để thực thi một tập tin là:

Trong tất cả các trường hợp khác, hệ thống sẽ đặt tiền tố cho tên đường dẫn còn lại, nếu có, với nội dung của liên kết tượng trưng, ​​ngoại trừ nếu nội dung của liên kết tượng trưng là chuỗi trống, thì độ phân giải tên đường dẫn sẽ không thành công với các hàm báo cáo [ENOENT ] lỗi và tiện ích viết một thông báo chẩn đoán tương đương hoặc tên đường dẫn của thư mục chứa liên kết tượng trưng sẽ được sử dụng thay cho nội dung của liên kết tượng trưng. Nếu nội dung của liên kết tượng trưng chỉ bao gồm các ký tự, thì tất cả các ký tự đầu của tên đường dẫn còn lại sẽ bị bỏ qua khỏi tên đường dẫn kết hợp kết quả, chỉ để lại các ký tự đầu từ nội dung liên kết tượng trưng. Trong trường hợp xảy ra tiền tố, nếu độ dài kết hợp vượt quá {PATH_MAX} và việc triển khai coi đây là một lỗi, giải quyết tên đường dẫn sẽ không thành công với các chức năng báo cáo lỗi [ENAMETOOLONG] và các tiện ích viết một thông báo chẩn đoán tương đương. Nếu không, tên đường dẫn được giải quyết sẽ là độ phân giải của tên đường dẫn vừa tạo. Nếu tên đường dẫn kết quả không bắt đầu bằng a, tiền thân của tên tệp đầu tiên của tên đường dẫn được lấy là thư mục chứa liên kết tượng trưng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.