কিছু শেল `রিড` বিল্টইন` / প্রোকো-তে ফাইল থেকে পুরো লাইনটি পড়তে ব্যর্থ হয় কেন?


19

কিছু বোর্ন মত শেল, readbuiltin ফাইল থেকে পুরো লাইন পড়তে পারে না /proc(কমান্ড নিচে চালানো হবে zsh, প্রতিস্থাপন $=shellসঙ্গে $shellঅন্যান্য শাঁস সহ):

$ for shell in bash dash ksh mksh yash zsh schily-sh heirloom-sh "busybox sh"; do
  printf '[%s]\n' "$shell"
  $=shell -c 'IFS= read x </proc/sys/fs/file-max; echo "$x"'       
done
[bash]
602160
[dash]
6
[ksh]
602160
[mksh]
6
[yash]
6
[zsh]
6
[schily-sh]
602160
[heirloom-sh]
602160
[busybox sh]
6

readস্ট্যান্ডার্ডটির জন্য স্ট্যান্ডার্ড ইনপুটটিকে একটি পাঠ্য ফাইল হওয়া দরকার , সেই প্রয়োজনীয়তাটি কি বিচিত্র আচরণের কারণ হয়?


পাঠ্য ফাইলটির পসিক্স সংজ্ঞাটি পড়ুন , আমি কিছু যাচাইকরণ করছি:

$ od -t a </proc/sys/fs/file-max 
0000000   6   0   2   1   6   0  nl
0000007

$ find /proc/sys/fs -type f -name 'file-max'
/proc/sys/fs/file-max

এর NULসামগ্রীতে কোনও চরিত্র নেই /proc/sys/fs/file-maxএবং findএটি নিয়মিত ফাইল হিসাবে রিপোর্ট করেছেন (এটি কি কোনও বাগ ইন find?)।

আমার ধারণা শেলটি হুডের নীচে কিছু করেছিল, যেমন file:

$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty

উত্তর:


31

সমস্যাটি হ'ল /procলিনাক্সের এই ফাইলগুলি পাঠ্য ফাইল হিসাবে উপস্থিত হিসাবে দেখা দেয় stat()/fstat(), তবে এর মতো আচরণ করে না।

এটি গতিশীল ডেটা read()হওয়ায় আপনি কেবলমাত্র তাদের কাছে একটি সিস্টেমে কল করতে পারেন (তাদের মধ্যে কয়েকটির জন্য অন্তত)। একাধিক কাজ করার ফলে আপনি দুটি পৃথক বিষয়বস্তুর দুটি অংশ পেতে পারেন, সুতরাং পরিবর্তে read()তাদের কাছে এটি দ্বিতীয় বলে মনে হয় কেবল কিছুই প্রত্যাবর্তন করে না (অর্থাত্ ফাইল-এর অর্থ শেষ) (যদি না আপনি lseek()শুরুতে ফিরে যান (এবং কেবলমাত্র শুরুতে))।

readউপযোগ গত newline অক্ষর পড়া নিশ্চিত হতে না একটি সময়ে এক বাইট ফাইল সামগ্রী পড়তে হবে। এটি কি dashকরে:

 $ strace -fe read dash -c 'read a < /proc/sys/fs/file-max'
 read(0, "1", 1)                         = 1
 read(0, "", 1)                          = 0

কিছু শেলের মতো bashঅনেকগুলি read()সিস্টেমে কল করা এড়াতে অপ্টিমাইজেশন থাকে । তারা প্রথমে ফাইলটি সন্ধানযোগ্য কিনা তা পরীক্ষা করে দেখেছে এবং যদি তা হয়, তবে তারা জানে যে তারা কার্সারটিকে নতুন লাইনের পরে রেখে দিতে পারে যদি তারা এটি পড়ে থাকে তবে:

$ strace -e lseek,read bash -c 'read a' < /proc/sys/fs/file-max
lseek(0, 0, SEEK_CUR)                   = 0
read(0, "1628689\n", 128)               = 8

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

bash-dবিকল্পটি যখন ব্যবহৃত হয় তখন সেই অপ্টিমাইজেশনটি অক্ষম করে ।

ksh93জালিয়াতি হয়ে ওঠার জন্য আরও অনেক বেশি গ্রহণ করে। ksh93 এর readপিছনে সন্ধান করে না, তবে পরবর্তীটির জন্য পড়া অতিরিক্ত ডেটা মনে রাখে read, সুতরাং পরবর্তী read(বা এর অন্যান্য বিল্টিনগুলির মধ্যে যেগুলি ডেটা পড়বে catবা এর মতো headকরে) এমনকি readডেটা চেষ্টা করে না (এমনকি যদি সেই ডেটা দ্বারা সংশোধন করা হয় তবেও এর মধ্যে অন্যান্য কমান্ড):

$ seq 10 > a; ksh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 2
$ seq 10 > a; sh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 st

আহ্ হ্যাঁ, একটি straceভিত্তিক ব্যাখ্যাটি বোঝা অনেক সহজ!
স্টিফেন কিট

ধন্যবাদ, গতিশীল ডেটা বোধগম্য। তাহলে শেলটি কীভাবে এটি গতিশীল ডেটা সনাক্ত করে? আমি যদি করি cat /proc/sys/fs/file-max | ..., সমস্যাটি চলে গেল।
cuonglm

3
শেল এটি সনাক্ত করে না। এটি গতিশীল ডেটার অর্থ এই যে একই ফাইলটিতে procfsএকাধিক পরপর read(2)কলগুলি পরিচালনা করতে পারে না ; আচরণ শেলের উপর নির্ভর করে না। ব্যবহার catএবং পাইপ কাজ করে কারণ catফাইলটি যথেষ্ট পরিমাণে পড়ে; শেলের readবিল্ট-ইন পরে পাইপ থেকে একবারে একটি অক্ষর পড়ে।
স্টিফেন কিট

1
কিছুটা নোংরা কাজ আছে mkshread -N 10 a < /proc/sys/fs/file-max
ইপোর স্যারসার

1
@IporSircer। প্রকৃতপক্ষে. অনুরূপ একটি কাজ প্রায় নিয়ে কাজ করতেছেন zsh: read -u0 -k10(অথবা ব্যবহার sysread; $mapfile[/proc/sys/fs/file-max]ঐ ফাইল হিসেবে কাজ হতে পারে না না mmapইডি)। যে কোনও ক্ষেত্রে, যে কোনও শেল সহ, সর্বদা এটি করতে পারে a=$(cat /proc/sys/fs/file-max)। কিছু সহ mksh, zshএবং ksh93, a=$(</proc/sys/fs/file-max)কাজ করে এবং পাঠটি করার জন্য কোনও প্রক্রিয়াও জোর করে না।
স্টাফেন চেজেলাস

9

আপনি যদি আগ্রহী হন তবে কেন জানবেন? এটি তাই, আপনি এখানে কার্নেল উত্সে উত্তরটি দেখতে পারেন :

    if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
            *lenp = 0;
            return 0;
    }

মূলত, ( *ppos0 নয় !write) সন্ধান করা সাইক্লিটল মানগুলির সংখ্যা ( ) পড়ার জন্য প্রয়োগ করা হয় না । যখনই কোনও পাঠ করা হয় /proc/sys/fs/file-max, একই ফাইলে কনফিগারেশন টেবিলের__do_proc_doulongvec_minmax() জন্য প্রবেশের সময় থেকে রুটিনকে জিজ্ঞাসা করা হয় ।file-max

অন্যান্য এন্ট্রি, যেমন /proc/sys/kernel/poweroff_cmdপ্রয়োগ করা হয় proc_dostring()যার মাধ্যমে অনুসন্ধানের অনুমতি দেয় না, তাই আপনি dd bs=1এটি করতে পারেন এবং কোনও সমস্যা ছাড়াই আপনার শেল থেকে পড়তে পারেন।

নোট করুন যেহেতু কার্নেল ২.6 সর্বাধিক পঠনগুলি seq_file/proc নামে একটি নতুন এপিআইয়ের মাধ্যমে প্রয়োগ করা হয়েছিল এবং এটি সিক্সকে সমর্থন করে যাতে উদাহরণস্বরূপ পড়ার /proc/statফলে সমস্যা না হয়। /proc/sys/বাস্তবায়ন, যেমন আমরা দেখতে পারি, এই API ব্যবহার করে না।


3

প্রথম প্রয়াসে, এটি শেলগুলির মধ্যে একটি বাগের মতো দেখতে পাওয়া যায় যা সত্য বোর্ন শেল বা এর ডেরিভেটিভস রিটার্নের চেয়ে কম (শ, বোশ, কেএস, উত্তরাধিকারী) ফিরে আসে।

আসল বোর্ন শেল একটি নতুন ব্লক (by৪ বাইট) পড়ার চেষ্টা করে নতুন বোর্ন শেল ভেরিয়েন্টগুলি 128 বাইট পড়ে, তবে নতুন লাইনের চরিত্র না থাকলে তারা আবার পড়া শুরু করে।

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

প্রদত্ত যে পসিক্স স্ট্যান্ডার্ডের জন্য যে কোনও সময়ে সংক্ষিপ্ত পাঠের আশা করার জন্য ইউটিলিটিগুলি প্রয়োজন , এমন সফ্টওয়্যার যা বিশ্বাস করে যে অর্ডার করা পরিমাণ বাইটের read()চেয়ে কম ফেরত পাওয়া একটি ইওএফ ইঙ্গিতটি ভেঙে গেছে। একটি সঠিকভাবে প্রয়োগ করা ইউটিলিটি দ্বিতীয়বার কল করে যে এটি প্রত্যাশার চেয়ে কম ফেরত দেয় - যতক্ষণ না 0 প্রত্যাবর্তিত হয়। অন্তর্নির্মিত ক্ষেত্রে, অবশ্যই এটি পড়া না হওয়া অবধি বা পড়া না হওয়া পর্যন্ত যথেষ্ট ।read()readEOF NL

যদি আপনি চালনা করেন trussবা ট্রস ক্লোন 6করেন তবে আপনার শেলগুলির জন্য সেই ভুল আচরণটি যা কেবলমাত্র আপনার পরীক্ষায় ফিরে আসে তা যাচাই করতে সক্ষম হওয়া উচিত ।

এই বিশেষ ক্ষেত্রে এটি একটি লিনাক্স কার্নেল বাগ হিসাবে মনে হচ্ছে, দেখুন:

$ sdd -debug bs=1 if= /proc/sys/fs/file-max 
Simple copy ...
readbuf  (3, 12AC000, 1) = 1
writebuf (1, 12AC000, 1)
8readbuf  (3, 12AC000, 1) = 0

sdd: Read  1 records + 0 bytes (total of 1 bytes = 0.00k).
sdd: Wrote 1 records + 0 bytes (total of 1 bytes = 0.00k).

লিনাক্স কার্নেল দ্বিতীয়টি দিয়ে 0 প্রদান করে readএবং এটি অবশ্যই ভুল।

উপসংহার: শেলগুলি যেগুলি প্রথমে প্রচুর পরিমাণে ডেটা পড়ার চেষ্টা করে এই লিনাক্স কার্নেল বাগটি ট্রিগার করে না।


ঠিক আছে, একটি লিনাক্স কার্নেল বাগের জন্য একটি নতুন যাচাইকরণের সাথে উত্তর থেকে বেরিয়ে এসেছেন।
সহজেই

এটি কোনও বাগ নয়, এটি একটি বৈশিষ্ট্য!
গুন্ট্রাম ব্লহম

এটি সত্যিই এক অদ্ভুত দাবি।
শীঘ্রই

এটি নথিভুক্ত করা হলে এটি একটি বৈশিষ্ট্য হবে। কার্নেল.আর / ডক / ডকুমেন্টেশন / ফাইলস সিস্টেম / প্রোক.টিএসটি পড়া , আমি আচরণের জন্য কোনও ডকুমেন্টেশন দেখছি না। এটি বলেছে, এটি বাস্তবায়িতভাবে-বাস্তবায়িতভাবে-ই-ইচ্ছাকৃতভাবে কাজ করছে, সুতরাং এটি যদি বাগ হিসাবে বিবেচনা করা হয় তবে এটি ডিজাইনের ক্ষেত্রে বাগ, বাস্তবায়ন নয়।
চার্লস ডাফি

0

/ Proc এর অধীনে থাকা ফাইলগুলি কখনও কখনও ফাইলের অভ্যন্তরে পৃথক ক্ষেত্রগুলি পৃথক করতে NULL অক্ষর ব্যবহার করে। দেখে মনে হচ্ছে পঠন এটি হ্যান্ডেল করতে সক্ষম নয়।

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