1 /* $OpenBSD: args.c,v 1.31 2019/02/16 10:54:00 bluhm Exp $ */ 2 /* $NetBSD: args.c,v 1.7 1996/03/01 01:18:58 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1991, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Keith Muller of the University of California, San Diego and Lance 10 * Visser of Convex Computer Corporation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/time.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <limits.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 #include "dd.h" 48 #include "extern.h" 49 50 static int c_arg(const void *, const void *); 51 static void f_bs(char *); 52 static void f_cbs(char *); 53 static void f_conv(char *); 54 static void f_count(char *); 55 static void f_files(char *); 56 static void f_ibs(char *); 57 static void f_if(char *); 58 static void f_obs(char *); 59 static void f_of(char *); 60 static void f_seek(char *); 61 static void f_skip(char *); 62 static void f_status(char *); 63 static size_t get_bsz(char *); 64 static off_t get_off(char *); 65 66 static const struct arg { 67 const char *name; 68 void (*f)(char *); 69 u_int set, noset; 70 } args[] = { 71 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 72 { "cbs", f_cbs, C_CBS, C_CBS }, 73 { "conv", f_conv, 0, 0 }, 74 { "count", f_count, C_COUNT, C_COUNT }, 75 { "files", f_files, C_FILES, C_FILES }, 76 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 77 { "if", f_if, C_IF, C_IF }, 78 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 79 { "of", f_of, C_OF, C_OF }, 80 { "seek", f_seek, C_SEEK, C_SEEK }, 81 { "skip", f_skip, C_SKIP, C_SKIP }, 82 { "status", f_status, C_STATUS,C_STATUS }, 83 }; 84 85 static char *oper; 86 87 /* 88 * args -- parse JCL syntax of dd. 89 */ 90 void 91 jcl(char **argv) 92 { 93 struct arg *ap, tmp; 94 char *arg; 95 96 in.dbsz = out.dbsz = 512; 97 98 while (*++argv != NULL) { 99 if ((oper = strdup(*argv)) == NULL) 100 err(1, NULL); 101 if ((arg = strchr(oper, '=')) == NULL) 102 errx(1, "unknown operand %s", oper); 103 *arg++ = '\0'; 104 if (!*arg) 105 errx(1, "no value specified for %s", oper); 106 tmp.name = oper; 107 if (!(ap = (struct arg *)bsearch(&tmp, args, 108 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 109 c_arg))) 110 errx(1, "unknown operand %s", tmp.name); 111 if (ddflags & ap->noset) 112 errx(1, "%s: illegal argument combination or already set", 113 tmp.name); 114 ddflags |= ap->set; 115 ap->f(arg); 116 free(oper); 117 } 118 119 /* Final sanity checks. */ 120 121 if (ddflags & C_BS) { 122 /* 123 * Bs is turned off by any conversion -- we assume the user 124 * just wanted to set both the input and output block sizes 125 * and didn't want the bs semantics, so we don't warn. 126 */ 127 if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK)) 128 ddflags &= ~C_BS; 129 130 /* Bs supersedes ibs and obs. */ 131 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) 132 warnx("bs supersedes ibs and obs"); 133 } 134 135 /* 136 * Ascii/ebcdic and cbs implies block/unblock. 137 * Block/unblock requires cbs and vice-versa. 138 */ 139 if (ddflags & (C_BLOCK|C_UNBLOCK)) { 140 if (!(ddflags & C_CBS)) 141 errx(1, "record operations require cbs"); 142 if (cbsz == 0) 143 errx(1, "cbs cannot be zero"); 144 cfunc = ddflags & C_BLOCK ? block : unblock; 145 } else if (ddflags & C_CBS) { 146 if (ddflags & (C_ASCII|C_EBCDIC)) { 147 if (ddflags & C_ASCII) { 148 ddflags |= C_UNBLOCK; 149 cfunc = unblock; 150 } else { 151 ddflags |= C_BLOCK; 152 cfunc = block; 153 } 154 } else 155 errx(1, "cbs meaningless if not doing record operations"); 156 if (cbsz == 0) 157 errx(1, "cbs cannot be zero"); 158 } else 159 cfunc = def; 160 161 if (in.dbsz == 0 || out.dbsz == 0) 162 errx(1, "buffer sizes cannot be zero"); 163 164 /* 165 * Read and write take size_t's as arguments. Lseek, however, 166 * takes an off_t. 167 */ 168 if (cbsz > SSIZE_MAX || in.dbsz > SSIZE_MAX || out.dbsz > SSIZE_MAX) 169 errx(1, "buffer sizes cannot be greater than %zd", 170 (ssize_t)SSIZE_MAX); 171 if (in.offset > LLONG_MAX / in.dbsz || out.offset > LLONG_MAX / out.dbsz) 172 errx(1, "seek offsets cannot be larger than %lld", LLONG_MAX); 173 } 174 175 static int 176 c_arg(const void *a, const void *b) 177 { 178 179 return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name)); 180 } 181 182 static void 183 f_bs(char *arg) 184 { 185 186 in.dbsz = out.dbsz = get_bsz(arg); 187 } 188 189 static void 190 f_cbs(char *arg) 191 { 192 193 cbsz = get_bsz(arg); 194 } 195 196 static void 197 f_count(char *arg) 198 { 199 200 if ((cpy_cnt = get_bsz(arg)) == 0) 201 cpy_cnt = (size_t)-1; 202 } 203 204 static void 205 f_files(char *arg) 206 { 207 208 files_cnt = get_bsz(arg); 209 } 210 211 static void 212 f_ibs(char *arg) 213 { 214 215 if (!(ddflags & C_BS)) 216 in.dbsz = get_bsz(arg); 217 } 218 219 static void 220 f_if(char *arg) 221 { 222 if ((in.name = strdup(arg)) == NULL) 223 err(1, NULL); 224 } 225 226 static void 227 f_obs(char *arg) 228 { 229 230 if (!(ddflags & C_BS)) 231 out.dbsz = get_bsz(arg); 232 } 233 234 static void 235 f_of(char *arg) 236 { 237 if ((out.name = strdup(arg)) == NULL) 238 err(1, NULL); 239 } 240 241 static void 242 f_seek(char *arg) 243 { 244 245 out.offset = get_off(arg); 246 } 247 248 static void 249 f_skip(char *arg) 250 { 251 252 in.offset = get_off(arg); 253 } 254 255 static void 256 f_status(char *arg) 257 { 258 259 if (strcmp(arg, "none") == 0) 260 ddflags |= C_NOINFO; 261 else if (strcmp(arg, "noxfer") == 0) 262 ddflags |= C_NOXFER; 263 else 264 errx(1, "unknown status %s", arg); 265 } 266 267 268 static const struct conv { 269 const char *name; 270 u_int set, noset; 271 const u_char *ctab; 272 } clist[] = { 273 #ifndef NO_CONV 274 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 275 { "block", C_BLOCK, C_UNBLOCK, NULL }, 276 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 277 { "fsync", C_FSYNC, 0, NULL }, 278 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 279 { "lcase", C_LCASE, C_UCASE, NULL }, 280 { "osync", C_OSYNC, C_BS, NULL }, 281 { "swab", C_SWAB, 0, NULL }, 282 { "sync", C_SYNC, 0, NULL }, 283 { "ucase", C_UCASE, C_LCASE, NULL }, 284 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 285 #endif 286 { "noerror", C_NOERROR, 0, NULL }, 287 { "notrunc", C_NOTRUNC, 0, NULL }, 288 { NULL, 0, 0, NULL } 289 }; 290 291 static void 292 f_conv(char *arg) 293 { 294 const struct conv *cp; 295 const char *name; 296 297 while (arg != NULL) { 298 name = strsep(&arg, ","); 299 for (cp = &clist[0]; cp->name; cp++) 300 if (strcmp(name, cp->name) == 0) 301 break; 302 if (!cp->name) 303 errx(1, "unknown conversion %s", name); 304 if (ddflags & cp->noset) 305 errx(1, "%s: illegal conversion combination", name); 306 ddflags |= cp->set; 307 if (cp->ctab) 308 ctab = cp->ctab; 309 } 310 } 311 312 /* 313 * Convert an expression of the following forms to a size_t 314 * 1) A positive decimal number, optionally followed by 315 * b - multiply by 512. 316 * k, m or g - multiply by 1024 each. 317 * w - multiply by sizeof int 318 * 2) Two or more of the above, separated by x 319 * (or * for backwards compatibility), specifying 320 * the product of the indicated values. 321 */ 322 static size_t 323 get_bsz(char *val) 324 { 325 size_t num, t; 326 char *expr; 327 328 if (strchr(val, '-')) 329 errx(1, "%s: illegal numeric value", oper); 330 331 errno = 0; 332 num = strtoul(val, &expr, 0); 333 if (num == ULONG_MAX && errno == ERANGE) /* Overflow. */ 334 err(1, "%s", oper); 335 if (expr == val) /* No digits. */ 336 errx(1, "%s: illegal numeric value", oper); 337 338 switch(*expr) { 339 case 'b': 340 t = num; 341 num *= 512; 342 if (t > num) 343 goto erange; 344 ++expr; 345 break; 346 case 'g': 347 case 'G': 348 t = num; 349 num *= 1024; 350 if (t > num) 351 goto erange; 352 /* fallthrough */ 353 case 'm': 354 case 'M': 355 t = num; 356 num *= 1024; 357 if (t > num) 358 goto erange; 359 /* fallthrough */ 360 case 'k': 361 case 'K': 362 t = num; 363 num *= 1024; 364 if (t > num) 365 goto erange; 366 ++expr; 367 break; 368 case 'w': 369 t = num; 370 num *= sizeof(int); 371 if (t > num) 372 goto erange; 373 ++expr; 374 break; 375 } 376 377 switch(*expr) { 378 case '\0': 379 break; 380 case '*': /* Backward compatible. */ 381 case 'x': 382 t = num; 383 num *= get_bsz(expr + 1); 384 if (t > num) 385 goto erange; 386 break; 387 default: 388 errx(1, "%s: illegal numeric value", oper); 389 } 390 return (num); 391 erange: 392 errc(1, ERANGE, "%s", oper); 393 } 394 395 /* 396 * Convert an expression of the following forms to an off_t 397 * 1) A positive decimal number, optionally followed by 398 * b - multiply by 512. 399 * k, m or g - multiply by 1024 each. 400 * w - multiply by sizeof int 401 * 2) Two or more of the above, separated by x 402 * (or * for backwards compatibility), specifying 403 * the product of the indicated values. 404 */ 405 static off_t 406 get_off(char *val) 407 { 408 off_t num, t; 409 char *expr; 410 411 errno = 0; 412 num = strtoll(val, &expr, 0); 413 if (num == LLONG_MAX && errno == ERANGE) /* Overflow. */ 414 err(1, "%s", oper); 415 if (expr == val) /* No digits. */ 416 errx(1, "%s: illegal numeric value", oper); 417 418 switch(*expr) { 419 case 'b': 420 t = num; 421 num *= 512; 422 if (t > num) 423 goto erange; 424 ++expr; 425 break; 426 case 'g': 427 case 'G': 428 t = num; 429 num *= 1024; 430 if (t > num) 431 goto erange; 432 /* fallthrough */ 433 case 'm': 434 case 'M': 435 t = num; 436 num *= 1024; 437 if (t > num) 438 goto erange; 439 /* fallthrough */ 440 case 'k': 441 case 'K': 442 t = num; 443 num *= 1024; 444 if (t > num) 445 goto erange; 446 ++expr; 447 break; 448 case 'w': 449 t = num; 450 num *= sizeof(int); 451 if (t > num) 452 goto erange; 453 ++expr; 454 break; 455 } 456 457 switch(*expr) { 458 case '\0': 459 break; 460 case '*': /* Backward compatible. */ 461 case 'x': 462 t = num; 463 num *= get_off(expr + 1); 464 if (t > num) 465 goto erange; 466 break; 467 default: 468 errx(1, "%s: illegal numeric value", oper); 469 } 470 return (num); 471 erange: 472 errc(1, ERANGE, "%s", oper); 473 } 474