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