Buat data acak dengan dd dan dapatkan "peringatan baca sebagian". Apakah data setelah peringatan sekarang benar-benar acak?

16

Saya membuat file 1TB dengan data acak dd if=/dev/urandom of=file bs=1M count=1000000. Sekarang saya memeriksa kill -SIGUSR1 <PID>perkembangannya dan mendapatkan yang berikut:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

Saya tidak bisa menafsirkan peringatan itu. Apa yang dikatakan? Apakah file saya benar-benar acak setelah peringatan atau ada masalah? Apa artinya +0 atau +1 800950+1 Datensätze eindan 800950+0 Datensätze ausartinya? Setelah peringatan itu +1. Apakah ini jumlah kesalahan?

menghapus
sumber
Ini akan lebih mudah dijawab jika Anda bisa menerjemahkan pesan ke dalam bahasa Inggris. Juga, tentukan "sangat acak". Tingkat keacakan apa yang Anda butuhkan, untuk apa Anda menggunakannya?
terdon
Untuk mendapatkan pesan bahasa Inggris, gunakan LC_ALL=Cdi depan perintah, sepertiLC_ALL=C dd if=...
Volker Siegel

Jawaban:

38

Ringkasan: ddadalah alat rewel yang sulit digunakan dengan benar. Jangan gunakan itu, meskipun banyak tutorial yang memberitahu Anda begitu. ddmemiliki getaran "unix street cred" yang melekat padanya - tetapi jika Anda benar-benar memahami apa yang Anda lakukan, Anda akan tahu bahwa Anda tidak boleh menyentuhnya dengan tiang 10 kaki.

ddmelakukan satu panggilan ke panggilan readsistem per blok (ditentukan oleh nilai bs). Tidak ada jaminan bahwa readpanggilan sistem mengembalikan data sebanyak ukuran buffer yang ditentukan. Ini cenderung berfungsi untuk file biasa dan memblokir perangkat, tetapi tidak untuk pipa dan beberapa perangkat karakter. Lihat Kapan dd cocok untuk menyalin data? (atau, ketika dibaca () dan tulis () parsial) untuk informasi lebih lanjut. Jika readpanggilan sistem mengembalikan kurang dari satu blok penuh, maka ddtransfer sebagian blok. Masih menyalin jumlah blok yang ditentukan, sehingga jumlah total byte yang ditransfer kurang dari yang diminta.

Peringatan tentang "pembacaan parsial" memberi tahu Anda hal ini dengan tepat: salah satu bacaannya parsial, jadi ddmentransfer blok yang tidak lengkap. Dalam jumlah blok, +1berarti satu blok dibaca sebagian; karena jumlah outputnya adalah +0, semua blok ditulis sebagai telah dibaca.

Ini tidak mempengaruhi keacakan data: semua byte yang ddmenulis adalah byte yang dibaca /dev/urandom. Tetapi Anda mendapat byte lebih sedikit dari yang diharapkan.

Linux /dev/urandommengakomodasi permintaan besar yang sewenang-wenang (sumber: extract_entropy_userdalam drivers/char/random.c), jadi ddbiasanya aman saat membacanya. Namun, membaca data dalam jumlah besar membutuhkan waktu. Jika proses menerima sinyal, readpanggilan sistem kembali sebelum mengisi buffer outputnya. Ini adalah perilaku normal, dan aplikasi seharusnya memanggil readdalam satu lingkaran; ddtidak melakukan ini, karena alasan historis ( ddasal-usulnya suram, tetapi tampaknya telah dimulai sebagai alat untuk mengakses kaset, yang memiliki persyaratan khusus, dan tidak pernah diadaptasi menjadi alat tujuan umum). Saat Anda memeriksa progresnya, ini mengirimkan ddproses sinyal yang mengganggu pembacaan. Anda memiliki pilihan antara mengetahui berapa byteddakan menyalin secara total (pastikan untuk tidak menghentikannya - tidak ada pemeriksaan kemajuan, tidak ada penangguhan), atau mengetahui berapa banyak byte yang ddtelah disalin sejauh ini, dalam hal ini Anda tidak bisa tahu berapa banyak lagi byte yang akan disalin.

Versi dddalam GNU coreutils (seperti yang ditemukan pada Linux yang tidak tertanam dan pada Cygwin) memiliki bendera fullblockyang memberitahu dduntuk memanggil readdalam satu lingkaran (dan juga untuk write) dan dengan demikian selalu mentransfer blok penuh. Pesan kesalahan menyarankan agar Anda menggunakannya; Anda harus selalu menggunakannya (dalam flag input dan output), kecuali dalam keadaan yang sangat khusus (kebanyakan ketika mengakses kaset) - jika Anda menggunakan ddsemuanya, yaitu: biasanya ada solusi yang lebih baik (lihat di bawah).

dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000

Cara lain yang mungkin untuk memastikan apa yang ddakan dilakukan adalah dengan melewatkan ukuran blok 1. Kemudian Anda dapat mengetahui berapa banyak byte yang disalin dari jumlah blok, meskipun saya tidak yakin apa yang akan terjadi jika a readterganggu sebelum membaca yang pertama. byte (yang sangat tidak mungkin dalam praktek tetapi bisa terjadi). Namun, bahkan jika itu berhasil, ini sangat lambat.

Saran umum tentang penggunaan ddadalah jangan gunakandd . Meskipun ddsering diiklankan sebagai perintah tingkat rendah untuk mengakses perangkat, sebenarnya tidak ada hal seperti itu: semua keajaiban terjadi pada file perangkat (bagian /dev/…), ddhanyalah alat biasa dengan potensi penyalahgunaan yang tinggi yang mengakibatkan hilangnya data . Dalam kebanyakan kasus, ada cara yang lebih sederhana dan lebih aman untuk melakukan apa yang Anda inginkan, setidaknya di Linux.

Misalnya, untuk membaca sejumlah byte pada awal file, panggil saja head:

head -c 1000000m </dev/urandom >file

Saya membuat patokan cepat pada mesin saya dan tidak melihat perbedaan kinerja antara dddengan ukuran blok yang besar dan head.

Jika Anda perlu melewati beberapa byte di awal, pipa tailke head:

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

Jika Anda ingin melihat kemajuan, panggil lsofuntuk melihat offset file. Ini hanya berfungsi pada file biasa (file output pada contoh Anda), bukan pada perangkat karakter.

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

Anda dapat menelepon pvuntuk mendapatkan laporan kemajuan (lebih baik dari ddpada), dengan mengorbankan item tambahan di dalam pipa (dari sisi kinerja, hampir tidak terlihat).

Gilles 'SANGAT berhenti menjadi jahat'
sumber
2
+1. Ini adalah salah satu posting yang paling banyak diteliti yang pernah saya baca di jaringan StackExchange dalam waktu yang lama. Ini ringkas namun memuat semua detail (bersejarah dan masa kini) tentang ddperintah yang tidak saya sadari perlu saya ketahui. Terima kasih.
Cosmic Ossifrage
4
Saya minta maaf tapi saya tidak setuju dengan pernyataan Anda bahwa dd adalah "alat rewel yang sulit digunakan dengan benar" dan "jangan gunakan dd". Ini adalah utilitas yang sangat baik jika digunakan dengan benar oleh seseorang yang telah meluangkan waktu untuk memahaminya. Memang tool forensik disk hampir semua bergantung pada dd atau turunan seperti dcfldd.
fpmurphy
1
@ fpmurphy1 GNU dddapat digunakan dengan aman, berkat fullblockpilihannya. Tetapi jika Anda memiliki GNU coreutils, Anda tidak perlu ddbanyak. “Derivatif” seperti dcflddyang tidak dd , mereka tidak menderita cacat desain, jadi jawaban saya tidak berlaku untuk mereka. Mayoritas orang yang menggunakan ddbelum meluangkan waktu untuk memahaminya (paling banyak, mereka meluangkan waktu untuk berpikir bahwa mereka memahaminya) dan cara mereka menggunakannya menyebabkan hilangnya data.
Gilles 'SO- berhenti menjadi jahat'
1
@Gilles Jadi kita tidak boleh menggunakan "echo" b / c potensinya untuk disalahgunakan (sudo echo hello world> / dev / sda)?
whitey04
2
@ whitey04 Saya sarankan tidak menangani barel nitrogliserin. Saya tidak mengatakan bahwa Anda tidak harus menggunakan korek api.
Gilles 'SANGAT berhenti menjadi jahat'
9

Peringatan terjadi ketika ddtidak bisa mendapatkan data yang cukup untuk mengisi blok dalam sekali baca. Ini terjadi dengan sumber data yang tidak menentu atau lambat, atau sumber yang menulis data dalam unit yang lebih kecil dari ukuran blok yang Anda minta.

Tidak ada masalah dengan integritas data, tetapi masalahnya adalah bahwa ddsebagian membaca masih sebagai blok baca.

Jika Anda tidak menggunakan countopsi, peringatan itu tidak terlalu berarti, itu hanya pertimbangan kinerja. Tetapi dengan count, Anda tidak akan mendapatkan jumlah data yang Anda minta. Karena pembacaan parsial, ofakan lebih kecil dari count*bspada akhirnya.

Jadi ketika Anda menggunakan count, secara teknis Anda harus selalu menggunakannya iflag=fullblockjuga.

The +xharus jumlah blok parsial.

frostschutz
sumber
-3
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^ Itu hanya akan berhasil. Informasi yang keliru yang dinyatakan di sini secara nyata salah. ddBuffernya eksplisit dan untuk buffer input untuk menghitung kejadian Anda perlu buffer secara eksplisit. Itu semuanya. Jangan beli fud.

mikeserv
sumber