File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #define _GNU_SOURCE
0035
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039
0040 #if 0
0041 #ifndef lint
0042 static char const copyright[] =
0043 "@(#) Copyright (c) 1991, 1993, 1994\n\
0044 The Regents of the University of California. All rights reserved.\n";
0045 #endif
0046
0047 #ifndef lint
0048 static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
0049 #endif
0050 #include <sys/cdefs.h>
0051 __FBSDID("$FreeBSD: src/bin/dd/dd.c,v 1.43 2004/08/15 19:10:05 rwatson Exp $");
0052 #endif
0053
0054 #include <rtems.h>
0055 #include <rtems/shell.h>
0056 #include <rtems/shellconfig.h>
0057
0058 #include <sys/param.h>
0059 #include <sys/stat.h>
0060 #if RTEMS_REMOVED
0061 #include <sys/conf.h>
0062 #include <sys/disklabel.h>
0063 #endif
0064 #include <sys/filio.h>
0065 #include <sys/time.h>
0066
0067 #include <ctype.h>
0068 #include "err.h"
0069 #include <errno.h>
0070 #include <fcntl.h>
0071 #include <inttypes.h>
0072 #include <locale.h>
0073 #include <stdio.h>
0074 #include <stdlib.h>
0075 #include <string.h>
0076 #include <unistd.h>
0077
0078 #include "dd.h"
0079 #include "extern-dd.h"
0080
0081 #ifndef __unused
0082 #define __unused RTEMS_UNUSED
0083 #endif
0084
0085 #define DD_DEFFILEMODE 0
0086
0087 static void dd_close(rtems_shell_dd_globals* globals);
0088 static void dd_in(rtems_shell_dd_globals* globals);
0089 static void getfdtype(rtems_shell_dd_globals* globals, rtems_shell_dd_IO *);
0090 static void setup(rtems_shell_dd_globals* globals);
0091
0092 #if RTEMS_REMOVED
0093 IO in, out;
0094 STAT st;
0095 void (*cfunc)(void);
0096 uintmax_t cpy_cnt;
0097 static off_t pending = 0;
0098 u_int ddflags = 0;
0099 size_t cbsz;
0100 uintmax_t files_cnt = 1;
0101 const u_char *ctab;
0102 char fill_char;
0103 #endif
0104
0105 static off_t pending = 0;
0106
0107 void
0108 rtems_shell_dd_exit (rtems_shell_dd_globals* globals, int code)
0109 {
0110 globals->exit_code = code;
0111 longjmp (globals->exit_jmp, 1);
0112 }
0113
0114 static int main_dd(rtems_shell_dd_globals* globals, int argc, char *argv[]);
0115
0116 static int
0117 rtems_shell_main_dd(int argc, char *argv[])
0118 {
0119 rtems_shell_dd_globals dd_globals;
0120 rtems_shell_dd_globals* globals = &dd_globals;
0121 memset (globals, 0, sizeof (dd_globals));
0122 pending = 0;
0123 ddflags = 0;
0124 files_cnt = 1;
0125 dd_globals.exit_code = 1;
0126 if (setjmp (dd_globals.exit_jmp) == 0)
0127 dd_globals.exit_code = main_dd (globals, argc, argv);
0128 if (in.fd)
0129 close(in.fd);
0130 if (out.fd)
0131 close(out.fd);
0132 if (in.name)
0133 free((void*)in.name);
0134 if (out.name)
0135 free((void*)out.name);
0136 if (in.db)
0137 free(in.db);
0138 if (out.db && (in.db != out.db))
0139 free(out.db);
0140 return dd_globals.exit_code;
0141 }
0142
0143 int
0144 main_dd(rtems_shell_dd_globals* globals, int argc __unused, char *argv[])
0145 {
0146 (void)setlocale(LC_CTYPE, "");
0147 jcl(globals, argv);
0148 setup(globals);
0149
0150 #if RTEMS_REMOVED
0151 (void)signal(SIGINFO, summaryx);
0152 (void)signal(SIGINT, terminate);
0153
0154 atexit(summary);
0155 #endif
0156
0157 while (files_cnt--)
0158 dd_in(globals);
0159
0160 dd_close(globals);
0161 exit(0);
0162
0163 return 0;
0164 }
0165
0166 static int
0167 parity(u_char c)
0168 {
0169 int i;
0170
0171 i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^
0172 (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7);
0173 return (i & 1);
0174 }
0175
0176 static void
0177 setup(rtems_shell_dd_globals* globals)
0178 {
0179 u_int cnt;
0180 struct timeval tv;
0181
0182 if (in.name == NULL) {
0183 in.name = "stdin";
0184 in.fd = STDIN_FILENO;
0185 } else {
0186 in.fd = open(in.name, O_RDONLY, 0);
0187 if (in.fd == -1)
0188 err(exit_jump, 1, "%s", in.name);
0189 }
0190
0191 getfdtype(globals, &in);
0192
0193 if (files_cnt > 1 && !(in.flags & ISTAPE))
0194 errx(exit_jump, 1, "files is not supported for non-tape devices");
0195
0196 if (out.name == NULL) {
0197
0198 out.fd = STDOUT_FILENO;
0199 out.name = "stdout";
0200 } else {
0201 #define OFLAGS \
0202 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
0203 out.fd = open(out.name, O_RDWR | OFLAGS, DD_DEFFILEMODE);
0204
0205
0206
0207
0208
0209 if (out.fd == -1) {
0210 out.fd = open(out.name, O_WRONLY | OFLAGS, DD_DEFFILEMODE);
0211 out.flags |= NOREAD;
0212 }
0213 if (out.fd == -1)
0214 err(exit_jump, 1, "%s", out.name);
0215 }
0216
0217 getfdtype(globals, &out);
0218
0219
0220
0221
0222
0223 if (!(ddflags & (C_BLOCK | C_UNBLOCK))) {
0224 if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
0225 err(exit_jump, 1, "input buffer");
0226 out.db = in.db;
0227 } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL ||
0228 (out.db = malloc(out.dbsz + cbsz)) == NULL)
0229 err(exit_jump, 1, "output buffer");
0230 in.dbp = in.db;
0231 out.dbp = out.db;
0232
0233
0234 if (in.offset)
0235 pos_in(globals);
0236 if (out.offset)
0237 pos_out(globals);
0238
0239
0240
0241
0242
0243 if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) &&
0244 out.flags & ISTRUNC)
0245 if (ftruncate(out.fd, out.offset * out.dbsz) == -1)
0246 err(exit_jump, 1, "truncating %s", out.name);
0247
0248 if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) {
0249 if (ctab != NULL) {
0250 for (cnt = 0; cnt <= 0377; ++cnt)
0251 casetab[cnt] = ctab[cnt];
0252 } else {
0253 for (cnt = 0; cnt <= 0377; ++cnt)
0254 casetab[cnt] = cnt;
0255 }
0256 if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) {
0257
0258
0259
0260
0261 for (cnt = 200; cnt <= 0377; ++cnt)
0262 casetab[cnt] = casetab[cnt & 0x7f];
0263 }
0264 if (ddflags & C_LCASE) {
0265 for (cnt = 0; cnt <= 0377; ++cnt)
0266 casetab[cnt] = tolower(casetab[cnt]);
0267 } else if (ddflags & C_UCASE) {
0268 for (cnt = 0; cnt <= 0377; ++cnt)
0269 casetab[cnt] = toupper(casetab[cnt]);
0270 }
0271 if ((ddflags & C_PARITY)) {
0272
0273
0274
0275
0276 for (cnt = 0; cnt <= 0377; ++cnt)
0277 casetab[cnt] = casetab[cnt] & 0x7f;
0278 }
0279 if ((ddflags & C_PARSET)) {
0280 for (cnt = 0; cnt <= 0377; ++cnt)
0281 casetab[cnt] = casetab[cnt] | 0x80;
0282 }
0283 if ((ddflags & C_PAREVEN)) {
0284 for (cnt = 0; cnt <= 0377; ++cnt)
0285 if (parity(casetab[cnt]))
0286 casetab[cnt] = casetab[cnt] | 0x80;
0287 }
0288 if ((ddflags & C_PARODD)) {
0289 for (cnt = 0; cnt <= 0377; ++cnt)
0290 if (!parity(casetab[cnt]))
0291 casetab[cnt] = casetab[cnt] | 0x80;
0292 }
0293
0294 ctab = casetab;
0295 }
0296
0297 (void)gettimeofday(&tv, (struct timezone *)NULL);
0298 st.start = tv.tv_sec + tv.tv_usec * 1e-6;
0299 }
0300
0301 static void
0302 getfdtype(rtems_shell_dd_globals* globals, rtems_shell_dd_IO *io)
0303 {
0304 struct stat sb;
0305 #if RTEMS_REMOVED
0306 int type;
0307 #endif
0308
0309 if (fstat(io->fd, &sb) == -1)
0310 err(exit_jump, 1, "%s", io->name);
0311 if (S_ISREG(sb.st_mode))
0312 io->flags |= ISTRUNC;
0313 #if RTEMS_REMOVED
0314 if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
0315 if (ioctl(io->fd, FIODTYPE, &type) == -1) {
0316 err(exit_jump, 1, "%s", io->name);
0317 } else {
0318 if (type & D_TAPE)
0319 io->flags |= ISTAPE;
0320 else if (type & (D_DISK | D_MEM))
0321 io->flags |= ISSEEK;
0322 if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0)
0323 io->flags |= ISCHR;
0324 }
0325 return;
0326 }
0327 #else
0328 io->flags |= ISSEEK;
0329 #endif
0330 errno = 0;
0331 if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
0332 io->flags |= ISPIPE;
0333 else
0334 io->flags |= ISSEEK;
0335 }
0336
0337 static void
0338 swapbytes(void *v, size_t len)
0339 {
0340 unsigned char *p = v;
0341 unsigned char t;
0342
0343 while (len > 1) {
0344 t = p[0];
0345 p[0] = p[1];
0346 p[1] = t;
0347 p += 2;
0348 len -= 2;
0349 }
0350 }
0351
0352 static void
0353 dd_in(rtems_shell_dd_globals* globals)
0354 {
0355 ssize_t n;
0356
0357 for (;;) {
0358 switch (cpy_cnt) {
0359 case -1:
0360 return;
0361 case 0:
0362 break;
0363 default:
0364 if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt)
0365 return;
0366 break;
0367 }
0368
0369
0370
0371
0372
0373 if (ddflags & C_SYNC) {
0374 if (ddflags & C_FILL)
0375 memset(in.dbp, fill_char, in.dbsz);
0376 else if (ddflags & (C_BLOCK | C_UNBLOCK))
0377 memset(in.dbp, ' ', in.dbsz);
0378 else
0379 memset(in.dbp, 0, in.dbsz);
0380 }
0381
0382 n = read(in.fd, in.dbp, in.dbsz);
0383 if (n == 0) {
0384 in.dbrcnt = 0;
0385 return;
0386 }
0387
0388
0389 if (n == -1) {
0390
0391
0392
0393
0394 if (!(ddflags & C_NOERROR))
0395 err(exit_jump, 1, "%s", in.name);
0396 warn("%s", in.name);
0397 summary(globals);
0398
0399
0400
0401
0402
0403
0404
0405 if (in.flags & ISSEEK &&
0406 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
0407 warn("%s", in.name);
0408
0409
0410 if (!(ddflags & C_SYNC))
0411 continue;
0412
0413
0414 in.dbcnt += in.dbrcnt = in.dbsz;
0415 ++st.in_full;
0416
0417
0418 } else if ((size_t)n == in.dbsz) {
0419 in.dbcnt += in.dbrcnt = n;
0420 ++st.in_full;
0421
0422
0423 } else {
0424
0425 if (ddflags & C_SYNC)
0426 in.dbcnt += in.dbrcnt = in.dbsz;
0427 else
0428 in.dbcnt += in.dbrcnt = n;
0429 ++st.in_part;
0430 }
0431
0432
0433
0434
0435
0436
0437 if (ddflags & C_BS) {
0438 out.dbcnt = in.dbcnt;
0439 dd_out(globals, 1);
0440 in.dbcnt = 0;
0441 continue;
0442 }
0443
0444 if (ddflags & C_SWAB) {
0445 if ((n = in.dbrcnt) & 1) {
0446 ++st.swab;
0447 --n;
0448 }
0449 swapbytes(in.dbp, (size_t)n);
0450 }
0451
0452 in.dbp += in.dbrcnt;
0453 (*cfunc)(globals);
0454 }
0455 }
0456
0457
0458
0459
0460
0461 static void
0462 dd_close(rtems_shell_dd_globals* globals)
0463 {
0464 if (cfunc == def)
0465 def_close(globals);
0466 else if (cfunc == block)
0467 block_close(globals);
0468 else if (cfunc == unblock)
0469 unblock_close(globals);
0470 if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) {
0471 if (ddflags & C_FILL)
0472 memset(out.dbp, fill_char, out.dbsz - out.dbcnt);
0473 else if (ddflags & (C_BLOCK | C_UNBLOCK))
0474 memset(out.dbp, ' ', out.dbsz - out.dbcnt);
0475 else
0476 memset(out.dbp, 0, out.dbsz - out.dbcnt);
0477 out.dbcnt = out.dbsz;
0478 }
0479 if (out.dbcnt || pending)
0480 dd_out(globals, 1);
0481 }
0482
0483 void
0484 dd_out(rtems_shell_dd_globals* globals, int force)
0485 {
0486 u_char *outp;
0487 size_t cnt, i, n;
0488 ssize_t nw;
0489 static int warned;
0490 int sparse;
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508 outp = out.db;
0509 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
0510 for (cnt = n;; cnt -= nw) {
0511 sparse = 0;
0512 if (ddflags & C_SPARSE) {
0513 sparse = 1;
0514 for (i = 0; i < cnt; i++)
0515 if (outp[i] != 0) {
0516 sparse = 0;
0517 break;
0518 }
0519 }
0520 if (sparse && !force) {
0521 pending += cnt;
0522 nw = cnt;
0523 } else {
0524 if (pending != 0) {
0525 if (force)
0526 pending--;
0527 if (lseek(out.fd, pending, SEEK_CUR) ==
0528 -1)
0529 err(exit_jump, 2, "%s: seek error creating sparse file",
0530 out.name);
0531 if (force)
0532 write(out.fd, outp, 1);
0533 pending = 0;
0534 }
0535 if (cnt)
0536 nw = write(out.fd, outp, cnt);
0537 else
0538 return;
0539 }
0540
0541 if (nw <= 0) {
0542 if (nw == 0)
0543 errx(exit_jump, 1, "%s: end of device", out.name);
0544 if (errno != EINTR)
0545 err(exit_jump, 1, "%s", out.name);
0546 nw = 0;
0547 }
0548 outp += nw;
0549 st.bytes += nw;
0550 if ((size_t)nw == n) {
0551 if (n != out.dbsz)
0552 ++st.out_part;
0553 else
0554 ++st.out_full;
0555 break;
0556 }
0557 ++st.out_part;
0558 if ((size_t)nw == cnt)
0559 break;
0560 if (out.flags & ISTAPE)
0561 errx(exit_jump, 1, "%s: short write on tape device",
0562 out.name);
0563 if (out.flags & ISCHR && !warned) {
0564 warned = 1;
0565 warnx("%s: short write on character device",
0566 out.name);
0567 }
0568 }
0569 if ((out.dbcnt -= n) < out.dbsz)
0570 break;
0571 }
0572
0573
0574 if (out.dbcnt)
0575 (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
0576 out.dbp = out.db + out.dbcnt;
0577 }
0578
0579 rtems_shell_cmd_t rtems_shell_DD_Command = {
0580 "dd",
0581 "dd [OPERAND]...",
0582 "files",
0583 rtems_shell_main_dd,
0584 NULL,
0585 NULL
0586 };