/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012, Josef 'Jeff' Sipek . All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * convert and copy */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* The BIG parameter is machine dependent. It should be a long integer */ /* constant that can be used by the number parser to check the validity */ /* of numeric parameters. On 16-bit machines, it should probably be */ /* the maximum unsigned integer, 0177777L. On 32-bit machines where */ /* longs are the same size as ints, the maximum signed integer is more */ /* appropriate. This value is 017777777777L. In 64 bit environments, */ /* the maximum signed integer value is 0777777777777777777777LL */ #define BIG 0777777777777777777777LL #define BSIZE 512 /* Option parameters */ #define COPY 0 /* file copy, preserve input block size */ #define REBLOCK 1 /* file copy, change block size */ #define LCREBLOCK 2 /* file copy, convert to lower case */ #define UCREBLOCK 3 /* file copy, convert to upper case */ #define NBASCII 4 /* file copy, convert from EBCDIC to ASCII */ #define LCNBASCII 5 /* file copy, EBCDIC to lower case ASCII */ #define UCNBASCII 6 /* file copy, EBCDIC to upper case ASCII */ #define NBEBCDIC 7 /* file copy, convert from ASCII to EBCDIC */ #define LCNBEBCDIC 8 /* file copy, ASCII to lower case EBCDIC */ #define UCNBEBCDIC 9 /* file copy, ASCII to upper case EBCDIC */ #define NBIBM 10 /* file copy, convert from ASCII to IBM */ #define LCNBIBM 11 /* file copy, ASCII to lower case IBM */ #define UCNBIBM 12 /* file copy, ASCII to upper case IBM */ #define UNBLOCK 13 /* convert blocked ASCII to ASCII */ #define LCUNBLOCK 14 /* convert blocked ASCII to lower case ASCII */ #define UCUNBLOCK 15 /* convert blocked ASCII to upper case ASCII */ #define ASCII 16 /* convert blocked EBCDIC to ASCII */ #define LCASCII 17 /* convert blocked EBCDIC to lower case ASCII */ #define UCASCII 18 /* convert blocked EBCDIC to upper case ASCII */ #define BLOCK 19 /* convert ASCII to blocked ASCII */ #define LCBLOCK 20 /* convert ASCII to lower case blocked ASCII */ #define UCBLOCK 21 /* convert ASCII to upper case blocked ASCII */ #define EBCDIC 22 /* convert ASCII to blocked EBCDIC */ #define LCEBCDIC 23 /* convert ASCII to lower case blocked EBCDIC */ #define UCEBCDIC 24 /* convert ASCII to upper case blocked EBCDIC */ #define IBM 25 /* convert ASCII to blocked IBM */ #define LCIBM 26 /* convert ASCII to lower case blocked IBM */ #define UCIBM 27 /* convert ASCII to upper case blocked IBM */ #define LCASE 01 /* flag - convert to lower case */ #define UCASE 02 /* flag - convert to upper case */ #define SWAB 04 /* flag - swap bytes before conversion */ #define NERR 010 /* flag - proceed on input errors */ #define SYNC 020 /* flag - pad short input blocks with nulls */ #define BADLIMIT 5 /* give up if no progress after BADLIMIT trys */ #define SVR4XLATE 0 /* use default EBCDIC translation */ #define BSDXLATE 1 /* use BSD-compatible EBCDIC translation */ #define USAGE\ "usage: dd [if=file] [of=file] [ibs=n|nk|nb|nxm] [obs=n|nk|nb|nxm]\n"\ " [bs=n|nk|nb|nxm] [cbs=n|nk|nb|nxm] [files=n] [skip=n]\n"\ " [iseek=n] [oseek=n] [seek=n] [count=n] [conv=[ascii]\n"\ " [,ebcdic][,ibm][,asciib][,ebcdicb][,ibmb]\n"\ " [,block|unblock][,lcase|ucase][,swab]\n"\ " [,noerror][,notrunc][,sync]]\n"\ " [oflag=[dsync][sync]]\n" /* Global references */ /* Local routine declarations */ static int match(char *); static void term(); static unsigned long long number(); static unsigned char *flsh(); static void stats(); /* Local data definitions */ static unsigned ibs; /* input buffer size */ static unsigned obs; /* output buffer size */ static unsigned bs; /* buffer size, overrules ibs and obs */ static unsigned cbs; /* conversion buffer size, used for block conversions */ static unsigned ibc; /* number of bytes still in the input buffer */ static unsigned obc; /* number of bytes in the output buffer */ static unsigned cbc; /* number of bytes in the conversion buffer */ static int ibf; /* input file descriptor */ static int obf; /* output file descriptor */ static int cflag; /* conversion option flags */ static int oflag; /* output flag options */ static int skipf; /* if skipf == 1, skip rest of input line */ static unsigned long long nifr; /* count of full input records */ static unsigned long long nipr; /* count of partial input records */ static unsigned long long nofr; /* count of full output records */ static unsigned long long nopr; /* count of partial output records */ static unsigned long long ntrunc; /* count of truncated input lines */ static unsigned long long nbad; /* count of bad records since last */ /* good one */ static int files; /* number of input files to concatenate (tape only) */ static off_t skip; /* number of input records to skip */ static off_t iseekn; /* number of input records to seek past */ static off_t oseekn; /* number of output records to seek past */ static unsigned long long count; /* number of input records to copy */ /* (0 = all) */ static int trantype; /* BSD or SVr4 compatible EBCDIC */ static char *string; /* command arg pointer */ static char *ifile; /* input file name pointer */ static char *ofile; /* output file name pointer */ static unsigned char *ibuf; /* input buffer pointer */ static unsigned char *obuf; /* output buffer pointer */ static hrtime_t startt; /* hrtime copy started */ static unsigned long long obytes; /* output bytes */ static sig_atomic_t nstats; /* do we need to output stats */ /* This is an EBCDIC to ASCII conversion table */ /* from a proposed BTL standard April 16, 1979 */ static unsigned char svr4_etoa [] = { 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174, 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176, 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320, 0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347, 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, }; /* This is an ASCII to EBCDIC conversion table */ /* from a proposed BTL standard April 16, 1979 */ static unsigned char svr4_atoe [] = { 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155, 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007, 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236, 0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277, 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, }; /* Table for ASCII to IBM (alternate EBCDIC) code conversion */ static unsigned char svr4_atoibm[] = { 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, }; /* Table for conversion of ASCII to lower case ASCII */ static unsigned char utol[] = { 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, }; /* Table for conversion of ASCII to upper case ASCII */ static unsigned char ltou[] = { 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, }; /* BSD-compatible EBCDIC to ASCII translate table */ static unsigned char bsd_etoa[] = { 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041, 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136, 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077, 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, }; /* BSD-compatible ASCII to EBCDIC translate table */ static unsigned char bsd_atoe[] = { 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007, 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, }; /* BSD-compatible ASCII to IBM translate table */ static unsigned char bsd_atoibm[] = { 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, }; /* set up to use SVr4 ascii-ebcdic translation by default */ static unsigned char *atoe = svr4_atoe; static unsigned char *etoa = svr4_etoa; static unsigned char *atoibm = svr4_atoibm; /*ARGSUSED*/ static void siginfo_handler(int sig, siginfo_t *sip, void *ucp) { nstats = 1; } int main(int argc, char **argv) { unsigned char *ip, *op; /* input and output buffer pointers */ int c; /* character counter */ int ic; /* input character */ int conv; /* conversion option code */ int trunc; /* whether output file is truncated */ struct stat file_stat; struct sigaction sact; /* Set option defaults */ ibs = BSIZE; obs = BSIZE; files = 1; conv = COPY; trunc = 1; /* default: truncate output file */ trantype = SVR4XLATE; /* use SVR4 EBCDIC by default */ /* Parse command options */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); while ((c = getopt(argc, argv, "")) != EOF) switch (c) { case '?': (void) fprintf(stderr, USAGE); exit(2); } /* not getopt()'ed because dd has no options but only operand(s) */ for (c = optind; c < argc; c++) { string = argv[c]; if (match("ibs=")) { ibs = (unsigned)number(BIG); continue; } if (match("obs=")) { obs = (unsigned)number(BIG); continue; } if (match("cbs=")) { cbs = (unsigned)number(BIG); continue; } if (match("bs=")) { bs = (unsigned)number(BIG); continue; } if (match("if=")) { ifile = string; continue; } if (match("of=")) { ofile = string; continue; } if (match("skip=")) { skip = number(BIG); continue; } if (match("iseek=")) { iseekn = number(BIG); continue; } if (match("oseek=")) { oseekn = number(BIG); continue; } if (match("seek=")) /* retained for compatibility */ { oseekn = number(BIG); continue; } if (match("count=")) { count = number(BIG); continue; } if (match("files=")) { files = (int)number(BIG); continue; } if (match("conv=")) { for (;;) { if (match(",")) { continue; } if (*string == '\0') { break; } if (match("block")) { conv = BLOCK; continue; } if (match("unblock")) { conv = UNBLOCK; continue; } /* ebcdicb, ibmb, and asciib must precede */ /* ebcdic, ibm, and ascii in this test */ if (match("ebcdicb")) { conv = EBCDIC; trantype = BSDXLATE; continue; } if (match("ibmb")) { conv = IBM; trantype = BSDXLATE; continue; } if (match("asciib")) { conv = ASCII; trantype = BSDXLATE; continue; } if (match("ebcdic")) { conv = EBCDIC; trantype = SVR4XLATE; continue; } if (match("ibm")) { conv = IBM; trantype = SVR4XLATE; continue; } if (match("ascii")) { conv = ASCII; trantype = SVR4XLATE; continue; } if (match("lcase")) { cflag |= LCASE; continue; } if (match("ucase")) { cflag |= UCASE; continue; } if (match("swab")) { cflag |= SWAB; continue; } if (match("noerror")) { cflag |= NERR; continue; } if (match("notrunc")) { trunc = 0; continue; } if (match("sync")) { cflag |= SYNC; continue; } goto badarg; } continue; } if (match("oflag=")) { for (;;) { if (match(",")) { continue; } if (*string == '\0') { break; } if (match("dsync")) { oflag |= O_DSYNC; continue; } if (match("sync")) { oflag |= O_SYNC; continue; } goto badarg; } continue; } badarg: (void) fprintf(stderr, "dd: %s \"%s\"\n", gettext("bad argument:"), string); exit(2); } /* Perform consistency checks on options, decode strange conventions */ if (bs) { ibs = obs = bs; } if ((ibs == 0) || (obs == 0)) { (void) fprintf(stderr, "dd: %s\n", gettext("buffer sizes cannot be zero")); exit(2); } if (conv == COPY) { if ((bs == 0) || (cflag&(LCASE|UCASE))) { conv = REBLOCK; } } if (cbs == 0) { switch (conv) { case BLOCK: case UNBLOCK: conv = REBLOCK; break; case ASCII: conv = NBASCII; break; case EBCDIC: conv = NBEBCDIC; break; case IBM: conv = NBIBM; break; } } /* Expand options into lower and upper case versions if necessary */ switch (conv) { case REBLOCK: if (cflag&LCASE) conv = LCREBLOCK; else if (cflag&UCASE) conv = UCREBLOCK; break; case UNBLOCK: if (cflag&LCASE) conv = LCUNBLOCK; else if (cflag&UCASE) conv = UCUNBLOCK; break; case BLOCK: if (cflag&LCASE) conv = LCBLOCK; else if (cflag&UCASE) conv = UCBLOCK; break; case ASCII: if (cflag&LCASE) conv = LCASCII; else if (cflag&UCASE) conv = UCASCII; break; case NBASCII: if (cflag&LCASE) conv = LCNBASCII; else if (cflag&UCASE) conv = UCNBASCII; break; case EBCDIC: if (cflag&LCASE) conv = LCEBCDIC; else if (cflag&UCASE) conv = UCEBCDIC; break; case NBEBCDIC: if (cflag&LCASE) conv = LCNBEBCDIC; else if (cflag&UCASE) conv = UCNBEBCDIC; break; case IBM: if (cflag&LCASE) conv = LCIBM; else if (cflag&UCASE) conv = UCIBM; break; case NBIBM: if (cflag&LCASE) conv = LCNBIBM; else if (cflag&UCASE) conv = UCNBIBM; break; } /* If BSD-compatible translation is selected, change the tables */ if (trantype == BSDXLATE) { atoe = bsd_atoe; atoibm = bsd_atoibm; etoa = bsd_etoa; } /* Open the input file, or duplicate standard input */ ibf = -1; if (ifile) { ibf = open(ifile, 0); } else { ifile = ""; ibf = dup(0); } if (ibf == -1) { (void) fprintf(stderr, "dd: %s: ", ifile); perror("open"); exit(2); } /* Open the output file, or duplicate standard output */ obf = -1; if (ofile) { if (trunc == 0) /* do not truncate output file */ obf = open(ofile, (O_WRONLY|O_CREAT|oflag), (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)); else if (oseekn && (trunc == 1)) { obf = open(ofile, O_WRONLY|O_CREAT|oflag, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)); if (obf == -1) { (void) fprintf(stderr, "dd: %s: ", ofile); perror("open"); exit(2); } (void) fstat(obf, &file_stat); if (((file_stat.st_mode & S_IFMT) == S_IFREG) && (ftruncate(obf, (((off_t)oseekn) * ((off_t)obs))) == -1)) { perror("ftruncate"); exit(2); } } else obf = open(ofile, O_WRONLY|O_CREAT|O_TRUNC|oflag, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)); } else { ofile = ""; obf = dup(1); } if (obf == -1) { (void) fprintf(stderr, "dd: %s: ", ofile); perror("open"); exit(2); } /* Expand memory to get an input buffer */ ibuf = (unsigned char *)valloc(ibs + 10); /* If no conversions, the input buffer is the output buffer */ if (conv == COPY) { obuf = ibuf; } /* Expand memory to get an output buffer. Leave enough room at the */ /* end to convert a logical record when doing block conversions. */ else { obuf = (unsigned char *)valloc(obs + cbs + 10); } if ((ibuf == (unsigned char *)NULL) || (obuf == (unsigned char *)NULL)) { (void) fprintf(stderr, "dd: %s\n", gettext("not enough memory")); exit(2); } /* * Enable a statistics message when we terminate on SIGINT * Also enable it to be queried via SIGINFO and SIGUSR1 */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, term); } bzero(&sact, sizeof (struct sigaction)); sact.sa_flags = SA_SIGINFO; sact.sa_sigaction = siginfo_handler; (void) sigemptyset(&sact.sa_mask); if (sigaction(SIGINFO, &sact, NULL) != 0) { (void) fprintf(stderr, "dd: %s: %s\n", gettext("failed to enable siginfo handler"), gettext(strerror(errno))); exit(2); } if (sigaction(SIGUSR1, &sact, NULL) != 0) { (void) fprintf(stderr, "dd: %s: %s\n", gettext("failed to enable sigusr1 handler"), gettext(strerror(errno))); exit(2); } /* Skip input blocks */ while (skip) { ibc = read(ibf, (char *)ibuf, ibs); if (ibc == (unsigned)-1) { if (++nbad > BADLIMIT) { (void) fprintf(stderr, "dd: %s\n", gettext("skip failed")); exit(2); } else { perror("read"); } } else { if (ibc == 0) { (void) fprintf(stderr, "dd: %s\n", gettext("cannot skip past end-of-file")); exit(3); } else { nbad = 0; } } skip--; } /* Seek past input blocks */ if (iseekn && lseek(ibf, (((off_t)iseekn) * ((off_t)ibs)), 1) == -1) { perror("lseek"); exit(2); } /* Seek past output blocks */ if (oseekn && lseek(obf, (((off_t)oseekn) * ((off_t)obs)), 1) == -1) { perror("lseek"); exit(2); } /* Initialize all buffer pointers */ skipf = 0; /* not skipping an input line */ ibc = 0; /* no input characters yet */ obc = 0; /* no output characters yet */ cbc = 0; /* the conversion buffer is empty */ op = obuf; /* point to the output buffer */ /* Read and convert input blocks until end of file(s) */ /* Grab our start time for siginfo purposes */ startt = gethrtime(); for (;;) { if (nstats != 0) { stats(); nstats = 0; } if ((count == 0) || (nifr+nipr < count)) { /* If proceed on error is enabled, zero the input buffer */ if (cflag&NERR) { ip = ibuf + ibs; c = ibs; if (c & 1) /* if the size is odd, */ { *--ip = 0; /* clear the odd byte */ } if (c >>= 1) /* divide by two */ { do { /* clear two at a time */ *--ip = 0; *--ip = 0; } while (--c); } } /* Read the next input block */ ibc = read(ibf, (char *)ibuf, ibs); /* Process input errors */ if (ibc == (unsigned)-1) { perror("read"); if (((cflag&NERR) == 0) || (++nbad > BADLIMIT)) { while (obc) { (void) flsh(); } term(2); } else { stats(); ibc = ibs; /* assume a full block */ } } else { nbad = 0; } } /* Record count satisfied, simulate end of file */ else { ibc = 0; files = 1; } /* Process end of file */ if (ibc == 0) { switch (conv) { case UNBLOCK: case LCUNBLOCK: case UCUNBLOCK: case ASCII: case LCASCII: case UCASCII: /* Trim trailing blanks from the last line */ if ((c = cbc) != 0) { do { if ((*--op) != ' ') { op++; break; } } while (--c); *op++ = '\n'; obc -= cbc - c - 1; cbc = 0; /* Flush the output buffer if full */ while (obc >= obs) { op = flsh(); } } break; case BLOCK: case LCBLOCK: case UCBLOCK: case EBCDIC: case LCEBCDIC: case UCEBCDIC: case IBM: case LCIBM: case UCIBM: /* Pad trailing blanks if the last line is short */ if (cbc) { obc += c = cbs - cbc; cbc = 0; if (c > 0) { /* Use the right kind of blank */ switch (conv) { case BLOCK: case LCBLOCK: case UCBLOCK: ic = ' '; break; case EBCDIC: case LCEBCDIC: case UCEBCDIC: ic = atoe[' ']; break; case IBM: case LCIBM: case UCIBM: ic = atoibm[' ']; break; } /* Pad with trailing blanks */ do { *op++ = ic; } while (--c); } } /* Flush the output buffer if full */ while (obc >= obs) { op = flsh(); } break; } /* If no more files to read, flush the output buffer */ if (--files <= 0) { (void) flsh(); if ((close(obf) != 0) || (fclose(stdout) != 0)) { perror(gettext("dd: close error")); exit(2); } term(0); /* successful exit */ } else { continue; /* read the next file */ } } /* Normal read, check for special cases */ else if (ibc == ibs) { nifr++; /* count another full input record */ } else { nipr++; /* count a partial input record */ /* If `sync' enabled, pad nulls */ if ((cflag&SYNC) && ((cflag&NERR) == 0)) { c = ibs - ibc; ip = ibuf + ibs; do { if ((conv == BLOCK) || (conv == UNBLOCK)) *--ip = ' '; else *--ip = '\0'; } while (--c); ibc = ibs; } } /* Swap the bytes in the input buffer if necessary */ if (cflag&SWAB) { ip = ibuf; if (ibc & 1) /* if the byte count is odd, */ { ip[ibc] = 0; /* make it even, pad with zero */ } c = ibc >> 1; /* compute the pair count */ do { ic = *ip++; ip[-1] = *ip; *ip++ = ic; } while (--c); /* do two bytes at a time */ } /* Select the appropriate conversion loop */ ip = ibuf; switch (conv) { /* Simple copy: no conversion, preserve the input block size */ case COPY: obc = ibc; (void) flsh(); break; /* Simple copy: pack all output into equal sized blocks */ case REBLOCK: case LCREBLOCK: case UCREBLOCK: case NBASCII: case LCNBASCII: case UCNBASCII: case NBEBCDIC: case LCNBEBCDIC: case UCNBEBCDIC: case NBIBM: case LCNBIBM: case UCNBIBM: while ((c = ibc) != 0) { if (c > (obs - obc)) { c = obs - obc; } ibc -= c; obc += c; switch (conv) { case REBLOCK: do { *op++ = *ip++; } while (--c); break; case LCREBLOCK: do { *op++ = utol[*ip++]; } while (--c); break; case UCREBLOCK: do { *op++ = ltou[*ip++]; } while (--c); break; case NBASCII: do { *op++ = etoa[*ip++]; } while (--c); break; case LCNBASCII: do { *op++ = utol[etoa[*ip++]]; } while (--c); break; case UCNBASCII: do { *op++ = ltou[etoa[*ip++]]; } while (--c); break; case NBEBCDIC: do { *op++ = atoe[*ip++]; } while (--c); break; case LCNBEBCDIC: do { *op++ = atoe[utol[*ip++]]; } while (--c); break; case UCNBEBCDIC: do { *op++ = atoe[ltou[*ip++]]; } while (--c); break; case NBIBM: do { *op++ = atoibm[*ip++]; } while (--c); break; case LCNBIBM: do { *op++ = atoibm[utol[*ip++]]; } while (--c); break; case UCNBIBM: do { *op++ = atoibm[ltou[*ip++]]; } while (--c); break; } if (obc >= obs) { op = flsh(); } } break; /* Convert from blocked records to lines terminated by newline */ case UNBLOCK: case LCUNBLOCK: case UCUNBLOCK: case ASCII: case LCASCII: case UCASCII: while ((c = ibc) != 0) { if (c > (cbs - cbc)) /* if more than one record, */ { c = cbs - cbc; /* only copy one record */ } ibc -= c; cbc += c; obc += c; switch (conv) { case UNBLOCK: do { *op++ = *ip++; } while (--c); break; case LCUNBLOCK: do { *op++ = utol[*ip++]; } while (--c); break; case UCUNBLOCK: do { *op++ = ltou[*ip++]; } while (--c); break; case ASCII: do { *op++ = etoa[*ip++]; } while (--c); break; case LCASCII: do { *op++ = utol[etoa[*ip++]]; } while (--c); break; case UCASCII: do { *op++ = ltou[etoa[*ip++]]; } while (--c); break; } /* Trim trailing blanks if the line is full */ if (cbc == cbs) { c = cbs; /* `do - while' is usually */ do { /* faster than `for' */ if ((*--op) != ' ') { op++; break; } } while (--c); *op++ = '\n'; obc -= cbs - c - 1; cbc = 0; /* Flush the output buffer if full */ while (obc >= obs) { op = flsh(); } } } break; /* Convert to blocked records */ case BLOCK: case LCBLOCK: case UCBLOCK: case EBCDIC: case LCEBCDIC: case UCEBCDIC: case IBM: case LCIBM: case UCIBM: while ((c = ibc) != 0) { int nlflag = 0; /* We may have to skip to the end of a long line */ if (skipf) { do { if ((ic = *ip++) == '\n') { skipf = 0; c--; break; } } while (--c); if ((ibc = c) == 0) { continue; /* read another block */ } } /* If anything left, copy until newline */ if (c > (cbs - cbc + 1)) { c = cbs - cbc + 1; } ibc -= c; cbc += c; obc += c; switch (conv) { case BLOCK: do { if ((ic = *ip++) != '\n') { *op++ = ic; } else { nlflag = 1; break; } } while (--c); break; case LCBLOCK: do { if ((ic = *ip++) != '\n') { *op++ = utol[ic]; } else { nlflag = 1; break; } } while (--c); break; case UCBLOCK: do { if ((ic = *ip++) != '\n') { *op++ = ltou[ic]; } else { nlflag = 1; break; } } while (--c); break; case EBCDIC: do { if ((ic = *ip++) != '\n') { *op++ = atoe[ic]; } else { nlflag = 1; break; } } while (--c); break; case LCEBCDIC: do { if ((ic = *ip++) != '\n') { *op++ = atoe[utol[ic]]; } else { nlflag = 1; break; } } while (--c); break; case UCEBCDIC: do { if ((ic = *ip++) != '\n') { *op++ = atoe[ltou[ic]]; } else { nlflag = 1; break; } } while (--c); break; case IBM: do { if ((ic = *ip++) != '\n') { *op++ = atoibm[ic]; } else { nlflag = 1; break; } } while (--c); break; case LCIBM: do { if ((ic = *ip++) != '\n') { *op++ = atoibm[utol[ic]]; } else { nlflag = 1; break; } } while (--c); break; case UCIBM: do { if ((ic = *ip++) != '\n') { *op++ = atoibm[ltou[ic]]; } else { nlflag = 1; break; } } while (--c); break; } /* If newline found, update all the counters and */ /* pointers, pad with trailing blanks if necessary */ if (nlflag) { ibc += c - 1; obc += cbs - cbc; c += cbs - cbc; cbc = 0; if (c > 0) { /* Use the right kind of blank */ switch (conv) { case BLOCK: case LCBLOCK: case UCBLOCK: ic = ' '; break; case EBCDIC: case LCEBCDIC: case UCEBCDIC: ic = atoe[' ']; break; case IBM: case LCIBM: case UCIBM: ic = atoibm[' ']; break; } /* Pad with trailing blanks */ do { *op++ = ic; } while (--c); } } /* If not end of line, this line may be too long */ else if (cbc > cbs) { skipf = 1; /* note skip in progress */ obc--; op--; cbc = 0; ntrunc++; /* count another long line */ } /* Flush the output buffer if full */ while (obc >= obs) { op = flsh(); } } break; } } /* NOTREACHED */ return (0); } /* match ************************************************************** */ /* */ /* Compare two text strings for equality */ /* */ /* Arg: s - pointer to string to match with a command arg */ /* Global arg: string - pointer to command arg */ /* */ /* Return: 1 if match, 0 if no match */ /* If match, also reset `string' to point to the text */ /* that follows the matching text. */ /* */ /* ******************************************************************** */ static int match(s) char *s; { char *cs; cs = string; while (*cs++ == *s) { if (*s++ == '\0') { goto true; } } if (*s != '\0') { return (0); } true: cs--; string = cs; return (1); } /* number ************************************************************* */ /* */ /* Convert a numeric arg to binary */ /* */ /* Arg: big - maximum valid input number */ /* Global arg: string - pointer to command arg */ /* */ /* Valid forms: 123 | 123k | 123M | 123G | 123T | 123P | 123E | 123Z | */ /* 123w | 123b | 123*123 | 123x123 */ /* plus combinations such as 2b*3kw*4w */ /* */ /* Return: converted number */ /* */ /* ******************************************************************** */ static unsigned long long number(big) long long big; { char *cs; long long n; long long cut = BIG / 10; /* limit to avoid overflow */ cs = string; n = 0; while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) { n = n*10 + *cs++ - '0'; } for (;;) { switch (*cs++) { case 'Z': n *= 1024; /* FALLTHROUGH */ case 'E': n *= 1024; /* FALLTHROUGH */ case 'P': n *= 1024; /* FALLTHROUGH */ case 'T': n *= 1024; /* FALLTHROUGH */ case 'G': n *= 1024; /* FALLTHROUGH */ case 'M': n *= 1024; /* FALLTHROUGH */ case 'k': n *= 1024; continue; case 'w': n *= 2; continue; case 'b': n *= BSIZE; continue; case '*': case 'x': string = cs; n *= number(BIG); /* FALLTHROUGH */ /* Fall into exit test, recursion has read rest of string */ /* End of string, check for a valid number */ case '\0': if ((n > big) || (n < 0)) { (void) fprintf(stderr, "dd: %s \"%llu\"\n", gettext("argument out of range:"), n); exit(2); } return (n); default: (void) fprintf(stderr, "dd: %s \"%s\"\n", gettext("bad numeric argument:"), string); exit(2); } } /* never gets here */ } /* flsh *************************************************************** */ /* */ /* Flush the output buffer, move any excess bytes down to the beginning */ /* */ /* Arg: none */ /* Global args: obuf, obc, obs, nofr, nopr */ /* */ /* Return: Pointer to the first free byte in the output buffer. */ /* Also reset `obc' to account for moved bytes. */ /* */ /* ******************************************************************** */ static unsigned char *flsh() { unsigned char *op, *cp; int bc; unsigned int oc; if (obc) /* don't flush if the buffer is empty */ { if (obc >= obs) { oc = obs; nofr++; /* count a full output buffer */ } else { oc = obc; nopr++; /* count a partial output buffer */ } bc = write(obf, (char *)obuf, oc); if (bc != oc) { if (bc < 0) perror("write"); else (void) fprintf(stderr, gettext("dd: unexpected short write, " "wrote %d bytes, expected %d\n"), bc, oc); term(2); } obc -= oc; op = obuf; obytes += bc; /* If any data in the conversion buffer, move it into */ /* the output buffer */ if (obc) { cp = obuf + obs; bc = obc; do { *op++ = *cp++; } while (--bc); } return (op); } return (obuf); } /* term *************************************************************** */ /* */ /* Write record statistics, then exit */ /* */ /* Arg: c - exit status code */ /* */ /* Return: no return, calls exit */ /* */ /* ******************************************************************** */ static void term(c) int c; { stats(); exit(c); } /* stats ************************************************************** */ /* */ /* Write record statistics onto standard error */ /* */ /* Args: none */ /* Global args: nifr, nipr, nofr, nopr, ntrunc */ /* */ /* Return: void */ /* */ /* ******************************************************************** */ static void stats() { hrtime_t delta = gethrtime() - startt; double secs = delta * 1e-9; (void) fprintf(stderr, gettext("%llu+%llu records in\n"), nifr, nipr); (void) fprintf(stderr, gettext("%llu+%llu records out\n"), nofr, nopr); if (ntrunc) { (void) fprintf(stderr, gettext("%llu truncated record(s)\n"), ntrunc); } /* * If we got here before we started copying somehow, don't bother * printing the rest. */ if (startt == 0) return; (void) fprintf(stderr, gettext("%llu bytes transferred in %.6f secs (%.0f bytes/sec)\n"), obytes, secs, obytes / secs); }