1/*
2 * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com>
3 * Copyright (c) 2016-2017 The strace developers.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "defs.h"
30
31#ifdef HAVE_LINUX_BTRFS_H
32
33#include DEF_MPERS_TYPE(struct_btrfs_ioctl_dev_replace_args)
34#include DEF_MPERS_TYPE(struct_btrfs_ioctl_send_args)
35#include DEF_MPERS_TYPE(struct_btrfs_ioctl_received_subvol_args)
36#include DEF_MPERS_TYPE(struct_btrfs_ioctl_vol_args_v2)
37
38# include <linux/btrfs.h>
39
40typedef struct btrfs_ioctl_dev_replace_args
41	struct_btrfs_ioctl_dev_replace_args;
42typedef struct btrfs_ioctl_send_args
43	struct_btrfs_ioctl_send_args;
44typedef struct btrfs_ioctl_received_subvol_args
45	struct_btrfs_ioctl_received_subvol_args;
46typedef struct btrfs_ioctl_vol_args_v2
47	struct_btrfs_ioctl_vol_args_v2;
48
49#endif /* HAVE_LINUX_BTRFS_H */
50
51#include MPERS_DEFS
52
53#ifdef HAVE_LINUX_BTRFS_H
54
55#include <linux/fs.h>
56
57/*
58 * Prior to Linux 3.12, the BTRFS_IOC_DEFAULT_SUBVOL used u64 in
59 * its definition, which isn't exported by the kernel.
60 */
61typedef __u64 u64;
62
63#ifndef HAVE_STRUCT_BTRFS_IOCTL_FEATURE_FLAGS_COMPAT_FLAGS
64struct btrfs_ioctl_feature_flags {
65	uint64_t compat_flags;
66	uint64_t compat_ro_flags;
67	uint64_t incompat_flags;
68};
69#endif
70
71#ifndef HAVE_STRUCT_BTRFS_IOCTL_DEFRAG_RANGE_ARGS_START
72struct btrfs_ioctl_defrag_range_args {
73	uint64_t start;
74	uint64_t len;
75	uint64_t flags;
76	uint32_t extent_thresh;
77	uint32_t compress_type;
78	uint32_t unused[4];
79};
80#endif
81
82#ifndef BTRFS_LABEL_SIZE
83# define BTRFS_LABEL_SIZE 256
84#endif
85
86#ifndef BTRFS_FIRST_FREE_OBJECTID
87# define BTRFS_FIRST_FREE_OBJECTID 256ULL
88#endif
89
90#ifndef BTRFS_IOC_QUOTA_RESCAN
91struct btrfs_ioctl_quota_rescan_args {
92	uint64_t flags, progress, reserved[6];
93};
94# define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \
95					struct btrfs_ioctl_quota_rescan_args)
96# define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \
97					struct btrfs_ioctl_quota_rescan_args)
98#endif
99
100#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
101# define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
102#endif
103
104#ifndef BTRFS_IOC_GET_FEATURES
105# define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
106					struct btrfs_ioctl_feature_flags)
107# define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \
108					struct btrfs_ioctl_feature_flags[2])
109# define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
110					struct btrfs_ioctl_feature_flags[3])
111#endif
112
113#ifndef BTRFS_IOC_TREE_SEARCH_V2
114# define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \
115					struct btrfs_ioctl_search_args_v2)
116struct btrfs_ioctl_search_args_v2 {
117	struct btrfs_ioctl_search_key key; /* in/out - search parameters */
118	uint64_t buf_size;		   /* in - size of buffer
119					    * out - on EOVERFLOW: needed size
120					    *       to store item */
121	uint64_t buf[0];		   /* out - found items */
122};
123#endif
124
125#include "xlat/btrfs_balance_args.h"
126#include "xlat/btrfs_balance_ctl_cmds.h"
127#include "xlat/btrfs_balance_flags.h"
128#include "xlat/btrfs_balance_state.h"
129#include "xlat/btrfs_compress_types.h"
130#include "xlat/btrfs_defrag_flags.h"
131#include "xlat/btrfs_dev_replace_cmds.h"
132#include "xlat/btrfs_dev_replace_results.h"
133#include "xlat/btrfs_dev_replace_state.h"
134#include "xlat/btrfs_dev_stats_flags.h"
135#include "xlat/btrfs_dev_stats_values.h"
136#include "xlat/btrfs_features_compat.h"
137#include "xlat/btrfs_features_compat_ro.h"
138#include "xlat/btrfs_features_incompat.h"
139#include "xlat/btrfs_key_types.h"
140#include "xlat/btrfs_qgroup_ctl_cmds.h"
141#include "xlat/btrfs_qgroup_inherit_flags.h"
142#include "xlat/btrfs_qgroup_limit_flags.h"
143#include "xlat/btrfs_qgroup_status_flags.h"
144#include "xlat/btrfs_scrub_flags.h"
145#include "xlat/btrfs_send_flags.h"
146#include "xlat/btrfs_snap_flags_v2.h"
147#include "xlat/btrfs_space_info_flags.h"
148#include "xlat/btrfs_tree_objectids.h"
149
150static inline char
151prnibble(char v)
152{
153	if (v >= 10)
154		return 'a' + (v - 10);
155	return '0' + v;
156}
157
158/* 8-4-4-4-12 = 36 characters */
159#define UUID_STRING_SIZE 36
160
161/* Formats uuid, returns 0 if it's all zeroes */
162static int
163btrfs_unparse_uuid(unsigned char *uuid, char *out)
164{
165	int i;
166	int ret = 0;
167	for (i = 0; i < BTRFS_UUID_SIZE; i++) {
168		if (i == 4 || i == 6 || i == 8 || i == 10)
169			*out++ = '-';
170		*out++ = prnibble(uuid[i] >> 4);
171		*out++ = prnibble(uuid[i] & 0xf);
172		if (uuid[i])
173			ret = 1;
174	}
175	*out = '\0';
176	return ret;
177}
178
179static void
180print_u64(const char *name, uint64_t value)
181{
182	tprintf(", %s=%" PRIu64, name, value);
183	if (value == UINT64_MAX)
184		tprints_comment("UINT64_MAX");
185}
186
187#define print_member_u64(obj, name) print_u64(#name, obj->name)
188
189static void
190btrfs_print_balance_args(const char *name, const struct btrfs_balance_args *bba)
191{
192	tprintf(", %s={profiles=", name);
193	printflags64(btrfs_space_info_flags, bba->profiles,
194		     "BTRFS_BLOCK_GROUP_???");
195	print_member_u64(bba, usage);
196	print_member_u64(bba, devid);
197	print_member_u64(bba, pstart);
198	print_member_u64(bba, pend);
199	print_member_u64(bba, vstart);
200	print_member_u64(bba, vend);
201	print_member_u64(bba, target);
202	tprints(", flags=");
203	printflags64(btrfs_balance_args, bba->flags, "BTRFS_BALANCE_ARGS_???");
204	tprints("}");
205}
206
207static void
208btrfs_print_balance(struct tcb *const tcp, const kernel_ulong_t arg, bool out)
209{
210	struct btrfs_ioctl_balance_args balance_args;
211
212	if (umove_or_printaddr(tcp, arg, &balance_args))
213		return;
214
215	tprints("{flags=");
216	printflags64(btrfs_balance_flags, balance_args.flags,
217		     "BTRFS_BALANCE_???");
218	if (out) {
219		tprints(", state=");
220		printflags64(btrfs_balance_state, balance_args.state,
221			     "BTRFS_BALANCE_STATE_???");
222	}
223
224	if (balance_args.flags & BTRFS_BALANCE_DATA)
225		btrfs_print_balance_args("data", &balance_args.data);
226	if (balance_args.flags & BTRFS_BALANCE_METADATA)
227		btrfs_print_balance_args("meta", &balance_args.meta);
228	if (balance_args.flags & BTRFS_BALANCE_SYSTEM)
229		btrfs_print_balance_args("sys", &balance_args.sys);
230	tprints("}");
231}
232
233static void
234btrfs_print_features(const struct btrfs_ioctl_feature_flags *flags)
235{
236	tprints("{compat_flags=");
237	printflags64(btrfs_features_compat, flags->compat_flags,
238		     "BTRFS_FEATURE_COMPAT_???");
239
240	tprints(", compat_ro_flags=");
241	printflags64(btrfs_features_compat_ro, flags->compat_ro_flags,
242		     "BTRFS_FEATURE_COMPAT_RO_???");
243
244	tprints(", incompat_flags=");
245	printflags64(btrfs_features_incompat, flags->incompat_flags,
246		     "BTRFS_FEATURE_INCOMPAT_???");
247	tprints("}");
248}
249
250static void
251btrfs_print_qgroup_limit(const struct btrfs_qgroup_limit *lim)
252{
253	tprints("{flags=");
254	printflags64(btrfs_qgroup_limit_flags, lim->flags,
255		     "BTRFS_QGROUP_LIMIT_???");
256	tprintf(", max_rfer=%" PRI__u64 ", max_excl=%" PRI__u64
257		", rsv_rfer=%" PRI__u64 ", rsv_excl=%" PRI__u64 "}",
258		lim->max_rfer, lim->max_excl,
259		lim->rsv_rfer, lim->rsv_excl);
260}
261
262static void
263btrfs_print_key_type(uint32_t type)
264{
265	tprintf("%u", type);
266	tprints_comment(xlookup(btrfs_key_types, type));
267}
268
269static void
270btrfs_print_objectid(uint64_t objectid)
271{
272	tprintf("%" PRIu64, objectid);
273	tprints_comment(xlookup(btrfs_tree_objectids, objectid));
274}
275
276static void
277btrfs_print_data_container_header(const struct btrfs_data_container *container)
278{
279	tprintf("{bytes_left=%u, bytes_missing=%u"
280		", elem_cnt=%u, elem_missed=%u, val=",
281		container->bytes_left, container->bytes_missing,
282		container->elem_cnt, container->elem_missed);
283}
284
285static void
286btrfs_print_data_container_footer(void)
287{
288	tprints("}");
289}
290
291static bool
292print_btrfs_data_container_logical_ino(struct tcb *tcp, void *elem_buf,
293				       size_t elem_size, void *data)
294{
295	const uint64_t *const record = elem_buf;
296
297	tprintf("{inum=%" PRIu64 ", offset=%" PRIu64 ", root=%" PRIu64 "}",
298		record[0], record[1], record[2]);
299
300	return true;
301}
302
303static void
304btrfs_print_logical_ino_container(struct tcb *tcp,
305				  const uint64_t inodes_addr)
306{
307	struct btrfs_data_container container;
308
309	if (umove_or_printaddr(tcp, inodes_addr, &container))
310		return;
311
312	btrfs_print_data_container_header(&container);
313
314	if (abbrev(tcp)) {
315		tprints("...");
316	} else {
317		const uint64_t val_addr =
318			inodes_addr + offsetof(typeof(container), val);
319		uint64_t record[3];
320		print_array(tcp, val_addr, container.elem_cnt / 3,
321			    record, sizeof(record),
322			    umoven_or_printaddr,
323			    print_btrfs_data_container_logical_ino, 0);
324	}
325
326	btrfs_print_data_container_footer();
327}
328
329static bool
330print_btrfs_data_container_ino_path(struct tcb *tcp, void *elem_buf,
331				       size_t elem_size, void *data)
332{
333	const uint64_t *const offset = elem_buf;
334	const uint64_t *const val_addr = data;
335
336	printpath(tcp, *val_addr + *offset);
337
338	return true;
339}
340
341static void
342btrfs_print_ino_path_container(struct tcb *tcp,
343			       const uint64_t fspath_addr)
344{
345	struct btrfs_data_container container;
346
347	if (umove_or_printaddr(tcp, fspath_addr, &container))
348		return;
349
350	btrfs_print_data_container_header(&container);
351
352	if (abbrev(tcp)) {
353		tprints("...");
354	} else {
355		uint64_t val_addr =
356			fspath_addr + offsetof(typeof(container), val);
357		uint64_t offset;
358		print_array(tcp, val_addr, container.elem_cnt,
359			    &offset, sizeof(offset),
360			    umoven_or_printaddr,
361			    print_btrfs_data_container_ino_path, &val_addr);
362	}
363
364	btrfs_print_data_container_footer();
365}
366
367static bool
368print_uint64(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
369{
370	tprintf("%" PRIu64, *(uint64_t *) elem_buf);
371
372	return true;
373}
374
375static void
376btrfs_print_qgroup_inherit(struct tcb *const tcp, const kernel_ulong_t qgi_addr)
377{
378	struct btrfs_qgroup_inherit inherit;
379
380	if (umove_or_printaddr(tcp, qgi_addr, &inherit))
381		return;
382
383	tprints("{flags=");
384	printflags64(btrfs_qgroup_inherit_flags, inherit.flags,
385		     "BTRFS_QGROUP_INHERIT_???");
386	tprintf(", num_qgroups=%" PRI__u64 ", num_ref_copies=%" PRI__u64
387		", num_excl_copies=%" PRI__u64 ", lim=",
388		inherit.num_qgroups, inherit.num_ref_copies,
389		inherit.num_excl_copies);
390
391	btrfs_print_qgroup_limit(&inherit.lim);
392
393	tprints(", qgroups=");
394
395	if (abbrev(tcp)) {
396		tprints("...");
397	} else {
398		uint64_t record;
399		print_array(tcp, qgi_addr + offsetof(typeof(inherit), qgroups),
400			    inherit.num_qgroups, &record, sizeof(record),
401			    umoven_or_printaddr, print_uint64, 0);
402	}
403	tprints("}");
404}
405
406static void
407print_key_value_internal(struct tcb *tcp, const char *name, uint64_t value)
408{
409	if (value) {
410		tprintf(", %s=%" PRIu64, name, value);
411		if (value == UINT64_MAX)
412			tprints_comment("UINT64_MAX");
413	}
414}
415#define print_key_value(tcp, key, name)					\
416	print_key_value_internal((tcp), #name, (key)->name)
417
418static void
419btrfs_print_tree_search(struct tcb *tcp, struct btrfs_ioctl_search_key *key,
420			uint64_t buf_addr, uint64_t buf_size, bool print_size)
421{
422	if (entering(tcp)) {
423		tprints("{key={tree_id=");
424		btrfs_print_objectid(key->tree_id);
425
426		if (key->min_objectid != BTRFS_FIRST_FREE_OBJECTID ||
427		    !abbrev(tcp)) {
428			tprints(", min_objectid=");
429			btrfs_print_objectid(key->min_objectid);
430		}
431
432		if (key->max_objectid != BTRFS_LAST_FREE_OBJECTID ||
433		    !abbrev(tcp)) {
434			tprints(", max_objectid=");
435			btrfs_print_objectid(key->max_objectid);
436		}
437
438		print_key_value(tcp, key, min_offset);
439		print_key_value(tcp, key, max_offset);
440		print_key_value(tcp, key, min_transid);
441		print_key_value(tcp, key, max_transid);
442
443		tprints(", min_type=");
444		btrfs_print_key_type(key->min_type);
445		tprints(", max_type=");
446		btrfs_print_key_type(key->max_type);
447		tprintf(", nr_items=%u}", key->nr_items);
448		if (print_size)
449			tprintf(", buf_size=%" PRIu64, buf_size);
450		tprints("}");
451	} else {
452		tprintf("{key={nr_items=%u}", key->nr_items);
453		if (print_size)
454			tprintf(", buf_size=%" PRIu64, buf_size);
455		tprints(", buf=");
456		if (abbrev(tcp))
457			tprints("...");
458		else {
459			uint64_t i;
460			uint64_t off = 0;
461			tprints("[");
462			for (i = 0; i < key->nr_items; i++) {
463				struct btrfs_ioctl_search_header sh;
464				uint64_t addr = buf_addr + off;
465				if (i)
466					tprints(", ");
467				if (i > max_strlen ||
468				    umove(tcp, addr, &sh)) {
469					tprints("...");
470					break;
471				}
472				tprintf("{transid=%" PRI__u64 ", objectid=",
473					sh.transid);
474				btrfs_print_objectid(sh.objectid);
475				tprintf(", offset=%" PRI__u64 ", type=", sh.offset);
476				btrfs_print_key_type(sh.type);
477				tprintf(", len=%u}", sh.len);
478				off += sizeof(sh) + sh.len;
479
480			}
481			tprints("]");
482		}
483		tprints("}");
484	}
485}
486
487static bool
488print_objectid_callback(struct tcb *tcp, void *elem_buf,
489			size_t elem_size, void *data)
490{
491	btrfs_print_objectid(*(uint64_t *) elem_buf);
492
493	return true;
494}
495
496static bool
497print_btrfs_ioctl_space_info(struct tcb *tcp, void *elem_buf,
498			     size_t elem_size, void *data)
499{
500	const struct btrfs_ioctl_space_info *info = elem_buf;
501
502	tprints("{flags=");
503	printflags64(btrfs_space_info_flags, info->flags,
504		     "BTRFS_SPACE_INFO_???");
505	tprintf(", total_bytes=%" PRI__u64 ", used_bytes=%" PRI__u64 "}",
506		info->total_bytes, info->used_bytes);
507
508	return true;
509}
510
511MPERS_PRINTER_DECL(int, btrfs_ioctl,
512		   struct tcb *const tcp, const unsigned int code,
513		   const kernel_ulong_t arg)
514{
515	switch (code) {
516	/* Take no arguments; command only. */
517	case BTRFS_IOC_TRANS_START:
518	case BTRFS_IOC_TRANS_END:
519	case BTRFS_IOC_SYNC:
520	case BTRFS_IOC_SCRUB_CANCEL:
521	case BTRFS_IOC_QUOTA_RESCAN_WAIT:
522	/*
523	 * The codes for these ioctls are based on each accepting a
524	 * vol_args but none of them actually consume an argument.
525	 */
526	case BTRFS_IOC_DEFRAG:
527	case BTRFS_IOC_BALANCE:
528		break;
529
530	/* takes a signed int */
531	case BTRFS_IOC_BALANCE_CTL:
532		tprints(", ");
533		printxval(btrfs_balance_ctl_cmds, arg, "BTRFS_BALANCE_CTL_???");
534		break;
535
536	/* returns a 64 */
537	case BTRFS_IOC_START_SYNC: /* R */
538		if (entering(tcp))
539			return 0;
540	/* fall through */
541	/* takes a u64 */
542	case BTRFS_IOC_DEFAULT_SUBVOL: /* W */
543	case BTRFS_IOC_WAIT_SYNC: /* W */
544		tprints(", ");
545		printnum_int64(tcp, arg, "%" PRIu64);
546		break;
547
548	/* u64 but describe a flags bitfield; we can make that symbolic */
549	case BTRFS_IOC_SUBVOL_GETFLAGS: { /* R */
550		uint64_t flags;
551
552		if (entering(tcp))
553			return 0;
554
555		tprints(", ");
556
557		if (umove_or_printaddr(tcp, arg, &flags))
558			break;
559
560		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
561		break;
562	}
563
564	case BTRFS_IOC_SUBVOL_SETFLAGS: { /* W */
565		uint64_t flags;
566
567		tprints(", ");
568
569		if (umove_or_printaddr(tcp, arg, &flags))
570			break;
571
572		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
573		break;
574	}
575
576	/* More complex types */
577	case BTRFS_IOC_BALANCE_V2: /* RW */
578		if (entering(tcp)) {
579			tprints(", ");
580			btrfs_print_balance(tcp, arg, false);
581			return 0;
582		}
583
584		if (syserror(tcp))
585			break;
586
587		tprints(" => ");
588		btrfs_print_balance(tcp, arg, true);
589		break;
590	case BTRFS_IOC_BALANCE_PROGRESS: /* R */
591		if (entering(tcp))
592			return 0;
593
594		tprints(", ");
595		btrfs_print_balance(tcp, arg, true);
596		break;
597
598	case BTRFS_IOC_DEFRAG_RANGE: { /* W */
599		struct btrfs_ioctl_defrag_range_args args;
600
601		tprints(", ");
602
603		if (umove_or_printaddr(tcp, arg, &args))
604			break;
605
606		tprintf("{start=%" PRIu64 ", len=", (uint64_t)args.start);
607
608		tprintf("%" PRIu64, (uint64_t) args.len);
609		if (args.len == UINT64_MAX)
610			tprints_comment("UINT64_MAX");
611
612		tprints(", flags=");
613		printflags64(btrfs_defrag_flags, args.flags,
614			     "BTRFS_DEFRAG_RANGE_???");
615		tprintf(", extent_thresh=%u, compress_type=",
616			args.extent_thresh);
617		printxval(btrfs_compress_types, args.compress_type,
618			  "BTRFS_COMPRESS_???");
619		tprints("}");
620		break;
621	}
622
623	case BTRFS_IOC_DEV_INFO: { /* RW */
624		struct btrfs_ioctl_dev_info_args args;
625		char uuid[UUID_STRING_SIZE+1];
626		int valid;
627
628		if (entering(tcp))
629			tprints(", ");
630		else if (syserror(tcp))
631			break;
632		else
633			tprints(" => ");
634		if (umove_or_printaddr(tcp, arg, &args))
635			break;
636		tprints("{");
637
638		valid = btrfs_unparse_uuid(args.uuid, uuid);
639		if (entering(tcp)) {
640			tprintf("devid=%" PRI__u64, args.devid);
641			if (valid)
642				tprintf(", uuid=%s", uuid);
643			tprints("}");
644			return 0;
645		}
646		if (valid)
647			tprintf("uuid=%s, ", uuid);
648		tprintf("bytes_used=%" PRI__u64
649			", total_bytes=%" PRI__u64 ", path=",
650			args.bytes_used, args.total_bytes);
651		print_quoted_string((const char *)args.path, sizeof(args.path),
652				    QUOTE_0_TERMINATED);
653		tprints("}");
654		break;
655	}
656
657	case BTRFS_IOC_DEV_REPLACE: { /* RW */
658		struct_btrfs_ioctl_dev_replace_args args;
659
660		if (entering(tcp))
661			tprints(", ");
662		else if (syserror(tcp))
663			break;
664		else
665			tprints(" => ");
666
667		if (umove_or_printaddr(tcp, arg, &args))
668			break;
669
670		if (entering(tcp)) {
671			tprints("{cmd=");
672			printxval64(btrfs_dev_replace_cmds, args.cmd,
673				    "BTRFS_IOCTL_DEV_REPLACE_CMD_???");
674			if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_START) {
675				const char *str;
676				tprintf(", start={srcdevid=%" PRIu64
677				   ", cont_reading_from_srcdev_mode=%" PRIu64
678				   ", srcdev_name=",
679				   (uint64_t) args.start.srcdevid,
680				   (uint64_t) args.start.cont_reading_from_srcdev_mode);
681
682				str = (const char *) args.start.srcdev_name;
683				print_quoted_string(str,
684						sizeof(args.start.srcdev_name),
685						QUOTE_0_TERMINATED);
686				tprints(", tgtdev_name=");
687				str = (const char *) args.start.tgtdev_name;
688				print_quoted_string(str,
689						sizeof(args.start.tgtdev_name),
690						QUOTE_0_TERMINATED);
691				tprints("}");
692
693			}
694			tprints("}");
695			return 0;
696		}
697
698		tprints("{result=");
699		printxval64(btrfs_dev_replace_results, args.result,
700			    "BTRFS_IOCTL_DEV_REPLACE_RESULT_???");
701		if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS) {
702			tprints(", ");
703			printxval64(btrfs_dev_replace_state,
704				   args.status.replace_state,
705				   "BTRFS_IOCTL_DEV_REPLACE_STATE_???");
706			tprintf(", progress_1000=%" PRIu64,
707				(uint64_t) args.status.progress_1000);
708
709			if (args.status.progress_1000 <= 1000)
710				tprintf_comment("%u.%u%%",
711					(unsigned) args.status.progress_1000 / 10,
712					(unsigned) args.status.progress_1000 % 10);
713
714			tprintf(", time_started=%" PRIu64,
715				(uint64_t) args.status.time_started);
716			tprints_comment(sprinttime(args.status.time_started));
717
718			tprintf(", time_stopped=%" PRIu64,
719				(uint64_t) args.status.time_stopped);
720			tprints_comment(sprinttime(args.status.time_stopped));
721
722			tprintf(", num_write_errors=%" PRIu64
723				", num_uncorrectable_read_errors=%" PRIu64,
724				(uint64_t) args.status.num_write_errors,
725				(uint64_t) args.status.num_uncorrectable_read_errors);
726		}
727		tprints("}");
728		break;
729	}
730
731	case BTRFS_IOC_GET_FEATURES: { /* R */
732		struct btrfs_ioctl_feature_flags flags;
733
734		if (entering(tcp))
735			return 0;
736
737		tprints(", ");
738		if (umove_or_printaddr(tcp, arg, &flags))
739			break;
740
741		btrfs_print_features(&flags);
742		break;
743	}
744
745	case BTRFS_IOC_SET_FEATURES: { /* W */
746		struct btrfs_ioctl_feature_flags flarg[2];
747
748		tprints(", ");
749
750		if (umove_or_printaddr(tcp, arg, &flarg))
751			break;
752
753		tprints("[");
754		btrfs_print_features(&flarg[0]);
755		tprints(", ");
756		btrfs_print_features(&flarg[1]);
757		tprints("]");
758		break;
759	}
760
761	case BTRFS_IOC_GET_SUPPORTED_FEATURES: { /* R */
762		struct btrfs_ioctl_feature_flags flarg[3];
763
764		if (entering(tcp))
765			return 0;
766
767		tprints(", ");
768		if (umove_or_printaddr(tcp, arg, &flarg))
769			break;
770
771		tprints("[");
772		btrfs_print_features(&flarg[0]);
773		tprints_comment("supported");
774
775		tprints(", ");
776		btrfs_print_features(&flarg[1]);
777		tprints_comment("safe to set");
778
779		tprints(", ");
780		btrfs_print_features(&flarg[2]);
781		tprints_comment("safe to clear");
782		tprints("]");
783
784		break;
785	}
786
787	case BTRFS_IOC_FS_INFO: { /* R */
788		struct btrfs_ioctl_fs_info_args args;
789		char uuid[UUID_STRING_SIZE+1];
790		uint32_t nodesize, sectorsize, clone_alignment;
791#ifndef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
792		__u32 *reserved32;
793#endif
794
795		if (entering(tcp))
796			return 0;
797
798		tprints(", ");
799		if (umove_or_printaddr(tcp, arg, &args))
800			break;
801
802#ifdef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
803		nodesize = args.nodesize,
804		sectorsize = args.sectorsize,
805		clone_alignment = args.clone_alignment;
806#else
807		reserved32 = (__u32 *) (void *) args.reserved;
808		nodesize = reserved32[0];
809		sectorsize = reserved32[1];
810		clone_alignment = reserved32[2];
811#endif
812		btrfs_unparse_uuid(args.fsid, uuid);
813
814		tprints("{");
815		tprintf("max_id=%" PRI__u64 ", num_devices=%" PRI__u64
816			", fsid=%s, nodesize=%u, sectorsize=%u"
817			", clone_alignment=%u",
818			args.max_id, args.num_devices, uuid,
819			nodesize, sectorsize, clone_alignment);
820		tprints("}");
821		break;
822	}
823
824	case BTRFS_IOC_GET_DEV_STATS: { /* RW */
825		struct btrfs_ioctl_get_dev_stats args;
826		uint64_t i;
827
828		if (entering(tcp))
829			tprints(", ");
830		else if (syserror(tcp))
831			break;
832		else
833			tprints(" => ");
834		if (umove_or_printaddr(tcp, arg, &args))
835			break;
836
837		tprints("{");
838
839		if (entering(tcp))
840			tprintf("devid=%" PRI__u64 ", ", args.devid);
841
842		tprintf("nr_items=%" PRI__u64 ", flags=", args.nr_items);
843		printflags64(btrfs_dev_stats_flags, args.flags,
844			     "BTRFS_DEV_STATS_???");
845
846		if (entering(tcp)) {
847			tprints("}");
848			return 0;
849		}
850
851		/*
852		 * The structure has a 1k limit; Let's make sure we don't
853		 * go off into the middle of nowhere with a bad nr_items
854		 * value.
855		 */
856		tprints(", [");
857		for (i = 0; i < args.nr_items; i++) {
858			if (i)
859				tprints(", ");
860			if (i >= ARRAY_SIZE(args.values)) {
861				tprints("...");
862				break;
863			}
864			tprintf("%" PRI__u64, args.values[i]);
865			tprints_comment(xlookup(btrfs_dev_stats_values, i));
866		}
867		tprints("]}");
868		break;
869	}
870
871	case BTRFS_IOC_INO_LOOKUP: { /* RW */
872		struct btrfs_ioctl_ino_lookup_args args;
873
874		if (entering(tcp))
875			tprints(", ");
876		else if (syserror(tcp))
877			break;
878		else
879			tprints(" => ");
880
881		if (umove_or_printaddr(tcp, arg, &args))
882			break;
883
884		if (entering(tcp)) {
885			/* Use subvolume id of the containing root */
886			if (args.treeid == 0)
887				set_tcb_priv_ulong(tcp, 1);
888
889			tprints("{treeid=");
890			btrfs_print_objectid(args.treeid);
891			tprints(", objectid=");
892			btrfs_print_objectid(args.objectid);
893			tprints("}");
894			return 0;
895		}
896
897		tprints("{");
898		if (get_tcb_priv_ulong(tcp)) {
899			tprints("treeid=");
900			btrfs_print_objectid(args.treeid);
901			tprints(", ");
902		}
903
904		tprints("name=");
905		print_quoted_string(args.name, sizeof(args.name),
906				    QUOTE_0_TERMINATED);
907		tprints("}");
908		break;
909	}
910
911	case BTRFS_IOC_INO_PATHS: { /* RW */
912		struct btrfs_ioctl_ino_path_args args;
913
914		if (entering(tcp))
915			tprints(", ");
916		else if (syserror(tcp))
917			break;
918		else
919			tprints(" => ");
920
921		if (umove_or_printaddr(tcp, arg, &args))
922			break;
923
924		tprints("{");
925
926		if (entering(tcp)) {
927			tprintf("inum=%" PRI__u64 ", size=%" PRI__u64,
928				args.inum, args.size);
929			tprintf(", fspath=0x%" PRI__x64 "}", args.fspath);
930			return 0;
931		}
932
933		tprints("fspath=");
934		btrfs_print_ino_path_container(tcp, args.fspath);
935
936		tprints("}");
937		break;
938	}
939
940	case BTRFS_IOC_LOGICAL_INO: { /* RW */
941		struct btrfs_ioctl_logical_ino_args args;
942
943		if (entering(tcp))
944			tprints(", ");
945		else if (syserror(tcp))
946			break;
947		else
948			tprints(" => ");
949
950		if (umove_or_printaddr(tcp, arg, &args))
951			break;
952
953		tprints("{");
954
955		if (entering(tcp)) {
956			tprintf("logical=%" PRI__u64 ", size=%" PRI__u64,
957				args.logical, args.size);
958			tprintf(", inodes=0x%" PRI__x64 "}", args.inodes);
959			return 0;
960		}
961
962		tprints("inodes=");
963		btrfs_print_logical_ino_container(tcp, args.inodes);
964
965		tprints("}");
966		break;
967	}
968
969	case BTRFS_IOC_QGROUP_ASSIGN: { /* W */
970		struct btrfs_ioctl_qgroup_assign_args args;
971
972		tprints(", ");
973		if (umove_or_printaddr(tcp, arg, &args))
974			break;
975
976		tprintf("{assign=%" PRI__u64 ", src=%" PRI__u64
977			", dst=%" PRI__u64 "}",
978			args.assign, args.src, args.dst);
979		break;
980	}
981
982	case BTRFS_IOC_QGROUP_CREATE: { /* W */
983		struct btrfs_ioctl_qgroup_create_args args;
984
985		tprints(", ");
986		if (umove_or_printaddr(tcp, arg, &args))
987			break;
988
989		tprintf("{create=%" PRI__u64 ", qgroupid=%" PRI__u64 "}",
990			args.create, args.qgroupid);
991		break;
992	}
993
994	case BTRFS_IOC_QGROUP_LIMIT: { /* R */
995		struct btrfs_ioctl_qgroup_limit_args args;
996
997		if (entering(tcp))
998			return 0;
999
1000		tprints(", ");
1001		if (umove_or_printaddr(tcp, arg, &args))
1002			break;
1003
1004		tprintf("{qgroupid=%" PRI__u64 ", lim=", args.qgroupid);
1005		btrfs_print_qgroup_limit(&args.lim);
1006		tprints("}");
1007		break;
1008	}
1009
1010	case BTRFS_IOC_QUOTA_CTL: { /* W */
1011		struct btrfs_ioctl_quota_ctl_args args;
1012
1013		tprints(", ");
1014		if (umove_or_printaddr(tcp, arg, &args))
1015			break;
1016
1017		printxval64(btrfs_qgroup_ctl_cmds, args.cmd,
1018			    "BTRFS_QUOTA_CTL_???");
1019		tprints("}");
1020
1021		break;
1022	}
1023
1024	case BTRFS_IOC_QUOTA_RESCAN: { /* W */
1025		struct btrfs_ioctl_quota_rescan_args args;
1026
1027		tprints(", ");
1028		if (umove_or_printaddr(tcp, arg, &args))
1029			break;
1030
1031		tprintf("{flags=%" PRIu64 "}", (uint64_t) args.flags);
1032		break;
1033	}
1034
1035	case BTRFS_IOC_QUOTA_RESCAN_STATUS: { /* R */
1036		struct btrfs_ioctl_quota_rescan_args args;
1037
1038		if (entering(tcp))
1039			return 0;
1040
1041		tprints(", ");
1042		if (umove_or_printaddr(tcp, arg, &args))
1043			break;
1044
1045		tprintf("{flags=%" PRIu64 ", progress=", (uint64_t) args.flags);
1046		btrfs_print_objectid(args.progress);
1047		tprints("}");
1048		break;
1049	}
1050
1051	case BTRFS_IOC_SET_RECEIVED_SUBVOL: { /* RW */
1052		struct_btrfs_ioctl_received_subvol_args args;
1053		char uuid[UUID_STRING_SIZE+1];
1054
1055		if (entering(tcp))
1056			tprints(", ");
1057		else if (syserror(tcp))
1058			break;
1059		else
1060			tprints(" => ");
1061
1062		if (umove_or_printaddr(tcp, arg, &args))
1063			break;
1064
1065		if (entering(tcp)) {
1066			btrfs_unparse_uuid((unsigned char *)args.uuid, uuid);
1067			tprintf("{uuid=%s, stransid=%" PRIu64
1068				", stime=%" PRIu64 ".%u, flags=%" PRIu64
1069				"}", uuid, (uint64_t) args.stransid,
1070				(uint64_t) args.stime.sec, args.stime.nsec,
1071				(uint64_t) args.flags);
1072			return 0;
1073		}
1074		tprintf("{rtransid=%" PRIu64 ", rtime=%" PRIu64 ".%u}",
1075			(uint64_t) args.rtransid, (uint64_t) args.rtime.sec,
1076			args.rtime.nsec);
1077		break;
1078	}
1079
1080	case BTRFS_IOC_SCRUB: /* RW */
1081	case BTRFS_IOC_SCRUB_PROGRESS: { /* RW */
1082		struct btrfs_ioctl_scrub_args args;
1083
1084		if (entering(tcp))
1085			tprints(", ");
1086		else if (syserror(tcp))
1087			break;
1088		else
1089			tprints(" => ");
1090
1091		if (umove_or_printaddr(tcp, arg, &args))
1092			break;
1093
1094		if (entering(tcp)) {
1095			tprintf("{devid=%" PRI__u64, args.devid);
1096			if (code == BTRFS_IOC_SCRUB) {
1097				tprintf(", start=%" PRI__u64 ", end=",
1098					args.start);
1099				tprintf("%" PRI__u64, args.end);
1100				if (args.end == UINT64_MAX)
1101					tprints_comment("UINT64_MAX");
1102				tprints(", flags=");
1103				printflags64(btrfs_scrub_flags, args.flags,
1104					     "BTRFS_SCRUB_???");
1105			}
1106			tprints("}");
1107			return 0;
1108		}
1109		tprintf("{data_extents_scrubbed=%" PRI__u64
1110			", tree_extents_scrubbed=%" PRI__u64
1111			", data_bytes_scrubbed=%" PRI__u64
1112			", tree_bytes_scrubbed=%" PRI__u64
1113			", read_errors=%" PRI__u64
1114			", csum_errors=%" PRI__u64
1115			", verify_errors=%" PRI__u64
1116			", no_csum=%" PRI__u64
1117			", csum_discards=%" PRI__u64
1118			", super_errors=%" PRI__u64
1119			", malloc_errors=%" PRI__u64
1120			", uncorrectable_errors=%" PRI__u64
1121			", corrected_errors=%" PRI__u64
1122			", last_physical=%" PRI__u64
1123			", unverified_errors=%" PRI__u64 "}",
1124			args.progress.data_extents_scrubbed,
1125			args.progress.tree_extents_scrubbed,
1126			args.progress.data_bytes_scrubbed,
1127			args.progress.tree_bytes_scrubbed,
1128			args.progress.read_errors,
1129			args.progress.csum_errors,
1130			args.progress.verify_errors,
1131			args.progress.no_csum,
1132			args.progress.csum_discards,
1133			args.progress.super_errors,
1134			args.progress.malloc_errors,
1135			args.progress.uncorrectable_errors,
1136			args.progress.corrected_errors,
1137			args.progress.last_physical,
1138			args.progress.unverified_errors);
1139		break;
1140	}
1141
1142	case BTRFS_IOC_TREE_SEARCH: { /* RW */
1143		struct btrfs_ioctl_search_args args;
1144		uint64_t buf_offset;
1145
1146		if (entering(tcp))
1147			tprints(", ");
1148		else if (syserror(tcp))
1149			break;
1150		else
1151			tprints(" => ");
1152
1153		if (umove_or_printaddr(tcp, arg, &args))
1154			break;
1155
1156		buf_offset = offsetof(struct btrfs_ioctl_search_args, buf);
1157		btrfs_print_tree_search(tcp, &args.key, arg + buf_offset,
1158					sizeof(args.buf), false);
1159		if (entering(tcp))
1160			return 0;
1161		break;
1162	}
1163
1164	case BTRFS_IOC_TREE_SEARCH_V2: { /* RW */
1165		struct btrfs_ioctl_search_args_v2 args;
1166		uint64_t buf_offset;
1167
1168		if (entering(tcp))
1169			tprints(", ");
1170		else if (syserror(tcp)) {
1171			if (tcp->u_error == EOVERFLOW) {
1172				tprints(" => ");
1173				tcp->u_error = 0;
1174				if (!umove_or_printaddr(tcp, arg, &args))
1175					tprintf("{buf_size=%" PRIu64 "}",
1176						(uint64_t)args.buf_size);
1177				tcp->u_error = EOVERFLOW;
1178			}
1179			break;
1180		} else
1181			tprints(" => ");
1182
1183		if (umove_or_printaddr(tcp, arg, &args))
1184			break;
1185
1186		buf_offset = offsetof(struct btrfs_ioctl_search_args_v2, buf);
1187		btrfs_print_tree_search(tcp, &args.key, arg + buf_offset,
1188					args.buf_size, true);
1189		if (entering(tcp))
1190			return 0;
1191		break;
1192	}
1193
1194	case BTRFS_IOC_SEND: { /* W */
1195		struct_btrfs_ioctl_send_args args;
1196
1197		tprints(", ");
1198		if (umove_or_printaddr(tcp, arg, &args))
1199			break;
1200
1201		tprints("{send_fd=");
1202		printfd(tcp, args.send_fd);
1203		tprintf(", clone_sources_count=%" PRIu64 ", clone_sources=",
1204			(uint64_t) args.clone_sources_count);
1205
1206		if (abbrev(tcp))
1207			tprints("...");
1208		else {
1209			uint64_t record;
1210			print_array(tcp, ptr_to_kulong(args.clone_sources),
1211				    args.clone_sources_count,
1212				    &record, sizeof(record),
1213				    umoven_or_printaddr,
1214				    print_objectid_callback, 0);
1215		}
1216		tprints(", parent_root=");
1217		btrfs_print_objectid(args.parent_root);
1218		tprints(", flags=");
1219		printflags64(btrfs_send_flags, args.flags,
1220			     "BTRFS_SEND_FLAGS_???");
1221		tprints("}");
1222		break;
1223	}
1224
1225	case BTRFS_IOC_SPACE_INFO: { /* RW */
1226		struct btrfs_ioctl_space_args args;
1227
1228		if (entering(tcp))
1229			tprints(", ");
1230		else if (syserror(tcp))
1231			break;
1232		else
1233			tprints(" => ");
1234
1235		if (umove_or_printaddr(tcp, arg, &args))
1236			break;
1237
1238		tprints("{");
1239		if (entering(tcp)) {
1240			tprintf("space_slots=%" PRI__u64 "}", args.space_slots);
1241			return 0;
1242		}
1243
1244		tprintf("total_spaces=%" PRI__u64, args.total_spaces);
1245
1246		if (args.space_slots == 0 && args.total_spaces) {
1247			tprints("}");
1248			break;
1249		}
1250
1251		tprints(", spaces=");
1252
1253		if (abbrev(tcp))
1254			tprints("...");
1255		else {
1256			struct btrfs_ioctl_space_info info;
1257			print_array(tcp, arg + offsetof(typeof(args), spaces),
1258				    args.total_spaces,
1259				    &info, sizeof(info), umoven_or_printaddr,
1260				    print_btrfs_ioctl_space_info, 0);
1261		}
1262		tprints("}");
1263		break;
1264	}
1265
1266	case BTRFS_IOC_SNAP_CREATE:
1267	case BTRFS_IOC_RESIZE:
1268	case BTRFS_IOC_SCAN_DEV:
1269	case BTRFS_IOC_ADD_DEV:
1270	case BTRFS_IOC_RM_DEV:
1271	case BTRFS_IOC_SUBVOL_CREATE:
1272	case BTRFS_IOC_SNAP_DESTROY:
1273	case BTRFS_IOC_DEVICES_READY: { /* W */
1274		struct btrfs_ioctl_vol_args args;
1275
1276		tprints(", ");
1277		if (umove_or_printaddr(tcp, arg, &args))
1278			break;
1279
1280		tprints("{fd=");
1281		printfd(tcp, args.fd);
1282		tprints(", name=");
1283		print_quoted_string(args.name, sizeof(args.name),
1284				    QUOTE_0_TERMINATED);
1285		tprints("}");
1286		break;
1287	}
1288
1289	case BTRFS_IOC_SNAP_CREATE_V2:
1290	case BTRFS_IOC_SUBVOL_CREATE_V2: { /* code is W, but is actually RW */
1291		struct_btrfs_ioctl_vol_args_v2 args;
1292
1293		if (entering(tcp))
1294			tprints(", ");
1295		else if (syserror(tcp))
1296			break;
1297		else
1298			tprints(" => ");
1299
1300		if (umove_or_printaddr(tcp, arg, &args))
1301			break;
1302
1303		if (entering(tcp)) {
1304			tprints("{fd=");
1305			printfd(tcp, args.fd);
1306			tprints(", flags=");
1307			printflags64(btrfs_snap_flags_v2, args.flags,
1308				     "BTRFS_SUBVOL_???");
1309			if (args.flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
1310				tprintf(", size=%" PRIu64 ", qgroup_inherit=",
1311					(uint64_t) args.size);
1312
1313				btrfs_print_qgroup_inherit(tcp,
1314					ptr_to_kulong(args.qgroup_inherit));
1315			}
1316			tprints(", name=");
1317			print_quoted_string(args.name, sizeof(args.name),
1318					    QUOTE_0_TERMINATED);
1319			tprints("}");
1320			return 0;
1321		}
1322		tprintf("{transid=%" PRIu64 "}", (uint64_t) args.transid);
1323		break;
1324	}
1325
1326	case BTRFS_IOC_GET_FSLABEL: /* R */
1327		if (entering(tcp))
1328			return 0;
1329		/* fall through */
1330	case BTRFS_IOC_SET_FSLABEL: { /* W */
1331		char label[BTRFS_LABEL_SIZE];
1332
1333		tprints(", ");
1334		if (umove_or_printaddr(tcp, arg, &label))
1335			break;
1336		print_quoted_string(label, sizeof(label), QUOTE_0_TERMINATED);
1337		break;
1338	}
1339
1340	case BTRFS_IOC_CLONE:			/* FICLONE */
1341	case BTRFS_IOC_CLONE_RANGE:		/* FICLONERANGE */
1342#ifdef BTRFS_IOC_FILE_EXTENT_SAME
1343	case BTRFS_IOC_FILE_EXTENT_SAME:	/* FIDEDUPERANGE */
1344#endif
1345		/*
1346		 * FICLONE, FICLONERANGE, and FIDEDUPERANGE started out as
1347		 * btrfs ioctls and the code was kept for the generic
1348		 * implementations.  We use the BTRFS_* names here because
1349		 * they will be available on older systems.
1350		 */
1351		return file_ioctl(tcp, code, arg);
1352
1353	default:
1354		return RVAL_DECODED;
1355	};
1356	return RVAL_DECODED | 1;
1357}
1358#endif /* HAVE_LINUX_BTRFS_H */
1359