mirror of
				https://github.com/samba-team/samba.git
				synced 2025-10-31 12:23:52 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			606 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			606 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|    CIFSDD - dd for SMB.
 | |
|    Main program, argument handling and block copying.
 | |
| 
 | |
|    Copyright (C) James Peach 2005-2006
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; either version 3 of the License, or
 | |
|    (at your option) any later version.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| #include "includes.h"
 | |
| #include "system/filesys.h"
 | |
| #include "auth/gensec/gensec.h"
 | |
| #include "lib/cmdline/popt_common.h"
 | |
| #include "libcli/resolve/resolve.h"
 | |
| #include "libcli/raw/libcliraw.h"
 | |
| 
 | |
| #include "cifsdd.h"
 | |
| #include "param/param.h"
 | |
| 
 | |
| const char * const PROGNAME = "cifsdd";
 | |
| 
 | |
| #define SYNTAX_EXIT_CODE	 1	/* Invokation syntax or logic error. */
 | |
| #define EOM_EXIT_CODE		 9	/* Out of memory error. */
 | |
| #define FILESYS_EXIT_CODE	10	/* File manipulation error. */
 | |
| #define IOERROR_EXIT_CODE	11	/* Error during IO phase. */
 | |
| 
 | |
| struct	dd_stats_record dd_stats;
 | |
| 
 | |
| static int dd_sigint;
 | |
| static int dd_sigusr1;
 | |
| 
 | |
| static void dd_handle_signal(int sig)
 | |
| {
 | |
| 	switch (sig)
 | |
| 	{
 | |
| 		case SIGINT:
 | |
| 			++dd_sigint;
 | |
| 			break;
 | |
| 		case SIGUSR1:
 | |
| 			++dd_sigusr1;
 | |
| 			break;
 | |
| 		default:
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------- */
 | |
| /* Argument handling.							     */
 | |
| /* ------------------------------------------------------------------------- */
 | |
| 
 | |
| static const char * argtype_str(enum argtype arg_type)
 | |
| {
 | |
| 	static const struct {
 | |
| 		enum argtype arg_type;
 | |
| 		const char * arg_name;
 | |
| 	} names [] = 
 | |
| 	{
 | |
| 		{ ARG_NUMERIC, "COUNT" },
 | |
| 		{ ARG_SIZE, "SIZE" },
 | |
| 		{ ARG_PATHNAME, "FILE" },
 | |
| 		{ ARG_BOOL, "BOOLEAN" },
 | |
| 	};
 | |
| 
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < ARRAY_SIZE(names); ++i) {
 | |
| 		if (arg_type == names[i].arg_type) {
 | |
| 			return(names[i].arg_name);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return("<unknown>");
 | |
| }
 | |
| 
 | |
| static struct argdef args[] =
 | |
| {
 | |
| 	{ "bs",	ARG_SIZE,	"force ibs and obs to SIZE bytes" },
 | |
| 	{ "ibs", ARG_SIZE,	"read SIZE bytes at a time" },
 | |
| 	{ "obs", ARG_SIZE,	"write SIZE bytes at a time" },
 | |
| 
 | |
| 	{ "count", ARG_NUMERIC,	"copy COUNT input blocks" },
 | |
| 	{ "seek",ARG_NUMERIC,	"skip COUNT blocks at start of output" },
 | |
| 	{ "skip",ARG_NUMERIC,	"skip COUNT blocks at start of input" },
 | |
| 
 | |
| 	{ "if",	ARG_PATHNAME,	"read input from FILE" },
 | |
| 	{ "of",	ARG_PATHNAME,	"write output to FILE" },
 | |
| 
 | |
| 	{ "direct", ARG_BOOL,	"use direct I/O if non-zero" },
 | |
| 	{ "sync", ARG_BOOL,	"use synchronous writes if non-zero" },
 | |
| 	{ "oplock", ARG_BOOL,	"take oplocks on the input and output files" },
 | |
| 
 | |
| /* FIXME: We should support using iflags and oflags for setting oplock and I/O
 | |
|  * options. This would make us compatible with GNU dd.
 | |
|  */
 | |
| };
 | |
| 
 | |
| static struct argdef * find_named_arg(const char * arg)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < ARRAY_SIZE(args); ++i) {
 | |
| 		if (strwicmp(arg, args[i].arg_name) == 0) {
 | |
| 			return(&args[i]);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return(NULL);
 | |
| }
 | |
| 
 | |
| int set_arg_argv(const char * argv)
 | |
| {
 | |
| 	struct argdef *	arg;
 | |
| 
 | |
| 	char *	name;
 | |
| 	char *	val;
 | |
| 
 | |
| 	if ((name = strdup(argv)) == NULL) {
 | |
| 		return(0);
 | |
| 	}
 | |
| 
 | |
| 	if ((val = strchr(name, '=')) == NULL) {
 | |
| 		fprintf(stderr, "%s: malformed argument \"%s\"\n",
 | |
| 				PROGNAME, argv);
 | |
| 		goto fail;
 | |
| 	}
 | |
| 
 | |
| 	*val = '\0';
 | |
| 	val++;
 | |
| 
 | |
| 	if ((arg = find_named_arg(name)) == NULL) {
 | |
| 		fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
 | |
| 				PROGNAME, name);
 | |
| 		goto fail;
 | |
| 	}
 | |
| 
 | |
| 	/* Found a matching name; convert the variable argument. */
 | |
| 	switch (arg->arg_type) {
 | |
| 		case ARG_NUMERIC:
 | |
| 			if (!conv_str_u64(val, &arg->arg_val.nval)) {
 | |
| 				goto fail;
 | |
| 			}
 | |
| 			break;
 | |
| 		case ARG_SIZE:
 | |
| 			if (!conv_str_size(val, &arg->arg_val.nval)) {
 | |
| 				goto fail;
 | |
| 			}
 | |
| 			break;
 | |
| 		case ARG_BOOL:
 | |
| 			if (!conv_str_bool(val, &arg->arg_val.bval)) {
 | |
| 				goto fail;
 | |
| 			}
 | |
| 			break;
 | |
| 		case ARG_PATHNAME:
 | |
| 			if (!(arg->arg_val.pval = strdup(val))) {
 | |
| 				goto fail;
 | |
| 			}
 | |
| 			break;
 | |
| 		default:
 | |
| 			fprintf(stderr, "%s: argument \"%s\" is of "
 | |
| 				"unknown type\n", PROGNAME, name);
 | |
| 			goto fail;
 | |
| 	}
 | |
| 
 | |
| 	free(name);
 | |
| 	return(1);
 | |
| 
 | |
| fail:
 | |
| 	free(name);
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| void set_arg_val(const char * name, ...)
 | |
| {
 | |
| 	va_list		ap;
 | |
| 	struct argdef * arg;
 | |
| 
 | |
| 	va_start(ap, name);
 | |
| 	if ((arg = find_named_arg(name)) == NULL) {
 | |
| 		goto fail;
 | |
| 	}
 | |
| 
 | |
| 	/* Found a matching name; convert the variable argument. */
 | |
| 	switch (arg->arg_type) {
 | |
| 		case ARG_NUMERIC:
 | |
| 		case ARG_SIZE:
 | |
| 			arg->arg_val.nval = va_arg(ap, uint64_t);
 | |
| 			break;
 | |
| 		case ARG_BOOL:
 | |
| 			arg->arg_val.bval = va_arg(ap, int);
 | |
| 			break;
 | |
| 		case ARG_PATHNAME:
 | |
| 			arg->arg_val.pval = va_arg(ap, char *);
 | |
| 			if (arg->arg_val.pval) {
 | |
| 				arg->arg_val.pval = strdup(arg->arg_val.pval);
 | |
| 			}
 | |
| 			break;
 | |
| 		default:
 | |
| 			fprintf(stderr, "%s: argument \"%s\" is of "
 | |
| 				"unknown type\n", PROGNAME, name);
 | |
| 			goto fail;
 | |
| 	}
 | |
| 
 | |
| 	va_end(ap);
 | |
| 	return;
 | |
| 
 | |
| fail:
 | |
| 	fprintf(stderr, "%s: ignoring unknown argument \"%s\"\n",
 | |
| 			PROGNAME, name);
 | |
| 	va_end(ap);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| bool check_arg_bool(const char * name)
 | |
| {
 | |
| 	struct argdef * arg;
 | |
| 
 | |
| 	if ((arg = find_named_arg(name)) &&
 | |
| 	    (arg->arg_type == ARG_BOOL)) {
 | |
| 		return(arg->arg_val.bval);
 | |
| 	}
 | |
| 
 | |
| 	DEBUG(0, ("invalid argument name: %s", name));
 | |
| 	SMB_ASSERT(0);
 | |
| 	return(false);
 | |
| }
 | |
| 
 | |
| uint64_t check_arg_numeric(const char * name)
 | |
| {
 | |
| 	struct argdef * arg;
 | |
| 
 | |
| 	if ((arg = find_named_arg(name)) &&
 | |
| 	    (arg->arg_type == ARG_NUMERIC || arg->arg_type == ARG_SIZE)) {
 | |
| 		return(arg->arg_val.nval);
 | |
| 	}
 | |
| 
 | |
| 	DEBUG(0, ("invalid argument name: %s", name));
 | |
| 	SMB_ASSERT(0);
 | |
| 	return(-1);
 | |
| }
 | |
| 
 | |
| const char * check_arg_pathname(const char * name)
 | |
| {
 | |
| 	struct argdef * arg;
 | |
| 
 | |
| 	if ((arg = find_named_arg(name)) &&
 | |
| 	    (arg->arg_type == ARG_PATHNAME)) {
 | |
| 		return(arg->arg_val.pval);
 | |
| 	}
 | |
| 
 | |
| 	DEBUG(0, ("invalid argument name: %s", name));
 | |
| 	SMB_ASSERT(0);
 | |
| 	return(NULL);
 | |
| }
 | |
| 
 | |
| static void dump_args(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	DEBUG(10, ("dumping argument values:\n"));
 | |
| 	for (i = 0; i < ARRAY_SIZE(args); ++i) {
 | |
| 		switch (args[i].arg_type) {
 | |
| 			case ARG_NUMERIC:
 | |
| 			case ARG_SIZE:
 | |
| 				DEBUG(10, ("\t%s=%llu\n", args[i].arg_name,
 | |
| 					(unsigned long long)args[i].arg_val.nval));
 | |
| 				break;
 | |
| 			case ARG_BOOL:
 | |
| 				DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
 | |
| 					args[i].arg_val.bval ? "yes" : "no"));
 | |
| 				break;
 | |
| 			case ARG_PATHNAME:
 | |
| 				DEBUG(10, ("\t%s=%s\n", args[i].arg_name,
 | |
| 					args[i].arg_val.pval ?
 | |
| 						args[i].arg_val.pval :
 | |
| 						"(NULL)"));
 | |
| 				break;
 | |
| 			default:
 | |
| 				SMB_ASSERT(0);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void cifsdd_help_message(poptContext pctx,
 | |
| 		enum poptCallbackReason preason,
 | |
| 		struct poptOption * poption, 
 | |
| 		const char * parg,
 | |
| 		void * pdata)
 | |
| {
 | |
| 	static const char notes[] = 
 | |
| "FILE can be a local filename or a UNC path of the form //server/share/path.\n";
 | |
| 
 | |
| 	char prefix[24];
 | |
| 	int i;
 | |
| 
 | |
| 	if (poption->shortName != '?') {
 | |
| 		poptPrintUsage(pctx, stdout, 0);
 | |
| 		fprintf(stdout, "        [dd options]\n");
 | |
| 		exit(0);
 | |
| 	}
 | |
| 
 | |
| 	poptPrintHelp(pctx, stdout, 0);
 | |
| 	fprintf(stdout, "\nCIFS dd options:\n");
 | |
| 
 | |
| 	for (i = 0; i < ARRAY_SIZE(args); ++i) {
 | |
| 		if (args[i].arg_name == NULL) {
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		snprintf(prefix, sizeof(prefix), "%s=%-*s",
 | |
| 			args[i].arg_name,
 | |
| 			(int)(sizeof(prefix) - strlen(args[i].arg_name) - 2),
 | |
| 			argtype_str(args[i].arg_type));
 | |
| 		prefix[sizeof(prefix) - 1] = '\0';
 | |
| 		fprintf(stdout, "  %s%s\n", prefix, args[i].arg_help);
 | |
| 	}
 | |
| 
 | |
| 	fprintf(stdout, "\n%s\n", notes);
 | |
| 	exit(0);
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------- */
 | |
| /* Main block copying routine.						     */
 | |
| /* ------------------------------------------------------------------------- */
 | |
| 
 | |
| static void print_transfer_stats(void)
 | |
| {
 | |
| 	if (DEBUGLEVEL > 0) {
 | |
| 		printf("%llu+%llu records in (%llu bytes)\n"
 | |
| 			"%llu+%llu records out (%llu bytes)\n",
 | |
| 			(unsigned long long)dd_stats.in.fblocks,
 | |
| 			(unsigned long long)dd_stats.in.pblocks,
 | |
| 			(unsigned long long)dd_stats.in.bytes,
 | |
| 			(unsigned long long)dd_stats.out.fblocks,
 | |
| 			(unsigned long long)dd_stats.out.pblocks,
 | |
| 			(unsigned long long)dd_stats.out.bytes);
 | |
| 	} else {
 | |
| 		printf("%llu+%llu records in\n%llu+%llu records out\n",
 | |
| 				(unsigned long long)dd_stats.in.fblocks,
 | |
| 				(unsigned long long)dd_stats.in.pblocks,
 | |
| 				(unsigned long long)dd_stats.out.fblocks,
 | |
| 				(unsigned long long)dd_stats.out.pblocks);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static struct dd_iohandle * open_file(struct resolve_context *resolve_ctx, 
 | |
| 				      const char * which, const char **ports,
 | |
| 				      struct smbcli_options *smb_options)
 | |
| {
 | |
| 	int			options = 0;
 | |
| 	const char *		path = NULL;
 | |
| 	struct dd_iohandle *	handle = NULL;
 | |
| 
 | |
| 	if (check_arg_bool("direct")) {
 | |
| 		options |= DD_DIRECT_IO;
 | |
| 	}
 | |
| 
 | |
| 	if (check_arg_bool("sync")) {
 | |
| 		options |= DD_SYNC_IO;
 | |
| 	}
 | |
| 
 | |
| 	if (check_arg_bool("oplock")) {
 | |
| 		options |= DD_OPLOCK;
 | |
| 	}
 | |
| 
 | |
| 	if (strcmp(which, "if") == 0) {
 | |
| 		path = check_arg_pathname("if");
 | |
| 		handle = dd_open_path(resolve_ctx, path, ports, 
 | |
| 				      check_arg_numeric("ibs"), options,
 | |
| 				      smb_options);
 | |
| 	} else if (strcmp(which, "of") == 0) {
 | |
| 		options |= DD_WRITE;
 | |
| 		path = check_arg_pathname("of");
 | |
| 		handle = dd_open_path(resolve_ctx, path, ports, 
 | |
| 				      check_arg_numeric("obs"), options,
 | |
| 				      smb_options);
 | |
| 	} else {
 | |
| 		SMB_ASSERT(0);
 | |
| 		return(NULL);
 | |
| 	}
 | |
| 
 | |
| 	if (!handle) {
 | |
| 		fprintf(stderr, "%s: failed to open %s\n", PROGNAME, path);
 | |
| 	}
 | |
| 
 | |
| 	return(handle);
 | |
| }
 | |
| 
 | |
| static int copy_files(struct loadparm_context *lp_ctx)
 | |
| {
 | |
| 	uint8_t *	iobuf;	/* IO buffer. */
 | |
| 	uint64_t	iomax;	/* Size of the IO buffer. */
 | |
| 	uint64_t	data_size; /* Amount of data in the IO buffer. */
 | |
| 
 | |
| 	uint64_t	ibs;
 | |
| 	uint64_t	obs;
 | |
| 	uint64_t	count;
 | |
| 
 | |
| 	struct dd_iohandle *	ifile;
 | |
| 	struct dd_iohandle *	ofile;
 | |
| 
 | |
| 	struct smbcli_options options;
 | |
| 
 | |
| 	ibs = check_arg_numeric("ibs");
 | |
| 	obs = check_arg_numeric("obs");
 | |
| 	count = check_arg_numeric("count");
 | |
| 
 | |
| 	lp_smbcli_options(lp_ctx, &options);
 | |
| 
 | |
| 	/* Allocate IO buffer. We need more than the max IO size because we
 | |
| 	 * could accumulate a remainder if ibs and obs don't match.
 | |
| 	 */
 | |
| 	iomax = 2 * MAX(ibs, obs);
 | |
| 	if ((iobuf = malloc_array_p(uint8_t, iomax)) == NULL) {
 | |
| 		fprintf(stderr,
 | |
| 			"%s: failed to allocate IO buffer of %llu bytes\n",
 | |
| 			PROGNAME, (unsigned long long)iomax);
 | |
| 		return(EOM_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	options.max_xmit = MAX(ibs, obs);
 | |
| 
 | |
| 	DEBUG(4, ("IO buffer size is %llu, max xmit is %d\n",
 | |
| 			(unsigned long long)iomax, options.max_xmit));
 | |
| 
 | |
| 	if (!(ifile = open_file(lp_resolve_context(lp_ctx), "if", 
 | |
| 				lp_smb_ports(lp_ctx), &options))) {
 | |
| 		return(FILESYS_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	if (!(ofile = open_file(lp_resolve_context(lp_ctx), "of", 
 | |
| 				lp_smb_ports(lp_ctx), &options))) {
 | |
| 		return(FILESYS_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	/* Seek the files to their respective starting points. */
 | |
| 	ifile->io_seek(ifile, check_arg_numeric("skip") * ibs);
 | |
| 	ofile->io_seek(ofile, check_arg_numeric("seek") * obs);
 | |
| 
 | |
| 	DEBUG(4, ("max xmit was negotiated to be %d\n", options.max_xmit));
 | |
| 
 | |
| 	for (data_size = 0;;) {
 | |
| 
 | |
| 		/* Handle signals. We are somewhat compatible with GNU dd.
 | |
| 		 * SIGINT makes us stop, but still print transfer statistics.
 | |
| 		 * SIGUSR1 makes us print transfer statistics but we continue
 | |
| 		 * copying.
 | |
| 		 */
 | |
| 		if (dd_sigint) {
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (dd_sigusr1) {
 | |
| 			print_transfer_stats();
 | |
| 			dd_sigusr1 = 0;
 | |
| 		}
 | |
| 
 | |
| 		if (ifile->io_flags & DD_END_OF_FILE) {
 | |
| 			DEBUG(4, ("flushing %llu bytes at EOF\n",
 | |
| 					(unsigned long long)data_size));
 | |
| 			while (data_size > 0) {
 | |
| 				if (!dd_flush_block(ofile, iobuf,
 | |
| 							&data_size, obs)) {
 | |
| 					return(IOERROR_EXIT_CODE);
 | |
| 				}
 | |
| 			}
 | |
| 			goto done;
 | |
| 		}
 | |
| 
 | |
| 		/* Try and read enough blocks of ibs bytes to be able write
 | |
| 		 * out one of obs bytes.
 | |
| 		 */
 | |
| 		if (!dd_fill_block(ifile, iobuf, &data_size, obs, ibs)) {
 | |
| 			return(IOERROR_EXIT_CODE);
 | |
| 		}
 | |
| 
 | |
| 		if (data_size == 0) {
 | |
| 			/* Done. */
 | |
| 			SMB_ASSERT(ifile->io_flags & DD_END_OF_FILE);
 | |
| 		}
 | |
| 
 | |
| 		/* Stop reading when we hit the block count. */
 | |
| 		if (dd_stats.in.bytes >= (ibs * count)) {
 | |
| 			ifile->io_flags |= DD_END_OF_FILE;
 | |
| 		}
 | |
| 
 | |
| 		/* If we wanted to be a legitimate dd, we would do character
 | |
| 		 * conversions and other shenanigans here.
 | |
| 		 */
 | |
| 
 | |
| 		/* Flush what we read in units of obs bytes. We want to have
 | |
| 		 * at least obs bytes in the IO buffer but might not if the
 | |
| 		 * file is too small.
 | |
| 		 */
 | |
| 		if (data_size && 
 | |
| 		    !dd_flush_block(ofile, iobuf, &data_size, obs)) {
 | |
| 			return(IOERROR_EXIT_CODE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| done:
 | |
| 	print_transfer_stats();
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------- */
 | |
| /* Main.								     */
 | |
| /* ------------------------------------------------------------------------- */
 | |
| 
 | |
| struct poptOption cifsddHelpOptions[] = {
 | |
|   { NULL, '\0', POPT_ARG_CALLBACK, (void *)&cifsdd_help_message, '\0', NULL, NULL },
 | |
|   { "help", '?', 0, NULL, '?', "Show this help message", NULL },
 | |
|   { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
 | |
|   { NULL }
 | |
| } ;
 | |
| 
 | |
| int main(int argc, const char ** argv)
 | |
| {
 | |
| 	int i;
 | |
| 	const char ** dd_args;
 | |
| 
 | |
| 	poptContext pctx;
 | |
| 	struct poptOption poptions[] = {
 | |
| 		/* POPT_AUTOHELP */
 | |
| 		{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, cifsddHelpOptions,
 | |
| 			0, "Help options:", NULL },
 | |
| 		POPT_COMMON_SAMBA
 | |
| 		POPT_COMMON_CONNECTION
 | |
| 		POPT_COMMON_CREDENTIALS
 | |
| 		POPT_COMMON_VERSION
 | |
| 		{ NULL }
 | |
| 	};
 | |
| 
 | |
| 	/* Block sizes. */
 | |
| 	set_arg_val("bs", (uint64_t)4096);
 | |
| 	set_arg_val("ibs", (uint64_t)4096);
 | |
| 	set_arg_val("obs", (uint64_t)4096);
 | |
| 	/* Block counts. */
 | |
| 	set_arg_val("count", (uint64_t)-1);
 | |
| 	set_arg_val("seek", (uint64_t)0);
 | |
| 	set_arg_val("seek", (uint64_t)0);
 | |
| 	/* Files. */
 | |
| 	set_arg_val("if", NULL);
 | |
| 	set_arg_val("of", NULL);
 | |
| 	/* Options. */
 | |
| 	set_arg_val("direct", false);
 | |
| 	set_arg_val("sync", false);
 | |
| 	set_arg_val("oplock", false);
 | |
| 
 | |
| 	pctx = poptGetContext(PROGNAME, argc, argv, poptions, 0);
 | |
| 	while ((i = poptGetNextOpt(pctx)) != -1) {
 | |
| 		;
 | |
| 	}
 | |
| 
 | |
| 	for (dd_args = poptGetArgs(pctx); dd_args && *dd_args; ++dd_args) {
 | |
| 
 | |
| 		if (!set_arg_argv(*dd_args)) {
 | |
| 			fprintf(stderr, "%s: invalid option: %s\n",
 | |
| 					PROGNAME, *dd_args);
 | |
| 			exit(SYNTAX_EXIT_CODE);
 | |
| 		}
 | |
| 
 | |
| 		/* "bs" has the side-effect of setting "ibs" and "obs". */
 | |
| 		if (strncmp(*dd_args, "bs=", 3) == 0) {
 | |
| 			uint64_t bs = check_arg_numeric("bs");
 | |
| 			set_arg_val("ibs", bs);
 | |
| 			set_arg_val("obs", bs);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	gensec_init(cmdline_lp_ctx);
 | |
| 	dump_args();
 | |
| 
 | |
| 	if (check_arg_numeric("ibs") == 0 || check_arg_numeric("ibs") == 0) {
 | |
| 		fprintf(stderr, "%s: block sizes must be greater that zero\n",
 | |
| 				PROGNAME);
 | |
| 		exit(SYNTAX_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	if (check_arg_pathname("if") == NULL) {
 | |
| 		fprintf(stderr, "%s: missing input filename\n", PROGNAME);
 | |
| 		exit(SYNTAX_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	if (check_arg_pathname("of") == NULL) {
 | |
| 		fprintf(stderr, "%s: missing output filename\n", PROGNAME);
 | |
| 		exit(SYNTAX_EXIT_CODE);
 | |
| 	}
 | |
| 
 | |
| 	CatchSignal(SIGINT, dd_handle_signal);
 | |
| 	CatchSignal(SIGUSR1, dd_handle_signal);
 | |
| 	return(copy_files(cmdline_lp_ctx));
 | |
| }
 | |
| 
 | |
| /* vim: set sw=8 sts=8 ts=8 tw=79 : */
 |