aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/man1/dd.1198
-rw-r--r--src/cmd/dd.c69
2 files changed, 239 insertions, 28 deletions
diff --git a/man/man1/dd.1 b/man/man1/dd.1
new file mode 100644
index 00000000..63b35e14
--- /dev/null
+++ b/man/man1/dd.1
@@ -0,0 +1,198 @@
+.TH DD 1
+.SH NAME
+dd \- convert and copy a file
+.SH SYNOPSIS
+.B dd
+[
+.I option value
+]
+\&...
+.SH DESCRIPTION
+.I Dd\^
+copies the specified input file
+to the specified output with
+possible conversions.
+The standard input and output are used by default.
+The input and output block size may be
+specified to take advantage of raw physical I/O.
+The options are
+.TF "quiet\ \ \fIn
+.PD
+.TP
+.BI -if\ f
+Open file
+.I f
+for input.
+.TP
+.BI -of\ f
+Open file
+.I f
+for output.
+.TP
+.BI -ibs\ n\^
+Set input block size to
+.I n\^
+bytes (default 512).
+.TP
+.BI -obs\ n\^
+Set output block size (default 512).
+.TP
+.BI -bs\ n\^
+Set both input and output block size,
+superseding
+.I ibs\^
+and
+.IR obs .
+If no conversion is specified,
+preserve the input block size instead of packing short blocks
+into the output buffer.
+This is particularly efficient since no in-core copy need be done.
+.TP
+.BI -cbs\ n\^
+Set conversion buffer size.
+.TP
+.BI -skip\ n\^
+Skip
+.I n
+input records before copying.
+.TP
+.BI -iseek\ n\^
+Seek
+.I n
+records forward on input file
+before copying.
+.TP
+.BI -files\ n\^
+Catenate
+.I n
+input files (useful only for magnetic tape or similar input device).
+.TP
+.BI -oseek\ n\^
+Seek
+.I n\^
+records from beginning of output file before copying.
+.TP
+.BI -count\ n\^
+Copy only
+.I n
+input records.
+.TP
+.BI -trunc\ n\^
+By default,
+.I dd
+truncates the output file when it opens it;
+.B -trunc
+.B 0
+opens it without truncation.
+.TP
+.BI -quiet\ n\^
+By default,
+.I dd
+prints the number of blocks read and written
+once it is finished.
+.B -quiet
+.B 1
+silences this summary.
+.HP
+\fL-conv\ ascii\ \ \ \ \fRConvert
+.SM EBCDIC
+to
+.SM ASCII.
+.PD0
+.RS "\w'\fLconv\ \fP'u"
+.TP "\w'\fLunblock\ \ \fP'u"
+.B ebcdic
+Convert
+.SM ASCII
+to
+.SM EBCDIC.
+.TP
+.B ibm
+Like
+.B ebcdic
+but with a slightly different character map.
+.TP
+.B block
+Convert variable length
+.SM ASCII
+records to fixed length.
+.TP
+.B unblock
+Convert fixed length
+.SM ASCII
+records to variable length.
+.TP
+.B lcase
+Map alphabetics to lower case.
+.TP
+.B ucase
+Map alphabetics to upper case.
+.TP
+.B swab
+Swap every pair of bytes.
+.TP
+.B noerror
+Do not stop processing on an error.
+.TP
+.B sync
+Pad every input record to
+.I ibs\^
+bytes.
+.RE
+.PD
+.PP
+.fi
+Where sizes are specified,
+a number of bytes is expected.
+A number may end with
+.L k
+or
+.LR b
+to specify multiplication by
+1024 or 512 respectively;
+a pair of numbers may be separated by
+.L x
+to indicate a product.
+Multiple conversions may be specified in the style:
+.LR "-conv ebcdic,ucase" .
+.PP
+.L Cbs\^
+is used only if
+.LR ascii\^ ,
+.LR unblock\^ ,
+.LR ebcdic\^ ,
+.LR ibm\^ ,
+or
+.L block\^
+conversion is specified.
+In the first two cases,
+.I n
+characters are copied into the conversion buffer, any specified
+character mapping is done,
+trailing blanks are trimmed and new-line is added
+before sending the line to the output.
+In the latter three cases, characters are read into the
+conversion buffer and blanks are added to make up an
+output record of size
+.IR n .
+If
+.L cbs\^
+is unspecified or zero, the
+.LR ascii\^ ,
+.LR ebcdic\^ ,
+and
+.L ibm\^
+options convert the character set without changing the block
+structure of the input file; the
+.L unblock\^
+and
+.L block\^
+options become a simple file copy.
+.SH SOURCE
+.B \*9/src/cmd/dd.c
+.SH "SEE ALSO"
+.IR cp (1)
+.SH DIAGNOSTICS
+.I Dd
+reports the number of full + partial input and output
+blocks handled.
diff --git a/src/cmd/dd.c b/src/cmd/dd.c
index 15599145..ad433d8e 100644
--- a/src/cmd/dd.c
+++ b/src/cmd/dd.c
@@ -1,23 +1,28 @@
#include <u.h>
#include <libc.h>
-#define BIG 2147483647
+#define BIG ((1UL<<31)-1)
+#define VBIG ((1ULL<<63)-1)
#define LCASE (1<<0)
#define UCASE (1<<1)
#define SWAB (1<<2)
#define NERR (1<<3)
#define SYNC (1<<4)
+
int cflag;
int fflag;
+
char *string;
char *ifile;
char *ofile;
char *ibuf;
char *obuf;
+
vlong skip;
vlong oseekn;
vlong iseekn;
vlong count;
+
long files = 1;
long ibs = 512;
long obs = 512;
@@ -31,18 +36,23 @@ long nipr;
long nofr;
long nopr;
long ntrunc;
+
int dotrunc = 1;
int ibf;
int obf;
+
char *op;
int nspace;
+
uchar etoa[256];
uchar atoe[256];
uchar atoibm[256];
+int quiet;
+
void flsh(void);
int match(char *s);
-vlong number(long big);
+vlong number(vlong big);
void cnull(int cc);
void null(int c);
void ascii(int cc);
@@ -50,12 +60,12 @@ void unblock(int cc);
void ebcdic(int cc);
void ibm(int cc);
void block(int cc);
-void term(void);
+void term(char*);
void stats(void);
#define iskey(s) ((key[0] == '-') && (strcmp(key+1, s) == 0))
-void
+int
main(int argc, char *argv[])
{
void (*conv)(int);
@@ -99,20 +109,24 @@ main(int argc, char *argv[])
dotrunc = number(BIG);
continue;
}
+ if(iskey("quiet")) {
+ quiet = number(BIG);
+ continue;
+ }
if(iskey("skip")) {
- skip = number(BIG);
+ skip = number(VBIG);
continue;
}
if(iskey("seek") || iskey("oseek")) {
- oseekn = number(BIG);
+ oseekn = number(VBIG);
continue;
}
if(iskey("iseek")) {
- iseekn = number(BIG);
+ iseekn = number(VBIG);
continue;
}
if(iskey("count")) {
- count = number(BIG);
+ count = number(VBIG);
continue;
}
if(iskey("files")) {
@@ -165,6 +179,8 @@ main(int argc, char *argv[])
cflag |= SYNC;
goto cloop;
}
+ fprint(2, "dd: bad conv %s\n", argv[c]);
+ exits("arg");
}
fprint(2, "dd: bad arg: %s\n", key);
exits("arg");
@@ -243,17 +259,17 @@ loop:
perror("read");
if((cflag&NERR) == 0) {
flsh();
- term();
+ term("errors");
}
ibc = 0;
for(c=0; c<ibs; c++)
if(ibuf[c] != 0)
- ibc = c;
+ ibc = c+1;
+ seek(ibf, ibs, 1);
stats();
- }
- if(ibc == 0 && --files<=0) {
+ }else if(ibc == 0 && --files<=0) {
flsh();
- term();
+ term(nil);
}
if(ibc != ibs) {
nipr++;
@@ -290,12 +306,14 @@ flsh(void)
int c;
if(obc) {
+ /* don't perror dregs of previous errors on a short write */
+ werrstr("");
c = write(obf, obuf, obc);
if(c != obc) {
if(c > 0)
++nopr;
perror("write");
- term();
+ term("errors");
}
if(obc == obs)
nofr++;
@@ -324,10 +342,10 @@ true:
}
vlong
-number(long big)
+number(vlong big)
{
char *cs;
- vlong n;
+ uvlong n;
cs = string;
n = 0;
@@ -340,11 +358,6 @@ number(long big)
n *= 1024;
continue;
-/* case 'w':
- n *= sizeof(int);
- continue;
-*/
-
case 'b':
n *= 512;
continue;
@@ -352,11 +365,11 @@ number(long big)
/* case '*':*/
case 'x':
string = cs;
- n *= number(BIG);
+ n *= number(VBIG);
case '\0':
- if(n>=big || n<0) {
- fprint(2, "dd: argument %lld out of range\n", n);
+ if(n > big) {
+ fprint(2, "dd: argument %llud out of range\n", n);
exits("range");
}
return n;
@@ -536,17 +549,17 @@ block(int cc)
}
void
-term(void)
+term(char *status)
{
-
stats();
- exits(0);
+ exits(status);
}
void
stats(void)
{
-
+ if(quiet)
+ return;
fprint(2, "%lud+%lud records in\n", nifr, nipr);
fprint(2, "%lud+%lud records out\n", nofr, nopr);
if(ntrunc)