1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini dd implementation for busybox 4 * 5 * 6 * Copyright (C) 2000,2001 Matt Kraai 7 * 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 */ 10 11#include <signal.h> /* For FEATURE_DD_SIGNAL_HANDLING */ 12#include "libbb.h" 13 14/* This is a NOEXEC applet. Be very careful! */ 15 16 17static const struct suffix_mult dd_suffixes[] = { 18 { "c", 1 }, 19 { "w", 2 }, 20 { "b", 512 }, 21 { "kD", 1000 }, 22 { "k", 1024 }, 23 { "K", 1024 }, /* compat with coreutils dd */ 24 { "MD", 1000000 }, 25 { "M", 1048576 }, 26 { "GD", 1000000000 }, 27 { "G", 1073741824 }, 28 { } 29}; 30 31struct globals { 32 off_t out_full, out_part, in_full, in_part; 33}; 34#define G (*(struct globals*)&bb_common_bufsiz1) 35/* We have to zero it out because of NOEXEC */ 36#define INIT_G() memset(&G, 0, sizeof(G)) 37 38 39static void dd_output_status(int ATTRIBUTE_UNUSED cur_signal) 40{ 41 /* Deliberately using %u, not %d */ 42 fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n" 43 "%"OFF_FMT"u+%"OFF_FMT"u records out\n", 44 G.in_full, G.in_part, 45 G.out_full, G.out_part); 46} 47 48static ssize_t full_write_or_warn(int fd, const void *buf, size_t len, 49 const char *const filename) 50{ 51 ssize_t n = full_write(fd, buf, len); 52 if (n < 0) 53 bb_perror_msg("writing '%s'", filename); 54 return n; 55} 56 57static bool write_and_stats(int fd, const void *buf, size_t len, size_t obs, 58 const char *filename) 59{ 60 ssize_t n = full_write_or_warn(fd, buf, len, filename); 61 if (n < 0) 62 return 1; 63 if (n == obs) 64 G.out_full++; 65 else if (n) /* > 0 */ 66 G.out_part++; 67 return 0; 68} 69 70#if ENABLE_LFS 71#define XATOU_SFX xatoull_sfx 72#else 73#define XATOU_SFX xatoul_sfx 74#endif 75 76int dd_main(int argc, char **argv); 77int dd_main(int argc, char **argv) 78{ 79 enum { 80 FLAG_SYNC = 1 << 0, 81 FLAG_NOERROR = 1 << 1, 82 FLAG_NOTRUNC = 1 << 2, 83 FLAG_TWOBUFS = 1 << 3, 84 FLAG_COUNT = 1 << 4, 85 }; 86 static const char keywords[] ALIGN1 = 87 "bs=\0""count=\0""seek=\0""skip=\0""if=\0""of=\0" 88#if ENABLE_FEATURE_DD_IBS_OBS 89 "ibs=\0""obs=\0""conv=\0""notrunc\0""sync\0""noerror\0" 90#endif 91 ; 92 enum { 93 OP_bs = 1, 94 OP_count, 95 OP_seek, 96 OP_skip, 97 OP_if, 98 OP_of, 99#if ENABLE_FEATURE_DD_IBS_OBS 100 OP_ibs, 101 OP_obs, 102 OP_conv, 103 OP_conv_notrunc, 104 OP_conv_sync, 105 OP_conv_noerror, 106#endif 107 }; 108 size_t ibs = 512, obs = 512; 109 ssize_t n, w; 110 char *ibuf, *obuf; 111 /* And these are all zeroed at once! */ 112 struct { 113 int flags; 114 int ifd, ofd; 115 size_t oc; 116 off_t count; 117 off_t seek, skip; 118 const char *infile, *outfile; 119#if ENABLE_FEATURE_DD_SIGNAL_HANDLING 120 struct sigaction sigact; 121#endif 122 } Z; 123#define flags (Z.flags ) 124#define ifd (Z.ifd ) 125#define ofd (Z.ofd ) 126#define oc (Z.oc ) 127#define count (Z.count ) 128#define seek (Z.seek ) 129#define skip (Z.skip ) 130#define infile (Z.infile ) 131#define outfile (Z.outfile) 132#define sigact (Z.sigact ) 133 134 memset(&Z, 0, sizeof(Z)); 135 INIT_G(); 136 137#if ENABLE_FEATURE_DD_SIGNAL_HANDLING 138 sigact.sa_handler = dd_output_status; 139 sigact.sa_flags = SA_RESTART; 140 sigemptyset(&sigact.sa_mask); 141 sigaction(SIGUSR1, &sigact, NULL); 142#endif 143 144 for (n = 1; n < argc; n++) { 145 smalluint key_len; 146 smalluint what; 147 char *key; 148 char *arg = argv[n]; 149 150//if (*arg == '-' && *++arg == '-' && !*++arg) continue; 151 key = strstr(arg, "="); 152 if (key == NULL) 153 bb_show_usage(); 154 key_len = key - arg + 1; 155 key = xstrndup(arg, key_len); 156 what = index_in_strings(keywords, key) + 1; 157 if (ENABLE_FEATURE_CLEAN_UP) 158 free(key); 159 if (what == 0) 160 bb_show_usage(); 161 arg += key_len; 162 /* Must fit into positive ssize_t */ 163#if ENABLE_FEATURE_DD_IBS_OBS 164 if (what == OP_ibs) { 165 ibs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes); 166 continue; 167 } 168 if (what == OP_obs) { 169 obs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes); 170 continue; 171 } 172 if (what == OP_conv) { 173 while (1) { 174 /* find ',', replace them with nil so we can use arg for 175 * index_in_strings() without copying. 176 * We rely on arg being non-null, else strchr would fault. 177 */ 178 key = strchr(arg, ','); 179 if (key) 180 *key = '\0'; 181 what = index_in_strings(keywords, arg) + 1; 182 if (what < OP_conv_notrunc) 183 bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv"); 184 if (what == OP_conv_notrunc) 185 flags |= FLAG_NOTRUNC; 186 if (what == OP_conv_sync) 187 flags |= FLAG_SYNC; 188 if (what == OP_conv_noerror) 189 flags |= FLAG_NOERROR; 190 if (!key) /* no ',' left, so this was the last specifier */ 191 break; 192 arg = key + 1; /* skip this keyword and ',' */ 193 } 194 continue; 195 } 196#endif 197 if (what == OP_bs) { 198 ibs = obs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes); 199 continue; 200 } 201 /* These can be large: */ 202 if (what == OP_count) { 203 flags |= FLAG_COUNT; 204 count = XATOU_SFX(arg, dd_suffixes); 205 continue; 206 } 207 if (what == OP_seek) { 208 seek = XATOU_SFX(arg, dd_suffixes); 209 continue; 210 } 211 if (what == OP_skip) { 212 skip = XATOU_SFX(arg, dd_suffixes); 213 continue; 214 } 215 if (what == OP_if) { 216 infile = arg; 217 continue; 218 } 219 if (what == OP_of) 220 outfile = arg; 221 } 222 ibuf = obuf = xmalloc(ibs); 223 if (ibs != obs) { 224 flags |= FLAG_TWOBUFS; 225 obuf = xmalloc(obs); 226 } 227 if (infile != NULL) 228 ifd = xopen(infile, O_RDONLY); 229 else { 230 /* ifd = STDIN_FILENO; - it's zero and it's already there */ 231 infile = bb_msg_standard_input; 232 } 233 if (outfile != NULL) { 234 int oflag = O_WRONLY | O_CREAT; 235 236 if (!seek && !(flags & FLAG_NOTRUNC)) 237 oflag |= O_TRUNC; 238 239 ofd = xopen(outfile, oflag); 240 241 if (seek && !(flags & FLAG_NOTRUNC)) { 242 if (ftruncate(ofd, seek * obs) < 0) { 243 struct stat st; 244 245 if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) || 246 S_ISDIR(st.st_mode)) 247 goto die_outfile; 248 } 249 } 250 } else { 251 ofd = STDOUT_FILENO; 252 outfile = bb_msg_standard_output; 253 } 254 if (skip) { 255 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { 256 while (skip-- > 0) { 257 n = safe_read(ifd, ibuf, ibs); 258 if (n < 0) 259 goto die_infile; 260 if (n == 0) 261 break; 262 } 263 } 264 } 265 if (seek) { 266 if (lseek(ofd, seek * obs, SEEK_CUR) < 0) 267 goto die_outfile; 268 } 269 270 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 271 if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */ 272 memset(ibuf, 0, ibs); 273 n = safe_read(ifd, ibuf, ibs); 274 if (n == 0) 275 break; 276 if (n < 0) { 277 if (flags & FLAG_NOERROR) { 278 n = ibs; 279 bb_perror_msg("%s", infile); 280 } else 281 goto die_infile; 282 } 283 if ((size_t)n == ibs) 284 G.in_full++; 285 else { 286 G.in_part++; 287 if (flags & FLAG_SYNC) { 288 memset(ibuf + n, '\0', ibs - n); 289 n = ibs; 290 } 291 } 292 if (flags & FLAG_TWOBUFS) { 293 char *tmp = ibuf; 294 while (n) { 295 size_t d = obs - oc; 296 297 if (d > n) 298 d = n; 299 memcpy(obuf + oc, tmp, d); 300 n -= d; 301 tmp += d; 302 oc += d; 303 if (oc == obs) { 304 if (write_and_stats(ofd, obuf, obs, obs, outfile)) 305 goto out_status; 306 oc = 0; 307 } 308 } 309 } else if (write_and_stats(ofd, ibuf, n, obs, outfile)) 310 goto out_status; 311 } 312 313 if (ENABLE_FEATURE_DD_IBS_OBS && oc) { 314 w = full_write_or_warn(ofd, obuf, oc, outfile); 315 if (w < 0) goto out_status; 316 if (w > 0) 317 G.out_part++; 318 } 319 if (close(ifd) < 0) { 320 die_infile: 321 bb_perror_msg_and_die("%s", infile); 322 } 323 324 if (close(ofd) < 0) { 325 die_outfile: 326 bb_perror_msg_and_die("%s", outfile); 327 } 328 out_status: 329 dd_output_status(0); 330 331 return EXIT_SUCCESS; 332} 333