Crea dati casuali con dd e ricevi un "avviso di lettura parziale". I dati dopo l'avviso ora sono davvero casuali?


16

Creo un file da 1 TB con dati casuali con dd if=/dev/urandom of=file bs=1M count=1000000. Ora controllo kill -SIGUSR1 <PID>l'avanzamento e ottengo quanto segue:

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

Non riesco a interpretare l'avvertimento. Cosa dice? Il mio file è davvero casuale dopo l'avviso o c'è un problema? Cosa significa +0 o +1 in 800950+1 Datensätze eine 800950+0 Datensätze aussignifica? Dopo l'avviso è +1. È un conteggio errori?


Sarebbe più facile rispondere se potessi tradurre i messaggi in inglese. Inoltre, definisci "davvero casuale". Per quale livello di casualità hai bisogno, per quale motivo lo utilizzerai?
terdon

Per ricevere messaggi in inglese, usa LC_ALL=Cdavanti al comando, comeLC_ALL=C dd if=...
Volker Siegel,

Risposte:


38

Riepilogo: ddè uno strumento irritabile che è difficile da usare correttamente. Non usarlo, nonostante i numerosi tutorial che lo dicono. ddha un'atmosfera da “unix street cred”, ma se capisci veramente cosa stai facendo, saprai che non dovresti toccarlo con un palo da 10 piedi.

ddeffettua una singola chiamata alla chiamata di readsistema per blocco (definita dal valore di bs). Non vi è alcuna garanzia che la readchiamata di sistema restituisca tutti i dati della dimensione del buffer specificata. Questo tende a funzionare per file regolari e dispositivi a blocchi, ma non per pipe e alcuni dispositivi a caratteri. Vedi Quando dd è adatto alla copia dei dati? (o, quando sono read () e write () parziale) per ulteriori informazioni. Se la readchiamata di sistema restituisce meno di un blocco completo, quindi ddtrasferisce un blocco parziale. Copia ancora il numero specificato di blocchi, quindi la quantità totale di byte trasferiti è inferiore a quella richiesta.

L'avvertimento su una "lettura parziale" dice esattamente questo: una delle letture era parziale, quindi ddtrasferito un blocco incompleto. Nel conteggio dei blocchi, +1significa che un blocco è stato letto parzialmente; poiché il conteggio delle uscite è +0, tutti i blocchi sono stati scritti come letti.

Ciò non influisce sulla casualità dei dati: tutti i byte che vengono ddscritti sono byte da cui vengono letti /dev/urandom. Ma hai meno byte del previsto.

Linux /dev/urandomaccetta richieste arbitrarie di grandi dimensioni (fonte: extract_entropy_userin drivers/char/random.c), quindi ddè normalmente sicuro quando si legge da esso. Tuttavia, la lettura di grandi quantità di dati richiede tempo. Se il processo riceve un segnale, la readchiamata di sistema ritorna prima di riempire il buffer di output. Questo è un comportamento normale e le applicazioni dovrebbero chiamare readin un ciclo; ddnon lo fa, per ragioni storiche ( ddle origini sono oscure, ma sembra essere nato come uno strumento per accedere ai nastri, che hanno requisiti particolari, e non è mai stato adattato per essere uno strumento generico). Quando si controlla l'avanzamento, questo invia al ddprocesso un segnale che interrompe la lettura. Puoi scegliere tra sapere quanti byteddcopierà in totale (assicurati di non interromperlo - nessun controllo di avanzamento, nessuna sospensione), o sapendo quanti byte ddha copiato finora, nel qual caso non puoi sapere quanti più byte copierà.

La versione di ddin GNU coreutils (come si trova su Linux non incorporato e su Cygwin) ha un flag fullblockche dice dddi chiamare readin un ciclo (e idem per write) e quindi trasferire sempre blocchi completi. Il messaggio di errore suggerisce che lo usi; dovresti sempre usarlo (in entrambi i flag di input e output), tranne in circostanze molto speciali (soprattutto quando accedi ai nastri) - se lo usi ddaffatto, cioè: di solito ci sono soluzioni migliori (vedi sotto).

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

Un altro modo possibile per essere sicuri di cosa ddfarà è passare una dimensione del blocco di 1. Quindi puoi dire quanti byte sono stati copiati dal conteggio dei blocchi, anche se non sono sicuro di cosa accadrà se a readviene interrotto prima di leggere il primo byte (che non è molto probabile in pratica ma può accadere). Tuttavia, anche se funziona, è molto lento.

Il consiglio generale sull'uso ddè di non usaredd . Sebbene ddsia spesso pubblicizzato come un comando di basso livello per accedere ai dispositivi, in realtà non è una cosa del genere: tutta la magia accade nel file del dispositivo (la /dev/…) parte, ddè solo uno strumento normale con un alto potenziale di uso improprio con conseguente perdita di dati . Nella maggior parte dei casi, esiste un modo più semplice e sicuro di fare ciò che vuoi, almeno su Linux.

Ad esempio, per leggere un certo numero di byte all'inizio di un file, basta chiamare head:

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

Ho fatto un rapido benchmark sulla mia macchina e non ho osservato alcuna differenza di prestazioni tra ddcon un blocco di grandi dimensioni e head.

Se è necessario saltare alcuni byte all'inizio, eseguire il pipe tailin head:

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

Se vuoi vedere i progressi, chiama lsofper vedere l'offset del file. Funziona solo su un file normale (il file di output sul tuo esempio), non su un dispositivo a caratteri.

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

È possibile chiamare pvper ottenere un rapporto sullo stato di avanzamento (meglio di quello dd), a spese di un elemento aggiuntivo in cantiere (dal punto di vista delle prestazioni, è appena percettibile).


2
+1. Questo è uno dei post più ricercati che ho letto sulla rete StackExchange da molto tempo. È sintetico ma contiene tutti i dettagli (storici e attuali) sul ddcomando che non mi ero reso conto di dover conoscere. Grazie.
Cosmic Ossifrage

4
Mi dispiace ma non sono d'accordo con la tua affermazione che dd è uno "strumento irritabile che è difficile da usare correttamente" e "non usare dd". È un'utilità perfettamente valida se utilizzata correttamente da qualcuno che ha avuto il tempo di capirla. In effetti i toolkit forensi su disco dipendono quasi tutti da dd o da un derivato come dcfldd.
fpmurphy,

1
@ fpmurphy1 GNU ddpuò essere utilizzato in sicurezza, grazie alla sua fullblockopzione. Ma se hai coreutils GNU non hai bisogno di ddmolto. "Derivati" come non lodcfldd sono , non soffrono dei suoi difetti di progettazione, quindi la mia risposta non si applica a loro. Una vasta, vasta maggioranza delle persone che usano non ha impiegato abbastanza tempo per capirlo (al massimo, ha impiegato del tempo per pensare di capirlo) e il modo in cui lo usano porta alla perdita di dati. dddd
Gilles 'SO- smetti di essere malvagio' il

1
@Gilles Quindi non dovremmo usare "echo" b / c del suo potenziale di uso improprio (sudo echo hello world> / dev / sda)?
whitey04

2
@ whitey04 Consiglio di non maneggiare barili di nitroglicerina. Non ho detto che non dovresti usare le partite.
Gilles 'SO- smetti di essere malvagio' il

9

L'avviso si verifica quando ddnon è stato possibile ottenere dati sufficienti per riempire un blocco in una sola lettura. Ciò accade con origini dati errate o lente o fonti che scrivono dati in unità più piccole rispetto alla dimensione richiesta.

Non vi è alcun problema con l'integrità dei dati, ma il problema è che ddconta una lettura parziale come blocco di lettura.

Se non si utilizza l' countopzione, l'avviso è poco importante, è solo una considerazione delle prestazioni. Ma con count, non otterrai la quantità di dati richiesti. A causa di letture parziali, ofsarà più piccolo rispetto count*bsalla fine.

Quindi, quando si utilizza count, tecnicamente si dovrebbe sempre usare iflag=fullblockanche.

Il +xdovrebbe essere il numero di blocchi parziali.


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

^ Funzionerà. La disinformazione che altrimenti avrebbe avuto qui è manifestamente falsa. ddI buffer sono espliciti e quindi, per bufferizzare l'input per contare le occorrenze è necessario bufferizzare esplicitamente. Questo è tutto. Non comprare il fud.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.