Bagaimana cara mengeklik perangkat blok di Linux?

4

Saya mencoba untuk mendapatkan 1024 byte terakhir dari / dev / sda2. Ketika saya melakukannya sudo tail -c 1024 /dev/sda2 | hd, prompt hanya hang sampai saya menekan Ctrl-C. Namun, ketika saya tail -c 1024 ddfilecopyofsda2 | hd, saya langsung mendapatkan output yang bagus dari 1024 byte terakhir dari file. Saya baca di sini ( https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system ) bahwa "Perangkat blok biasanya dicari, "Jadi, apa yang saya lewatkan?

clearcom0
sumber

Jawaban:

8

Inilah salah satu cara untuk mendapatkan 1024 byte terakhir dari perangkat blok:

last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE

Ganti DEVICEdengan jalur perangkat. Dalam kasus Anda, Anda akan menggunakannya /dev/sda2.


Sekarang untuk pertanyaan yang lebih menarik untuk dijawab ...

Mengapa tail -c 1024 /dev/sda2mencari seluruh disk?

Alasannya bagaimana tailpenerapannya. Ketika tailtahu ukuran file yang dibacanya, ia tahu persis berapa banyak yang harus dicari. Kalau tidak, ia harus membaca file atau streaming sepanjang jalan untuk mengetahui seberapa jauh untuk menghitung mundur.

Dengan pipa, masuk akal, seperti cat /dev/sda2 | tail -c 1024. tailmenerima konten sebagai aliran dan tidak memiliki cara untuk mengetahui kapan data akan berakhir.

Anda mungkin berharap tail -c 1024 /dev/sda2dapat mengetahui ukuran /dev/sda2, tetapi sebenarnya, ketika tailmelihat ke atas /dev/sda2, itu dibuka sebagai perangkat blok bukan file biasa.

Detail implementasi adalah tailpanggilan fstat()untuk mendapatkan informasi tentang file.

tail pada file biasa

Inilah bagian yang relevan stracedari contoh tailmembuka file:

21:30:27 open("/var/log/syslog", O_RDONLY) = 3
21:30:27 fstat(3, {st_dev=makedev(0, 22), st_ino=4715, st_mode=S_IFREG|0640, st_nlink=1, st_uid=104, st_gid=4, st_blksize=131072, st_blocks=54, st_size=175500, st_atime=2017/11/10-21:28:39.243133398, st_mtime=2017/11/10-21:30:20.438031639, st_ctime=2017/11/10-21:30:20.438031639}) = 0
21:30:27 lseek(3, 0, SEEK_CUR)          = 0
21:30:27 lseek(3, 174476, SEEK_SET)     = 174476

fstat()menyediakan st_size=175500. Sekarang tailhanya perlu menghitung mundur 1024 byte:

175500 - 1024 = 174476

... dan inilah tepatnya yang taildilakukannya:

lseek(3, 174476, SEEK_SET)     = 174476

tail pada perangkat blok

fstat() tidak mengembalikan ukuran saat ini !:

21:29:43 open("/dev/sda", O_RDONLY)     = 3
21:29:43 fstat(3, {st_dev=makedev(0, 6), st_ino=17488, st_mode=S_IFBLK|0660, st_nlink=1, st_uid=0, st_gid=6, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2017/11/10-09:21:15.643998960, st_mtime=2017/11/10-09:21:15.555998962, st_ctime=2017/11/10-09:21:15.555998962}) = 0

Tanpa st_size, tailtidak dapat mengetahui sejauh mana pencarian, sehingga default untuk membaca seluruh perangkat blok hingga akhir.

Inilah sebabnya mengapa Anda umumnya harus menggunakan alat blok perangkat suka ddmemanipulasi perangkat blok daripada alat yang ditujukan untuk file biasa seperti tail.


Anda mungkin bertanya, "Seberapa blockdev --getsize64cepat mendapatkan ukuran perangkat blok?"

Inilah sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda:

21:53:15 open("/dev/sda", O_RDONLY)     = 3
21:53:15 ioctl(3, BLKGETSIZE64, [512110190592]) = 0

blockdevdimaksudkan untuk mendapatkan perangkat blok ioctls, dan BLKGETSIZE64mendapatkan ukuran perangkat blok.


Adapun mengapa tail tidak melakukannya BLKGETSIZE64, saya tidak tahu. The kode sumber menunjukkan:

#define IS_TAILABLE_FILE_TYPE(Mode) \
  (S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode))

Saya hanya tahu dari baris itu bahwa tanpa S_ISBLK(), penulis tidak bermaksud tailmendukung perangkat blok.

Deltik
sumber
2
Saya berharap saya dapat menjawab jawaban ini sekitar 5 kali! Terima kasih atas penjelasan yang terperinci!
clearcom0
1
Catatan GNU dd sejak 8.16 (2012-03-26) mendukung iflag=skip_bytesopsi. Ini memungkinkan seseorang untuk secara efisien melewati bagian input sembarang sembarang independen dari ukuran blok yang digunakan untuk I / O. Orang sering ingin menggunakan besar bsuntuk efisiensi.
pixelbeat
Terima kasih @pixelbeat! Saya telah memperbarui jawaban saya untuk digunakan dd iflag=skip_bytessebagai gantinya.
Deltik