Exemplo n.º 1
0
int
term_ioctl(struct tcb *const tcp, const unsigned int code,
	   const kernel_ulong_t arg)
{
	switch (code) {
	/* struct termios */
	case TCGETS:
#ifdef TCGETS2
	case TCGETS2:
#endif
	case TIOCGLCKTRMIOS:
		if (entering(tcp))
			return 0;
	case TCSETS:
#ifdef TCSETS2
	case TCSETS2:
#endif
	case TCSETSW:
#ifdef TCSETSW2
	case TCSETSW2:
#endif
	case TCSETSF:
#ifdef TCSETSF2
	case TCSETSF2:
#endif
	case TIOCSLCKTRMIOS:
		decode_termios(tcp, arg);
		break;

	/* struct termio */
	case TCGETA:
		if (entering(tcp))
			return 0;
	case TCSETA:
	case TCSETAW:
	case TCSETAF:
		decode_termio(tcp, arg);
		break;

	/* struct winsize */
	case TIOCGWINSZ:
		if (entering(tcp))
			return 0;
	case TIOCSWINSZ:
		decode_winsize(tcp, arg);
		break;

	/* struct ttysize */
#ifdef TIOCGSIZE
	case TIOCGSIZE:
		if (entering(tcp))
			return 0;
	case TIOCSSIZE:
		decode_ttysize(tcp, arg);
		break;
#endif

	/* ioctls with a direct decodable arg */
	case TCXONC:
		tprints(", ");
		printxval64(tcxonc_options, arg, "TC???");
		break;
	case TCFLSH:
		tprints(", ");
		printxval64(tcflsh_options, arg, "TC???");
		break;
	case TCSBRK:
	case TCSBRKP:
	case TIOCSCTTY:
		tprintf(", %d", (int) arg);
		break;

	/* ioctls with an indirect parameter displayed as modem flags */
	case TIOCMGET:
		if (entering(tcp))
			return 0;
	case TIOCMBIS:
	case TIOCMBIC:
	case TIOCMSET:
		decode_modem_flags(tcp, arg);
		break;

	/* ioctls with an indirect parameter displayed in decimal */
	case TIOCGPGRP:
	case TIOCGSID:
	case TIOCGETD:
	case TIOCGSOFTCAR:
	case TIOCGPTN:
	case FIONREAD:
	case TIOCOUTQ:
#ifdef TIOCGEXCL
	case TIOCGEXCL:
#endif
#ifdef TIOCGDEV
	case TIOCGDEV:
#endif
		if (entering(tcp))
			return 0;
	case TIOCSPGRP:
	case TIOCSETD:
	case FIONBIO:
	case FIOASYNC:
	case TIOCPKT:
	case TIOCSSOFTCAR:
	case TIOCSPTLCK:
		tprints(", ");
		printnum_int(tcp, arg, "%d");
		break;

	/* ioctls with an indirect parameter displayed as a char */
	case TIOCSTI:
		tprints(", ");
		printstrn(tcp, arg, 1);
		break;

	/* ioctls with no parameters */

	case TIOCSBRK:
	case TIOCCBRK:
	case TIOCCONS:
	case TIOCNOTTY:
	case TIOCEXCL:
	case TIOCNXCL:
	case FIOCLEX:
	case FIONCLEX:
#ifdef TIOCVHANGUP
	case TIOCVHANGUP:
#endif
#ifdef TIOCSSERIAL
	case TIOCSSERIAL:
#endif
		break;

	/* ioctls which are unknown */

	default:
		return RVAL_DECODED;
	}

	return RVAL_IOCTL_DECODED;
}
Exemplo n.º 2
0
MPERS_PRINTER_DECL(int, btrfs_ioctl,
		   struct tcb *tcp, const unsigned int code, const long arg)
{
	switch (code) {
	/* Take no arguments; command only. */
	case BTRFS_IOC_TRANS_START:
	case BTRFS_IOC_TRANS_END:
	case BTRFS_IOC_SYNC:
	case BTRFS_IOC_SCRUB_CANCEL:
	case BTRFS_IOC_QUOTA_RESCAN_WAIT:
	/*
	 * The codes for these ioctls are based on each accepting a
	 * vol_args but none of them actually consume an argument.
	 */
	case BTRFS_IOC_DEFRAG:
	case BTRFS_IOC_BALANCE:
		break;

	/* takes a signed int */
	case BTRFS_IOC_BALANCE_CTL:
		tprints(", ");
		printxval(btrfs_balance_ctl_cmds, arg, "BTRFS_BALANCE_CTL_???");
		break;

	/* returns a 64 */
	case BTRFS_IOC_START_SYNC: /* R */
		if (entering(tcp))
			return 0;
	/* fall through */
	/* takes a u64 */
	case BTRFS_IOC_DEFAULT_SUBVOL: /* W */
	case BTRFS_IOC_WAIT_SYNC: /* W */
		tprints(", ");
		printnum_int64(tcp, arg, "%" PRIu64);
		break;

	/* u64 but describe a flags bitfield; we can make that symbolic */
	case BTRFS_IOC_SUBVOL_GETFLAGS: { /* R */
		uint64_t flags;

		if (entering(tcp))
			return 0;

		tprints(", ");

		if (umove_or_printaddr(tcp, arg, &flags))
			break;

		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
		break;
	}

	case BTRFS_IOC_SUBVOL_SETFLAGS: { /* W */
		uint64_t flags;

		tprints(", ");

		if (umove_or_printaddr(tcp, arg, &flags))
			break;

		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
		break;
	}

	/* More complex types */
	case BTRFS_IOC_BALANCE_V2: /* RW */
		if (entering(tcp)) {
			tprints(", ");
			btrfs_print_balance(tcp, arg, false);
			return 0;
		}

		if (syserror(tcp))
			break;

		tprints(" => ");
		btrfs_print_balance(tcp, arg, true);
		break;
	case BTRFS_IOC_BALANCE_PROGRESS: /* R */
		if (entering(tcp))
			return 0;

		tprints(", ");
		btrfs_print_balance(tcp, arg, true);
		break;

	case BTRFS_IOC_DEFRAG_RANGE: { /* W */
		struct btrfs_ioctl_defrag_range_args args;

		tprints(", ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{start=%" PRIu64 ", len=", (uint64_t)args.start);

		tprintf("%" PRIu64, (uint64_t) args.len);
		if (args.len == UINT64_MAX)
			tprints(" /* UINT64_MAX */");

		tprints(", flags=");
		printflags64(btrfs_defrag_flags, args.flags,
			     "BTRFS_DEFRAG_RANGE_???");
		tprintf(", extent_thresh=%u, compress_type=",
			args.extent_thresh);
		printxval(btrfs_compress_types, args.compress_type,
			  "BTRFS_COMPRESS_???");
		tprints("}");
		break;
	}

	case BTRFS_IOC_DEV_INFO: { /* RW */
		struct btrfs_ioctl_dev_info_args args;
		char uuid[UUID_STRING_SIZE+1];
		int valid;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;
		tprints("{");

		valid = btrfs_unparse_uuid(args.uuid, uuid);
		if (entering(tcp)) {
			tprintf("devid=%" PRI__u64, args.devid);
			if (valid)
				tprintf(", uuid=%s", uuid);
			tprints("}");
			return 0;
		}
		if (valid)
			tprintf("uuid=%s, ", uuid);
		tprintf("bytes_used=%" PRI__u64
			", total_bytes=%" PRI__u64 ", path=",
			args.bytes_used, args.total_bytes);
		print_quoted_string((const char *)args.path, sizeof(args.path),
				    QUOTE_0_TERMINATED);
		tprints("}");
		break;
	}

	case BTRFS_IOC_DEV_REPLACE: { /* RW */
		struct_btrfs_ioctl_dev_replace_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		if (entering(tcp)) {
			tprints("{cmd=");
			printxval64(btrfs_dev_replace_cmds, args.cmd,
				    "BTRFS_IOCTL_DEV_REPLACE_CMD_???");
			if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_START) {
				const char *str;
				tprintf(", start={srcdevid=%" PRIu64
				   ", cont_reading_from_srcdev_mode=%" PRIu64
				   ", srcdev_name=",
				   (uint64_t) args.start.srcdevid,
				   (uint64_t) args.start.cont_reading_from_srcdev_mode);

				str = (const char*) args.start.srcdev_name;
				print_quoted_string(str,
						sizeof(args.start.srcdev_name),
						QUOTE_0_TERMINATED);
				tprints(", tgtdev_name=");
				str = (const char*) args.start.tgtdev_name;
				print_quoted_string(str,
						sizeof(args.start.tgtdev_name),
						QUOTE_0_TERMINATED);
				tprints("}");

			}
			tprints("}");
			return 0;
		}

		tprints("{result=");
		printxval64(btrfs_dev_replace_results, args.result,
			    "BTRFS_IOCTL_DEV_REPLACE_RESULT_???");
		if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS) {
			char buf[sizeof("HH:MM:SS") + 1];
			time_t time;
			tprints(", ");
			printxval64(btrfs_dev_replace_state,
				   args.status.replace_state,
				   "BTRFS_IOCTL_DEV_REPLACE_STATE_???");
			tprintf(", progress_1000=%" PRIu64 " /* ",
				(uint64_t) args.status.progress_1000);
			if (args.status.progress_1000 <= 1000)
				tprintf("%" PRIu64 ".%.2" PRIu64 "%%",
					(uint64_t) args.status.progress_1000 / 10,
					(uint64_t) args.status.progress_1000 % 10);
			else
				tprints("???");
			tprints(" */ ,");

			time = args.status.time_started;
			strftime(buf, sizeof(buf), "%T",
				 localtime(&time));
			tprintf("time_started=%" PRIu64" /* %s */, ",
				(uint64_t) args.status.time_started, buf);

			time = args.status.time_stopped;
			strftime(buf, sizeof(buf), "%T",
				 localtime(&time));
			tprintf("time_stopped=%" PRIu64" /* %s */, ",
				(uint64_t) args.status.time_stopped, buf);

			tprintf("num_write_errors=%" PRIu64
				", num_uncorrectable_read_errors=%" PRIu64,
				(uint64_t) args.status.num_write_errors,
				(uint64_t) args.status.num_uncorrectable_read_errors);
		}
		tprints("}");
		break;
	}

	case BTRFS_IOC_GET_FEATURES: { /* R */
		struct btrfs_ioctl_feature_flags flags;

		if (entering(tcp))
			return 0;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &flags))
			break;

		btrfs_print_features(&flags);
		break;
	}

	case BTRFS_IOC_SET_FEATURES: { /* W */
		struct btrfs_ioctl_feature_flags flarg[2];

		tprints(", ");

		if (umove_or_printaddr(tcp, arg, &flarg))
			break;

		tprints("[");
		btrfs_print_features(&flarg[0]);
		tprints(", ");
		btrfs_print_features(&flarg[1]);
		tprints("]");
		break;
	}

	case BTRFS_IOC_GET_SUPPORTED_FEATURES: { /* R */
		struct btrfs_ioctl_feature_flags flarg[3];

		if (entering(tcp))
			return 0;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &flarg))
			break;

		tprints("[ /* supported */ ");
		btrfs_print_features(&flarg[0]);

		tprints(", /* safe to set */ ");
		btrfs_print_features(&flarg[1]);

		tprints(", /* safe to clear */ ");
		btrfs_print_features(&flarg[2]);
		tprints("]");

		break;
	}

	case BTRFS_IOC_FS_INFO: { /* R */
		struct btrfs_ioctl_fs_info_args args;
		char uuid[UUID_STRING_SIZE+1];
		uint32_t nodesize, sectorsize, clone_alignment;
#ifndef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
		__u32 *reserved32;
#endif

		if (entering(tcp))
			return 0;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

#ifdef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
		nodesize = args.nodesize,
		sectorsize = args.sectorsize,
		clone_alignment = args.clone_alignment;
#else
		reserved32 = (__u32 *) (void *) args.reserved;
		nodesize = reserved32[0];
		sectorsize = reserved32[1];
		clone_alignment = reserved32[2];
#endif
		btrfs_unparse_uuid(args.fsid, uuid);

		tprints("{");
		tprintf("max_id=%" PRI__u64 ", num_devices=%" PRI__u64
			", fsid=%s, nodesize=%u, sectorsize=%u"
			", clone_alignment=%u",
			args.max_id, args.num_devices, uuid,
			nodesize, sectorsize, clone_alignment);
		tprints("}");
		break;
	}

	case BTRFS_IOC_GET_DEV_STATS: { /* RW */
		struct btrfs_ioctl_get_dev_stats args;
		uint64_t i;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{");

		if (entering(tcp))
			tprintf("devid=%" PRI__u64 ", ", args.devid);

		tprintf("nr_items=%" PRI__u64 ", flags=", args.nr_items);
		printflags64(btrfs_dev_stats_flags, args.flags,
			     "BTRFS_DEV_STATS_???");

		if (entering(tcp)) {
			tprints("}");
			return 0;
		}

		/*
		 * The structure has a 1k limit; Let's make sure we don't
		 * go off into the middle of nowhere with a bad nr_items
		 * value.
		 */
		tprints(", [");
		for (i = 0; i < args.nr_items; i++) {
			if (i)
				tprints(", ");
			if (i >= ARRAY_SIZE(args.values)) {
				tprints("...");
				break;
			}
			const char *name = xlookup(btrfs_dev_stats_values, i);
			if (name)
				tprintf("/* %s */ ", name);
			tprintf("%" PRI__u64, args.values[i]);
		}
		tprints("]}");
		break;
	}

	case BTRFS_IOC_INO_LOOKUP: { /* RW */
		struct btrfs_ioctl_ino_lookup_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		if (entering(tcp)) {
			/* Use subvolume id of the containing root */
			if (args.treeid == 0)
				set_tcb_priv_ulong(tcp, 1);

			tprints("{treeid=");
			btrfs_print_objectid(args.treeid);
			tprints(", objectid=");
			btrfs_print_objectid(args.objectid);
			tprints("}");
			return 0;
		}

		tprints("{");
		if (get_tcb_priv_ulong(tcp)) {
			tprints("treeid=");
			btrfs_print_objectid(args.treeid);
			tprints(", ");
		}

		tprints("name=");
		print_quoted_string(args.name, sizeof(args.name),
				    QUOTE_0_TERMINATED);
		tprints("}");
		break;
	}

	case BTRFS_IOC_INO_PATHS: { /* RW */
		struct btrfs_ioctl_ino_path_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{");

		if (entering(tcp)) {
			tprintf("inum=%" PRI__u64 ", size=%" PRI__u64,
				args.inum, args.size);
			tprintf(", fspath=0x%" PRI__x64 "}", args.fspath);
			return 0;
		}

		tprints("fspath=");
		btrfs_print_ino_path_container(tcp, args.fspath);

		tprints("}");
		break;
	}

	case BTRFS_IOC_LOGICAL_INO: { /* RW */
		struct btrfs_ioctl_logical_ino_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{");

		if (entering(tcp)) {
			tprintf("logical=%" PRI__u64 ", size=%" PRI__u64,
				args.logical, args.size);
			tprintf(", inodes=0x%" PRI__x64 "}", args.inodes);
			return 0;
		}

		tprints("inodes=");
		btrfs_print_logical_ino_container(tcp, args.inodes);

		tprints("}");
		break;
	}

	case BTRFS_IOC_QGROUP_ASSIGN: { /* W */
		struct btrfs_ioctl_qgroup_assign_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{assign=%" PRI__u64 ", src=%" PRI__u64
			", dst=%" PRI__u64 "}",
			args.assign, args.src, args.dst);
		break;
	}

	case BTRFS_IOC_QGROUP_CREATE: { /* W */
		struct btrfs_ioctl_qgroup_create_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{create=%" PRI__u64 ", qgroupid=%" PRI__u64 "}",
			args.create, args.qgroupid);
		break;
	}

	case BTRFS_IOC_QGROUP_LIMIT: { /* R */
		struct btrfs_ioctl_qgroup_limit_args args;

		if (entering(tcp))
			return 0;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{qgroupid=%" PRI__u64 ", lim=", args.qgroupid);
		btrfs_print_qgroup_limit(&args.lim);
		tprints("}");
		break;
	}

	case BTRFS_IOC_QUOTA_CTL: { /* W */
		struct btrfs_ioctl_quota_ctl_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		printxval64(btrfs_qgroup_ctl_cmds, args.cmd,
			    "BTRFS_QUOTA_CTL_???");
		tprints("}");

		break;
	}

	case BTRFS_IOC_QUOTA_RESCAN: { /* W */
		struct btrfs_ioctl_quota_rescan_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{flags=%" PRIu64 "}", (uint64_t) args.flags);
		break;
	}

	case BTRFS_IOC_QUOTA_RESCAN_STATUS: { /* R */
		struct btrfs_ioctl_quota_rescan_args args;

		if (entering(tcp))
			return 0;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprintf("{flags=%" PRIu64 ", progress=", (uint64_t) args.flags);
		btrfs_print_objectid(args.progress);
		tprints("}");
		break;
	}

	case BTRFS_IOC_SET_RECEIVED_SUBVOL: { /* RW */
		struct_btrfs_ioctl_received_subvol_args args;
		char uuid[UUID_STRING_SIZE+1];

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		if (entering(tcp)) {
			btrfs_unparse_uuid((unsigned char *)args.uuid, uuid);
			tprintf("{uuid=%s, stransid=%" PRIu64
				", stime=%" PRIu64 ".%u, flags=%" PRIu64
				"}", uuid, (uint64_t) args.stransid,
				(uint64_t) args.stime.sec, args.stime.nsec,
				(uint64_t) args.flags);
			return 0;
		}
		tprintf("{rtransid=%" PRIu64 ", rtime=%" PRIu64 ".%u}",
			(uint64_t) args.rtransid, (uint64_t) args.rtime.sec,
			args.rtime.nsec);
		break;
	}

	case BTRFS_IOC_SCRUB: /* RW */
	case BTRFS_IOC_SCRUB_PROGRESS: { /* RW */
		struct btrfs_ioctl_scrub_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		if (entering(tcp)) {
			tprintf("{devid=%" PRI__u64, args.devid);
			if (code == BTRFS_IOC_SCRUB) {
				tprintf(", start=%" PRI__u64 ", end=",
					args.start);
				tprintf("%" PRI__u64, args.end);
				if (args.end == UINT64_MAX)
					tprints(" /* UINT64_MAX */");
				tprints(", flags=");
				printflags64(btrfs_scrub_flags, args.flags,
					     "BTRFS_SCRUB_???");
			}
			tprints("}");
			return 0;
		}
		tprintf("{data_extents_scrubbed=%" PRI__u64
			", tree_extents_scrubbed=%" PRI__u64
			", data_bytes_scrubbed=%" PRI__u64
			", tree_bytes_scrubbed=%" PRI__u64
			", read_errors=%" PRI__u64
			", csum_errors=%" PRI__u64
			", verify_errors=%" PRI__u64
			", no_csum=%" PRI__u64
			", csum_discards=%" PRI__u64
			", super_errors=%" PRI__u64
			", malloc_errors=%" PRI__u64
			", uncorrectable_errors=%" PRI__u64
			", corrected_errors=%" PRI__u64
			", last_physical=%" PRI__u64
			", unverified_errors=%" PRI__u64 "}",
			args.progress.data_extents_scrubbed,
			args.progress.tree_extents_scrubbed,
			args.progress.data_bytes_scrubbed,
			args.progress.tree_bytes_scrubbed,
			args.progress.read_errors,
			args.progress.csum_errors,
			args.progress.verify_errors,
			args.progress.no_csum,
			args.progress.csum_discards,
			args.progress.super_errors,
			args.progress.malloc_errors,
			args.progress.uncorrectable_errors,
			args.progress.corrected_errors,
			args.progress.last_physical,
			args.progress.unverified_errors);
		break;
	}

	case BTRFS_IOC_TREE_SEARCH: { /* RW */
		struct btrfs_ioctl_search_args args;
		uint64_t buf_offset;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		buf_offset = offsetof(struct btrfs_ioctl_search_args, buf);
		btrfs_print_tree_search(tcp, &args.key, arg + buf_offset,
					sizeof(args.buf), false);
		if (entering(tcp))
			return 0;
		break;
	}

	case BTRFS_IOC_TREE_SEARCH_V2: { /* RW */
		struct btrfs_ioctl_search_args_v2 args;
		uint64_t buf_offset;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp)) {
			if (tcp->u_error == EOVERFLOW) {
				tprints(" => ");
				tcp->u_error = 0;
				if (!umove_or_printaddr(tcp, arg, &args))
					tprintf("{buf_size=%" PRIu64 "}",
						(uint64_t)args.buf_size);
				tcp->u_error = EOVERFLOW;
			}
			break;
		} else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		buf_offset = offsetof(struct btrfs_ioctl_search_args_v2, buf);
		btrfs_print_tree_search(tcp, &args.key, arg + buf_offset,
					args.buf_size, true);
		if (entering(tcp))
			return 0;
		break;
	}

	case BTRFS_IOC_SEND: { /* W */
		struct_btrfs_ioctl_send_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{send_fd=");
		printfd(tcp, args.send_fd);
		tprintf(", clone_sources_count=%" PRIu64 ", clone_sources=",
			(uint64_t) args.clone_sources_count);

		if (abbrev(tcp))
			tprints("...");
		else {
			uint64_t record;
			print_array(tcp, (unsigned long) args.clone_sources,
				    args.clone_sources_count,
				    &record, sizeof(record),
				    umoven_or_printaddr,
				    print_objectid_callback, 0);
		}
		tprints(", parent_root=");
		btrfs_print_objectid(args.parent_root);
		tprints(", flags=");
		printflags64(btrfs_send_flags, args.flags,
			     "BTRFS_SEND_FLAGS_???");
		tprints("}");
		break;
	}

	case BTRFS_IOC_SPACE_INFO: { /* RW */
		struct btrfs_ioctl_space_args args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{");
		if (entering(tcp)) {
			tprintf("space_slots=%" PRI__u64 "}", args.space_slots);
			return 0;
		}

		tprintf("total_spaces=%" PRI__u64, args.total_spaces);

		if (args.space_slots == 0 && args.total_spaces) {
			tprints("}");
			break;
		}

		tprints(", spaces=");

		if (abbrev(tcp))
			tprints("...");
		else {
			struct btrfs_ioctl_space_info info;
			print_array(tcp, arg + offsetof(typeof(args), spaces),
				    args.total_spaces,
				    &info, sizeof(info), umoven_or_printaddr,
				    print_btrfs_ioctl_space_info, 0);
		}
		tprints("}");
		break;
	}

	case BTRFS_IOC_SNAP_CREATE:
	case BTRFS_IOC_RESIZE:
	case BTRFS_IOC_SCAN_DEV:
	case BTRFS_IOC_ADD_DEV:
	case BTRFS_IOC_RM_DEV:
	case BTRFS_IOC_SUBVOL_CREATE:
	case BTRFS_IOC_SNAP_DESTROY:
	case BTRFS_IOC_DEVICES_READY: { /* W */
		struct btrfs_ioctl_vol_args args;

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &args))
			break;

		tprints("{fd=");
		printfd(tcp, args.fd);
		tprints(", name=");
		print_quoted_string(args.name, sizeof(args.name),
				    QUOTE_0_TERMINATED);
		tprints("}");
		break;
	}

	case BTRFS_IOC_SNAP_CREATE_V2:
	case BTRFS_IOC_SUBVOL_CREATE_V2: { /* code is W, but is actually RW */
		struct btrfs_ioctl_vol_args_v2 args;

		if (entering(tcp))
			tprints(", ");
		else if (syserror(tcp))
			break;
		else
			tprints(" => ");

		if (umove_or_printaddr(tcp, arg, &args))
			break;

		if (entering(tcp)) {
			tprints("{fd=");
			printfd(tcp, args.fd);
			tprints(", flags=");
			printflags64(btrfs_snap_flags_v2, args.flags,
				     "BTRFS_SUBVOL_???");
			if (args.flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
				tprintf(", size=%" PRI__u64 ", qgroup_inherit=",
					args.size);

				btrfs_print_qgroup_inherit(tcp,
					(unsigned long)args.qgroup_inherit);
			}
			tprintf(", name=");
			print_quoted_string(args.name, sizeof(args.name),
					    QUOTE_0_TERMINATED);
			tprints("}");
			return 0;
		}
		tprintf("{transid=%" PRI__u64 "}", args.transid);
		break;
	}

	case BTRFS_IOC_GET_FSLABEL: /* R */
		if (entering(tcp))
			return 0;
		/* fall through */
	case BTRFS_IOC_SET_FSLABEL: { /* W */
		char label[BTRFS_LABEL_SIZE];

		tprints(", ");
		if (umove_or_printaddr(tcp, arg, &label))
			break;
		print_quoted_string(label, sizeof(label), QUOTE_0_TERMINATED);
		break;
	}

	case BTRFS_IOC_CLONE:			/* FICLONE */
	case BTRFS_IOC_CLONE_RANGE:		/* FICLONERANGE */
#ifdef BTRFS_IOC_FILE_EXTENT_SAME
	case BTRFS_IOC_FILE_EXTENT_SAME:	/* FIDEDUPERANGE */
#endif
		/*
		 * FICLONE, FICLONERANGE, and FIDEDUPERANGE started out as
		 * btrfs ioctls and the code was kept for the generic
		 * implementations.  We use the BTRFS_* names here because
		 * they will be available on older systems.
		 */
		return file_ioctl(tcp, code, arg);

	default:
		return RVAL_DECODED;
	};
	return RVAL_DECODED | 1;
}
Exemplo n.º 3
0
MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp,
		   const unsigned int code, const kernel_ulong_t arg)
{
	switch (code) {
	case MEMERASE:
	case MEMLOCK:
	case MEMUNLOCK:
	case MEMISLOCKED:
		decode_erase_info_user(tcp, arg);
		break;

	case MEMERASE64:
		decode_erase_info_user64(tcp, arg);
		break;

	case MEMWRITEOOB:
	case MEMREADOOB:
		decode_mtd_oob_buf(tcp, arg);
		break;

	case MEMWRITEOOB64:
	case MEMREADOOB64:
		decode_mtd_oob_buf64(tcp, arg);
		break;

	case MEMWRITE:
		decode_mtd_write_req(tcp, arg);
		break;

	case OTPGETREGIONINFO:
		if (entering(tcp))
			return 0;
		/* fall through */
	case OTPLOCK:
		decode_otp_info(tcp, arg);
		break;

	case OTPSELECT:
		decode_otp_select(tcp, arg);
		break;

	case MTDFILEMODE:
		tprints(", ");
		printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
		break;

	case MEMGETBADBLOCK:
	case MEMSETBADBLOCK:
		tprints(", ");
		printnum_int64(tcp, arg, "%" PRIu64);
		break;

	case MEMGETINFO:
		if (entering(tcp))
			return 0;
		decode_mtd_info_user(tcp, arg);
		break;

	case MEMGETOOBSEL:
		if (entering(tcp))
			return 0;
		decode_nand_oobinfo(tcp, arg);
		break;

	case ECCGETLAYOUT:
		if (entering(tcp))
			return 0;
		decode_nand_ecclayout_user(tcp, arg);
		break;

	case ECCGETSTATS:
		if (entering(tcp))
			return 0;
		decode_mtd_ecc_stats(tcp, arg);
		break;

	case OTPGETREGIONCOUNT:
		if (entering(tcp))
			return 0;
		tprints(", ");
		printnum_int(tcp, arg, "%u");
		break;

	case MEMGETREGIONCOUNT:
		if (entering(tcp))
			return 0;
		tprints(", ");
		printnum_int(tcp, arg, "%d");
		break;

	case MEMGETREGIONINFO:
		if (entering(tcp)) {
			struct region_info_user rinfo;

			tprints(", ");
			if (umove_or_printaddr(tcp, arg, &rinfo))
				break;
			tprintf("{regionindex=%#x", rinfo.regionindex);
			return 0;
		} else {
			struct region_info_user rinfo;

			if (!syserror(tcp) && !umove(tcp, arg, &rinfo))
				tprintf(", offset=%#x"
					", erasesize=%#x"
					", numblocks=%#x}",
					rinfo.offset,
					rinfo.erasesize,
					rinfo.numblocks);
			tprints("}");
			break;
		}

	default:
		return RVAL_DECODED;
	}

	return RVAL_IOCTL_DECODED;
}