File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #ifdef HAVE_CONFIG_H
0035 #include "config.h"
0036 #endif
0037
0038 #ifndef lint
0039 #if 0
0040 static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
0041 #endif
0042 #endif
0043 #include <sys/cdefs.h>
0044 __FBSDID("$FreeBSD: src/bin/dd/args.c,v 1.40 2004/08/15 19:10:05 rwatson Exp $");
0045
0046 #include <sys/types.h>
0047
0048 #include "err.h"
0049 #include <errno.h>
0050 #include <inttypes.h>
0051 #include <limits.h>
0052 #include <stdlib.h>
0053 #include <string.h>
0054
0055 #include "dd.h"
0056 #include "extern-dd.h"
0057
0058 #define strtouq strtoul
0059 #define strtoq strtol
0060
0061 static int c_arg(const void *, const void *);
0062 static int c_conv(const void *, const void *);
0063 static void f_bs(rtems_shell_dd_globals* globals, char *);
0064 static void f_cbs(rtems_shell_dd_globals* globals, char *);
0065 static void f_conv(rtems_shell_dd_globals* globals, char *);
0066 static void f_count(rtems_shell_dd_globals* globals, char *);
0067 static void f_files(rtems_shell_dd_globals* globals, char *);
0068 static void f_fillchar(rtems_shell_dd_globals* globals, char *);
0069 static void f_ibs(rtems_shell_dd_globals* globals, char *);
0070 static void f_if(rtems_shell_dd_globals* globals, char *);
0071 static void f_obs(rtems_shell_dd_globals* globals, char *);
0072 static void f_of(rtems_shell_dd_globals* globals, char *);
0073 static void f_seek(rtems_shell_dd_globals* globals, char *);
0074 static void f_skip(rtems_shell_dd_globals* globals, char *);
0075 static uintmax_t get_num(rtems_shell_dd_globals* globals, const char *);
0076 static off_t get_off_t(rtems_shell_dd_globals* globals, const char *);
0077
0078 static const struct arg {
0079 const char *name;
0080 void (*f)(rtems_shell_dd_globals* globals, char *);
0081 uint_least32_t set, noset;
0082 } args[] = {
0083 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
0084 { "cbs", f_cbs, C_CBS, C_CBS },
0085 { "conv", f_conv, 0, 0 },
0086 { "count", f_count, C_COUNT, C_COUNT },
0087 { "files", f_files, C_FILES, C_FILES },
0088 { "fillchar", f_fillchar, C_FILL, C_FILL },
0089 { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
0090 { "if", f_if, C_IF, C_IF },
0091 { "iseek", f_skip, C_SKIP, C_SKIP },
0092 { "obs", f_obs, C_OBS, C_BS|C_OBS },
0093 { "of", f_of, C_OF, C_OF },
0094 { "oseek", f_seek, C_SEEK, C_SEEK },
0095 { "seek", f_seek, C_SEEK, C_SEEK },
0096 { "skip", f_skip, C_SKIP, C_SKIP },
0097 };
0098
0099 static char *oper;
0100
0101
0102
0103
0104 void
0105 jcl(rtems_shell_dd_globals* globals, char **argv)
0106 {
0107 struct arg *ap, tmp;
0108 char *arg;
0109
0110 oper = NULL;
0111
0112 in.dbsz = out.dbsz = 512;
0113
0114 while ((oper = *++argv) != NULL) {
0115
0116
0117 if ((arg = strchr(oper, '=')) == NULL)
0118 errx(exit_jump, 1, "unknown operand %s", oper);
0119 *arg++ = '\0';
0120 if (!*arg)
0121 errx(exit_jump, 1, "no value specified for %s", oper);
0122 tmp.name = oper;
0123 if (!(ap = (struct arg *)bsearch(&tmp, args,
0124 sizeof(args)/sizeof(struct arg), sizeof(struct arg),
0125 c_arg)))
0126 errx(exit_jump, 1, "unknown operand %s", tmp.name);
0127 if (ddflags & ap->noset)
0128 errx(exit_jump, 1, "%s: illegal argument combination or already set",
0129 tmp.name);
0130 ddflags |= ap->set;
0131 ap->f(globals, arg);
0132 }
0133
0134
0135
0136 if (ddflags & C_BS) {
0137
0138
0139
0140
0141
0142 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
0143 C_UNBLOCK))
0144 ddflags &= ~C_BS;
0145
0146
0147 if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
0148 warnx("bs supersedes ibs and obs");
0149 }
0150
0151
0152
0153
0154
0155 if (ddflags & (C_BLOCK | C_UNBLOCK)) {
0156 if (!(ddflags & C_CBS))
0157 errx(exit_jump, 1, "record operations require cbs");
0158 if (cbsz == 0)
0159 errx(exit_jump, 1, "cbs cannot be zero");
0160 cfunc = ddflags & C_BLOCK ? block : unblock;
0161 } else if (ddflags & C_CBS) {
0162 if (ddflags & (C_ASCII | C_EBCDIC)) {
0163 if (ddflags & C_ASCII) {
0164 ddflags |= C_UNBLOCK;
0165 cfunc = unblock;
0166 } else {
0167 ddflags |= C_BLOCK;
0168 cfunc = block;
0169 }
0170 } else
0171 errx(exit_jump, 1, "cbs meaningless if not doing record operations");
0172 } else
0173 cfunc = def;
0174
0175
0176
0177
0178 if (in.offset > OFF_MAX / (ssize_t)in.dbsz ||
0179 out.offset > OFF_MAX / (ssize_t)out.dbsz)
0180 errx(exit_jump, 1, "seek offsets cannot be larger than %jd",
0181 (intmax_t)OFF_MAX);
0182 }
0183
0184 static int
0185 c_arg(const void *a, const void *b)
0186 {
0187
0188 return (strcmp(((const struct arg *)a)->name,
0189 ((const struct arg *)b)->name));
0190 }
0191
0192 static void
0193 f_bs(rtems_shell_dd_globals* globals, char *arg)
0194 {
0195 uintmax_t res;
0196
0197 res = get_num(globals, arg);
0198 if (res < 1 || res > SSIZE_MAX)
0199 errx(exit_jump, 1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
0200 in.dbsz = out.dbsz = (size_t)res;
0201 }
0202
0203 static void
0204 f_cbs(rtems_shell_dd_globals* globals, char *arg)
0205 {
0206 uintmax_t res;
0207
0208 res = get_num(globals, arg);
0209 if (res < 1 || res > SSIZE_MAX)
0210 errx(exit_jump, 1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
0211 cbsz = (size_t)res;
0212 }
0213
0214 static void
0215 f_count(rtems_shell_dd_globals* globals, char *arg)
0216 {
0217 intmax_t res;
0218
0219 res = (intmax_t)get_num(globals, arg);
0220 if (res < 0)
0221 errx(exit_jump, 1, "count cannot be negative");
0222 if (res == 0)
0223 cpy_cnt = (uintmax_t)-1;
0224 else
0225 cpy_cnt = (uintmax_t)res;
0226 }
0227
0228 static void
0229 f_files(rtems_shell_dd_globals* globals, char *arg)
0230 {
0231
0232 files_cnt = get_num(globals, arg);
0233 if (files_cnt < 1)
0234 errx(exit_jump, 1, "files must be between 1 and %jd", (uintmax_t)-1);
0235 }
0236
0237 static void
0238 f_fillchar(rtems_shell_dd_globals* globals, char *arg)
0239 {
0240
0241 if (strlen(arg) != 1)
0242 errx(exit_jump, 1, "need exactly one fill char");
0243
0244 fill_char = arg[0];
0245 }
0246
0247 static void
0248 f_ibs(rtems_shell_dd_globals* globals, char *arg)
0249 {
0250 uintmax_t res;
0251
0252 if (!(ddflags & C_BS)) {
0253 res = get_num(globals, arg);
0254 if (res < 1 || res > SSIZE_MAX)
0255 errx(exit_jump, 1, "ibs must be between 1 and %jd",
0256 (intmax_t)SSIZE_MAX);
0257 in.dbsz = (size_t)res;
0258 }
0259 }
0260
0261 static void
0262 f_if(rtems_shell_dd_globals* globals, char *arg)
0263 {
0264
0265 in.name = strdup(arg);
0266 }
0267
0268 static void
0269 f_obs(rtems_shell_dd_globals* globals, char *arg)
0270 {
0271 uintmax_t res;
0272
0273 if (!(ddflags & C_BS)) {
0274 res = get_num(globals, arg);
0275 if (res < 1 || res > SSIZE_MAX)
0276 errx(exit_jump, 1, "obs must be between 1 and %jd",
0277 (intmax_t)SSIZE_MAX);
0278 out.dbsz = (size_t)res;
0279 }
0280 }
0281
0282 static void
0283 f_of(rtems_shell_dd_globals* globals, char *arg)
0284 {
0285
0286 out.name = strdup(arg);
0287 }
0288
0289 static void
0290 f_seek(rtems_shell_dd_globals* globals, char *arg)
0291 {
0292
0293 out.offset = get_off_t(globals, arg);
0294 }
0295
0296 static void
0297 f_skip(rtems_shell_dd_globals* globals, char *arg)
0298 {
0299
0300 in.offset = get_off_t(globals, arg);
0301 }
0302
0303 static const struct conv {
0304 const char *name;
0305 uint_least32_t set, noset;
0306 const u_char *ctab_;
0307 } clist[] = {
0308 { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
0309 { "block", C_BLOCK, C_UNBLOCK, NULL },
0310 { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
0311 { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
0312 { "lcase", C_LCASE, C_UCASE, NULL },
0313 { "noerror", C_NOERROR, 0, NULL },
0314 { "notrunc", C_NOTRUNC, 0, NULL },
0315 { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
0316 { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
0317 { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
0318 { "osync", C_OSYNC, C_BS, NULL },
0319 { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL},
0320 { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL},
0321 { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL},
0322 { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL},
0323 { "sparse", C_SPARSE, 0, NULL },
0324 { "swab", C_SWAB, 0, NULL },
0325 { "sync", C_SYNC, 0, NULL },
0326 { "ucase", C_UCASE, C_LCASE, NULL },
0327 { "unblock", C_UNBLOCK, C_BLOCK, NULL },
0328 };
0329
0330 static void
0331 f_conv(rtems_shell_dd_globals* globals, char *arg)
0332 {
0333 struct conv *cp, tmp;
0334
0335 while (arg != NULL) {
0336 tmp.name = strsep(&arg, ",");
0337 cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
0338 sizeof(struct conv), c_conv);
0339 if (cp == NULL)
0340 errx(exit_jump, 1, "unknown conversion %s", tmp.name);
0341 if (ddflags & cp->noset)
0342 errx(exit_jump, 1, "%s: illegal conversion combination", tmp.name);
0343 ddflags |= cp->set;
0344 if (cp->ctab_)
0345 ctab = cp->ctab_;
0346 }
0347 }
0348
0349 static int
0350 c_conv(const void *a, const void *b)
0351 {
0352
0353 return (strcmp(((const struct conv *)a)->name,
0354 ((const struct conv *)b)->name));
0355 }
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 static uintmax_t
0370 get_num(rtems_shell_dd_globals* globals, const char *val)
0371 {
0372 uintmax_t num, mult, prevnum;
0373 char *expr;
0374
0375 errno = 0;
0376 num = strtouq(val, &expr, 0);
0377 if (errno != 0)
0378 err(exit_jump, 1, "%s", oper);
0379
0380 if (expr == val)
0381 errx(exit_jump, 1, "%s: illegal numeric value", oper);
0382
0383 mult = 0;
0384 switch (*expr) {
0385 case 'B':
0386 case 'b':
0387 mult = UINT32_C(512);
0388 break;
0389 case 'K':
0390 case 'k':
0391 mult = UINT32_C(1) << 10;
0392 break;
0393 case 'M':
0394 case 'm':
0395 mult = UINT32_C(1) << 20;
0396 break;
0397 case 'G':
0398 case 'g':
0399 mult = UINT32_C(1) << 30;
0400 break;
0401 case 'W':
0402 case 'w':
0403 mult = sizeof(int);
0404 break;
0405 default:
0406 ;
0407 }
0408
0409 if (mult != 0) {
0410 prevnum = num;
0411 num *= mult;
0412
0413 if (num / mult != prevnum)
0414 goto erange;
0415 expr++;
0416 }
0417
0418 switch (*expr) {
0419 case '\0':
0420 break;
0421 case '*':
0422 case 'X':
0423 case 'x':
0424 mult = get_num(globals, expr + 1);
0425 prevnum = num;
0426 num *= mult;
0427 if (num / mult == prevnum)
0428 break;
0429 erange:
0430 errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE));
0431 default:
0432 errx(exit_jump, 1, "%s: illegal numeric value", oper);
0433 }
0434 return (num);
0435 }
0436
0437
0438
0439
0440
0441
0442
0443 static off_t
0444 get_off_t(rtems_shell_dd_globals* globals, const char *val)
0445 {
0446 intmax_t num, mult, prevnum;
0447 char *expr;
0448
0449 errno = 0;
0450 num = strtoq(val, &expr, 0);
0451 if (errno != 0)
0452 err(exit_jump, 1, "%s", oper);
0453
0454 if (expr == val)
0455 errx(exit_jump, 1, "%s: illegal numeric value", oper);
0456
0457 mult = 0;
0458 switch (*expr) {
0459 case 'B':
0460 case 'b':
0461 mult = UINT32_C(512);
0462 break;
0463 case 'K':
0464 case 'k':
0465 mult = UINT32_C(1) << 10;
0466 break;
0467 case 'M':
0468 case 'm':
0469 mult = UINT32_C(1) << 20;
0470 break;
0471 case 'G':
0472 case 'g':
0473 mult = UINT32_C(1) << 30;
0474 break;
0475 case 'W':
0476 case 'w':
0477 mult = sizeof(int);
0478 break;
0479 }
0480
0481 if (mult != 0) {
0482 prevnum = num;
0483 num *= mult;
0484
0485 if ((prevnum > 0) != (num > 0) || num / mult != prevnum)
0486 goto erange;
0487 expr++;
0488 }
0489
0490 switch (*expr) {
0491 case '\0':
0492 break;
0493 case '*':
0494 case 'X':
0495 case 'x':
0496 mult = (intmax_t)get_off_t(globals, expr + 1);
0497 prevnum = num;
0498 num *= mult;
0499 if ((prevnum > 0) == (num > 0) && num / mult == prevnum)
0500 break;
0501 erange:
0502 errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE));
0503 default:
0504 errx(exit_jump, 1, "%s: illegal numeric value", oper);
0505 }
0506 return (num);
0507 }