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 / (ssize_t)in.dbsz || 163 out.offset > QUAD_MAX / (ssize_t)out.dbsz) { 164 errx(1, "seek offsets cannot be larger than %lld", QUAD_MAX); 165 } 166 } 167 168 static int 169 c_arg(const void *a, const void *b) 170 { 171 172 return (strcmp(((const struct arg *)a)->name, 173 ((const struct arg *)b)->name)); 174 } 175 176 static void 177 f_bs(char *arg) 178 { 179 quad_t res; 180 181 res = get_num(arg); 182 if (res < 1 || res > SSIZE_MAX) 183 errx(1, "bs must be between 1 and %zd", SSIZE_MAX); 184 in.dbsz = out.dbsz = (size_t)res; 185 } 186 187 static void 188 f_cbs(char *arg) 189 { 190 quad_t res; 191 192 res = get_num(arg); 193 if (res < 1 || res > SSIZE_MAX) 194 errx(1, "cbs must be between 1 and %zd", SSIZE_MAX); 195 cbsz = (size_t)res; 196 } 197 198 static void 199 f_count(char *arg) 200 { 201 202 cpy_cnt = get_num(arg); 203 if (cpy_cnt < 0) 204 errx(1, "count cannot be negative"); 205 if (cpy_cnt == 0) 206 cpy_cnt = -1; 207 } 208 209 static void 210 f_files(char *arg) 211 { 212 213 files_cnt = get_num(arg); 214 if (files_cnt < 1) 215 errx(1, "files must be between 1 and %qd", QUAD_MAX); 216 } 217 218 static void 219 f_ibs(char *arg) 220 { 221 quad_t res; 222 223 if (!(ddflags & C_BS)) { 224 res = get_num(arg); 225 if (res < 1 || res > SSIZE_MAX) 226 errx(1, "ibs must be between 1 and %zd", SSIZE_MAX); 227 in.dbsz = (size_t)res; 228 } 229 } 230 231 static void 232 f_if(char *arg) 233 { 234 235 in.name = arg; 236 } 237 238 static void 239 f_obs(char *arg) 240 { 241 quad_t res; 242 243 if (!(ddflags & C_BS)) { 244 res = get_num(arg); 245 if (res < 1 || res > SSIZE_MAX) 246 errx(1, "obs must be between 1 and %zd", SSIZE_MAX); 247 out.dbsz = (size_t)res; 248 } 249 } 250 251 static void 252 f_of(char *arg) 253 { 254 255 out.name = arg; 256 } 257 258 static void 259 f_seek(char *arg) 260 { 261 262 out.offset = get_offset(arg); 263 } 264 265 static void 266 f_skip(char *arg) 267 { 268 269 in.offset = get_offset(arg); 270 } 271 272 static const struct conv { 273 const char *name; 274 u_int set, noset; 275 const u_char *ctab; 276 } clist[] = { 277 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 278 { "block", C_BLOCK, C_UNBLOCK, NULL }, 279 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 280 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 281 { "lcase", C_LCASE, C_UCASE, NULL }, 282 { "noerror", C_NOERROR, 0, NULL }, 283 { "notrunc", C_NOTRUNC, 0, NULL }, 284 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 285 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 286 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 287 { "osync", C_OSYNC, C_BS, NULL }, 288 { "sparse", C_SPARSE, 0, NULL }, 289 { "swab", C_SWAB, 0, NULL }, 290 { "sync", C_SYNC, 0, NULL }, 291 { "ucase", C_UCASE, C_LCASE, NULL }, 292 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 293 }; 294 295 static void 296 f_conv(char *arg) 297 { 298 struct conv *cp, tmp; 299 300 while (arg != NULL) { 301 tmp.name = strsep(&arg, ","); 302 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 303 sizeof(struct conv), c_conv); 304 if (cp == NULL) 305 errx(1, "unknown conversion %s", tmp.name); 306 if (ddflags & cp->noset) 307 errx(1, "%s: illegal conversion combination", tmp.name); 308 ddflags |= cp->set; 309 if (cp->ctab) 310 ctab = cp->ctab; 311 } 312 } 313 314 static int 315 c_conv(const void *a, const void *b) 316 { 317 318 return (strcmp(((const struct conv *)a)->name, 319 ((const struct conv *)b)->name)); 320 } 321 322 /* 323 * Convert an expression of the following forms to a quad_t. 324 * 1) A positive decimal number. 325 * 2) A positive decimal number followed by a b (mult by 512.) 326 * 3) A positive decimal number followed by a k (mult by 1 << 10.) 327 * 4) A positive decimal number followed by a m (mult by 1 << 20.) 328 * 5) A positive decimal number followed by a g (mult by 1 << 30.) 329 * 5) A positive decimal number followed by a w (mult by sizeof int.) 330 * 6) Two or more positive decimal numbers (with/without [bkmgw]) 331 * separated by x (also * for backwards compatibility), specifying 332 * the product of the indicated values. 333 */ 334 static quad_t 335 get_num(char *val) 336 { 337 quad_t num, t; 338 char *expr; 339 340 errno = 0; 341 num = strtoll(val, &expr, 0); 342 if (errno != 0) /* Overflow or underflow. */ 343 err(1, "%s", oper); 344 345 if (expr == val) /* No valid digits. */ 346 errx(1, "%s: illegal numeric value", oper); 347 348 switch (*expr) { 349 case 'b': 350 case 'B': 351 t = num; 352 num *= 512; 353 if (t > num) 354 goto erange; 355 ++expr; 356 break; 357 case 'k': 358 case 'K': 359 t = num; 360 num *= 1 << 10; 361 if (t > num) 362 goto erange; 363 ++expr; 364 break; 365 case 'm': 366 case 'M': 367 t = num; 368 num *= 1 << 20; 369 if (t > num) 370 goto erange; 371 ++expr; 372 break; 373 case 'g': 374 case 'G': 375 t = num; 376 num *= 1 << 30; 377 if (t > num) 378 goto erange; 379 ++expr; 380 break; 381 case 'w': 382 t = num; 383 num *= sizeof(int); 384 if (t > num) 385 goto erange; 386 ++expr; 387 break; 388 } 389 390 switch (*expr) { 391 case '\0': 392 break; 393 case '*': /* Backward compatible. */ 394 case 'x': 395 t = num; 396 num *= get_num(expr + 1); 397 if (t <= num) 398 break; 399 erange: 400 errx(1, "%s: %s", oper, strerror(ERANGE)); 401 default: 402 errx(1, "%s: illegal numeric value", oper); 403 } 404 return (num); 405 } 406 407 static off_t 408 get_offset(char *val) 409 { 410 quad_t num; 411 412 num = get_num(val); 413 if (num > QUAD_MAX) /* XXX can't happen && quad_t != off_t */ 414 errx(1, "%s: illegal offset", oper); /* Too big. */ 415 return ((off_t)num); 416 } 417