1 /* $OpenBSD: args.c,v 1.30 2018/07/25 15:09:48 cheloha 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 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 278 { "lcase", C_LCASE, C_UCASE, NULL }, 279 { "osync", C_OSYNC, C_BS, NULL }, 280 { "swab", C_SWAB, 0, NULL }, 281 { "sync", C_SYNC, 0, NULL }, 282 { "ucase", C_UCASE, C_LCASE, NULL }, 283 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 284 #endif 285 { "noerror", C_NOERROR, 0, NULL }, 286 { "notrunc", C_NOTRUNC, 0, NULL }, 287 { NULL, 0, 0, NULL } 288 }; 289 290 static void 291 f_conv(char *arg) 292 { 293 const struct conv *cp; 294 const char *name; 295 296 while (arg != NULL) { 297 name = strsep(&arg, ","); 298 for (cp = &clist[0]; cp->name; cp++) 299 if (strcmp(name, cp->name) == 0) 300 break; 301 if (!cp->name) 302 errx(1, "unknown conversion %s", name); 303 if (ddflags & cp->noset) 304 errx(1, "%s: illegal conversion combination", name); 305 ddflags |= cp->set; 306 if (cp->ctab) 307 ctab = cp->ctab; 308 } 309 } 310 311 /* 312 * Convert an expression of the following forms to a size_t 313 * 1) A positive decimal number, optionally followed by 314 * b - multiply by 512. 315 * k, m or g - multiply by 1024 each. 316 * w - multiply by sizeof int 317 * 2) Two or more of the above, separated by x 318 * (or * for backwards compatibility), specifying 319 * the product of the indicated values. 320 */ 321 static size_t 322 get_bsz(char *val) 323 { 324 size_t num, t; 325 char *expr; 326 327 if (strchr(val, '-')) 328 errx(1, "%s: illegal numeric value", oper); 329 330 errno = 0; 331 num = strtoul(val, &expr, 0); 332 if (num == ULONG_MAX && errno == ERANGE) /* Overflow. */ 333 err(1, "%s", oper); 334 if (expr == val) /* No digits. */ 335 errx(1, "%s: illegal numeric value", oper); 336 337 switch(*expr) { 338 case 'b': 339 t = num; 340 num *= 512; 341 if (t > num) 342 goto erange; 343 ++expr; 344 break; 345 case 'g': 346 case 'G': 347 t = num; 348 num *= 1024; 349 if (t > num) 350 goto erange; 351 /* fallthrough */ 352 case 'm': 353 case 'M': 354 t = num; 355 num *= 1024; 356 if (t > num) 357 goto erange; 358 /* fallthrough */ 359 case 'k': 360 case 'K': 361 t = num; 362 num *= 1024; 363 if (t > num) 364 goto erange; 365 ++expr; 366 break; 367 case 'w': 368 t = num; 369 num *= sizeof(int); 370 if (t > num) 371 goto erange; 372 ++expr; 373 break; 374 } 375 376 switch(*expr) { 377 case '\0': 378 break; 379 case '*': /* Backward compatible. */ 380 case 'x': 381 t = num; 382 num *= get_bsz(expr + 1); 383 if (t > num) 384 goto erange; 385 break; 386 default: 387 errx(1, "%s: illegal numeric value", oper); 388 } 389 return (num); 390 erange: 391 errc(1, ERANGE, "%s", oper); 392 } 393 394 /* 395 * Convert an expression of the following forms to an off_t 396 * 1) A positive decimal number, optionally followed by 397 * b - multiply by 512. 398 * k, m or g - multiply by 1024 each. 399 * w - multiply by sizeof int 400 * 2) Two or more of the above, separated by x 401 * (or * for backwards compatibility), specifying 402 * the product of the indicated values. 403 */ 404 static off_t 405 get_off(char *val) 406 { 407 off_t num, t; 408 char *expr; 409 410 errno = 0; 411 num = strtoll(val, &expr, 0); 412 if (num == LLONG_MAX && errno == ERANGE) /* Overflow. */ 413 err(1, "%s", oper); 414 if (expr == val) /* No digits. */ 415 errx(1, "%s: illegal numeric value", oper); 416 417 switch(*expr) { 418 case 'b': 419 t = num; 420 num *= 512; 421 if (t > num) 422 goto erange; 423 ++expr; 424 break; 425 case 'g': 426 case 'G': 427 t = num; 428 num *= 1024; 429 if (t > num) 430 goto erange; 431 /* fallthrough */ 432 case 'm': 433 case 'M': 434 t = num; 435 num *= 1024; 436 if (t > num) 437 goto erange; 438 /* fallthrough */ 439 case 'k': 440 case 'K': 441 t = num; 442 num *= 1024; 443 if (t > num) 444 goto erange; 445 ++expr; 446 break; 447 case 'w': 448 t = num; 449 num *= sizeof(int); 450 if (t > num) 451 goto erange; 452 ++expr; 453 break; 454 } 455 456 switch(*expr) { 457 case '\0': 458 break; 459 case '*': /* Backward compatible. */ 460 case 'x': 461 t = num; 462 num *= get_off(expr + 1); 463 if (t > num) 464 goto erange; 465 break; 466 default: 467 errx(1, "%s: illegal numeric value", oper); 468 } 469 return (num); 470 erange: 471 errc(1, ERANGE, "%s", oper); 472 } 473