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 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; 41 #endif 42 #endif /* not lint */ 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 #include <sys/types.h> 47 48 #include <err.h> 49 #include <errno.h> 50 #include <limits.h> 51 #include <stdlib.h> 52 #include <string.h> 53 54 #include "dd.h" 55 #include "extern.h" 56 57 static int c_arg(const void *, const void *); 58 static int c_conv(const void *, const void *); 59 static void f_bs(char *); 60 static void f_cbs(char *); 61 static void f_conv(char *); 62 static void f_count(char *); 63 static void f_files(char *); 64 static void f_ibs(char *); 65 static void f_if(char *); 66 static void f_obs(char *); 67 static void f_of(char *); 68 static void f_seek(char *); 69 static void f_skip(char *); 70 static u_quad_t get_num(const char *); 71 static off_t get_off_t(const char *); 72 73 static 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 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 84 { "if", f_if, C_IF, C_IF }, 85 { "iseek", f_skip, C_SKIP, C_SKIP }, 86 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 87 { "of", f_of, C_OF, C_OF }, 88 { "oseek", f_seek, C_SEEK, C_SEEK }, 89 { "seek", f_seek, C_SEEK, C_SEEK }, 90 { "skip", f_skip, C_SKIP, C_SKIP }, 91 }; 92 93 static char *oper; 94 95 /* 96 * args -- parse JCL syntax of dd. 97 */ 98 void 99 jcl(char **argv) 100 { 101 struct arg *ap, tmp; 102 char *arg; 103 104 in.dbsz = out.dbsz = 512; 105 106 while ((oper = *++argv) != NULL) { 107 if ((oper = strdup(oper)) == NULL) 108 errx(1, "unable to allocate space for the argument \"%s\"", *argv); 109 if ((arg = strchr(oper, '=')) == NULL) 110 errx(1, "unknown operand %s", oper); 111 *arg++ = '\0'; 112 if (!*arg) 113 errx(1, "no value specified for %s", oper); 114 tmp.name = oper; 115 if (!(ap = (struct arg *)bsearch(&tmp, args, 116 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 117 c_arg))) 118 errx(1, "unknown operand %s", tmp.name); 119 if (ddflags & ap->noset) 120 errx(1, "%s: illegal argument combination or already set", 121 tmp.name); 122 ddflags |= ap->set; 123 ap->f(arg); 124 } 125 126 /* Final sanity checks. */ 127 128 if (ddflags & C_BS) { 129 /* 130 * Bs is turned off by any conversion -- we assume the user 131 * just wanted to set both the input and output block sizes 132 * and didn't want the bs semantics, so we don't warn. 133 */ 134 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 135 C_UNBLOCK)) 136 ddflags &= ~C_BS; 137 138 /* Bs supersedes ibs and obs. */ 139 if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 140 warnx("bs supersedes ibs and obs"); 141 } 142 143 /* 144 * Ascii/ebcdic and cbs implies block/unblock. 145 * Block/unblock requires cbs and vice-versa. 146 */ 147 if (ddflags & (C_BLOCK | C_UNBLOCK)) { 148 if (!(ddflags & C_CBS)) 149 errx(1, "record operations require cbs"); 150 if (cbsz == 0) 151 errx(1, "cbs cannot be zero"); 152 cfunc = ddflags & C_BLOCK ? block : unblock; 153 } else if (ddflags & C_CBS) { 154 if (ddflags & (C_ASCII | C_EBCDIC)) { 155 if (ddflags & C_ASCII) { 156 ddflags |= C_UNBLOCK; 157 cfunc = unblock; 158 } else { 159 ddflags |= C_BLOCK; 160 cfunc = block; 161 } 162 } else 163 errx(1, "cbs meaningless if not doing record operations"); 164 } else 165 cfunc = def; 166 167 /* 168 * Bail out if the calculation of a file offset would overflow. 169 */ 170 if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz) 171 errx(1, "seek offsets cannot be larger than %qd", QUAD_MAX); 172 } 173 174 static int 175 c_arg(const void *a, const void *b) 176 { 177 178 return (strcmp(((const struct arg *)a)->name, 179 ((const struct arg *)b)->name)); 180 } 181 182 static void 183 f_bs(char *arg) 184 { 185 u_quad_t res; 186 187 res = get_num(arg); 188 if (res < 1 || res > SSIZE_MAX) 189 errx(1, "bs must be between 1 and %d", SSIZE_MAX); 190 in.dbsz = out.dbsz = (size_t)res; 191 } 192 193 static void 194 f_cbs(char *arg) 195 { 196 u_quad_t res; 197 198 res = get_num(arg); 199 if (res < 1 || res > SSIZE_MAX) 200 errx(1, "cbs must be between 1 and %d", SSIZE_MAX); 201 cbsz = (size_t)res; 202 } 203 204 static void 205 f_count(char *arg) 206 { 207 u_quad_t res; 208 209 res = get_num(arg); 210 if ((quad_t)res < 0) 211 errx(1, "count cannot be negative"); 212 if (res == 0) 213 cpy_cnt = -1; 214 else 215 cpy_cnt = (quad_t)res; 216 } 217 218 static void 219 f_files(char *arg) 220 { 221 222 files_cnt = get_num(arg); 223 if (files_cnt < 1) 224 errx(1, "files must be between 1 and %qd", QUAD_MAX); 225 } 226 227 static void 228 f_ibs(char *arg) 229 { 230 u_quad_t res; 231 232 if (!(ddflags & C_BS)) { 233 res = get_num(arg); 234 if (res < 1 || res > SSIZE_MAX) 235 errx(1, "ibs must be between 1 and %d", 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 u_quad_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 %d", SSIZE_MAX); 256 out.dbsz = (size_t)res; 257 } 258 } 259 260 static void 261 f_of(char *arg) 262 { 263 264 out.name = arg; 265 } 266 267 static void 268 f_seek(char *arg) 269 { 270 271 out.offset = get_off_t(arg); 272 } 273 274 static void 275 f_skip(char *arg) 276 { 277 278 in.offset = get_off_t(arg); 279 } 280 281 static const struct conv { 282 const char *name; 283 u_int set, noset; 284 const u_char *ctab; 285 } clist[] = { 286 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 287 { "block", C_BLOCK, C_UNBLOCK, NULL }, 288 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 289 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 290 { "lcase", C_LCASE, C_UCASE, NULL }, 291 { "noerror", C_NOERROR, 0, NULL }, 292 { "notrunc", C_NOTRUNC, 0, NULL }, 293 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 294 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 295 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 296 { "osync", C_OSYNC, C_BS, NULL }, 297 { "sparse", C_SPARSE, 0, NULL }, 298 { "swab", C_SWAB, 0, NULL }, 299 { "sync", C_SYNC, 0, NULL }, 300 { "ucase", C_UCASE, C_LCASE, NULL }, 301 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 302 }; 303 304 static void 305 f_conv(char *arg) 306 { 307 struct conv *cp, tmp; 308 309 while (arg != NULL) { 310 tmp.name = strsep(&arg, ","); 311 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 312 sizeof(struct conv), c_conv); 313 if (cp == NULL) 314 errx(1, "unknown conversion %s", tmp.name); 315 if (ddflags & cp->noset) 316 errx(1, "%s: illegal conversion combination", tmp.name); 317 ddflags |= cp->set; 318 if (cp->ctab) 319 ctab = cp->ctab; 320 } 321 } 322 323 static int 324 c_conv(const void *a, const void *b) 325 { 326 327 return (strcmp(((const struct conv *)a)->name, 328 ((const struct conv *)b)->name)); 329 } 330 331 /* 332 * Convert an expression of the following forms to a u_quad_t. 333 * 1) A positive decimal number. 334 * 2) A positive decimal number followed by a b (mult by 512). 335 * 3) A positive decimal number followed by a k (mult by 1 << 10). 336 * 4) A positive decimal number followed by a m (mult by 1 << 20). 337 * 5) A positive decimal number followed by a g (mult by 1 << 30). 338 * 5) A positive decimal number followed by a w (mult by sizeof int). 339 * 6) Two or more positive decimal numbers (with/without [bkmgw]) 340 * separated by x (also * for backwards compatibility), specifying 341 * the product of the indicated values. 342 */ 343 static u_quad_t 344 get_num(const char *val) 345 { 346 u_quad_t num, mult, prevnum; 347 char *expr; 348 349 errno = 0; 350 num = strtouq(val, &expr, 0); 351 if (errno != 0) /* Overflow or underflow. */ 352 err(1, "%s", oper); 353 354 if (expr == val) /* No valid digits. */ 355 errx(1, "%s: illegal numeric value", oper); 356 357 mult = 0; 358 switch (*expr) { 359 case 'b': 360 mult = 512; 361 break; 362 case 'k': 363 mult = 1 << 10; 364 break; 365 case 'm': 366 mult = 1 << 20; 367 break; 368 case 'g': 369 mult = 1 << 30; 370 break; 371 case 'w': 372 mult = sizeof(int); 373 break; 374 default: 375 ; 376 } 377 378 if (mult != 0) { 379 prevnum = num; 380 num *= mult; 381 /* Check for overflow. */ 382 if (num / mult != prevnum) 383 goto erange; 384 expr++; 385 } 386 387 switch (*expr) { 388 case '\0': 389 break; 390 case '*': /* Backward compatible. */ 391 case 'x': 392 mult = get_num(expr + 1); 393 prevnum = num; 394 num *= mult; 395 if (num / mult == prevnum) 396 break; 397 erange: 398 errx(1, "%s: %s", oper, strerror(ERANGE)); 399 default: 400 errx(1, "%s: illegal numeric value", oper); 401 } 402 return (num); 403 } 404 405 /* 406 * Convert an expression of the following forms to an off_t. This is the 407 * same as get_num(), but it uses signed numbers. 408 * 409 * The major problem here is that an off_t may not necessarily be a quad_t. 410 * The right thing to do would be to use intmax_t when available and then 411 * cast down to an off_t, if possible. 412 */ 413 static off_t 414 get_off_t(const char *val) 415 { 416 quad_t num, mult, prevnum; 417 char *expr; 418 419 errno = 0; 420 num = strtoq(val, &expr, 0); 421 if (errno != 0) /* Overflow or underflow. */ 422 err(1, "%s", oper); 423 424 if (expr == val) /* No valid digits. */ 425 errx(1, "%s: illegal numeric value", oper); 426 427 mult = 0; 428 switch (*expr) { 429 case 'b': 430 mult = 512; 431 break; 432 case 'k': 433 mult = 1 << 10; 434 break; 435 case 'm': 436 mult = 1 << 20; 437 break; 438 case 'g': 439 mult = 1 << 30; 440 break; 441 case 'w': 442 mult = sizeof(int); 443 break; 444 } 445 446 if (mult != 0) { 447 prevnum = num; 448 num *= mult; 449 /* Check for overflow. */ 450 if ((prevnum > 0) != (num > 0) || num / mult != prevnum) 451 goto erange; 452 expr++; 453 } 454 455 switch (*expr) { 456 case '\0': 457 break; 458 case '*': /* Backward compatible. */ 459 case 'x': 460 mult = (quad_t)get_off_t(expr + 1); 461 prevnum = num; 462 num *= mult; 463 if ((prevnum > 0) == (num > 0) && num / mult == prevnum) 464 break; 465 erange: 466 errx(1, "%s: %s", oper, strerror(ERANGE)); 467 default: 468 errx(1, "%s: illegal numeric value", oper); 469 } 470 return (num); 471 } 472