GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
} |
Generated by: GCOVR (Version 3.3) |