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 * @(#)args.c 8.3 (Berkeley) 4/2/94 38 * $FreeBSD: src/bin/dd/args.c,v 1.25.2.2 2001/01/23 14:20:03 asmodai Exp $ 39 * $DragonFly: src/bin/dd/args.c,v 1.5 2004/03/19 17:17:46 cpressey Exp $ 40 */ 41 42 #include <sys/types.h> 43 44 #include <err.h> 45 #include <errno.h> 46 #include <limits.h> 47 #include <stdlib.h> 48 #include <string.h> 49 50 #include "dd.h" 51 #include "extern.h" 52 53 static int c_arg (const void *, const void *); 54 static int c_conv (const void *, const void *); 55 static void f_bs (char *); 56 static void f_cbs (char *); 57 static void f_conv (char *); 58 static void f_count (char *); 59 static void f_files (char *); 60 static void f_ibs (char *); 61 static void f_if (char *); 62 static void f_obs(char *); 63 static void f_of (char *); 64 static void f_seek (char *); 65 static void f_skip (char *); 66 static quad_t get_num (char *); 67 static off_t get_offset (char *); 68 69 static const struct arg { 70 const char *name; 71 void (*f) (char *); 72 u_int set, noset; 73 } args[] = { 74 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 75 { "cbs", f_cbs, C_CBS, C_CBS }, 76 { "conv", f_conv, 0, 0 }, 77 { "count", f_count, C_COUNT, C_COUNT }, 78 { "files", f_files, C_FILES, C_FILES }, 79 { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 80 { "if", f_if, C_IF, C_IF }, 81 { "iseek", f_skip, C_SKIP, C_SKIP }, 82 { "obs", f_obs, C_OBS, C_BS|C_OBS }, 83 { "of", f_of, C_OF, C_OF }, 84 { "oseek", f_seek, C_SEEK, C_SEEK }, 85 { "seek", f_seek, C_SEEK, C_SEEK }, 86 { "skip", f_skip, C_SKIP, C_SKIP }, 87 }; 88 89 static char *oper; 90 91 /* 92 * args -- parse JCL syntax of dd. 93 */ 94 void 95 jcl(char **argv) 96 { 97 struct arg *ap, tmp; 98 char *arg; 99 100 in.dbsz = out.dbsz = 512; 101 102 while ((oper = *++argv) != NULL) { 103 if ((oper = strdup(oper)) == NULL) 104 errx(1, "unable to allocate space for the argument \"%s\"", *argv); 105 if ((arg = strchr(oper, '=')) == NULL) 106 errx(1, "unknown operand %s", oper); 107 *arg++ = '\0'; 108 if (!*arg) 109 errx(1, "no value specified for %s", oper); 110 tmp.name = oper; 111 if (!(ap = (struct arg *)bsearch(&tmp, args, 112 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 113 c_arg))) 114 errx(1, "unknown operand %s", tmp.name); 115 if (ddflags & ap->noset) 116 errx(1, "%s: illegal argument combination or already set", 117 tmp.name); 118 ddflags |= ap->set; 119 ap->f(arg); 120 } 121 122 /* Final sanity checks. */ 123 124 if (ddflags & C_BS) { 125 /* 126 * Bs is turned off by any conversion -- we assume the user 127 * just wanted to set both the input and output block sizes 128 * and didn't want the bs semantics, so we don't warn. 129 */ 130 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 131 C_UNBLOCK)) 132 ddflags &= ~C_BS; 133 134 /* Bs supersedes ibs and obs. */ 135 if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 136 warnx("bs supersedes ibs and obs"); 137 } 138 139 /* 140 * Ascii/ebcdic and cbs implies block/unblock. 141 * Block/unblock requires cbs and vice-versa. 142 */ 143 if (ddflags & (C_BLOCK | C_UNBLOCK)) { 144 if (!(ddflags & C_CBS)) 145 errx(1, "record operations require cbs"); 146 if (cbsz == 0) 147 errx(1, "cbs cannot be zero"); 148 cfunc = ddflags & C_BLOCK ? block : unblock; 149 } else if (ddflags & C_CBS) { 150 if (ddflags & (C_ASCII | C_EBCDIC)) { 151 if (ddflags & C_ASCII) { 152 ddflags |= C_UNBLOCK; 153 cfunc = unblock; 154 } else { 155 ddflags |= C_BLOCK; 156 cfunc = block; 157 } 158 } else 159 errx(1, "cbs meaningless if not doing record operations"); 160 } else 161 cfunc = def; 162 163 /* 164 * Bail out if the calculation of a file offset would overflow. 165 */ 166 if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz) 167 errx(1, "seek offsets cannot be larger than %lld", QUAD_MAX); 168 } 169 170 static int 171 c_arg(const void *a, const void *b) 172 { 173 174 return (strcmp(((const struct arg *)a)->name, 175 ((const struct arg *)b)->name)); 176 } 177 178 static void 179 f_bs(char *arg) 180 { 181 quad_t res; 182 183 res = get_num(arg); 184 if (res < 1 || res > SSIZE_MAX) 185 errx(1, "bs must be between 1 and %d", SSIZE_MAX); 186 in.dbsz = out.dbsz = (size_t)res; 187 } 188 189 static void 190 f_cbs(char *arg) 191 { 192 quad_t res; 193 194 res = get_num(arg); 195 if (res < 1 || res > SSIZE_MAX) 196 errx(1, "cbs must be between 1 and %d", SSIZE_MAX); 197 cbsz = (size_t)res; 198 } 199 200 static void 201 f_count(char *arg) 202 { 203 204 cpy_cnt = get_num(arg); 205 if (cpy_cnt < 0) 206 errx(1, "count cannot be negative"); 207 if (cpy_cnt == 0) 208 cpy_cnt = -1; 209 } 210 211 static void 212 f_files(char *arg) 213 { 214 215 files_cnt = get_num(arg); 216 if (files_cnt < 1) 217 errx(1, "files must be between 1 and %qd", QUAD_MAX); 218 } 219 220 static void 221 f_ibs(char *arg) 222 { 223 quad_t res; 224 225 if (!(ddflags & C_BS)) { 226 res = get_num(arg); 227 if (res < 1 || res > SSIZE_MAX) 228 errx(1, "ibs must be between 1 and %d", SSIZE_MAX); 229 in.dbsz = (size_t)res; 230 } 231 } 232 233 static void 234 f_if(char *arg) 235 { 236 237 in.name = arg; 238 } 239 240 static void 241 f_obs(char *arg) 242 { 243 quad_t res; 244 245 if (!(ddflags & C_BS)) { 246 res = get_num(arg); 247 if (res < 1 || res > SSIZE_MAX) 248 errx(1, "obs must be between 1 and %d", SSIZE_MAX); 249 out.dbsz = (size_t)res; 250 } 251 } 252 253 static void 254 f_of(char *arg) 255 { 256 257 out.name = arg; 258 } 259 260 static void 261 f_seek(char *arg) 262 { 263 264 out.offset = get_offset(arg); 265 } 266 267 static void 268 f_skip(char *arg) 269 { 270 271 in.offset = get_offset(arg); 272 } 273 274 static const struct conv { 275 const char *name; 276 u_int set, noset; 277 const u_char *ctab; 278 } clist[] = { 279 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 280 { "block", C_BLOCK, C_UNBLOCK, NULL }, 281 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 282 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 283 { "lcase", C_LCASE, C_UCASE, NULL }, 284 { "noerror", C_NOERROR, 0, NULL }, 285 { "notrunc", C_NOTRUNC, 0, NULL }, 286 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 287 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 288 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 289 { "osync", C_OSYNC, C_BS, NULL }, 290 { "sparse", C_SPARSE, 0, NULL }, 291 { "swab", C_SWAB, 0, NULL }, 292 { "sync", C_SYNC, 0, NULL }, 293 { "ucase", C_UCASE, C_LCASE, NULL }, 294 { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 295 }; 296 297 static void 298 f_conv(char *arg) 299 { 300 struct conv *cp, tmp; 301 302 while (arg != NULL) { 303 tmp.name = strsep(&arg, ","); 304 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 305 sizeof(struct conv), c_conv); 306 if (cp == NULL) 307 errx(1, "unknown conversion %s", tmp.name); 308 if (ddflags & cp->noset) 309 errx(1, "%s: illegal conversion combination", tmp.name); 310 ddflags |= cp->set; 311 if (cp->ctab) 312 ctab = cp->ctab; 313 } 314 } 315 316 static int 317 c_conv(const void *a, const void *b) 318 { 319 320 return (strcmp(((const struct conv *)a)->name, 321 ((const struct conv *)b)->name)); 322 } 323 324 /* 325 * Convert an expression of the following forms to a quad_t. 326 * 1) A positive decimal number. 327 * 2) A positive decimal number followed by a b (mult by 512.) 328 * 3) A positive decimal number followed by a k (mult by 1 << 10.) 329 * 4) A positive decimal number followed by a m (mult by 1 << 20.) 330 * 5) A positive decimal number followed by a g (mult by 1 << 30.) 331 * 5) A positive decimal number followed by a w (mult by sizeof int.) 332 * 6) Two or more positive decimal numbers (with/without [bkmgw]) 333 * separated by x (also * for backwards compatibility), specifying 334 * the product of the indicated values. 335 */ 336 static quad_t 337 get_num(char *val) 338 { 339 quad_t num, t; 340 char *expr; 341 342 errno = 0; 343 num = strtoll(val, &expr, 0); 344 if (errno != 0) /* Overflow or underflow. */ 345 err(1, "%s", oper); 346 347 if (expr == val) /* No valid digits. */ 348 errx(1, "%s: illegal numeric value", oper); 349 350 switch (*expr) { 351 case 'b': 352 t = num; 353 num *= 512; 354 if (t > num) 355 goto erange; 356 ++expr; 357 break; 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 t = num; 367 num *= 1 << 20; 368 if (t > num) 369 goto erange; 370 ++expr; 371 break; 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