args.c revision 321140
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 34#ifndef lint 35#if 0 36static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; 37#endif 38#endif /* not lint */ 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: stable/10/bin/dd/args.c 321140 2017-07-18 17:36:25Z ngie $"); 41 42#include <sys/types.h> 43 44#include <err.h> 45#include <errno.h> 46#include <inttypes.h> 47#include <limits.h> 48#include <signal.h> 49#include <stdlib.h> 50#include <string.h> 51 52#include "dd.h" 53#include "extern.h" 54 55static int c_arg(const void *, const void *); 56static int c_conv(const void *, const void *); 57static void f_bs(char *); 58static void f_cbs(char *); 59static void f_conv(char *); 60static void f_count(char *); 61static void f_files(char *); 62static void f_fillchar(char *); 63static void f_ibs(char *); 64static void f_if(char *); 65static void f_obs(char *); 66static void f_of(char *); 67static void f_seek(char *); 68static void f_skip(char *); 69static void f_status(char *); 70static uintmax_t get_num(const char *); 71static off_t get_off_t(const char *); 72 73static const struct arg { 74 const char *name; 75 void (*f)(char *); 76 u_int set, noset; 77} args[] = { 78 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 79 { "cbs", f_cbs, C_CBS, C_CBS }, 80 { "conv", f_conv, 0, 0 }, 81 { "count", f_count, C_COUNT, C_COUNT }, 82 { "files", f_files, C_FILES, C_FILES }, 83 { "fillchar", f_fillchar, C_FILL, C_FILL }, 84 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 85 { "if", f_if, C_IF, C_IF }, 86 { "iseek", f_skip, C_SKIP, C_SKIP }, 87 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 88 { "of", f_of, C_OF, C_OF }, 89 { "oseek", f_seek, C_SEEK, C_SEEK }, 90 { "seek", f_seek, C_SEEK, C_SEEK }, 91 { "skip", f_skip, C_SKIP, C_SKIP }, 92 { "status", f_status, C_STATUS,C_STATUS }, 93}; 94 95static char *oper; 96 97/* 98 * args -- parse JCL syntax of dd. 99 */ 100void 101jcl(char **argv) 102{ 103 struct arg *ap, tmp; 104 char *arg; 105 106 in.dbsz = out.dbsz = 512; 107 108 while ((oper = *++argv) != NULL) { 109 if ((oper = strdup(oper)) == NULL) 110 errx(1, "unable to allocate space for the argument \"%s\"", *argv); 111 if ((arg = strchr(oper, '=')) == NULL) 112 errx(1, "unknown operand %s", oper); 113 *arg++ = '\0'; 114 if (!*arg) 115 errx(1, "no value specified for %s", oper); 116 tmp.name = oper; 117 if (!(ap = (struct arg *)bsearch(&tmp, args, 118 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 119 c_arg))) 120 errx(1, "unknown operand %s", tmp.name); 121 if (ddflags & ap->noset) 122 errx(1, "%s: illegal argument combination or already set", 123 tmp.name); 124 ddflags |= ap->set; 125 ap->f(arg); 126 } 127 128 /* Final sanity checks. */ 129 130 if (ddflags & C_BS) { 131 /* 132 * Bs is turned off by any conversion -- we assume the user 133 * just wanted to set both the input and output block sizes 134 * and didn't want the bs semantics, so we don't warn. 135 */ 136 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 137 C_UNBLOCK)) 138 ddflags &= ~C_BS; 139 140 /* Bs supersedes ibs and obs. */ 141 if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 142 warnx("bs supersedes ibs and obs"); 143 } 144 145 /* 146 * Ascii/ebcdic and cbs implies block/unblock. 147 * Block/unblock requires cbs and vice-versa. 148 */ 149 if (ddflags & (C_BLOCK | C_UNBLOCK)) { 150 if (!(ddflags & C_CBS)) 151 errx(1, "record operations require cbs"); 152 if (cbsz == 0) 153 errx(1, "cbs cannot be zero"); 154 cfunc = ddflags & C_BLOCK ? block : unblock; 155 } else if (ddflags & C_CBS) { 156 if (ddflags & (C_ASCII | C_EBCDIC)) { 157 if (ddflags & C_ASCII) { 158 ddflags |= C_UNBLOCK; 159 cfunc = unblock; 160 } else { 161 ddflags |= C_BLOCK; 162 cfunc = block; 163 } 164 } else 165 errx(1, "cbs meaningless if not doing record operations"); 166 } else 167 cfunc = def; 168} 169 170static int 171c_arg(const void *a, const void *b) 172{ 173 174 return (strcmp(((const struct arg *)a)->name, 175 ((const struct arg *)b)->name)); 176} 177 178static void 179f_bs(char *arg) 180{ 181 uintmax_t res; 182 183 res = get_num(arg); 184 if (res < 1 || res > SSIZE_MAX) 185 errx(1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX); 186 in.dbsz = out.dbsz = (size_t)res; 187} 188 189static void 190f_cbs(char *arg) 191{ 192 uintmax_t res; 193 194 res = get_num(arg); 195 if (res < 1 || res > SSIZE_MAX) 196 errx(1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX); 197 cbsz = (size_t)res; 198} 199 200static void 201f_count(char *arg) 202{ 203 intmax_t res; 204 205 res = (intmax_t)get_num(arg); 206 if (res < 0) 207 errx(1, "count cannot be negative"); 208 if (res == 0) 209 cpy_cnt = (uintmax_t)-1; 210 else 211 cpy_cnt = (uintmax_t)res; 212} 213 214static void 215f_files(char *arg) 216{ 217 218 files_cnt = get_num(arg); 219 if (files_cnt < 1) 220 errx(1, "files must be between 1 and %jd", (uintmax_t)-1); 221} 222 223static void 224f_fillchar(char *arg) 225{ 226 227 if (strlen(arg) != 1) 228 errx(1, "need exactly one fill char"); 229 230 fill_char = arg[0]; 231} 232 233static void 234f_ibs(char *arg) 235{ 236 uintmax_t res; 237 238 if (!(ddflags & C_BS)) { 239 res = get_num(arg); 240 if (res < 1 || res > SSIZE_MAX) 241 errx(1, "ibs must be between 1 and %jd", 242 (intmax_t)SSIZE_MAX); 243 in.dbsz = (size_t)res; 244 } 245} 246 247static void 248f_if(char *arg) 249{ 250 251 in.name = arg; 252} 253 254static void 255f_obs(char *arg) 256{ 257 uintmax_t res; 258 259 if (!(ddflags & C_BS)) { 260 res = get_num(arg); 261 if (res < 1 || res > SSIZE_MAX) 262 errx(1, "obs must be between 1 and %jd", 263 (intmax_t)SSIZE_MAX); 264 out.dbsz = (size_t)res; 265 } 266} 267 268static void 269f_of(char *arg) 270{ 271 272 out.name = arg; 273} 274 275static void 276f_seek(char *arg) 277{ 278 279 out.offset = get_off_t(arg); 280} 281 282static void 283f_skip(char *arg) 284{ 285 286 in.offset = get_off_t(arg); 287} 288 289static void 290f_status(char *arg) 291{ 292 293 if (strcmp(arg, "none") == 0) 294 ddflags |= C_NOINFO; 295 else if (strcmp(arg, "noxfer") == 0) 296 ddflags |= C_NOXFER; 297 else 298 errx(1, "unknown status %s", arg); 299} 300 301static const struct conv { 302 const char *name; 303 u_int set, noset; 304 const u_char *ctab; 305} clist[] = { 306 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 307 { "block", C_BLOCK, C_UNBLOCK, NULL }, 308 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 309 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 310 { "lcase", C_LCASE, C_UCASE, NULL }, 311 { "noerror", C_NOERROR, 0, NULL }, 312 { "notrunc", C_NOTRUNC, 0, NULL }, 313 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 314 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 315 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 316 { "osync", C_OSYNC, C_BS, NULL }, 317 { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL}, 318 { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL}, 319 { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL}, 320 { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, 321 { "sparse", C_SPARSE, 0, NULL }, 322 { "swab", C_SWAB, 0, NULL }, 323 { "sync", C_SYNC, 0, NULL }, 324 { "ucase", C_UCASE, C_LCASE, NULL }, 325 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 326}; 327 328static void 329f_conv(char *arg) 330{ 331 struct conv *cp, tmp; 332 333 while (arg != NULL) { 334 tmp.name = strsep(&arg, ","); 335 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 336 sizeof(struct conv), c_conv); 337 if (cp == NULL) 338 errx(1, "unknown conversion %s", tmp.name); 339 if (ddflags & cp->noset) 340 errx(1, "%s: illegal conversion combination", tmp.name); 341 ddflags |= cp->set; 342 if (cp->ctab) 343 ctab = cp->ctab; 344 } 345} 346 347static int 348c_conv(const void *a, const void *b) 349{ 350 351 return (strcmp(((const struct conv *)a)->name, 352 ((const struct conv *)b)->name)); 353} 354 355/* 356 * Convert an expression of the following forms to a uintmax_t. 357 * 1) A positive decimal number. 358 * 2) A positive decimal number followed by a 'b' or 'B' (mult by 512). 359 * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). 360 * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). 361 * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). 362 * 5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int). 363 * 6) Two or more positive decimal numbers (with/without [BbKkMmGgWw]) 364 * separated by 'x' or 'X' (also '*' for backwards compatibility), 365 * specifying the product of the indicated values. 366 */ 367static uintmax_t 368get_num(const char *val) 369{ 370 uintmax_t num, mult, prevnum; 371 char *expr; 372 373 errno = 0; 374 num = strtouq(val, &expr, 0); 375 if (errno != 0) /* Overflow or underflow. */ 376 err(1, "%s", oper); 377 378 if (expr == val) /* No valid digits. */ 379 errx(1, "%s: illegal numeric value", oper); 380 381 mult = 0; 382 switch (*expr) { 383 case 'B': 384 case 'b': 385 mult = 512; 386 break; 387 case 'K': 388 case 'k': 389 mult = 1 << 10; 390 break; 391 case 'M': 392 case 'm': 393 mult = 1 << 20; 394 break; 395 case 'G': 396 case 'g': 397 mult = 1 << 30; 398 break; 399 case 'W': 400 case 'w': 401 mult = sizeof(int); 402 break; 403 default: 404 ; 405 } 406 407 if (mult != 0) { 408 prevnum = num; 409 num *= mult; 410 /* Check for overflow. */ 411 if (num / mult != prevnum) 412 goto erange; 413 expr++; 414 } 415 416 switch (*expr) { 417 case '\0': 418 break; 419 case '*': /* Backward compatible. */ 420 case 'X': 421 case 'x': 422 mult = get_num(expr + 1); 423 prevnum = num; 424 num *= mult; 425 if (num / mult == prevnum) 426 break; 427erange: 428 errx(1, "%s: %s", oper, strerror(ERANGE)); 429 default: 430 errx(1, "%s: illegal numeric value", oper); 431 } 432 return (num); 433} 434 435/* 436 * Convert an expression of the following forms to an off_t. This is the 437 * same as get_num(), but it uses signed numbers. 438 * 439 * The major problem here is that an off_t may not necessarily be a intmax_t. 440 */ 441static off_t 442get_off_t(const char *val) 443{ 444 intmax_t num, mult, prevnum; 445 char *expr; 446 447 errno = 0; 448 num = strtoq(val, &expr, 0); 449 if (errno != 0) /* Overflow or underflow. */ 450 err(1, "%s", oper); 451 452 if (expr == val) /* No valid digits. */ 453 errx(1, "%s: illegal numeric value", oper); 454 455 mult = 0; 456 switch (*expr) { 457 case 'B': 458 case 'b': 459 mult = 512; 460 break; 461 case 'K': 462 case 'k': 463 mult = 1 << 10; 464 break; 465 case 'M': 466 case 'm': 467 mult = 1 << 20; 468 break; 469 case 'G': 470 case 'g': 471 mult = 1 << 30; 472 break; 473 case 'W': 474 case 'w': 475 mult = sizeof(int); 476 break; 477 } 478 479 if (mult != 0) { 480 prevnum = num; 481 num *= mult; 482 /* Check for overflow. */ 483 if ((prevnum > 0) != (num > 0) || num / mult != prevnum) 484 goto erange; 485 expr++; 486 } 487 488 switch (*expr) { 489 case '\0': 490 break; 491 case '*': /* Backward compatible. */ 492 case 'X': 493 case 'x': 494 mult = (intmax_t)get_off_t(expr + 1); 495 prevnum = num; 496 num *= mult; 497 if ((prevnum > 0) == (num > 0) && num / mult == prevnum) 498 break; 499erange: 500 errx(1, "%s: %s", oper, strerror(ERANGE)); 501 default: 502 errx(1, "%s: illegal numeric value", oper); 503 } 504 return (num); 505} 506