1 /*
2  * Copyright (c) 2012 The Chromium OS Authors.
3  * Written by Mike Frysinger <vapier@gentoo.org>.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "defs.h"
29 #include <linux/ioctl.h>
30 #include <linux/loop.h>
31 
32 #include "xlat/loop_flags_options.h"
33 #include "xlat/loop_crypt_type_options.h"
34 
35 static void
decode_loop_info(struct tcb * tcp,const long addr)36 decode_loop_info(struct tcb *tcp, const long addr)
37 {
38 	struct loop_info info;
39 
40 	tprints(", ");
41 	if (umove_or_printaddr(tcp, addr, &info))
42 		return;
43 
44 	tprintf("{number=%d", info.lo_number);
45 
46 	if (!abbrev(tcp)) {
47 		tprintf(", device=%#lx, inode=%lu, rdevice=%#lx",
48 			(unsigned long) info.lo_device,
49 			info.lo_inode,
50 			(unsigned long) info.lo_rdevice);
51 	}
52 
53 	tprintf(", offset=%#x", info.lo_offset);
54 
55 	if (!abbrev(tcp) || info.lo_encrypt_type != LO_CRYPT_NONE) {
56 		tprints(", encrypt_type=");
57 		printxval(loop_crypt_type_options, info.lo_encrypt_type,
58 			"LO_CRYPT_???");
59 		tprintf(", encrypt_key_size=%d", info.lo_encrypt_key_size);
60 	}
61 
62 	tprints(", flags=");
63 	printflags(loop_flags_options, info.lo_flags, "LO_FLAGS_???");
64 
65 	tprints(", name=");
66 	print_quoted_string(info.lo_name, LO_NAME_SIZE,
67 			    QUOTE_0_TERMINATED);
68 
69 	if (!abbrev(tcp) || info.lo_encrypt_type != LO_CRYPT_NONE) {
70 		tprints(", encrypt_key=");
71 		print_quoted_string((void *) info.lo_encrypt_key,
72 				    LO_KEY_SIZE, 0);
73 	}
74 
75 	if (!abbrev(tcp))
76 		tprintf(", init={%#lx, %#lx}"
77 			", reserved={%#x, %#x, %#x, %#x}}",
78 			info.lo_init[0], info.lo_init[1],
79 			info.reserved[0], info.reserved[1],
80 			info.reserved[2], info.reserved[3]);
81 	else
82 		tprints(", ...}");
83 }
84 
85 static void
decode_loop_info64(struct tcb * tcp,const long addr)86 decode_loop_info64(struct tcb *tcp, const long addr)
87 {
88 	struct loop_info64 info64;
89 
90 	tprints(", ");
91 	if (umove_or_printaddr(tcp, addr, &info64))
92 		return;
93 
94 	if (!abbrev(tcp)) {
95 		tprintf("{device=%" PRIu64 ", inode=%" PRIu64 ", "
96 			"rdevice=%" PRIu64 ", offset=%#" PRIx64 ", "
97 			"sizelimit=%" PRIu64 ", number=%" PRIu32,
98 			(uint64_t) info64.lo_device,
99 			(uint64_t) info64.lo_inode,
100 			(uint64_t) info64.lo_rdevice,
101 			(uint64_t) info64.lo_offset,
102 			(uint64_t) info64.lo_sizelimit,
103 			(uint32_t) info64.lo_number);
104 	} else {
105 		tprintf("{offset=%#" PRIx64 ", number=%" PRIu32,
106 			(uint64_t) info64.lo_offset,
107 			(uint32_t) info64.lo_number);
108 	}
109 
110 	if (!abbrev(tcp) || info64.lo_encrypt_type != LO_CRYPT_NONE) {
111 		tprints(", encrypt_type=");
112 		printxval(loop_crypt_type_options, info64.lo_encrypt_type,
113 			"LO_CRYPT_???");
114 		tprintf(", encrypt_key_size=%" PRIu32,
115 			info64.lo_encrypt_key_size);
116 	}
117 
118 	tprints(", flags=");
119 	printflags(loop_flags_options, info64.lo_flags, "LO_FLAGS_???");
120 
121 	tprints(", file_name=");
122 	print_quoted_string((void *) info64.lo_file_name,
123 			    LO_NAME_SIZE, QUOTE_0_TERMINATED);
124 
125 	if (!abbrev(tcp) || info64.lo_encrypt_type != LO_CRYPT_NONE) {
126 		tprints(", crypt_name=");
127 		print_quoted_string((void *) info64.lo_crypt_name,
128 				    LO_NAME_SIZE, QUOTE_0_TERMINATED);
129 		tprints(", encrypt_key=");
130 		print_quoted_string((void *) info64.lo_encrypt_key,
131 				    LO_KEY_SIZE, 0);
132 	}
133 
134 	if (!abbrev(tcp))
135 		tprintf(", init={%#" PRIx64 ", %#" PRIx64 "}}",
136 			(uint64_t) info64.lo_init[0],
137 			(uint64_t) info64.lo_init[1]);
138 	else
139 		tprints(", ...}");
140 }
141 
142 int
loop_ioctl(struct tcb * tcp,const unsigned int code,long arg)143 loop_ioctl(struct tcb *tcp, const unsigned int code, long arg)
144 {
145 	if (!verbose(tcp))
146 		return RVAL_DECODED;
147 
148 	switch (code) {
149 	case LOOP_SET_STATUS:
150 		decode_loop_info(tcp, arg);
151 		break;
152 
153 	case LOOP_GET_STATUS:
154 		if (entering(tcp))
155 			return 0;
156 		decode_loop_info(tcp, arg);
157 		break;
158 
159 	case LOOP_SET_STATUS64:
160 		decode_loop_info64(tcp, arg);
161 		break;
162 
163 	case LOOP_GET_STATUS64:
164 		if (entering(tcp))
165 			return 0;
166 		decode_loop_info64(tcp, arg);
167 		break;
168 
169 	case LOOP_CLR_FD:
170 #ifdef LOOP_SET_CAPACITY
171 	case LOOP_SET_CAPACITY:
172 #endif
173 #ifdef LOOP_CTL_GET_FREE
174 	/* newer loop-control stuff */
175 	case LOOP_CTL_GET_FREE:
176 #endif
177 		/* Takes no arguments */
178 		break;
179 
180 	case LOOP_SET_FD:
181 	case LOOP_CHANGE_FD:
182 		tprints(", ");
183 		printfd(tcp, arg);
184 		break;
185 
186 #ifdef LOOP_CTL_ADD
187 	/* newer loop-control stuff */
188 	case LOOP_CTL_ADD:
189 	case LOOP_CTL_REMOVE:
190 		tprintf(", %d", (int) arg);
191 		break;
192 #endif
193 
194 	default:
195 		return RVAL_DECODED;
196 	}
197 
198 	return RVAL_DECODED | 1;
199 }
200