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. 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 * @(#)args.c 8.3 (Berkeley) 4/2/94 34 * $FreeBSD: src/bin/dd/args.c,v 1.25.2.2 2001/01/23 14:20:03 asmodai Exp $ 35 * $DragonFly: src/bin/dd/args.c,v 1.6 2008/01/28 16:08:02 matthias Exp $ 36 */ 37 38 #include <sys/types.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <limits.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 #include "dd.h" 47 #include "extern.h" 48 49 static int c_arg (const void *, const void *); 50 static int c_conv (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 quad_t get_num (char *); 63 static off_t get_offset (char *); 64 65 static const struct arg { 66 const char *name; 67 void (*f) (char *); 68 u_int set, noset; 69 } args[] = { 70 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 71 { "cbs", f_cbs, C_CBS, C_CBS }, 72 { "conv", f_conv, 0, 0 }, 73 { "count", f_count, C_COUNT, C_COUNT }, 74 { "files", f_files, C_FILES, C_FILES }, 75 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 76 { "if", f_if, C_IF, C_IF }, 77 { "iseek", f_skip, C_SKIP, C_SKIP }, 78 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 79 { "of", f_of, C_OF, C_OF }, 80 { "oseek", f_seek, C_SEEK, C_SEEK }, 81 { "seek", f_seek, C_SEEK, C_SEEK }, 82 { "skip", f_skip, C_SKIP, C_SKIP }, 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 ((oper = *++argv) != NULL) { 99 if ((oper = strdup(oper)) == NULL) 100 errx(1, "unable to allocate space for the argument \"%s\"", *argv); 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 } 117 118 /* Final sanity checks. */ 119 120 if (ddflags & C_BS) { 121 /* 122 * Bs is turned off by any conversion -- we assume the user 123 * just wanted to set both the input and output block sizes 124 * and didn't want the bs semantics, so we don't warn. 125 */ 126 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 127 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 } else 157 cfunc = def; 158 159 /* 160 * Bail out if the calculation of a file offset would overflow. 161 */ 162 if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz) 163 errx(1, "seek offsets cannot be larger than %lld", QUAD_MAX); 164 } 165 166 static int 167 c_arg(const void *a, const void *b) 168 { 169 170 return (strcmp(((const struct arg *)a)->name, 171 ((const struct arg *)b)->name)); 172 } 173 174 static void 175 f_bs(char *arg) 176 { 177 quad_t res; 178 179 res = get_num(arg); 180 if (res < 1 || res > SSIZE_MAX) 181 errx(1, "bs must be between 1 and %d", SSIZE_MAX); 182 in.dbsz = out.dbsz = (size_t)res; 183 } 184 185 static void 186 f_cbs(char *arg) 187 { 188 quad_t res; 189 190 res = get_num(arg); 191 if (res < 1 || res > SSIZE_MAX) 192 errx(1, "cbs must be between 1 and %d", SSIZE_MAX); 193 cbsz = (size_t)res; 194 } 195 196 static void 197 f_count(char *arg) 198 { 199 200 cpy_cnt = get_num(arg); 201 if (cpy_cnt < 0) 202 errx(1, "count cannot be negative"); 203 if (cpy_cnt == 0) 204 cpy_cnt = -1; 205 } 206 207 static void 208 f_files(char *arg) 209 { 210 211 files_cnt = get_num(arg); 212 if (files_cnt < 1) 213 errx(1, "files must be between 1 and %qd", QUAD_MAX); 214 } 215 216 static void 217 f_ibs(char *arg) 218 { 219 quad_t res; 220 221 if (!(ddflags & C_BS)) { 222 res = get_num(arg); 223 if (res < 1 || res > SSIZE_MAX) 224 errx(1, "ibs must be between 1 and %d", SSIZE_MAX); 225 in.dbsz = (size_t)res; 226 } 227 } 228 229 static void 230 f_if(char *arg) 231 { 232 233 in.name = arg; 234 } 235 236 static void 237 f_obs(char *arg) 238 { 239 quad_t res; 240 241 if (!(ddflags & C_BS)) { 242 res = get_num(arg); 243 if (res < 1 || res > SSIZE_MAX) 244 errx(1, "obs must be between 1 and %d", SSIZE_MAX); 245 out.dbsz = (size_t)res; 246 } 247 } 248 249 static void 250 f_of(char *arg) 251 { 252 253 out.name = arg; 254 } 255 256 static void 257 f_seek(char *arg) 258 { 259 260 out.offset = get_offset(arg); 261 } 262 263 static void 264 f_skip(char *arg) 265 { 266 267 in.offset = get_offset(arg); 268 } 269 270 static const struct conv { 271 const char *name; 272 u_int set, noset; 273 const u_char *ctab; 274 } clist[] = { 275 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 276 { "block", C_BLOCK, C_UNBLOCK, NULL }, 277 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 278 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 279 { "lcase", C_LCASE, C_UCASE, NULL }, 280 { "noerror", C_NOERROR, 0, NULL }, 281 { "notrunc", C_NOTRUNC, 0, NULL }, 282 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 283 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 284 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 285 { "osync", C_OSYNC, C_BS, NULL }, 286 { "sparse", C_SPARSE, 0, NULL }, 287 { "swab", C_SWAB, 0, NULL }, 288 { "sync", C_SYNC, 0, NULL }, 289 { "ucase", C_UCASE, C_LCASE, NULL }, 290 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 291 }; 292 293 static void 294 f_conv(char *arg) 295 { 296 struct conv *cp, tmp; 297 298 while (arg != NULL) { 299 tmp.name = strsep(&arg, ","); 300 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 301 sizeof(struct conv), c_conv); 302 if (cp == NULL) 303 errx(1, "unknown conversion %s", tmp.name); 304 if (ddflags & cp->noset) 305 errx(1, "%s: illegal conversion combination", tmp.name); 306 ddflags |= cp->set; 307 if (cp->ctab) 308 ctab = cp->ctab; 309 } 310 } 311 312 static int 313 c_conv(const void *a, const void *b) 314 { 315 316 return (strcmp(((const struct conv *)a)->name, 317 ((const struct conv *)b)->name)); 318 } 319 320 /* 321 * Convert an expression of the following forms to a quad_t. 322 * 1) A positive decimal number. 323 * 2) A positive decimal number followed by a b (mult by 512.) 324 * 3) A positive decimal number followed by a k (mult by 1 << 10.) 325 * 4) A positive decimal number followed by a m (mult by 1 << 20.) 326 * 5) A positive decimal number followed by a g (mult by 1 << 30.) 327 * 5) A positive decimal number followed by a w (mult by sizeof int.) 328 * 6) Two or more positive decimal numbers (with/without [bkmgw]) 329 * separated by x (also * for backwards compatibility), specifying 330 * the product of the indicated values. 331 */ 332 static quad_t 333 get_num(char *val) 334 { 335 quad_t num, t; 336 char *expr; 337 338 errno = 0; 339 num = strtoll(val, &expr, 0); 340 if (errno != 0) /* Overflow or underflow. */ 341 err(1, "%s", oper); 342 343 if (expr == val) /* No valid digits. */ 344 errx(1, "%s: illegal numeric value", oper); 345 346 switch (*expr) { 347 case 'b': 348 case 'B': 349 t = num; 350 num *= 512; 351 if (t > num) 352 goto erange; 353 ++expr; 354 break; 355 case 'k': 356 case 'K': 357 t = num; 358 num *= 1 << 10; 359 if (t > num) 360 goto erange; 361 ++expr; 362 break; 363 case 'm': 364 case 'M': 365 t = num; 366 num *= 1 << 20; 367 if (t > num) 368 goto erange; 369 ++expr; 370 break; 371 case 'g': 372 case 'G': 373 t = num; 374 num *= 1 << 30; 375 if (t > num) 376 goto erange; 377 ++expr; 378 break; 379 case 'w': 380 t = num; 381 num *= sizeof(int); 382 if (t > num) 383 goto erange; 384 ++expr; 385 break; 386 } 387 388 switch (*expr) { 389 case '\0': 390 break; 391 case '*': /* Backward compatible. */ 392 case 'x': 393 t = num; 394 num *= get_num(expr + 1); 395 if (t <= num) 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 static off_t 406 get_offset(char *val) 407 { 408 quad_t num; 409 410 num = get_num(val); 411 if (num > QUAD_MAX) /* XXX can't happen && quad_t != off_t */ 412 errx(1, "%s: illegal offset", oper); /* Too big. */ 413 return ((off_t)num); 414 } 415