source: rtems/cpukit/libmisc/shell/dd-args.c @ 68e1ccc4

5
Last change on this file since 68e1ccc4 was 6cdaa85, checked in by Sebastian Huber <sebastian.huber@…>, on 10/04/18 at 18:16:45

shell: Use #include "..." for local header files

Update #3375.

  • Property mode set to 100644
File size: 13.1 KB
Line 
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 * 4. 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
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)args.c      8.3 (Berkeley) 4/2/94";
41#endif
42#endif /* not lint */
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: src/bin/dd/args.c,v 1.40 2004/08/15 19:10:05 rwatson Exp $");
45
46#include <sys/types.h>
47
48#include "err.h"
49#include <errno.h>
50#include <inttypes.h>
51#include <limits.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include "dd.h"
56#include "extern-dd.h"
57
58#define strtouq strtoul
59#define strtoq strtol
60
61static int      c_arg(const void *, const void *);
62static int      c_conv(const void *, const void *);
63static void     f_bs(rtems_shell_dd_globals* globals, char *);
64static void     f_cbs(rtems_shell_dd_globals* globals, char *);
65static void     f_conv(rtems_shell_dd_globals* globals, char *);
66static void     f_count(rtems_shell_dd_globals* globals, char *);
67static void     f_files(rtems_shell_dd_globals* globals, char *);
68static void     f_fillchar(rtems_shell_dd_globals* globals, char *);
69static void     f_ibs(rtems_shell_dd_globals* globals, char *);
70static void     f_if(rtems_shell_dd_globals* globals, char *);
71static void     f_obs(rtems_shell_dd_globals* globals, char *);
72static void     f_of(rtems_shell_dd_globals* globals, char *);
73static void     f_seek(rtems_shell_dd_globals* globals, char *);
74static void     f_skip(rtems_shell_dd_globals* globals, char *);
75static uintmax_t get_num(rtems_shell_dd_globals* globals, const char *);
76static off_t    get_off_t(rtems_shell_dd_globals* globals, const char *);
77
78static const struct arg {
79        const char *name;
80        void (*f)(rtems_shell_dd_globals* globals, char *);
81        uint_least32_t set, noset;
82} args[] = {
83        { "bs",         f_bs,           C_BS,    C_BS|C_IBS|C_OBS|C_OSYNC },
84        { "cbs",        f_cbs,          C_CBS,   C_CBS },
85        { "conv",       f_conv,         0,       0 },
86        { "count",      f_count,        C_COUNT, C_COUNT },
87        { "files",      f_files,        C_FILES, C_FILES },
88        { "fillchar",   f_fillchar,     C_FILL,  C_FILL },
89        { "ibs",        f_ibs,          C_IBS,   C_BS|C_IBS },
90        { "if",         f_if,           C_IF,    C_IF },
91        { "iseek",      f_skip,         C_SKIP,  C_SKIP },
92        { "obs",        f_obs,          C_OBS,   C_BS|C_OBS },
93        { "of",         f_of,           C_OF,    C_OF },
94        { "oseek",      f_seek,         C_SEEK,  C_SEEK },
95        { "seek",       f_seek,         C_SEEK,  C_SEEK },
96        { "skip",       f_skip,         C_SKIP,  C_SKIP },
97};
98
99static char *oper;
100
101/*
102 * args -- parse JCL syntax of dd.
103 */
104void
105jcl(rtems_shell_dd_globals* globals, char **argv)
106{
107        struct arg *ap, tmp;
108        char *arg;
109
110  oper = NULL;
111
112        in.dbsz = out.dbsz = 512;
113
114        while ((oper = *++argv) != NULL) {
115//              if ((oper = strdup(oper)) == NULL)
116//                      errx(exit_jump, 1, "unable to allocate space for the argument \"%s\"", *argv);
117                if ((arg = strchr(oper, '=')) == NULL)
118                        errx(exit_jump, 1, "unknown operand %s", oper);
119                *arg++ = '\0';
120                if (!*arg)
121                        errx(exit_jump, 1, "no value specified for %s", oper);
122                tmp.name = oper;
123                if (!(ap = (struct arg *)bsearch(&tmp, args,
124                    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
125                    c_arg)))
126                        errx(exit_jump, 1, "unknown operand %s", tmp.name);
127                if (ddflags & ap->noset)
128                        errx(exit_jump, 1, "%s: illegal argument combination or already set",
129                            tmp.name);
130                ddflags |= ap->set;
131                ap->f(globals, arg);
132        }
133
134        /* Final sanity checks. */
135
136        if (ddflags & C_BS) {
137                /*
138                 * Bs is turned off by any conversion -- we assume the user
139                 * just wanted to set both the input and output block sizes
140                 * and didn't want the bs semantics, so we don't warn.
141                 */
142                if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
143                    C_UNBLOCK))
144                        ddflags &= ~C_BS;
145
146                /* Bs supersedes ibs and obs. */
147                if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
148                        warnx("bs supersedes ibs and obs");
149        }
150
151        /*
152         * Ascii/ebcdic and cbs implies block/unblock.
153         * Block/unblock requires cbs and vice-versa.
154         */
155        if (ddflags & (C_BLOCK | C_UNBLOCK)) {
156                if (!(ddflags & C_CBS))
157                        errx(exit_jump, 1, "record operations require cbs");
158                if (cbsz == 0)
159                        errx(exit_jump, 1, "cbs cannot be zero");
160                cfunc = ddflags & C_BLOCK ? block : unblock;
161        } else if (ddflags & C_CBS) {
162                if (ddflags & (C_ASCII | C_EBCDIC)) {
163                        if (ddflags & C_ASCII) {
164                                ddflags |= C_UNBLOCK;
165                                cfunc = unblock;
166                        } else {
167                                ddflags |= C_BLOCK;
168                                cfunc = block;
169                        }
170                } else
171                        errx(exit_jump, 1, "cbs meaningless if not doing record operations");
172        } else
173                cfunc = def;
174
175        /*
176         * Bail out if the calculation of a file offset would overflow.
177         */
178        if (in.offset > OFF_MAX / (ssize_t)in.dbsz ||
179            out.offset > OFF_MAX / (ssize_t)out.dbsz)
180                errx(exit_jump, 1, "seek offsets cannot be larger than %jd",
181                    (intmax_t)OFF_MAX);
182}
183
184static int
185c_arg(const void *a, const void *b)
186{
187
188        return (strcmp(((const struct arg *)a)->name,
189            ((const struct arg *)b)->name));
190}
191
192static void
193f_bs(rtems_shell_dd_globals* globals, char *arg)
194{
195        uintmax_t res;
196
197        res = get_num(globals, arg);
198        if (res < 1 || res > SSIZE_MAX)
199                errx(exit_jump, 1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
200        in.dbsz = out.dbsz = (size_t)res;
201}
202
203static void
204f_cbs(rtems_shell_dd_globals* globals, char *arg)
205{
206        uintmax_t res;
207
208        res = get_num(globals, arg);
209        if (res < 1 || res > SSIZE_MAX)
210                errx(exit_jump, 1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
211        cbsz = (size_t)res;
212}
213
214static void
215f_count(rtems_shell_dd_globals* globals, char *arg)
216{
217        intmax_t res;
218
219        res = (intmax_t)get_num(globals, arg);
220        if (res < 0)
221                errx(exit_jump, 1, "count cannot be negative");
222        if (res == 0)
223                cpy_cnt = (uintmax_t)-1;
224        else
225                cpy_cnt = (uintmax_t)res;
226}
227
228static void
229f_files(rtems_shell_dd_globals* globals, char *arg)
230{
231
232        files_cnt = get_num(globals, arg);
233        if (files_cnt < 1)
234                errx(exit_jump, 1, "files must be between 1 and %jd", (uintmax_t)-1);
235}
236
237static void
238f_fillchar(rtems_shell_dd_globals* globals, char *arg)
239{
240
241        if (strlen(arg) != 1)
242                errx(exit_jump, 1, "need exactly one fill char");
243
244        fill_char = arg[0];
245}
246
247static void
248f_ibs(rtems_shell_dd_globals* globals, char *arg)
249{
250        uintmax_t res;
251
252        if (!(ddflags & C_BS)) {
253                res = get_num(globals, arg);
254                if (res < 1 || res > SSIZE_MAX)
255                        errx(exit_jump, 1, "ibs must be between 1 and %jd",
256                            (intmax_t)SSIZE_MAX);
257                in.dbsz = (size_t)res;
258        }
259}
260
261static void
262f_if(rtems_shell_dd_globals* globals, char *arg)
263{
264
265        in.name = strdup(arg);
266}
267
268static void
269f_obs(rtems_shell_dd_globals* globals, char *arg)
270{
271        uintmax_t res;
272
273        if (!(ddflags & C_BS)) {
274                res = get_num(globals, arg);
275                if (res < 1 || res > SSIZE_MAX)
276                        errx(exit_jump, 1, "obs must be between 1 and %jd",
277                            (intmax_t)SSIZE_MAX);
278                out.dbsz = (size_t)res;
279        }
280}
281
282static void
283f_of(rtems_shell_dd_globals* globals, char *arg)
284{
285
286        out.name = strdup(arg);
287}
288
289static void
290f_seek(rtems_shell_dd_globals* globals, char *arg)
291{
292
293        out.offset = get_off_t(globals, arg);
294}
295
296static void
297f_skip(rtems_shell_dd_globals* globals, char *arg)
298{
299
300        in.offset = get_off_t(globals, arg);
301}
302
303static const struct conv {
304        const char *name;
305        uint_least32_t set, noset;
306        const u_char *ctab_;
307} clist[] = {
308        { "ascii",      C_ASCII,        C_EBCDIC,       e2a_POSIX },
309        { "block",      C_BLOCK,        C_UNBLOCK,      NULL },
310        { "ebcdic",     C_EBCDIC,       C_ASCII,        a2e_POSIX },
311        { "ibm",        C_EBCDIC,       C_ASCII,        a2ibm_POSIX },
312        { "lcase",      C_LCASE,        C_UCASE,        NULL },
313        { "noerror",    C_NOERROR,      0,              NULL },
314        { "notrunc",    C_NOTRUNC,      0,              NULL },
315        { "oldascii",   C_ASCII,        C_EBCDIC,       e2a_32V },
316        { "oldebcdic",  C_EBCDIC,       C_ASCII,        a2e_32V },
317        { "oldibm",     C_EBCDIC,       C_ASCII,        a2ibm_32V },
318        { "osync",      C_OSYNC,        C_BS,           NULL },
319        { "pareven",    C_PAREVEN,      C_PARODD|C_PARSET|C_PARNONE, NULL},
320        { "parnone",    C_PARNONE,      C_PARODD|C_PARSET|C_PAREVEN, NULL},
321        { "parodd",     C_PARODD,       C_PAREVEN|C_PARSET|C_PARNONE, NULL},
322        { "parset",     C_PARSET,       C_PARODD|C_PAREVEN|C_PARNONE, NULL},
323        { "sparse",     C_SPARSE,       0,              NULL },
324        { "swab",       C_SWAB,         0,              NULL },
325        { "sync",       C_SYNC,         0,              NULL },
326        { "ucase",      C_UCASE,        C_LCASE,        NULL },
327        { "unblock",    C_UNBLOCK,      C_BLOCK,        NULL },
328};
329
330static void
331f_conv(rtems_shell_dd_globals* globals, char *arg)
332{
333        struct conv *cp, tmp;
334
335        while (arg != NULL) {
336                tmp.name = strsep(&arg, ",");
337                cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
338                    sizeof(struct conv), c_conv);
339                if (cp == NULL)
340                        errx(exit_jump, 1, "unknown conversion %s", tmp.name);
341                if (ddflags & cp->noset)
342                        errx(exit_jump, 1, "%s: illegal conversion combination", tmp.name);
343                ddflags |= cp->set;
344                if (cp->ctab_)
345                        ctab = cp->ctab_;
346        }
347}
348
349static int
350c_conv(const void *a, const void *b)
351{
352
353        return (strcmp(((const struct conv *)a)->name,
354            ((const struct conv *)b)->name));
355}
356
357/*
358 * Convert an expression of the following forms to a uintmax_t.
359 *      1) A positive decimal number.
360 *      2) A positive decimal number followed by a 'b' or 'B' (mult by 512).
361 *      3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
362 *      4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
363 *      5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
364 *      5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int).
365 *      6) Two or more positive decimal numbers (with/without [BbKkMmGgWw])
366 *         separated by 'x' or 'X' (also '*' for backwards compatibility),
367 *         specifying the product of the indicated values.
368 */
369static uintmax_t
370get_num(rtems_shell_dd_globals* globals, const char *val)
371{
372        uintmax_t num, mult, prevnum;
373        char *expr;
374
375        errno = 0;
376        num = strtouq(val, &expr, 0);
377        if (errno != 0)                         /* Overflow or underflow. */
378                err(exit_jump, 1, "%s", oper);
379
380        if (expr == val)                        /* No valid digits. */
381                errx(exit_jump, 1, "%s: illegal numeric value", oper);
382
383        mult = 0;
384        switch (*expr) {
385        case 'B':
386        case 'b':
387                mult = UINT32_C(512);
388                break;
389        case 'K':
390        case 'k':
391                mult = UINT32_C(1) << 10;
392                break;
393        case 'M':
394        case 'm':
395                mult = UINT32_C(1) << 20;
396                break;
397        case 'G':
398        case 'g':
399                mult = UINT32_C(1) << 30;
400                break;
401        case 'W':
402        case 'w':
403                mult = sizeof(int);
404                break;
405        default:
406                ;
407        }
408
409        if (mult != 0) {
410                prevnum = num;
411                num *= mult;
412                /* Check for overflow. */
413                if (num / mult != prevnum)
414                        goto erange;
415                expr++;
416        }
417
418        switch (*expr) {
419                case '\0':
420                        break;
421                case '*':                       /* Backward compatible. */
422                case 'X':
423                case 'x':
424                        mult = get_num(globals, expr + 1);
425                        prevnum = num;
426                        num *= mult;
427                        if (num / mult == prevnum)
428                                break;
429erange:
430                        errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE));
431                default:
432                        errx(exit_jump, 1, "%s: illegal numeric value", oper);
433        }
434        return (num);
435}
436
437/*
438 * Convert an expression of the following forms to an off_t.  This is the
439 * same as get_num(), but it uses signed numbers.
440 *
441 * The major problem here is that an off_t may not necessarily be a intmax_t.
442 */
443static off_t
444get_off_t(rtems_shell_dd_globals* globals, const char *val)
445{
446        intmax_t num, mult, prevnum;
447        char *expr;
448
449        errno = 0;
450        num = strtoq(val, &expr, 0);
451        if (errno != 0)                         /* Overflow or underflow. */
452                err(exit_jump, 1, "%s", oper);
453
454        if (expr == val)                        /* No valid digits. */
455                errx(exit_jump, 1, "%s: illegal numeric value", oper);
456
457        mult = 0;
458        switch (*expr) {
459        case 'B':
460        case 'b':
461                mult = UINT32_C(512);
462                break;
463        case 'K':
464        case 'k':
465                mult = UINT32_C(1) << 10;
466                break;
467        case 'M':
468        case 'm':
469                mult = UINT32_C(1) << 20;
470                break;
471        case 'G':
472        case 'g':
473                mult = UINT32_C(1) << 30;
474                break;
475        case 'W':
476        case 'w':
477                mult = sizeof(int);
478                break;
479        }
480
481        if (mult != 0) {
482                prevnum = num;
483                num *= mult;
484                /* Check for overflow. */
485                if ((prevnum > 0) != (num > 0) || num / mult != prevnum)
486                        goto erange;
487                expr++;
488        }
489
490        switch (*expr) {
491                case '\0':
492                        break;
493                case '*':                       /* Backward compatible. */
494                case 'X':
495                case 'x':
496                        mult = (intmax_t)get_off_t(globals, expr + 1);
497                        prevnum = num;
498                        num *= mult;
499                        if ((prevnum > 0) == (num > 0) && num / mult == prevnum)
500                                break;
501erange:
502                        errx(exit_jump, 1, "%s: %s", oper, strerror(ERANGE));
503                default:
504                        errx(exit_jump, 1, "%s: illegal numeric value", oper);
505        }
506        return (num);
507}
Note: See TracBrowser for help on using the repository browser.