예제 #1
0
파일: stty.c 프로젝트: Crobisaur/busybox
static void set_control_char_or_die(const struct control_info *info,
			const char *arg, struct termios *mode)
{
	unsigned char value;

	if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
		value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
	else if (arg[0] == '\0' || arg[1] == '\0')
		value = arg[0];
	else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
		value = _POSIX_VDISABLE;
	else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
		value = arg[1] & 0x1f; /* Non-letters get weird results */
		if (arg[1] == '?')
			value = 127;
	} else
		value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
	mode->c_cc[info->offset] = value;
}
예제 #2
0
int hexdump_main(int argc, char **argv)
{
	const char *p;
	int ch;

	bb_dump_vflag = FIRST;
	bb_dump_length = -1;

	while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
		p = strchr(hexdump_opts, ch);
		if (!p)
			bb_show_usage();
		if ((p - hexdump_opts) < 5) {
			bb_dump_add(add_first);
			bb_dump_add(add_strings[(int)(p - hexdump_opts)]);
		} else if (ch == 'C') {
			bb_dump_add("\"%08.8_Ax\n\"");
			bb_dump_add("\"%08.8_ax  \" 8/1 \"%02x \" \"  \" 8/1 \"%02x \" ");
			bb_dump_add("\"  |\" 16/1 \"%_p\" \"|\\n\"");
		} else {
			/* Save a little bit of space below by omitting the 'else's. */
			if (ch == 'e') {
				bb_dump_add(optarg);
			} /* else */
			if (ch == 'f') {
				bb_dump_addfile(optarg);
			} /* else */
			if (ch == 'n') {
				bb_dump_length = xatoi_u(optarg);
			} /* else */
			if (ch == 's') {
				bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes);
			} /* else */
			if (ch == 'v') {
				bb_dump_vflag = ALL;
			}
		}
	}

	if (!bb_dump_fshead) {
		bb_dump_add(add_first);
		bb_dump_add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
	}

	argv += optind;

	return bb_dump_dump(argv);
}
예제 #3
0
파일: stty.c 프로젝트: Crobisaur/busybox
int stty_main(int argc UNUSED_PARAM, char **argv)
{
	struct termios mode;
	void (*output_func)(const struct termios *, int);
	const char *file_name = NULL;
	int display_all = 0;
	int stty_state;
	int k;

	INIT_G();

	stty_state = STTY_noargs;
	output_func = do_display;

	/* First pass: only parse/verify command line params */
	k = 0;
	while (argv[++k]) {
		const struct mode_info *mp;
		const struct control_info *cp;
		const char *arg = argv[k];
		const char *argnext = argv[k+1];
		int param;

		if (arg[0] == '-') {
			int i;
			mp = find_mode(arg+1);
			if (mp) {
				if (!(mp->flags & REV))
					goto invalid_argument;
				stty_state &= ~STTY_noargs;
				continue;
			}
			/* It is an option - parse it */
			i = 0;
			while (arg[++i]) {
				switch (arg[i]) {
				case 'a':
					stty_state |= STTY_verbose_output;
					output_func = do_display;
					display_all = 1;
					break;
				case 'g':
					stty_state |= STTY_recoverable_output;
					output_func = display_recoverable;
					break;
				case 'F':
					if (file_name)
						bb_error_msg_and_die("only one device may be specified");
					file_name = &arg[i+1]; /* "-Fdevice" ? */
					if (!file_name[0]) { /* nope, "-F device" */
						int p = k+1; /* argv[p] is argnext */
						file_name = argnext;
						if (!file_name)
							bb_error_msg_and_die(bb_msg_requires_arg, "-F");
						/* remove -F param from arg[vc] */
						while (argv[p]) {
							argv[p] = argv[p+1];
							++p;
						}
					}
					goto end_option;
				default:
					goto invalid_argument;
				}
			}
 end_option:
			continue;
		}

		mp = find_mode(arg);
		if (mp) {
			stty_state &= ~STTY_noargs;
			continue;
		}

		cp = find_control(arg);
		if (cp) {
			if (!argnext)
				bb_error_msg_and_die(bb_msg_requires_arg, arg);
			/* called for the side effect of xfunc death only */
			set_control_char_or_die(cp, argnext, &mode);
			stty_state &= ~STTY_noargs;
			++k;
			continue;
		}

		param = find_param(arg);
		if (param & param_need_arg) {
			if (!argnext)
				bb_error_msg_and_die(bb_msg_requires_arg, arg);
			++k;
		}

		switch (param) {
#ifdef __linux__
		case param_line:
# ifndef TIOCGWINSZ
			xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
			break;
# endif /* else fall-through */
#endif
#ifdef TIOCGWINSZ
		case param_rows:
		case param_cols:
		case param_columns:
			xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
			break;
		case param_size:
#endif
		case param_speed:
			break;
		case param_ispeed:
			/* called for the side effect of xfunc death only */
			set_speed_or_die(input_speed, argnext, &mode);
			break;
		case param_ospeed:
			/* called for the side effect of xfunc death only */
			set_speed_or_die(output_speed, argnext, &mode);
			break;
		default:
			if (recover_mode(arg, &mode) == 1) break;
			if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
 invalid_argument:
			bb_error_msg_and_die("invalid argument '%s'", arg);
		}
		stty_state &= ~STTY_noargs;
	}

	/* Specifying both -a and -g is an error */
	if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
		(STTY_verbose_output | STTY_recoverable_output)
	) {
		bb_error_msg_and_die("-a and -g are mutually exclusive");
	}
	/* Specifying -a or -g with non-options is an error */
	if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
	 && !(stty_state & STTY_noargs)
	) {
		bb_error_msg_and_die("modes may not be set when -a or -g is used");
	}

	/* Now it is safe to start doing things */
	if (file_name) {
		G.device_name = file_name;
		xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
		ndelay_off(STDIN_FILENO);
	}

	/* Initialize to all zeroes so there is no risk memcmp will report a
	   spurious difference in an uninitialized portion of the structure */
	memset(&mode, 0, sizeof(mode));
	if (tcgetattr(STDIN_FILENO, &mode))
		perror_on_device_and_die("%s");

	if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
		G.max_col = get_terminal_width(STDOUT_FILENO);
		output_func(&mode, display_all);
		return EXIT_SUCCESS;
	}

	/* Second pass: perform actions */
	k = 0;
	while (argv[++k]) {
		const struct mode_info *mp;
		const struct control_info *cp;
		const char *arg = argv[k];
		const char *argnext = argv[k+1];
		int param;

		if (arg[0] == '-') {
			mp = find_mode(arg+1);
			if (mp) {
				set_mode(mp, 1 /* reversed */, &mode);
				stty_state |= STTY_require_set_attr;
			}
			/* It is an option - already parsed. Skip it */
			continue;
		}

		mp = find_mode(arg);
		if (mp) {
			set_mode(mp, 0 /* non-reversed */, &mode);
			stty_state |= STTY_require_set_attr;
			continue;
		}

		cp = find_control(arg);
		if (cp) {
			++k;
			set_control_char_or_die(cp, argnext, &mode);
			stty_state |= STTY_require_set_attr;
			continue;
		}

		param = find_param(arg);
		if (param & param_need_arg) {
			++k;
		}

		switch (param) {
#ifdef __linux__
		case param_line:
			mode.c_line = xatoul_sfx(argnext, stty_suffixes);
			stty_state |= STTY_require_set_attr;
			break;
#endif
#ifdef TIOCGWINSZ
		case param_cols:
		case param_columns:
			set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
			break;
		case param_size:
			display_window_size(0);
			break;
		case param_rows:
			set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
			break;
#endif
		case param_speed:
			display_speed(&mode, 0);
			break;
		case param_ispeed:
			set_speed_or_die(input_speed, argnext, &mode);
			stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			break;
		case param_ospeed:
			set_speed_or_die(output_speed, argnext, &mode);
			stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			break;
		default:
			if (recover_mode(arg, &mode) == 1)
				stty_state |= STTY_require_set_attr;
			else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
				set_speed_or_die(both_speeds, arg, &mode);
				stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
			} /* else - impossible (caught in the first pass):
				bb_error_msg_and_die("invalid argument '%s'", arg); */
		}
	}

	if (stty_state & STTY_require_set_attr) {
		struct termios new_mode;

		if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
			perror_on_device_and_die("%s");

		/* POSIX (according to Zlotnick's book) tcsetattr returns zero if
		   it performs *any* of the requested operations.  This means it
		   can report 'success' when it has actually failed to perform
		   some proper subset of the requested operations.  To detect
		   this partial failure, get the current terminal attributes and
		   compare them to the requested ones */

		/* Initialize to all zeroes so there is no risk memcmp will report a
		   spurious difference in an uninitialized portion of the structure */
		memset(&new_mode, 0, sizeof(new_mode));
		if (tcgetattr(STDIN_FILENO, &new_mode))
			perror_on_device_and_die("%s");

		if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
/*
 * I think the below chunk is not necessary on Linux.
 * If you are deleting it, also delete STTY_speed_was_set bit -
 * it is only ever checked here.
 */
#if 0 /* was "if CIBAUD" */
			/* SunOS 4.1.3 (at least) has the problem that after this sequence,
			   tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
			   sometimes (m1 != m2).  The only difference is in the four bits
			   of the c_cflag field corresponding to the baud rate.  To save
			   Sun users a little confusion, don't report an error if this
			   happens.  But suppress the error only if we haven't tried to
			   set the baud rate explicitly -- otherwise we'd never give an
			   error for a true failure to set the baud rate */

			new_mode.c_cflag &= (~CIBAUD);
			if ((stty_state & STTY_speed_was_set)
			 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
#endif
				perror_on_device_and_die("%s: cannot perform all requested operations");
		}
	}

	return EXIT_SUCCESS;
}
예제 #4
0
int dd_main(int argc UNUSED_PARAM, char **argv)
{
	enum {
		/* Must be in the same order as OP_conv_XXX! */
		/* (see "flags |= (1 << what)" below) */
		FLAG_NOTRUNC = 1 << 0,
		FLAG_SYNC    = 1 << 1,
		FLAG_NOERROR = 1 << 2,
		FLAG_FSYNC   = 1 << 3,
		/* end of conv flags */
		FLAG_TWOBUFS = 1 << 4,
		FLAG_COUNT   = 1 << 5,
	};
	static const char keywords[] ALIGN1 =
		"bs\0""count\0""seek\0""skip\0""if\0""of\0"
#if ENABLE_FEATURE_DD_IBS_OBS
		"ibs\0""obs\0""conv\0"
#endif
		;
#if ENABLE_FEATURE_DD_IBS_OBS
	static const char conv_words[] ALIGN1 =
		"notrunc\0""sync\0""noerror\0""fsync\0";
#endif
	enum {
		OP_bs = 0,
		OP_count,
		OP_seek,
		OP_skip,
		OP_if,
		OP_of,
#if ENABLE_FEATURE_DD_IBS_OBS
		OP_ibs,
		OP_obs,
		OP_conv,
		/* Must be in the same order as FLAG_XXX! */
		OP_conv_notrunc = 0,
		OP_conv_sync,
		OP_conv_noerror,
		OP_conv_fsync,
	/* Unimplemented conv=XXX: */
	//nocreat       do not create the output file
	//excl          fail if the output file already exists
	//fdatasync     physically write output file data before finishing
	//swab          swap every pair of input bytes
	//lcase         change upper case to lower case
	//ucase         change lower case to upper case
	//block         pad newline-terminated records with spaces to cbs-size
	//unblock       replace trailing spaces in cbs-size records with newline
	//ascii         from EBCDIC to ASCII
	//ebcdic        from ASCII to EBCDIC
	//ibm           from ASCII to alternate EBCDIC
#endif
	};
	int exitcode = EXIT_FAILURE;
	size_t ibs = 512, obs = 512;
	ssize_t n, w;
	char *ibuf, *obuf;
	/* And these are all zeroed at once! */
	struct {
		int flags;
		size_t oc;
		off_t count;
		off_t seek, skip;
		const char *infile, *outfile;
	} Z;
#define flags   (Z.flags  )
#define oc      (Z.oc     )
#define count   (Z.count  )
#define seek    (Z.seek   )
#define skip    (Z.skip   )
#define infile  (Z.infile )
#define outfile (Z.outfile)

	memset(&Z, 0, sizeof(Z));
	INIT_G();
	//fflush(NULL); - is this needed because of NOEXEC?

#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
	signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
#endif

	for (n = 1; argv[n]; n++) {
		int what;
		char *val;
		char *arg = argv[n];

#if ENABLE_DESKTOP
		/* "dd --". NB: coreutils 6.9 will complain if they see
		 * more than one of them. We wouldn't. */
		if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
			continue;
#endif
		val = strchr(arg, '=');
		if (val == NULL)
			bb_show_usage();
		*val = '\0';
		what = index_in_strings(keywords, arg);
		if (what < 0)
			bb_show_usage();
		/* *val = '='; - to preserve ps listing? */
		val++;
#if ENABLE_FEATURE_DD_IBS_OBS
		if (what == OP_ibs) {
			/* Must fit into positive ssize_t */
			ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
			/*continue;*/
		}
		if (what == OP_obs) {
			obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
			/*continue;*/
		}
		if (what == OP_conv) {
			while (1) {
				/* find ',', replace them with NUL so we can use val for
				 * index_in_strings() without copying.
				 * We rely on val being non-null, else strchr would fault.
				 */
				arg = strchr(val, ',');
				if (arg)
					*arg = '\0';
				what = index_in_strings(conv_words, val);
				if (what < 0)
					bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
				flags |= (1 << what);
				if (!arg) /* no ',' left, so this was the last specifier */
					break;
				/* *arg = ','; - to preserve ps listing? */
				val = arg + 1; /* skip this keyword and ',' */
			}
			continue; /* we trashed 'what', can't fall through */
		}
#endif
		if (what == OP_bs) {
			ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
			/*continue;*/
		}
		/* These can be large: */
		if (what == OP_count) {
			flags |= FLAG_COUNT;
			count = XATOU_SFX(val, dd_suffixes);
			/*continue;*/
		}
		if (what == OP_seek) {
			seek = XATOU_SFX(val, dd_suffixes);
			/*continue;*/
		}
		if (what == OP_skip) {
			skip = XATOU_SFX(val, dd_suffixes);
			/*continue;*/
		}
		if (what == OP_if) {
			infile = val;
			/*continue;*/
		}
		if (what == OP_of) {
			outfile = val;
			/*continue;*/
		}
	} /* end of "for (argv[n])" */

//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
	ibuf = obuf = xmalloc(ibs);
	if (ibs != obs) {
		flags |= FLAG_TWOBUFS;
		obuf = xmalloc(obs);
	}
	if (infile != NULL)
		xmove_fd(xopen(infile, O_RDONLY), ifd);
	else {
		infile = bb_msg_standard_input;
	}
	if (outfile != NULL) {
		int oflag = O_WRONLY | O_CREAT;

		if (!seek && !(flags & FLAG_NOTRUNC))
			oflag |= O_TRUNC;

		xmove_fd(xopen(outfile, oflag), ofd);

		if (seek && !(flags & FLAG_NOTRUNC)) {
			if (ftruncate(ofd, seek * obs) < 0) {
				struct stat st;

				if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
						S_ISDIR(st.st_mode))
					goto die_outfile;
			}
		}
	} else {
		outfile = bb_msg_standard_output;
	}
	if (skip) {
		if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
			while (skip-- > 0) {
				n = safe_read(ifd, ibuf, ibs);
				if (n < 0)
					goto die_infile;
				if (n == 0)
					break;
			}
		}
	}
	if (seek) {
		if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
			goto die_outfile;
	}

	while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
		if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */
			memset(ibuf, 0, ibs);
		n = safe_read(ifd, ibuf, ibs);
		if (n == 0)
			break;
		if (n < 0) {
			if (!(flags & FLAG_NOERROR))
				goto die_infile;
			n = ibs;
			bb_simple_perror_msg(infile);
		}
		if ((size_t)n == ibs)
			G.in_full++;
		else {
			G.in_part++;
			if (flags & FLAG_SYNC) {
				memset(ibuf + n, '\0', ibs - n);
				n = ibs;
			}
		}
		if (flags & FLAG_TWOBUFS) {
			char *tmp = ibuf;
			while (n) {
				size_t d = obs - oc;

				if (d > (size_t)n)
					d = n;
				memcpy(obuf + oc, tmp, d);
				n -= d;
				tmp += d;
				oc += d;
				if (oc == obs) {
					if (write_and_stats(obuf, obs, obs, outfile))
						goto out_status;
					oc = 0;
				}
			}
		} else if (write_and_stats(ibuf, n, obs, outfile))
			goto out_status;

		if (flags & FLAG_FSYNC) {
			if (fsync(ofd) < 0)
				goto die_outfile;
		}
	}

	if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
		w = full_write_or_warn(obuf, oc, outfile);
		if (w < 0) goto out_status;
		if (w > 0) G.out_part++;
	}
	if (close(ifd) < 0) {
 die_infile:
		bb_simple_perror_msg_and_die(infile);
	}

	if (close(ofd) < 0) {
 die_outfile:
		bb_simple_perror_msg_and_die(outfile);
	}

	exitcode = EXIT_SUCCESS;
 out_status:
	dd_output_status(0);

	return exitcode;
}
예제 #5
0
int hexdump_main(int argc, char **argv)
{
	const char *p;
	int ch;
#if ENABLE_FEATURE_HEXDUMP_REVERSE
	FILE *fp;
	smallint rdump = 0;
#endif

	bb_dump_vflag = FIRST;
	bb_dump_length = -1;

	if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */
		ch = 'C';
		goto hd_applet;
	}

	/* We cannot use getopt32: in hexdump options are cumulative.
	 * E.g. "hexdump -C -C file" should dump each line twice */
	while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
		p = strchr(hexdump_opts, ch);
		if (!p)
			bb_show_usage();
		if ((p - hexdump_opts) < 5) {
			bb_dump_add(add_first);
			bb_dump_add(add_strings[(int)(p - hexdump_opts)]);
		}
		/* Save a little bit of space below by omitting the 'else's. */
		if (ch == 'C') {
 hd_applet:
			bb_dump_add("\"%08.8_Ax\n\"");
			bb_dump_add("\"%08.8_ax  \" 8/1 \"%02x \" \"  \" 8/1 \"%02x \" ");
			bb_dump_add("\"  |\" 16/1 \"%_p\" \"|\\n\"");
		}
		if (ch == 'e') {
			bb_dump_add(optarg);
		} /* else */
		if (ch == 'f') {
			bb_dump_addfile(optarg);
		} /* else */
		if (ch == 'n') {
			bb_dump_length = xatoi_u(optarg);
		} /* else */
		if (ch == 's') {
			bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes);
		} /* else */
		if (ch == 'v') {
			bb_dump_vflag = ALL;
		}
#if ENABLE_FEATURE_HEXDUMP_REVERSE
		if (ch == 'R') {
			rdump = 1;
		}
#endif
	}

	if (!bb_dump_fshead) {
		bb_dump_add(add_first);
		bb_dump_add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
	}

	argv += optind;

#if !ENABLE_FEATURE_HEXDUMP_REVERSE
	return bb_dump_dump(argv);
#else
	if (!rdump) {
		return bb_dump_dump(argv);
	}

	/* -R: reverse of 'hexdump -Cv' */
	fp = stdin;
	if (!*argv) {
		argv--;
		goto jump_in;
	}

	do {
		char *buf;
		fp = xfopen(*argv, "r");
 jump_in:
		while ((buf = xmalloc_getline(fp)) != NULL) {
			p = buf;
			while (1) {
				/* skip address or previous byte */
				while (isxdigit(*p)) p++;
				while (*p == ' ') p++;
				/* '|' char will break the line */
				if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1)
					break;
				putchar(ch);
			}
			free(buf);
		}
		fclose(fp);
	} while (*++argv);

	fflush_stdout_and_exit(EXIT_SUCCESS);
#endif
}
예제 #6
0
파일: dd.c 프로젝트: AlickHill/Lantern
int dd_main(int argc, char **argv)
{
	enum {
		SYNC_FLAG    = 1 << 0,
		NOERROR      = 1 << 1,
		TRUNC_FLAG   = 1 << 2,
		TWOBUFS_FLAG = 1 << 3,
	};
	static const char * const keywords[] = {
		"bs=", "count=", "seek=", "skip=", "if=", "of=",
#if ENABLE_FEATURE_DD_IBS_OBS
		"ibs=", "obs=", "conv=", "notrunc", "sync", "noerror",
#endif
		NULL
	};
	enum {
		OP_bs = 1,
		OP_count,
		OP_seek,
		OP_skip,
		OP_if,
		OP_of,
#if ENABLE_FEATURE_DD_IBS_OBS
		OP_ibs,
		OP_obs,
		OP_conv,
		OP_conv_notrunc,
		OP_conv_sync,
		OP_conv_noerror,
#endif
	};
	int flags = TRUNC_FLAG;
	size_t oc = 0, ibs = 512, obs = 512;
	ssize_t n, w;
	off_t seek = 0, skip = 0, count = OFF_T_MAX;
	int ifd, ofd;
	const char *infile = NULL, *outfile = NULL;
	char *ibuf, *obuf;

	memset(&G, 0, sizeof(G)); /* because of NOEXEC */

	if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
		struct sigaction sa;

		memset(&sa, 0, sizeof(sa));
		sa.sa_handler = dd_output_status;
		sa.sa_flags = SA_RESTART;
		sigemptyset(&sa.sa_mask);
		sigaction(SIGUSR1, &sa, 0);
	}

	for (n = 1; n < argc; n++) {
		smalluint key_len;
		smalluint what;
		char *key;
		char *arg = argv[n];

//XXX:FIXME: we reject plain "dd --" This would cost ~20 bytes, so..
//if (*arg == '-' && *++arg == '-' && !*++arg) continue;
		key = strstr(arg, "=");
		if (key == NULL)
			bb_show_usage();
		key_len = key - arg + 1;
		key = xstrndup(arg, key_len);
		what = index_in_str_array(keywords, key) + 1;
		if (ENABLE_FEATURE_CLEAN_UP)
			free(key);
		if (what == 0)
			bb_show_usage();
		arg += key_len;
		/* Must fit into positive ssize_t */
#if ENABLE_FEATURE_DD_IBS_OBS
			if (what == OP_ibs) {
				ibs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes);
				continue;
			}
			if (what == OP_obs) {
				obs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes);
				continue;
			}
			if (what == OP_conv) {
				while (1) {
					/* find ',', replace them with nil so we can use arg for
					 * index_in_str_array without copying.
					 * We rely on arg being non-null, else strchr would fault.
					 */
					key = strchr(arg, ',');
					if (key)
						*key = '\0';
					what = index_in_str_array(keywords, arg) + 1;
					if (what < OP_conv_notrunc)
						bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
					if (what == OP_conv_notrunc)
						flags &= ~TRUNC_FLAG;
					if (what == OP_conv_sync)
						flags |= SYNC_FLAG;
					if (what == OP_conv_noerror)
						flags |= NOERROR;
					if (!key) /* no ',' left, so this was the last specifier */
						break;
					arg = key + 1; /* skip this keyword and ',' */
				}
				continue;
			}
#endif
		if (what == OP_bs) {
			ibs = obs = xatoul_range_sfx(arg, 1, ((size_t)-1L)/2, dd_suffixes);
			continue;
		}
		/* These can be large: */
		if (what == OP_count) {
			count = XATOU_SFX(arg, dd_suffixes);
			continue;
		}
		if (what == OP_seek) {
			seek = XATOU_SFX(arg, dd_suffixes);
			continue;
		}
		if (what == OP_skip) {
			skip = XATOU_SFX(arg, dd_suffixes);
			continue;
		}
		if (what == OP_if) {
			infile = arg;
			continue;
		}
		if (what == OP_of)
			outfile = arg;
	}
//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
	ibuf = obuf = xmalloc(ibs);
	if (ibs != obs) {
		flags |= TWOBUFS_FLAG;
		obuf = xmalloc(obs);
	}
	if (infile != NULL)
		ifd = xopen(infile, O_RDONLY);
	else {
		ifd = STDIN_FILENO;
		infile = bb_msg_standard_input;
	}
	if (outfile != NULL) {
		int oflag = O_WRONLY | O_CREAT;

		if (!seek && (flags & TRUNC_FLAG))
			oflag |= O_TRUNC;

		ofd = xopen(outfile, oflag);

		if (seek && (flags & TRUNC_FLAG)) {
			if (ftruncate(ofd, seek * obs) < 0) {
				struct stat st;

				if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
						S_ISDIR(st.st_mode))
					goto die_outfile;
			}
		}
	} else {
		ofd = STDOUT_FILENO;
		outfile = bb_msg_standard_output;
	}
	if (skip) {
		if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
			while (skip-- > 0) {
				n = safe_read(ifd, ibuf, ibs);
				if (n < 0)
					goto die_infile;
				if (n == 0)
					break;
			}
		}
	}
	if (seek) {
		if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
			goto die_outfile;
	}

	while (G.in_full + G.in_part != count) {
		if (flags & NOERROR) /* Pre-zero the buffer when for NOERROR */
			memset(ibuf, '\0', ibs);
		n = safe_read(ifd, ibuf, ibs);
		if (n == 0)
			break;
		if (n < 0) {
			if (flags & NOERROR) {
				n = ibs;
				bb_perror_msg("%s", infile);
			} else
				goto die_infile;
		}
		if ((size_t)n == ibs)
			G.in_full++;
		else {
			G.in_part++;
			if (flags & SYNC_FLAG) {
				memset(ibuf + n, '\0', ibs - n);
				n = ibs;
			}
		}
		if (flags & TWOBUFS_FLAG) {
			char *tmp = ibuf;
			while (n) {
				size_t d = obs - oc;

				if (d > n)
					d = n;
				memcpy(obuf + oc, tmp, d);
				n -= d;
				tmp += d;
				oc += d;
				if (oc == obs) {
					if (write_and_stats(ofd, obuf, obs, obs, outfile))
						goto out_status;
					oc = 0;
				}
			}
		} else if (write_and_stats(ofd, ibuf, n, obs, outfile))
			goto out_status;
	}

	if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
		w = full_write_or_warn(ofd, obuf, oc, outfile);
		if (w < 0) goto out_status;
		if (w > 0)
			G.out_part++;
	}
	if (close(ifd) < 0) {
die_infile:
		bb_perror_msg_and_die("%s", infile);
	}

	if (close(ofd) < 0) {
die_outfile:
		bb_perror_msg_and_die("%s", outfile);
	}
out_status:
	dd_output_status(0);

	return EXIT_SUCCESS;
}
예제 #7
0
파일: dd.c 프로젝트: emuikernel/WNR2000v4
int dd_main(int argc, char **argv)
{
	enum {
		sync_flag    = 1 << 0,
		noerror      = 1 << 1,
		trunc_flag   = 1 << 2,
		twobufs_flag = 1 << 3,
	};
	int flags = trunc_flag;
	size_t oc = 0, ibs = 512, obs = 512;
	ssize_t n, w;
	off_t seek = 0, skip = 0, count = OFF_T_MAX;
	int oflag, ifd, ofd;
	const char *infile = NULL, *outfile = NULL;
	char *ibuf, *obuf;

	if (ENABLE_FEATURE_DD_SIGNAL_HANDLING) {
		struct sigaction sa;

		memset(&sa, 0, sizeof(sa));
		sa.sa_handler = dd_output_status;
		sa.sa_flags = SA_RESTART;
		sigemptyset(&sa.sa_mask);
		sigaction(SIGUSR1, &sa, 0);
	}

	for (n = 1; n < argc; n++) {
		char *arg = argv[n];
		/* Must fit into positive ssize_t */
		if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("ibs=", arg, 4))
			ibs = xatoul_range_sfx(arg+4, 0, ((size_t)-1L)/2, dd_suffixes);
		else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("obs=", arg, 4))
			obs = xatoul_range_sfx(arg+4, 0, ((size_t)-1L)/2, dd_suffixes);
		else if (!strncmp("bs=", arg, 3))
			ibs = obs = xatoul_range_sfx(arg+3, 0, ((size_t)-1L)/2, dd_suffixes);
		/* These can be large: */
		else if (!strncmp("count=", arg, 6))
			count = XATOU_SFX(arg+6, dd_suffixes);
		else if (!strncmp("seek=", arg, 5))
			seek = XATOU_SFX(arg+5, dd_suffixes);
		else if (!strncmp("skip=", arg, 5))
			skip = XATOU_SFX(arg+5, dd_suffixes);

		else if (!strncmp("if=", arg, 3))
			infile = arg+3;
		else if (!strncmp("of=", arg, 3))
			outfile = arg+3;
		else if (ENABLE_FEATURE_DD_IBS_OBS && !strncmp("conv=", arg, 5)) {
			arg += 5;
			while (1) {
				if (!strncmp("notrunc", arg, 7)) {
					flags &= ~trunc_flag;
					arg += 7;
				} else if (!strncmp("sync", arg, 4)) {
					flags |= sync_flag;
					arg += 4;
				} else if (!strncmp("noerror", arg, 7)) {
					flags |= noerror;
					arg += 7;
				} else {
					bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
				}
				if (arg[0] == '\0') break;
				if (*arg++ != ',') bb_show_usage();
			}
		} else
			bb_show_usage();
	}

	ibuf = obuf = xmalloc(ibs);
	if (ibs != obs) {
		flags |= twobufs_flag;
		obuf = xmalloc(obs);
	}

	if (infile != NULL)
		ifd = xopen(infile, O_RDONLY);
	else {
		ifd = STDIN_FILENO;
		infile = bb_msg_standard_input;
	}

	if (outfile != NULL) {
		oflag = O_WRONLY | O_CREAT;

		if (!seek && (flags & trunc_flag))
			oflag |= O_TRUNC;

		ofd = xopen(outfile, oflag);

		if (seek && (flags & trunc_flag)) {
			if (ftruncate(ofd, seek * obs) < 0) {
				struct stat st;

				if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
						S_ISDIR(st.st_mode))
					goto die_outfile;
			}
		}
	} else {
		ofd = STDOUT_FILENO;
		outfile = bb_msg_standard_output;
	}

	if (skip) {
		if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
			while (skip-- > 0) {
				n = safe_read(ifd, ibuf, ibs);
				if (n < 0)
					bb_perror_msg_and_die("%s", infile);
				if (n == 0)
					break;
			}
		}
	}

	if (seek) {
		if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
			goto die_outfile;
	}

	while (in_full + in_part != count) {
		if (flags & noerror) {
			/* Pre-zero the buffer when doing the noerror thing */
			memset(ibuf, '\0', ibs);
		}

		n = safe_read(ifd, ibuf, ibs);
		if (n == 0)
			break;
		if (n < 0) {
			if (flags & noerror) {
				n = ibs;
				bb_perror_msg("%s", infile);
			} else
				bb_perror_msg_and_die("%s", infile);
		}
		if ((size_t)n == ibs)
			in_full++;
		else {
			in_part++;
			if (flags & sync_flag) {
				memset(ibuf + n, '\0', ibs - n);
				n = ibs;
			}
		}
		if (flags & twobufs_flag) {
			char *tmp = ibuf;
			while (n) {
				size_t d = obs - oc;

				if (d > n)
					d = n;
				memcpy(obuf + oc, tmp, d);
				n -= d;
				tmp += d;
				oc += d;
				if (oc == obs) {
					w = full_write_or_warn(ofd, obuf, obs, outfile);
					if (w < 0) goto out_status;
					if (w == obs)
						out_full++;
					else if (w > 0)
						out_part++;
					oc = 0;
				}
			}
		} else {
			w = full_write_or_warn(ofd, ibuf, n, outfile);
			if (w < 0) goto out_status;
			if (w == obs)
				out_full++;
			else if (w > 0)
				out_part++;
		}
	}

	if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
		w = full_write_or_warn(ofd, obuf, oc, outfile);
		if (w < 0) goto out_status;
		if (w > 0)
			out_part++;
	}
	if (close(ifd) < 0) {
		bb_perror_msg_and_die("%s", infile);
	}

	if (close(ofd) < 0) {
 die_outfile:
		bb_perror_msg_and_die("%s", outfile);
	}
 out_status:
	dd_output_status(0);

	return EXIT_SUCCESS;
}