[e4a3d93] | 1 | /*- |
---|
| 2 | * Copyright (c) 1991, 1993, 1994 |
---|
| 3 | * The Regents of the University of California. All rights reserved. |
---|
| 4 | * |
---|
| 5 | * This code is derived from software contributed to Berkeley by |
---|
| 6 | * Keith Muller of the University of California, San Diego and Lance |
---|
| 7 | * Visser of Convex Computer Corporation. |
---|
| 8 | * |
---|
| 9 | * Redistribution and use in source and binary forms, with or without |
---|
| 10 | * modification, are permitted provided that the following conditions |
---|
| 11 | * are met: |
---|
| 12 | * 1. Redistributions of source code must retain the above copyright |
---|
| 13 | * notice, this list of conditions and the following disclaimer. |
---|
| 14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 15 | * notice, this list of conditions and the following disclaimer in the |
---|
| 16 | * documentation and/or other materials provided with the distribution. |
---|
| 17 | * 4. Neither the name of the University nor the names of its contributors |
---|
| 18 | * may be used to endorse or promote products derived from this software |
---|
| 19 | * without specific prior written permission. |
---|
| 20 | * |
---|
| 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
| 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
| 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 31 | * SUCH DAMAGE. |
---|
| 32 | */ |
---|
| 33 | |
---|
[9a77af8] | 34 | #ifdef HAVE_CONFIG_H |
---|
| 35 | #include "config.h" |
---|
| 36 | #endif |
---|
| 37 | |
---|
[e4a3d93] | 38 | #if 0 |
---|
| 39 | #ifndef lint |
---|
| 40 | static char const copyright[] = |
---|
| 41 | "@(#) Copyright (c) 1991, 1993, 1994\n\ |
---|
| 42 | The Regents of the University of California. All rights reserved.\n"; |
---|
| 43 | #endif /* not lint */ |
---|
| 44 | |
---|
| 45 | #ifndef lint |
---|
| 46 | static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; |
---|
| 47 | #endif /* not lint */ |
---|
| 48 | #include <sys/cdefs.h> |
---|
| 49 | __FBSDID("$FreeBSD: src/bin/dd/dd.c,v 1.43 2004/08/15 19:10:05 rwatson Exp $"); |
---|
| 50 | #endif |
---|
| 51 | |
---|
[71923138] | 52 | #define _GNU_SOURCE |
---|
[e4a3d93] | 53 | #include <rtems.h> |
---|
| 54 | #include <rtems/shell.h> |
---|
| 55 | #include <rtems/shellconfig.h> |
---|
| 56 | |
---|
| 57 | #include <sys/param.h> |
---|
| 58 | #include <sys/stat.h> |
---|
| 59 | #if RTEMS_REMOVED |
---|
[6576c1d7] | 60 | #include <sys/conf.h> |
---|
[e4a3d93] | 61 | #include <sys/disklabel.h> |
---|
| 62 | #endif |
---|
| 63 | #include <sys/filio.h> |
---|
| 64 | #include <sys/time.h> |
---|
| 65 | |
---|
| 66 | #include <ctype.h> |
---|
[6cdaa85] | 67 | #include "err.h" |
---|
[e4a3d93] | 68 | #include <errno.h> |
---|
| 69 | #include <fcntl.h> |
---|
| 70 | #include <inttypes.h> |
---|
| 71 | #include <locale.h> |
---|
| 72 | #include <stdio.h> |
---|
| 73 | #include <stdlib.h> |
---|
| 74 | #include <string.h> |
---|
| 75 | #include <unistd.h> |
---|
| 76 | |
---|
| 77 | #include "dd.h" |
---|
| 78 | #include "extern-dd.h" |
---|
| 79 | |
---|
[80e239fb] | 80 | #ifndef __unused |
---|
[f97536d] | 81 | #define __unused RTEMS_UNUSED |
---|
[80e239fb] | 82 | #endif |
---|
| 83 | |
---|
[2946682d] | 84 | #define DD_DEFFILEMODE 0 |
---|
[e4a3d93] | 85 | |
---|
| 86 | static void dd_close(rtems_shell_dd_globals* globals); |
---|
| 87 | static void dd_in(rtems_shell_dd_globals* globals); |
---|
| 88 | static void getfdtype(rtems_shell_dd_globals* globals, IO *); |
---|
| 89 | static void setup(rtems_shell_dd_globals* globals); |
---|
| 90 | |
---|
| 91 | #if RTEMS_REMOVED |
---|
| 92 | IO in, out; /* input/output state */ |
---|
| 93 | STAT st; /* statistics */ |
---|
| 94 | void (*cfunc)(void); /* conversion function */ |
---|
| 95 | uintmax_t cpy_cnt; /* # of blocks to copy */ |
---|
| 96 | static off_t pending = 0; /* pending seek if sparse */ |
---|
| 97 | u_int ddflags = 0; /* conversion options */ |
---|
| 98 | size_t cbsz; /* conversion block size */ |
---|
| 99 | uintmax_t files_cnt = 1; /* # of files to copy */ |
---|
| 100 | const u_char *ctab; /* conversion table */ |
---|
| 101 | char fill_char; /* Character to fill with if defined */ |
---|
| 102 | #endif |
---|
| 103 | |
---|
| 104 | static off_t pending = 0; /* pending seek if sparse */ |
---|
| 105 | |
---|
| 106 | void |
---|
| 107 | rtems_shell_dd_exit (rtems_shell_dd_globals* globals, int code) |
---|
| 108 | { |
---|
| 109 | globals->exit_code = code; |
---|
| 110 | longjmp (globals->exit_jmp, 1); |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | static int main_dd(rtems_shell_dd_globals* globals, int argc, char *argv[]); |
---|
| 114 | |
---|
[f1d9293e] | 115 | static int |
---|
[e4a3d93] | 116 | rtems_shell_main_dd(int argc, char *argv[]) |
---|
| 117 | { |
---|
| 118 | rtems_shell_dd_globals dd_globals; |
---|
| 119 | rtems_shell_dd_globals* globals = &dd_globals; |
---|
| 120 | memset (globals, 0, sizeof (dd_globals)); |
---|
| 121 | pending = 0; |
---|
| 122 | ddflags = 0; |
---|
| 123 | files_cnt = 1; |
---|
| 124 | dd_globals.exit_code = 1; |
---|
| 125 | if (setjmp (dd_globals.exit_jmp) == 0) |
---|
| 126 | dd_globals.exit_code = main_dd (globals, argc, argv); |
---|
| 127 | if (in.fd) |
---|
| 128 | close(in.fd); |
---|
| 129 | if (out.fd) |
---|
| 130 | close(out.fd); |
---|
| 131 | if (in.name) |
---|
| 132 | free((void*)in.name); |
---|
| 133 | if (out.name) |
---|
| 134 | free((void*)out.name); |
---|
| 135 | if (in.db) |
---|
| 136 | free(in.db); |
---|
| 137 | if (out.db && (in.db != out.db)) |
---|
| 138 | free(out.db); |
---|
| 139 | return dd_globals.exit_code; |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | int |
---|
| 143 | main_dd(rtems_shell_dd_globals* globals, int argc __unused, char *argv[]) |
---|
| 144 | { |
---|
| 145 | (void)setlocale(LC_CTYPE, ""); |
---|
| 146 | jcl(globals, argv); |
---|
| 147 | setup(globals); |
---|
| 148 | |
---|
| 149 | #if RTEMS_REMOVED |
---|
| 150 | (void)signal(SIGINFO, summaryx); |
---|
| 151 | (void)signal(SIGINT, terminate); |
---|
| 152 | |
---|
| 153 | atexit(summary); |
---|
| 154 | #endif |
---|
| 155 | |
---|
| 156 | while (files_cnt--) |
---|
| 157 | dd_in(globals); |
---|
| 158 | |
---|
| 159 | dd_close(globals); |
---|
| 160 | exit(0); |
---|
| 161 | /* NOTREACHED */ |
---|
| 162 | return 0; |
---|
| 163 | } |
---|
| 164 | |
---|
| 165 | static int |
---|
| 166 | parity(u_char c) |
---|
| 167 | { |
---|
| 168 | int i; |
---|
| 169 | |
---|
[0893220] | 170 | i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ |
---|
[e4a3d93] | 171 | (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); |
---|
| 172 | return (i & 1); |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | static void |
---|
| 176 | setup(rtems_shell_dd_globals* globals) |
---|
| 177 | { |
---|
| 178 | u_int cnt; |
---|
| 179 | struct timeval tv; |
---|
| 180 | |
---|
| 181 | if (in.name == NULL) { |
---|
| 182 | in.name = "stdin"; |
---|
| 183 | in.fd = STDIN_FILENO; |
---|
| 184 | } else { |
---|
| 185 | in.fd = open(in.name, O_RDONLY, 0); |
---|
| 186 | if (in.fd == -1) |
---|
| 187 | err(exit_jump, 1, "%s", in.name); |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | getfdtype(globals, &in); |
---|
| 191 | |
---|
| 192 | if (files_cnt > 1 && !(in.flags & ISTAPE)) |
---|
| 193 | errx(exit_jump, 1, "files is not supported for non-tape devices"); |
---|
| 194 | |
---|
| 195 | if (out.name == NULL) { |
---|
| 196 | /* No way to check for read access here. */ |
---|
| 197 | out.fd = STDOUT_FILENO; |
---|
| 198 | out.name = "stdout"; |
---|
| 199 | } else { |
---|
| 200 | #define OFLAGS \ |
---|
| 201 | (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) |
---|
[2946682d] | 202 | out.fd = open(out.name, O_RDWR | OFLAGS, DD_DEFFILEMODE); |
---|
[e4a3d93] | 203 | /* |
---|
| 204 | * May not have read access, so try again with write only. |
---|
| 205 | * Without read we may have a problem if output also does |
---|
| 206 | * not support seeks. |
---|
| 207 | */ |
---|
| 208 | if (out.fd == -1) { |
---|
[2946682d] | 209 | out.fd = open(out.name, O_WRONLY | OFLAGS, DD_DEFFILEMODE); |
---|
[e4a3d93] | 210 | out.flags |= NOREAD; |
---|
| 211 | } |
---|
| 212 | if (out.fd == -1) |
---|
| 213 | err(exit_jump, 1, "%s", out.name); |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | getfdtype(globals, &out); |
---|
| 217 | |
---|
| 218 | /* |
---|
| 219 | * Allocate space for the input and output buffers. If not doing |
---|
| 220 | * record oriented I/O, only need a single buffer. |
---|
| 221 | */ |
---|
| 222 | if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { |
---|
| 223 | if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) |
---|
| 224 | err(exit_jump, 1, "input buffer"); |
---|
| 225 | out.db = in.db; |
---|
| 226 | } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || |
---|
| 227 | (out.db = malloc(out.dbsz + cbsz)) == NULL) |
---|
| 228 | err(exit_jump, 1, "output buffer"); |
---|
| 229 | in.dbp = in.db; |
---|
| 230 | out.dbp = out.db; |
---|
| 231 | |
---|
| 232 | /* Position the input/output streams. */ |
---|
| 233 | if (in.offset) |
---|
| 234 | pos_in(globals); |
---|
| 235 | if (out.offset) |
---|
| 236 | pos_out(globals); |
---|
| 237 | |
---|
| 238 | /* |
---|
| 239 | * Truncate the output file. If it fails on a type of output file |
---|
| 240 | * that it should _not_ fail on, error out. |
---|
| 241 | */ |
---|
| 242 | if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && |
---|
| 243 | out.flags & ISTRUNC) |
---|
| 244 | if (ftruncate(out.fd, out.offset * out.dbsz) == -1) |
---|
| 245 | err(exit_jump, 1, "truncating %s", out.name); |
---|
| 246 | |
---|
| 247 | if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { |
---|
| 248 | if (ctab != NULL) { |
---|
| 249 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 250 | casetab[cnt] = ctab[cnt]; |
---|
| 251 | } else { |
---|
| 252 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 253 | casetab[cnt] = cnt; |
---|
| 254 | } |
---|
| 255 | if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { |
---|
| 256 | /* |
---|
| 257 | * If the input is not EBCDIC, and we do parity |
---|
| 258 | * processing, strip input parity. |
---|
| 259 | */ |
---|
| 260 | for (cnt = 200; cnt <= 0377; ++cnt) |
---|
| 261 | casetab[cnt] = casetab[cnt & 0x7f]; |
---|
| 262 | } |
---|
| 263 | if (ddflags & C_LCASE) { |
---|
| 264 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 265 | casetab[cnt] = tolower(casetab[cnt]); |
---|
| 266 | } else if (ddflags & C_UCASE) { |
---|
| 267 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 268 | casetab[cnt] = toupper(casetab[cnt]); |
---|
| 269 | } |
---|
| 270 | if ((ddflags & C_PARITY)) { |
---|
| 271 | /* |
---|
| 272 | * This should strictly speaking be a no-op, but I |
---|
| 273 | * wonder what funny LANG settings could get us. |
---|
| 274 | */ |
---|
| 275 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 276 | casetab[cnt] = casetab[cnt] & 0x7f; |
---|
| 277 | } |
---|
| 278 | if ((ddflags & C_PARSET)) { |
---|
| 279 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 280 | casetab[cnt] = casetab[cnt] | 0x80; |
---|
| 281 | } |
---|
| 282 | if ((ddflags & C_PAREVEN)) { |
---|
| 283 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 284 | if (parity(casetab[cnt])) |
---|
| 285 | casetab[cnt] = casetab[cnt] | 0x80; |
---|
| 286 | } |
---|
| 287 | if ((ddflags & C_PARODD)) { |
---|
| 288 | for (cnt = 0; cnt <= 0377; ++cnt) |
---|
| 289 | if (!parity(casetab[cnt])) |
---|
| 290 | casetab[cnt] = casetab[cnt] | 0x80; |
---|
| 291 | } |
---|
| 292 | |
---|
| 293 | ctab = casetab; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | (void)gettimeofday(&tv, (struct timezone *)NULL); |
---|
[0893220] | 297 | st.start = tv.tv_sec + tv.tv_usec * 1e-6; |
---|
[e4a3d93] | 298 | } |
---|
| 299 | |
---|
| 300 | static void |
---|
| 301 | getfdtype(rtems_shell_dd_globals* globals, IO *io) |
---|
| 302 | { |
---|
| 303 | struct stat sb; |
---|
| 304 | #if RTEMS_REMOVED |
---|
| 305 | int type; |
---|
| 306 | #endif |
---|
| 307 | |
---|
| 308 | if (fstat(io->fd, &sb) == -1) |
---|
| 309 | err(exit_jump, 1, "%s", io->name); |
---|
| 310 | if (S_ISREG(sb.st_mode)) |
---|
| 311 | io->flags |= ISTRUNC; |
---|
| 312 | #if RTEMS_REMOVED |
---|
[0893220] | 313 | if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { |
---|
[e4a3d93] | 314 | if (ioctl(io->fd, FIODTYPE, &type) == -1) { |
---|
| 315 | err(exit_jump, 1, "%s", io->name); |
---|
| 316 | } else { |
---|
| 317 | if (type & D_TAPE) |
---|
| 318 | io->flags |= ISTAPE; |
---|
| 319 | else if (type & (D_DISK | D_MEM)) |
---|
| 320 | io->flags |= ISSEEK; |
---|
| 321 | if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0) |
---|
| 322 | io->flags |= ISCHR; |
---|
| 323 | } |
---|
| 324 | return; |
---|
| 325 | } |
---|
| 326 | #else |
---|
| 327 | io->flags |= ISSEEK; |
---|
| 328 | #endif |
---|
| 329 | errno = 0; |
---|
| 330 | if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) |
---|
| 331 | io->flags |= ISPIPE; |
---|
| 332 | else |
---|
| 333 | io->flags |= ISSEEK; |
---|
| 334 | } |
---|
| 335 | |
---|
| 336 | static void |
---|
| 337 | dd_in(rtems_shell_dd_globals* globals) |
---|
| 338 | { |
---|
| 339 | ssize_t n; |
---|
| 340 | |
---|
| 341 | for (;;) { |
---|
| 342 | switch (cpy_cnt) { |
---|
| 343 | case -1: /* count=0 was specified */ |
---|
| 344 | return; |
---|
| 345 | case 0: |
---|
| 346 | break; |
---|
| 347 | default: |
---|
| 348 | if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) |
---|
| 349 | return; |
---|
| 350 | break; |
---|
| 351 | } |
---|
| 352 | |
---|
| 353 | /* |
---|
| 354 | * Zero the buffer first if sync; if doing block operations, |
---|
| 355 | * use spaces. |
---|
| 356 | */ |
---|
| 357 | if (ddflags & C_SYNC) { |
---|
| 358 | if (ddflags & C_FILL) |
---|
| 359 | memset(in.dbp, fill_char, in.dbsz); |
---|
| 360 | else if (ddflags & (C_BLOCK | C_UNBLOCK)) |
---|
| 361 | memset(in.dbp, ' ', in.dbsz); |
---|
| 362 | else |
---|
| 363 | memset(in.dbp, 0, in.dbsz); |
---|
| 364 | } |
---|
| 365 | |
---|
| 366 | n = read(in.fd, in.dbp, in.dbsz); |
---|
| 367 | if (n == 0) { |
---|
| 368 | in.dbrcnt = 0; |
---|
| 369 | return; |
---|
| 370 | } |
---|
| 371 | |
---|
| 372 | /* Read error. */ |
---|
| 373 | if (n == -1) { |
---|
| 374 | /* |
---|
| 375 | * If noerror not specified, die. POSIX requires that |
---|
| 376 | * the warning message be followed by an I/O display. |
---|
| 377 | */ |
---|
| 378 | if (!(ddflags & C_NOERROR)) |
---|
| 379 | err(exit_jump, 1, "%s", in.name); |
---|
| 380 | warn("%s", in.name); |
---|
| 381 | summary(globals); |
---|
| 382 | |
---|
| 383 | /* |
---|
| 384 | * If it's a seekable file descriptor, seek past the |
---|
| 385 | * error. If your OS doesn't do the right thing for |
---|
| 386 | * raw disks this section should be modified to re-read |
---|
| 387 | * in sector size chunks. |
---|
| 388 | */ |
---|
| 389 | if (in.flags & ISSEEK && |
---|
| 390 | lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) |
---|
| 391 | warn("%s", in.name); |
---|
| 392 | |
---|
| 393 | /* If sync not specified, omit block and continue. */ |
---|
| 394 | if (!(ddflags & C_SYNC)) |
---|
| 395 | continue; |
---|
| 396 | |
---|
| 397 | /* Read errors count as full blocks. */ |
---|
| 398 | in.dbcnt += in.dbrcnt = in.dbsz; |
---|
| 399 | ++st.in_full; |
---|
| 400 | |
---|
| 401 | /* Handle full input blocks. */ |
---|
| 402 | } else if ((size_t)n == in.dbsz) { |
---|
| 403 | in.dbcnt += in.dbrcnt = n; |
---|
| 404 | ++st.in_full; |
---|
| 405 | |
---|
| 406 | /* Handle partial input blocks. */ |
---|
| 407 | } else { |
---|
| 408 | /* If sync, use the entire block. */ |
---|
| 409 | if (ddflags & C_SYNC) |
---|
| 410 | in.dbcnt += in.dbrcnt = in.dbsz; |
---|
| 411 | else |
---|
| 412 | in.dbcnt += in.dbrcnt = n; |
---|
| 413 | ++st.in_part; |
---|
| 414 | } |
---|
| 415 | |
---|
| 416 | /* |
---|
| 417 | * POSIX states that if bs is set and no other conversions |
---|
| 418 | * than noerror, notrunc or sync are specified, the block |
---|
| 419 | * is output without buffering as it is read. |
---|
| 420 | */ |
---|
| 421 | if (ddflags & C_BS) { |
---|
| 422 | out.dbcnt = in.dbcnt; |
---|
| 423 | dd_out(globals, 1); |
---|
| 424 | in.dbcnt = 0; |
---|
| 425 | continue; |
---|
| 426 | } |
---|
| 427 | |
---|
| 428 | if (ddflags & C_SWAB) { |
---|
| 429 | if ((n = in.dbrcnt) & 1) { |
---|
| 430 | ++st.swab; |
---|
| 431 | --n; |
---|
| 432 | } |
---|
| 433 | swab(in.dbp, in.dbp, (size_t)n); |
---|
| 434 | } |
---|
| 435 | |
---|
| 436 | in.dbp += in.dbrcnt; |
---|
| 437 | (*cfunc)(globals); |
---|
| 438 | } |
---|
| 439 | } |
---|
| 440 | |
---|
| 441 | /* |
---|
| 442 | * Clean up any remaining I/O and flush output. If necessary, the output file |
---|
| 443 | * is truncated. |
---|
| 444 | */ |
---|
| 445 | static void |
---|
| 446 | dd_close(rtems_shell_dd_globals* globals) |
---|
| 447 | { |
---|
| 448 | if (cfunc == def) |
---|
| 449 | def_close(globals); |
---|
| 450 | else if (cfunc == block) |
---|
| 451 | block_close(globals); |
---|
| 452 | else if (cfunc == unblock) |
---|
| 453 | unblock_close(globals); |
---|
| 454 | if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { |
---|
| 455 | if (ddflags & C_FILL) |
---|
| 456 | memset(out.dbp, fill_char, out.dbsz - out.dbcnt); |
---|
| 457 | else if (ddflags & (C_BLOCK | C_UNBLOCK)) |
---|
| 458 | memset(out.dbp, ' ', out.dbsz - out.dbcnt); |
---|
| 459 | else |
---|
| 460 | memset(out.dbp, 0, out.dbsz - out.dbcnt); |
---|
| 461 | out.dbcnt = out.dbsz; |
---|
| 462 | } |
---|
| 463 | if (out.dbcnt || pending) |
---|
| 464 | dd_out(globals, 1); |
---|
| 465 | } |
---|
| 466 | |
---|
| 467 | void |
---|
| 468 | dd_out(rtems_shell_dd_globals* globals, int force) |
---|
| 469 | { |
---|
| 470 | u_char *outp; |
---|
| 471 | size_t cnt, i, n; |
---|
| 472 | ssize_t nw; |
---|
| 473 | static int warned; |
---|
| 474 | int sparse; |
---|
| 475 | |
---|
| 476 | /* |
---|
| 477 | * Write one or more blocks out. The common case is writing a full |
---|
| 478 | * output block in a single write; increment the full block stats. |
---|
| 479 | * Otherwise, we're into partial block writes. If a partial write, |
---|
| 480 | * and it's a character device, just warn. If a tape device, quit. |
---|
| 481 | * |
---|
| 482 | * The partial writes represent two cases. 1: Where the input block |
---|
| 483 | * was less than expected so the output block was less than expected. |
---|
| 484 | * 2: Where the input block was the right size but we were forced to |
---|
| 485 | * write the block in multiple chunks. The original versions of dd(1) |
---|
| 486 | * never wrote a block in more than a single write, so the latter case |
---|
| 487 | * never happened. |
---|
| 488 | * |
---|
| 489 | * One special case is if we're forced to do the write -- in that case |
---|
| 490 | * we play games with the buffer size, and it's usually a partial write. |
---|
| 491 | */ |
---|
| 492 | outp = out.db; |
---|
| 493 | for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { |
---|
| 494 | for (cnt = n;; cnt -= nw) { |
---|
| 495 | sparse = 0; |
---|
| 496 | if (ddflags & C_SPARSE) { |
---|
| 497 | sparse = 1; /* Is buffer sparse? */ |
---|
| 498 | for (i = 0; i < cnt; i++) |
---|
| 499 | if (outp[i] != 0) { |
---|
| 500 | sparse = 0; |
---|
| 501 | break; |
---|
| 502 | } |
---|
| 503 | } |
---|
| 504 | if (sparse && !force) { |
---|
| 505 | pending += cnt; |
---|
| 506 | nw = cnt; |
---|
| 507 | } else { |
---|
| 508 | if (pending != 0) { |
---|
| 509 | if (force) |
---|
| 510 | pending--; |
---|
| 511 | if (lseek(out.fd, pending, SEEK_CUR) == |
---|
| 512 | -1) |
---|
| 513 | err(exit_jump, 2, "%s: seek error creating sparse file", |
---|
| 514 | out.name); |
---|
| 515 | if (force) |
---|
| 516 | write(out.fd, outp, 1); |
---|
| 517 | pending = 0; |
---|
| 518 | } |
---|
| 519 | if (cnt) |
---|
| 520 | nw = write(out.fd, outp, cnt); |
---|
| 521 | else |
---|
| 522 | return; |
---|
| 523 | } |
---|
| 524 | |
---|
| 525 | if (nw <= 0) { |
---|
| 526 | if (nw == 0) |
---|
| 527 | errx(exit_jump, 1, "%s: end of device", out.name); |
---|
| 528 | if (errno != EINTR) |
---|
| 529 | err(exit_jump, 1, "%s", out.name); |
---|
| 530 | nw = 0; |
---|
| 531 | } |
---|
| 532 | outp += nw; |
---|
| 533 | st.bytes += nw; |
---|
| 534 | if ((size_t)nw == n) { |
---|
| 535 | if (n != out.dbsz) |
---|
| 536 | ++st.out_part; |
---|
| 537 | else |
---|
| 538 | ++st.out_full; |
---|
| 539 | break; |
---|
| 540 | } |
---|
| 541 | ++st.out_part; |
---|
| 542 | if ((size_t)nw == cnt) |
---|
| 543 | break; |
---|
| 544 | if (out.flags & ISTAPE) |
---|
| 545 | errx(exit_jump, 1, "%s: short write on tape device", |
---|
| 546 | out.name); |
---|
| 547 | if (out.flags & ISCHR && !warned) { |
---|
| 548 | warned = 1; |
---|
| 549 | warnx("%s: short write on character device", |
---|
| 550 | out.name); |
---|
| 551 | } |
---|
| 552 | } |
---|
| 553 | if ((out.dbcnt -= n) < out.dbsz) |
---|
| 554 | break; |
---|
| 555 | } |
---|
| 556 | |
---|
| 557 | /* Reassemble the output block. */ |
---|
| 558 | if (out.dbcnt) |
---|
| 559 | (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); |
---|
| 560 | out.dbp = out.db + out.dbcnt; |
---|
| 561 | } |
---|
| 562 | |
---|
| 563 | rtems_shell_cmd_t rtems_shell_DD_Command = { |
---|
| 564 | "dd", /* name */ |
---|
| 565 | "dd [OPERAND]...", /* usage */ |
---|
| 566 | "files", /* topic */ |
---|
| 567 | rtems_shell_main_dd, /* command */ |
---|
| 568 | NULL, /* alias */ |
---|
| 569 | NULL /* next */ |
---|
| 570 | }; |
---|