Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*-
0002  * Copyright (c) 1991, 1993, 1994
0003  *  The Regents of the University of California.  All rights reserved.
0004  *
0005  * This code is derived from software contributed to Berkeley by
0006  * Keith Muller of the University of California, San Diego and Lance
0007  * Visser of Convex Computer Corporation.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  * 4. Neither the name of the University nor the names of its contributors
0018  *    may be used to endorse or promote products derived from this software
0019  *    without specific prior written permission.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0031  * SUCH DAMAGE.
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 /* not lint */
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  * args -- parse JCL syntax of dd.
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 //      if ((oper = strdup(oper)) == NULL)
0116 //          errx(exit_jump, 1, "unable to allocate space for the argument \"%s\"", *argv);
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     /* Final sanity checks. */
0135 
0136     if (ddflags & C_BS) {
0137         /*
0138          * Bs is turned off by any conversion -- we assume the user
0139          * just wanted to set both the input and output block sizes
0140          * and didn't want the bs semantics, so we don't warn.
0141          */
0142         if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
0143             C_UNBLOCK))
0144             ddflags &= ~C_BS;
0145 
0146         /* Bs supersedes ibs and obs. */
0147         if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
0148             warnx("bs supersedes ibs and obs");
0149     }
0150 
0151     /*
0152      * Ascii/ebcdic and cbs implies block/unblock.
0153      * Block/unblock requires cbs and vice-versa.
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      * Bail out if the calculation of a file offset would overflow.
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  * Convert an expression of the following forms to a uintmax_t.
0359  *  1) A positive decimal number.
0360  *  2) A positive decimal number followed by a 'b' or 'B' (mult by 512).
0361  *  3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
0362  *  4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
0363  *  5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
0364  *  5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int).
0365  *  6) Two or more positive decimal numbers (with/without [BbKkMmGgWw])
0366  *     separated by 'x' or 'X' (also '*' for backwards compatibility),
0367  *     specifying the product of the indicated values.
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)             /* Overflow or underflow. */
0378         err(exit_jump, 1, "%s", oper);
0379 
0380     if (expr == val)            /* No valid digits. */
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         /* Check for overflow. */
0413         if (num / mult != prevnum)
0414             goto erange;
0415         expr++;
0416     }
0417 
0418     switch (*expr) {
0419         case '\0':
0420             break;
0421         case '*':           /* Backward compatible. */
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  * Convert an expression of the following forms to an off_t.  This is the
0439  * same as get_num(), but it uses signed numbers.
0440  *
0441  * The major problem here is that an off_t may not necessarily be a intmax_t.
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)             /* Overflow or underflow. */
0452         err(exit_jump, 1, "%s", oper);
0453 
0454     if (expr == val)            /* No valid digits. */
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         /* Check for overflow. */
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 '*':           /* Backward compatible. */
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 }