Line data Source code
1 : /*
2 : CIFSDD - dd for SMB.
3 : Main program, argument handling and block copying.
4 :
5 : Copyright (C) James Peach 2005-2006
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/filesys.h"
23 : #include "auth/gensec/gensec.h"
24 : #include "lib/cmdline/cmdline.h"
25 : #include "libcli/resolve/resolve.h"
26 : #include "libcli/raw/libcliraw.h"
27 : #include "lib/events/events.h"
28 :
29 : #include "cifsdd.h"
30 : #include "param/param.h"
31 :
32 : const char * const PROGNAME = "cifsdd";
33 :
34 : #define SYNTAX_EXIT_CODE 1 /* Invocation syntax or logic error. */
35 : #define EOM_EXIT_CODE 9 /* Out of memory error. */
36 : #define FILESYS_EXIT_CODE 10 /* File manipulation error. */
37 : #define IOERROR_EXIT_CODE 11 /* Error during IO phase. */
38 :
39 : struct dd_stats_record dd_stats;
40 :
41 : static int dd_sigint;
42 : static int dd_sigusr1;
43 :
44 0 : static void dd_handle_signal(int sig)
45 : {
46 0 : switch (sig)
47 : {
48 0 : case SIGINT:
49 0 : ++dd_sigint;
50 0 : break;
51 0 : case SIGUSR1:
52 0 : ++dd_sigusr1;
53 0 : break;
54 0 : default:
55 0 : break;
56 : }
57 0 : }
58 :
59 : /* ------------------------------------------------------------------------- */
60 : /* Argument handling. */
61 : /* ------------------------------------------------------------------------- */
62 :
63 : static const struct {
64 : enum argtype arg_type;
65 : const char * arg_name;
66 : } names [] = {
67 : { ARG_NUMERIC, "COUNT" },
68 : { ARG_SIZE, "SIZE" },
69 : { ARG_PATHNAME, "FILE" },
70 : { ARG_BOOL, "BOOLEAN" },
71 : };
72 :
73 0 : static const char * argtype_str(enum argtype arg_type)
74 : {
75 : int i;
76 :
77 0 : for (i = 0; i < ARRAY_SIZE(names); ++i) {
78 0 : if (arg_type == names[i].arg_type) {
79 0 : return(names[i].arg_name);
80 : }
81 : }
82 :
83 0 : return("<unknown>");
84 : }
85 :
86 : static struct argdef args[] =
87 : {
88 : {
89 : .arg_name = "bs",
90 : .arg_type = ARG_SIZE,
91 : .arg_help = "force ibs and obs to SIZE bytes",
92 : },
93 : {
94 : .arg_name = "ibs",
95 : .arg_type = ARG_SIZE,
96 : .arg_help = "read SIZE bytes at a time",
97 : },
98 : {
99 : .arg_name = "obs",
100 : .arg_type = ARG_SIZE,
101 : .arg_help = "write SIZE bytes at a time",
102 : },
103 :
104 : {
105 : .arg_name = "count",
106 : .arg_type = ARG_NUMERIC,
107 : .arg_help = "copy COUNT input blocks",
108 : },
109 : {
110 : .arg_name = "seek",
111 : .arg_type = ARG_NUMERIC,
112 : .arg_help = "skip COUNT blocks at start of output",
113 : },
114 : {
115 : .arg_name = "skip",
116 : .arg_type = ARG_NUMERIC,
117 : .arg_help = "skip COUNT blocks at start of input",
118 : },
119 :
120 : {
121 : .arg_name = "if",
122 : .arg_type = ARG_PATHNAME,
123 : .arg_help = "read input from FILE",
124 : },
125 : {
126 : .arg_name = "of",
127 : .arg_type = ARG_PATHNAME,
128 : .arg_help = "write output to FILE",
129 : },
130 :
131 : {
132 : .arg_name = "direct",
133 : .arg_type = ARG_BOOL,
134 : .arg_help = "use direct I/O if non-zero",
135 : },
136 : {
137 : .arg_name = "sync",
138 : .arg_type = ARG_BOOL,
139 : .arg_help = "use synchronous writes if non-zero",
140 : },
141 : {
142 : .arg_name = "oplock",
143 : .arg_type = ARG_BOOL,
144 : .arg_help = "take oplocks on the input and output files",
145 : },
146 :
147 : /* FIXME: We should support using iflags and oflags for setting oplock and I/O
148 : * options. This would make us compatible with GNU dd.
149 : */
150 : };
151 :
152 648 : static struct argdef * find_named_arg(const char * arg)
153 : {
154 : int i;
155 :
156 3744 : for (i = 0; i < ARRAY_SIZE(args); ++i) {
157 3744 : if (strwicmp(arg, args[i].arg_name) == 0) {
158 648 : return(&args[i]);
159 : }
160 : }
161 :
162 0 : return(NULL);
163 : }
164 :
165 54 : int set_arg_argv(const char * argv)
166 : {
167 : struct argdef * arg;
168 :
169 : char * name;
170 : char * val;
171 :
172 54 : if ((name = strdup(argv)) == NULL) {
173 0 : return(0);
174 : }
175 :
176 54 : if ((val = strchr(name, '=')) == NULL) {
177 0 : fprintf(stderr, "%s: malformed argument \"%s\"\n",
178 : PROGNAME, argv);
179 0 : goto fail;
180 : }
181 :
182 54 : *val = '\0';
183 54 : val++;
184 :
185 54 : if ((arg = find_named_arg(name)) == NULL) {
186 0 : fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
187 : PROGNAME, name);
188 0 : goto fail;
189 : }
190 :
191 : /* Found a matching name; convert the variable argument. */
192 54 : switch (arg->arg_type) {
193 0 : case ARG_NUMERIC:
194 0 : if (!conv_str_u64(val, &arg->arg_val.nval)) {
195 0 : goto fail;
196 : }
197 0 : break;
198 18 : case ARG_SIZE:
199 18 : if (!conv_str_size_error(val, &arg->arg_val.nval)) {
200 0 : goto fail;
201 : }
202 18 : break;
203 0 : case ARG_BOOL:
204 0 : if (!conv_str_bool(val, &arg->arg_val.bval)) {
205 0 : goto fail;
206 : }
207 0 : break;
208 36 : case ARG_PATHNAME:
209 36 : if (!(arg->arg_val.pval = strdup(val))) {
210 0 : goto fail;
211 : }
212 36 : break;
213 0 : default:
214 0 : fprintf(stderr, "%s: argument \"%s\" is of "
215 : "unknown type\n", PROGNAME, name);
216 0 : goto fail;
217 : }
218 :
219 54 : free(name);
220 54 : return(1);
221 :
222 0 : fail:
223 0 : free(name);
224 0 : return(0);
225 : }
226 :
227 234 : void set_arg_val(const char * name, ...)
228 : {
229 : va_list ap;
230 : struct argdef * arg;
231 :
232 234 : va_start(ap, name);
233 234 : if ((arg = find_named_arg(name)) == NULL) {
234 0 : goto fail;
235 : }
236 :
237 : /* Found a matching name; convert the variable argument. */
238 234 : switch (arg->arg_type) {
239 144 : case ARG_NUMERIC:
240 : case ARG_SIZE:
241 144 : arg->arg_val.nval = va_arg(ap, uint64_t);
242 144 : break;
243 54 : case ARG_BOOL:
244 54 : arg->arg_val.bval = va_arg(ap, int);
245 54 : break;
246 36 : case ARG_PATHNAME:
247 36 : arg->arg_val.pval = va_arg(ap, char *);
248 36 : if (arg->arg_val.pval) {
249 0 : arg->arg_val.pval = strdup(arg->arg_val.pval);
250 : }
251 36 : break;
252 0 : default:
253 0 : fprintf(stderr, "%s: argument \"%s\" is of "
254 : "unknown type\n", PROGNAME, name);
255 0 : goto fail;
256 : }
257 :
258 234 : va_end(ap);
259 234 : return;
260 :
261 0 : fail:
262 0 : fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
263 : PROGNAME, name);
264 0 : va_end(ap);
265 0 : return;
266 : }
267 :
268 108 : bool check_arg_bool(const char * name)
269 : {
270 : struct argdef * arg;
271 :
272 108 : if ((arg = find_named_arg(name)) &&
273 108 : (arg->arg_type == ARG_BOOL)) {
274 108 : return(arg->arg_val.bval);
275 : }
276 :
277 0 : DEBUG(0, ("invalid argument name: %s\n", name));
278 0 : SMB_ASSERT(0);
279 : return(false);
280 : }
281 :
282 180 : uint64_t check_arg_numeric(const char * name)
283 : {
284 : struct argdef * arg;
285 :
286 180 : if ((arg = find_named_arg(name)) &&
287 180 : (arg->arg_type == ARG_NUMERIC || arg->arg_type == ARG_SIZE)) {
288 180 : return(arg->arg_val.nval);
289 : }
290 :
291 0 : DEBUG(0, ("invalid argument name: %s\n", name));
292 0 : SMB_ASSERT(0);
293 : return(-1);
294 : }
295 :
296 72 : const char * check_arg_pathname(const char * name)
297 : {
298 : struct argdef * arg;
299 :
300 72 : if ((arg = find_named_arg(name)) &&
301 72 : (arg->arg_type == ARG_PATHNAME)) {
302 72 : return(arg->arg_val.pval);
303 : }
304 :
305 0 : DEBUG(0, ("invalid argument name: %s\n", name));
306 0 : SMB_ASSERT(0);
307 : return(NULL);
308 : }
309 :
310 18 : static void dump_args(void)
311 : {
312 : int i;
313 :
314 18 : DEBUG(10, ("dumping argument values:\n"));
315 216 : for (i = 0; i < ARRAY_SIZE(args); ++i) {
316 198 : switch (args[i].arg_type) {
317 108 : case ARG_NUMERIC:
318 : case ARG_SIZE:
319 108 : DEBUG(10, ("\t%s=%llu\n", args[i].arg_name,
320 : (unsigned long long)args[i].arg_val.nval));
321 108 : break;
322 54 : case ARG_BOOL:
323 54 : DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
324 : args[i].arg_val.bval ? "yes" : "no"));
325 54 : break;
326 36 : case ARG_PATHNAME:
327 36 : DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
328 : args[i].arg_val.pval ?
329 : args[i].arg_val.pval :
330 : "(NULL)"));
331 36 : break;
332 0 : default:
333 0 : SMB_ASSERT(0);
334 : }
335 : }
336 18 : }
337 :
338 0 : static void cifsdd_help_message(poptContext pctx,
339 : enum poptCallbackReason preason,
340 : struct poptOption * poption,
341 : const char * parg,
342 : void * pdata)
343 : {
344 : static const char notes[] =
345 : "FILE can be a local filename or a UNC path of the form //server/share/path.\n";
346 :
347 : char prefix[24];
348 : int i;
349 :
350 0 : if (poption->shortName != '?') {
351 0 : poptPrintUsage(pctx, stdout, 0);
352 0 : fprintf(stdout, " [dd options]\n");
353 0 : exit(0);
354 : }
355 :
356 0 : poptPrintHelp(pctx, stdout, 0);
357 0 : fprintf(stdout, "\nCIFS dd options:\n");
358 :
359 0 : for (i = 0; i < ARRAY_SIZE(args); ++i) {
360 0 : if (args[i].arg_name == NULL) {
361 0 : break;
362 : }
363 :
364 0 : snprintf(prefix, sizeof(prefix), "%s=%-*s",
365 : args[i].arg_name,
366 0 : (int)(sizeof(prefix) - strlen(args[i].arg_name) - 2),
367 : argtype_str(args[i].arg_type));
368 0 : prefix[sizeof(prefix) - 1] = '\0';
369 0 : fprintf(stdout, " %s%s\n", prefix, args[i].arg_help);
370 : }
371 :
372 0 : fprintf(stdout, "\n%s\n", notes);
373 0 : exit(0);
374 : }
375 :
376 : /* ------------------------------------------------------------------------- */
377 : /* Main block copying routine. */
378 : /* ------------------------------------------------------------------------- */
379 :
380 18 : static void print_transfer_stats(void)
381 : {
382 18 : if (DEBUGLEVEL > 0) {
383 18 : printf("%llu+%llu records in (%llu bytes)\n"
384 : "%llu+%llu records out (%llu bytes)\n",
385 18 : (unsigned long long)dd_stats.in.fblocks,
386 18 : (unsigned long long)dd_stats.in.pblocks,
387 18 : (unsigned long long)dd_stats.in.bytes,
388 18 : (unsigned long long)dd_stats.out.fblocks,
389 18 : (unsigned long long)dd_stats.out.pblocks,
390 18 : (unsigned long long)dd_stats.out.bytes);
391 : } else {
392 0 : printf("%llu+%llu records in\n%llu+%llu records out\n",
393 0 : (unsigned long long)dd_stats.in.fblocks,
394 0 : (unsigned long long)dd_stats.in.pblocks,
395 0 : (unsigned long long)dd_stats.out.fblocks,
396 0 : (unsigned long long)dd_stats.out.pblocks);
397 : }
398 18 : }
399 :
400 36 : static struct dd_iohandle * open_file(struct resolve_context *resolve_ctx,
401 : struct tevent_context *ev,
402 : const char * which, const char **ports,
403 : struct smbcli_options *smb_options,
404 : const char *socket_options,
405 : struct smbcli_session_options *smb_session_options,
406 : struct gensec_settings *gensec_settings)
407 : {
408 36 : int options = 0;
409 36 : const char * path = NULL;
410 36 : struct dd_iohandle * handle = NULL;
411 :
412 36 : if (check_arg_bool("direct")) {
413 0 : options |= DD_DIRECT_IO;
414 : }
415 :
416 36 : if (check_arg_bool("sync")) {
417 0 : options |= DD_SYNC_IO;
418 : }
419 :
420 36 : if (check_arg_bool("oplock")) {
421 0 : options |= DD_OPLOCK;
422 : }
423 :
424 36 : if (strcmp(which, "if") == 0) {
425 18 : path = check_arg_pathname("if");
426 18 : handle = dd_open_path(resolve_ctx, ev, path, ports,
427 : check_arg_numeric("ibs"), options,
428 : socket_options,
429 : smb_options, smb_session_options,
430 : gensec_settings);
431 18 : } else if (strcmp(which, "of") == 0) {
432 18 : options |= DD_WRITE;
433 18 : path = check_arg_pathname("of");
434 18 : handle = dd_open_path(resolve_ctx, ev, path, ports,
435 : check_arg_numeric("obs"), options,
436 : socket_options,
437 : smb_options, smb_session_options,
438 : gensec_settings);
439 : } else {
440 0 : SMB_ASSERT(0);
441 : return(NULL);
442 : }
443 :
444 36 : if (!handle) {
445 0 : fprintf(stderr, "%s: failed to open %s\n", PROGNAME, path);
446 : }
447 :
448 36 : return(handle);
449 : }
450 :
451 18 : static int copy_files(struct tevent_context *ev, struct loadparm_context *lp_ctx)
452 : {
453 : uint8_t * iobuf; /* IO buffer. */
454 : uint64_t iomax; /* Size of the IO buffer. */
455 : uint64_t data_size; /* Amount of data in the IO buffer. */
456 :
457 : uint64_t ibs;
458 : uint64_t obs;
459 : uint64_t count;
460 :
461 : struct dd_iohandle * ifile;
462 : struct dd_iohandle * ofile;
463 :
464 : struct smbcli_options options;
465 : struct smbcli_session_options session_options;
466 :
467 18 : ibs = check_arg_numeric("ibs");
468 18 : obs = check_arg_numeric("obs");
469 18 : count = check_arg_numeric("count");
470 :
471 18 : lpcfg_smbcli_options(lp_ctx, &options);
472 18 : lpcfg_smbcli_session_options(lp_ctx, &session_options);
473 :
474 : /* Allocate IO buffer. We need more than the max IO size because we
475 : * could accumulate a remainder if ibs and obs don't match.
476 : */
477 18 : iomax = 2 * MAX(ibs, obs);
478 18 : if ((iobuf = malloc_array_p(uint8_t, iomax)) == NULL) {
479 0 : fprintf(stderr,
480 : "%s: failed to allocate IO buffer of %llu bytes\n",
481 : PROGNAME, (unsigned long long)iomax);
482 0 : return(EOM_EXIT_CODE);
483 : }
484 :
485 18 : options.max_xmit = MAX(ibs, obs);
486 :
487 18 : DEBUG(4, ("IO buffer size is %llu, max xmit is %d\n",
488 : (unsigned long long)iomax, options.max_xmit));
489 :
490 18 : if (!(ifile = open_file(lpcfg_resolve_context(lp_ctx), ev, "if",
491 : lpcfg_smb_ports(lp_ctx), &options,
492 : lpcfg_socket_options(lp_ctx),
493 : &session_options,
494 : lpcfg_gensec_settings(lp_ctx, lp_ctx)))) {
495 0 : SAFE_FREE(iobuf);
496 0 : return(FILESYS_EXIT_CODE);
497 : }
498 :
499 18 : if (!(ofile = open_file(lpcfg_resolve_context(lp_ctx), ev, "of",
500 : lpcfg_smb_ports(lp_ctx), &options,
501 : lpcfg_socket_options(lp_ctx),
502 : &session_options,
503 : lpcfg_gensec_settings(lp_ctx, lp_ctx)))) {
504 0 : SAFE_FREE(iobuf);
505 0 : return(FILESYS_EXIT_CODE);
506 : }
507 :
508 : /* Seek the files to their respective starting points. */
509 18 : ifile->io_seek(ifile, check_arg_numeric("skip") * ibs);
510 18 : ofile->io_seek(ofile, check_arg_numeric("seek") * obs);
511 :
512 18 : DEBUG(4, ("max xmit was negotiated to be %d\n", options.max_xmit));
513 :
514 18 : for (data_size = 0;;) {
515 :
516 : /* Handle signals. We are somewhat compatible with GNU dd.
517 : * SIGINT makes us stop, but still print transfer statistics.
518 : * SIGUSR1 makes us print transfer statistics but we continue
519 : * copying.
520 : */
521 714 : if (dd_sigint) {
522 0 : break;
523 : }
524 :
525 714 : if (dd_sigusr1) {
526 0 : print_transfer_stats();
527 0 : dd_sigusr1 = 0;
528 : }
529 :
530 714 : if (ifile->io_flags & DD_END_OF_FILE) {
531 18 : DEBUG(4, ("flushing %llu bytes at EOF\n",
532 : (unsigned long long)data_size));
533 18 : while (data_size > 0) {
534 0 : if (!dd_flush_block(ofile, iobuf,
535 : &data_size, obs)) {
536 0 : SAFE_FREE(iobuf);
537 0 : return(IOERROR_EXIT_CODE);
538 : }
539 : }
540 18 : goto done;
541 : }
542 :
543 : /* Try and read enough blocks of ibs bytes to be able write
544 : * out one of obs bytes.
545 : */
546 696 : if (!dd_fill_block(ifile, iobuf, &data_size, obs, ibs)) {
547 0 : SAFE_FREE(iobuf);
548 0 : return(IOERROR_EXIT_CODE);
549 : }
550 :
551 696 : if (data_size == 0) {
552 : /* Done. */
553 6 : SMB_ASSERT(ifile->io_flags & DD_END_OF_FILE);
554 : }
555 :
556 : /* Stop reading when we hit the block count. */
557 696 : if (dd_stats.in.bytes >= (ibs * count)) {
558 0 : ifile->io_flags |= DD_END_OF_FILE;
559 : }
560 :
561 : /* If we wanted to be a legitimate dd, we would do character
562 : * conversions and other shenanigans here.
563 : */
564 :
565 : /* Flush what we read in units of obs bytes. We want to have
566 : * at least obs bytes in the IO buffer but might not if the
567 : * file is too small.
568 : */
569 696 : if (data_size &&
570 690 : !dd_flush_block(ofile, iobuf, &data_size, obs)) {
571 0 : SAFE_FREE(iobuf);
572 0 : return(IOERROR_EXIT_CODE);
573 : }
574 : }
575 :
576 18 : done:
577 18 : SAFE_FREE(iobuf);
578 18 : print_transfer_stats();
579 18 : return(0);
580 : }
581 :
582 : /* ------------------------------------------------------------------------- */
583 : /* Main. */
584 : /* ------------------------------------------------------------------------- */
585 :
586 : struct poptOption cifsddHelpOptions[] = {
587 : {
588 : .longName = NULL,
589 : .shortName = '\0',
590 : .argInfo = POPT_ARG_CALLBACK,
591 : .arg = (void *)&cifsdd_help_message,
592 : .val = '\0',
593 : },
594 : {
595 : .longName = "help",
596 : .shortName = '?',
597 : .val = '?',
598 : .descrip = "Show this help message",
599 : },
600 : {
601 : .longName = "usage",
602 : .shortName = '\0',
603 : .val = 'u',
604 : .descrip = "Display brief usage message",
605 : },
606 : POPT_TABLEEND
607 : };
608 :
609 18 : int main(int argc, char *argv[])
610 : {
611 18 : const char **const_argv = discard_const_p(const char *, argv);
612 : int i;
613 : const char ** dd_args;
614 18 : TALLOC_CTX *mem_ctx = NULL;
615 18 : struct loadparm_context *lp_ctx = NULL;
616 : struct tevent_context *ev;
617 : bool ok;
618 : int rc;
619 :
620 : poptContext pctx;
621 108 : struct poptOption poptions[] = {
622 : /* POPT_AUTOHELP */
623 : { NULL, '\0', POPT_ARG_INCLUDE_TABLE, cifsddHelpOptions,
624 : 0, "Help options:", NULL },
625 18 : POPT_COMMON_SAMBA
626 18 : POPT_COMMON_CONNECTION
627 18 : POPT_COMMON_CREDENTIALS
628 18 : POPT_LEGACY_S4
629 18 : POPT_COMMON_VERSION
630 : POPT_TABLEEND
631 : };
632 :
633 : /* Block sizes. */
634 18 : set_arg_val("bs", (uint64_t)4096);
635 18 : set_arg_val("ibs", (uint64_t)4096);
636 18 : set_arg_val("obs", (uint64_t)4096);
637 : /* Block counts. */
638 18 : set_arg_val("count", (uint64_t)-1);
639 18 : set_arg_val("seek", (uint64_t)0);
640 18 : set_arg_val("skip", (uint64_t)0);
641 : /* Files. */
642 18 : set_arg_val("if", NULL);
643 18 : set_arg_val("of", NULL);
644 : /* Options. */
645 18 : set_arg_val("direct", false);
646 18 : set_arg_val("sync", false);
647 18 : set_arg_val("oplock", false);
648 :
649 18 : mem_ctx = talloc_init("cifsdd.c/main");
650 18 : if (mem_ctx == NULL) {
651 0 : d_printf("Not enough memory\n");
652 0 : exit(1);
653 : }
654 :
655 18 : ok = samba_cmdline_init(mem_ctx,
656 : SAMBA_CMDLINE_CONFIG_CLIENT,
657 : false /* require_smbconf */);
658 18 : if (!ok) {
659 0 : DBG_ERR("Failed to init cmdline parser!\n");
660 0 : TALLOC_FREE(mem_ctx);
661 0 : exit(1);
662 : }
663 :
664 18 : pctx = samba_popt_get_context(getprogname(), argc, const_argv, poptions, 0);
665 18 : if (pctx == NULL) {
666 0 : DBG_ERR("Failed to setup popt context!\n");
667 0 : TALLOC_FREE(mem_ctx);
668 0 : exit(1);
669 : }
670 :
671 18 : while ((i = poptGetNextOpt(pctx)) != -1) {
672 0 : switch (i) {
673 0 : case POPT_ERROR_BADOPT:
674 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
675 : poptBadOption(pctx, 0), poptStrerror(i));
676 0 : poptPrintUsage(pctx, stderr, 0);
677 0 : exit(1);
678 : }
679 : }
680 :
681 72 : for (dd_args = poptGetArgs(pctx); dd_args && *dd_args; ++dd_args) {
682 :
683 54 : if (!set_arg_argv(*dd_args)) {
684 0 : fprintf(stderr, "%s: invalid option: %s\n",
685 : PROGNAME, *dd_args);
686 0 : exit(SYNTAX_EXIT_CODE);
687 : }
688 :
689 : /* "bs" has the side-effect of setting "ibs" and "obs". */
690 54 : if (strncmp(*dd_args, "bs=", 3) == 0) {
691 18 : uint64_t bs = check_arg_numeric("bs");
692 18 : set_arg_val("ibs", bs);
693 18 : set_arg_val("obs", bs);
694 : }
695 : }
696 :
697 18 : poptFreeContext(pctx);
698 18 : samba_cmdline_burn(argc, argv);
699 :
700 18 : ev = s4_event_context_init(mem_ctx);
701 18 : lp_ctx = samba_cmdline_get_lp_ctx();
702 :
703 18 : gensec_init();
704 18 : dump_args();
705 :
706 18 : if (check_arg_numeric("ibs") == 0 || check_arg_numeric("obs") == 0) {
707 0 : fprintf(stderr, "%s: block sizes must be greater that zero\n",
708 : PROGNAME);
709 0 : talloc_free(mem_ctx);
710 0 : exit(SYNTAX_EXIT_CODE);
711 : }
712 :
713 18 : if (check_arg_pathname("if") == NULL) {
714 0 : fprintf(stderr, "%s: missing input filename\n", PROGNAME);
715 0 : talloc_free(mem_ctx);
716 0 : exit(SYNTAX_EXIT_CODE);
717 : }
718 :
719 18 : if (check_arg_pathname("of") == NULL) {
720 0 : fprintf(stderr, "%s: missing output filename\n", PROGNAME);
721 0 : talloc_free(mem_ctx);
722 0 : exit(SYNTAX_EXIT_CODE);
723 : }
724 :
725 18 : CatchSignal(SIGINT, dd_handle_signal);
726 18 : CatchSignal(SIGUSR1, dd_handle_signal);
727 18 : rc = copy_files(ev, lp_ctx);
728 :
729 18 : talloc_free(mem_ctx);
730 18 : return rc;
731 : }
732 :
733 : /* vim: set sw=8 sts=8 ts=8 tw=79 : */
|