GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/dd/args.c Lines: 74 141 52.5 %
Date: 2017-11-07 Branches: 41 122 33.6 %

Line Branch Exec Source
1
/*	$OpenBSD: args.c,v 1.28 2016/08/16 16:44:55 krw Exp $	*/
2
/*	$NetBSD: args.c,v 1.7 1996/03/01 01:18:58 jtc Exp $	*/
3
4
/*-
5
 * Copyright (c) 1991, 1993, 1994
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Keith Muller of the University of California, San Diego and Lance
10
 * Visser of Convex Computer Corporation.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. Neither the name of the University nor the names of its contributors
21
 *    may be used to endorse or promote products derived from this software
22
 *    without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
 * SUCH DAMAGE.
35
 */
36
37
#include <sys/types.h>
38
#include <sys/time.h>
39
40
#include <err.h>
41
#include <errno.h>
42
#include <limits.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
47
#include "dd.h"
48
#include "extern.h"
49
50
static int	c_arg(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 void	f_status(char *);
63
static size_t	get_bsz(char *);
64
static off_t	get_off(char *);
65
66
static const struct arg {
67
	const char *name;
68
	void (*f)(char *);
69
	u_int set, noset;
70
} args[] = {
71
	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
72
	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
73
	{ "conv",	f_conv,		0,	 0 },
74
	{ "count",	f_count,	C_COUNT, C_COUNT },
75
	{ "files",	f_files,	C_FILES, C_FILES },
76
	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
77
	{ "if",		f_if,		C_IF,	 C_IF },
78
	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
79
	{ "of",		f_of,		C_OF,	 C_OF },
80
	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
81
	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
82
	{ "status",	f_status,	C_STATUS,C_STATUS },
83
};
84
85
static char *oper;
86
87
/*
88
 * args -- parse JCL syntax of dd.
89
 */
90
void
91
jcl(char **argv)
92
{
93
6760
	struct arg *ap, tmp;
94
	char *arg;
95
96
3380
	in.dbsz = out.dbsz = 512;
97
98
38284
	while ((oper = *++argv) != NULL) {
99
15762
		if ((oper = strdup(oper)) == NULL)
100
			errx(1, "out of memory");
101
15762
		if ((arg = strchr(oper, '=')) == NULL)
102
			errx(1, "unknown operand %s", oper);
103
15762
		*arg++ = '\0';
104
15762
		if (!*arg)
105
			errx(1, "no value specified for %s", oper);
106
15762
		tmp.name = oper;
107
15762
		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
15762
		if (ddflags & ap->noset)
112
			errx(1, "%s: illegal argument combination or already set",
113
			    tmp.name);
114
15762
		ddflags |= ap->set;
115
15762
		ap->f(arg);
116
	}
117
118
	/* Final sanity checks. */
119
120
3380
	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
3380
		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
127
			ddflags &= ~C_BS;
128
129
		/* Bs supersedes ibs and obs. */
130

6760
		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
131
			warnx("bs supersedes ibs and obs");
132
	}
133
134
	/*
135
	 * Ascii/ebcdic and cbs implies block/unblock.
136
	 * Block/unblock requires cbs and vice-versa.
137
	 */
138
3380
	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
139
		if (!(ddflags & C_CBS))
140
			errx(1, "record operations require cbs");
141
		if (cbsz == 0)
142
			errx(1, "cbs cannot be zero");
143
		cfunc = ddflags & C_BLOCK ? block : unblock;
144
3380
	} else if (ddflags & C_CBS) {
145
		if (ddflags & (C_ASCII|C_EBCDIC)) {
146
			if (ddflags & C_ASCII) {
147
				ddflags |= C_UNBLOCK;
148
				cfunc = unblock;
149
			} else {
150
				ddflags |= C_BLOCK;
151
				cfunc = block;
152
			}
153
		} else
154
			errx(1, "cbs meaningless if not doing record operations");
155
		if (cbsz == 0)
156
			errx(1, "cbs cannot be zero");
157
	} else
158
		cfunc = def;
159
160
6760
	if (in.dbsz == 0 || out.dbsz == 0)
161
		errx(1, "buffer sizes cannot be zero");
162
163
	/*
164
	 * Read and write take size_t's as arguments.  Lseek, however,
165
	 * takes an off_t.
166
	 */
167
3380
	if (cbsz > SSIZE_MAX || in.dbsz > SSIZE_MAX || out.dbsz > SSIZE_MAX)
168
		errx(1, "buffer sizes cannot be greater than %zd",
169
		    (ssize_t)SSIZE_MAX);
170

6760
	if (in.offset > LLONG_MAX / in.dbsz || out.offset > LLONG_MAX / out.dbsz)
171
		errx(1, "seek offsets cannot be larger than %lld", LLONG_MAX);
172
3380
}
173
174
static int
175
c_arg(const void *a, const void *b)
176
{
177
178
92116
	return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
179
}
180
181
static void
182
f_bs(char *arg)
183
{
184
185
6760
	in.dbsz = out.dbsz = get_bsz(arg);
186
3380
}
187
188
static void
189
f_cbs(char *arg)
190
{
191
192
	cbsz = get_bsz(arg);
193
}
194
195
static void
196
f_count(char *arg)
197
{
198
199
2338
	if ((cpy_cnt = get_bsz(arg)) == 0)
200
1169
		cpy_cnt = (size_t)-1;
201
1169
}
202
203
static void
204
f_files(char *arg)
205
{
206
207
	files_cnt = get_bsz(arg);
208
}
209
210
static void
211
f_ibs(char *arg)
212
{
213
214
	if (!(ddflags & C_BS))
215
		in.dbsz = get_bsz(arg);
216
}
217
218
static void
219
f_if(char *arg)
220
{
221
222
4530
	in.name = arg;
223
2265
}
224
225
static void
226
f_obs(char *arg)
227
{
228
229
	if (!(ddflags & C_BS))
230
		out.dbsz = get_bsz(arg);
231
}
232
233
static void
234
f_of(char *arg)
235
{
236
237
4560
	out.name = arg;
238
2280
}
239
240
static void
241
f_seek(char *arg)
242
{
243
244
2262
	out.offset = get_off(arg);
245
1131
}
246
247
static void
248
f_skip(char *arg)
249
{
250
251
2222
	in.offset = get_off(arg);
252
1111
}
253
254
static void
255
f_status(char *arg)
256
{
257
258
6630
	if (strcmp(arg, "none") == 0)
259
		ddflags |= C_NOINFO;
260
	else if (strcmp(arg, "noxfer") == 0)
261
		ddflags |= C_NOXFER;
262
	else
263
		errx(1, "unknown status %s", arg);
264
3315
}
265
266
267
static const struct conv {
268
	const char *name;
269
	u_int set, noset;
270
	const u_char *ctab;
271
} clist[] = {
272
#ifndef	NO_CONV
273
	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
274
	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
275
	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
276
	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
277
	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
278
	{ "osync",	C_OSYNC,	C_BS,		NULL },
279
	{ "swab",	C_SWAB,		0,		NULL },
280
	{ "sync",	C_SYNC,		0,		NULL },
281
	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
282
	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
283
#endif
284
	{ "noerror",	C_NOERROR,	0,		NULL },
285
	{ "notrunc",	C_NOTRUNC,	0,		NULL },
286
	{ NULL,		0,		0,		NULL }
287
};
288
289
static void
290
f_conv(char *arg)
291
{
292
	const struct conv *cp;
293
	const char *name;
294
295
3333
	while (arg != NULL) {
296
1111
		name = strsep(&arg, ",");
297
26664
		for (cp = &clist[0]; cp->name; cp++)
298
13332
			if (strcmp(name, cp->name) == 0)
299
				break;
300
1111
		if (!cp->name)
301
			errx(1, "unknown conversion %s", name);
302
1111
		if (ddflags & cp->noset)
303
			errx(1, "%s: illegal conversion combination", name);
304
1111
		ddflags |= cp->set;
305
1111
		if (cp->ctab)
306
			ctab = cp->ctab;
307
	}
308
1111
}
309
310
/*
311
 * Convert an expression of the following forms to a size_t
312
 *	1) A positive decimal number, optionally followed by
313
 *		b - multiply by 512.
314
 *		k, m or g - multiply by 1024 each.
315
 *		w - multiply by sizeof int
316
 *	2) Two or more of the above, separated by x
317
 *	   (or * for backwards compatibility), specifying
318
 *	   the product of the indicated values.
319
 */
320
static size_t
321
get_bsz(char *val)
322
{
323
	size_t num, t;
324
9098
	char *expr;
325
326
4549
	if (strchr(val, '-'))
327
		errx(1, "%s: illegal numeric value", oper);
328
329
4549
	errno = 0;
330
4549
	num = strtoul(val, &expr, 0);
331

4549
	if (num == ULONG_MAX && errno == ERANGE)	/* Overflow. */
332
		err(1, "%s", oper);
333
4549
	if (expr == val)			/* No digits. */
334
		errx(1, "%s: illegal numeric value", oper);
335
336


5693
	switch(*expr) {
337
	case 'b':
338
		t = num;
339
		num *= 512;
340
		if (t > num)
341
			goto erange;
342
		++expr;
343
		break;
344
	case 'g':
345
	case 'G':
346
		t = num;
347
		num *= 1024;
348
		if (t > num)
349
			goto erange;
350
		/* fallthrough */
351
	case 'm':
352
	case 'M':
353
		t = num;
354
		num *= 1024;
355
		if (t > num)
356
			goto erange;
357
		/* fallthrough */
358
	case 'k':
359
	case 'K':
360
		t = num;
361
1144
		num *= 1024;
362
1144
		if (t > num)
363
			goto erange;
364
1144
		++expr;
365
1144
		break;
366
	case 'w':
367
		t = num;
368
		num *= sizeof(int);
369
		if (t > num)
370
			goto erange;
371
		++expr;
372
		break;
373
	}
374
375

4549
	switch(*expr) {
376
		case '\0':
377
			break;
378
		case '*':			/* Backward compatible. */
379
		case 'x':
380
			t = num;
381
			num *= get_bsz(expr + 1);
382
			if (t > num)
383
				goto erange;
384
			break;
385
		default:
386
			errx(1, "%s: illegal numeric value", oper);
387
	}
388
4549
	return (num);
389
erange:
390
	errc(1, ERANGE, "%s", oper);
391
4549
}
392
393
/*
394
 * Convert an expression of the following forms to an off_t
395
 *	1) A positive decimal number, optionally followed by
396
 *		b - multiply by 512.
397
 *		k, m or g - multiply by 1024 each.
398
 *		w - multiply by sizeof int
399
 *	2) Two or more of the above, separated by x
400
 *	   (or * for backwards compatibility), specifying
401
 *	   the product of the indicated values.
402
 */
403
static off_t
404
get_off(char *val)
405
{
406
	off_t num, t;
407
4484
	char *expr;
408
409
2242
	num = strtoll(val, &expr, 0);
410
2242
	if (num == LLONG_MAX)			/* Overflow. */
411
		err(1, "%s", oper);
412
2242
	if (expr == val)			/* No digits. */
413
		errx(1, "%s: illegal numeric value", oper);
414
415


2252
	switch(*expr) {
416
	case 'b':
417
		t = num;
418
		num *= 512;
419
		if (t > num)
420
			goto erange;
421
		++expr;
422
		break;
423
	case 'g':
424
	case 'G':
425
		t = num;
426
		num *= 1024;
427
		if (t > num)
428
			goto erange;
429
		/* fallthrough */
430
	case 'm':
431
	case 'M':
432
		t = num;
433
5
		num *= 1024;
434
5
		if (t > num)
435
			goto erange;
436
		/* fallthrough */
437
	case 'k':
438
	case 'K':
439
		t = num;
440
5
		num *= 1024;
441
5
		if (t > num)
442
			goto erange;
443
5
		++expr;
444
5
		break;
445
	case 'w':
446
		t = num;
447
		num *= sizeof(int);
448
		if (t > num)
449
			goto erange;
450
		++expr;
451
		break;
452
	}
453
454

2242
	switch(*expr) {
455
		case '\0':
456
			break;
457
		case '*':			/* Backward compatible. */
458
		case 'x':
459
			t = num;
460
			num *= get_off(expr + 1);
461
			if (t > num)
462
				goto erange;
463
			break;
464
		default:
465
			errx(1, "%s: illegal numeric value", oper);
466
	}
467
2242
	return (num);
468
erange:
469
	errc(1, ERANGE, "%s", oper);
470
2242
}