summaryrefslogtreecommitdiff
path: root/src/fs_f_ioctl.c
blob: d0de799f9743e98a408145d4e8697ff311c8e968 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com>
 * Copyright (c) 2016-2021 The strace developers.
 * All rights reserved.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "defs.h"
#include <linux/fs.h>
#include "types/fiemap.h"
#include "xlat/fiemap_flags.h"
#include "xlat/fiemap_extent_flags.h"
#include "xlat/fs_ioc_flags.h"
#define XLAT_MACROS_ONLY
# include "xlat/fs_f_ioctl_cmds.h"
#undef XLAT_MACROS_ONLY

static bool
print_fiemap_extent(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
{
	const struct_fiemap_extent *fe = elem_buf;

	tprint_struct_begin();
	PRINT_FIELD_U(*fe, fe_logical);
	tprint_struct_next();
	PRINT_FIELD_U(*fe, fe_physical);
	tprint_struct_next();
	PRINT_FIELD_U(*fe, fe_length);
	tprint_struct_next();
	PRINT_FIELD_FLAGS(*fe, fe_flags, fiemap_extent_flags,
			  "FIEMAP_EXTENT_???");
	tprint_struct_end();

	return true;
}

static int
decode_fiemap(struct tcb *const tcp, const kernel_ulong_t arg)
{
	struct_fiemap args;

	if (entering(tcp))
		tprints(", ");
	else if (syserror(tcp))
		return RVAL_IOCTL_DECODED;
	else
		tprint_value_changed();

	if (umove_or_printaddr(tcp, arg, &args))
		return RVAL_IOCTL_DECODED;

	if (entering(tcp)) {
		tprint_struct_begin();
		PRINT_FIELD_U(args, fm_start);
		tprint_struct_next();
		PRINT_FIELD_U(args, fm_length);
		tprint_struct_next();
		PRINT_FIELD_FLAGS(args, fm_flags, fiemap_flags,
				  "FIEMAP_FLAG_???");
		tprint_struct_next();
		PRINT_FIELD_U(args, fm_extent_count);
		tprint_struct_end();
		return 0;
	}

	tprint_struct_begin();
	PRINT_FIELD_FLAGS(args, fm_flags, fiemap_flags, "FIEMAP_FLAG_???");
	tprint_struct_next();
	PRINT_FIELD_U(args, fm_mapped_extents);
	if (abbrev(tcp)) {
		tprint_struct_next();
		tprint_more_data_follows();
	} else {
		struct_fiemap_extent fe;
		tprint_struct_next();
		tprints_field_name("fm_extents");
		print_array(tcp, arg + offsetof(typeof(args), fm_extents),
			    args.fm_mapped_extents, &fe, sizeof(fe),
			    tfetch_mem, print_fiemap_extent, 0);
	}
	tprint_struct_end();

	return RVAL_IOCTL_DECODED;
}

static void
decode_fs_ioc_flags(struct tcb *const tcp, const kernel_ulong_t arg)
{
	unsigned int flags;

	if (!umove_or_printaddr(tcp, arg, &flags)) {
		tprints("[");
		printflags(fs_ioc_flags, flags, "FS_???_FL");
		tprints("]");
	}
}

int
fs_f_ioctl(struct tcb *const tcp, const unsigned int code,
	   const kernel_ulong_t arg)
{
	switch (code) {
	case FS_IOC_FIEMAP:
		return decode_fiemap(tcp, arg);

	case FS_IOC_GETFLAGS:
#if SIZEOF_LONG > 4
	case FS_IOC32_GETFLAGS:
#endif
		if (entering(tcp))
			return 0;
		ATTRIBUTE_FALLTHROUGH;

	case FS_IOC_SETFLAGS:
#if SIZEOF_LONG > 4
	case FS_IOC32_SETFLAGS:
#endif
		tprints(", ");
		decode_fs_ioc_flags(tcp, arg);
		break;

	default:
		return RVAL_DECODED;
	};

	return RVAL_IOCTL_DECODED;
}