1/*
2 * Check decoding of ioctl SG_IO v3 commands.
3 *
4 * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "tests.h"
31
32#ifdef HAVE_SCSI_SG_H
33
34# include <inttypes.h>
35# include <stdio.h>
36# include <sys/ioctl.h>
37# include <sys/uio.h>
38# include <scsi/sg.h>
39
40int
41main(void)
42{
43	ioctl(-1, SG_IO, 0);
44	printf("ioctl(-1, SG_IO, NULL) = -1 EBADF (%m)\n");
45
46	struct sg_io_hdr *const sg_io = tail_alloc(sizeof(*sg_io));
47	fill_memory(sg_io, sizeof(*sg_io));
48
49	const void *const efault = sg_io + 1;
50	ioctl(-1, SG_IO, efault);
51	printf("ioctl(-1, SG_IO, %p) = -1 EBADF (%m)\n", efault);
52
53	ioctl(-1, SG_IO, sg_io);
54	printf("ioctl(-1, SG_IO, [%u]) = -1 EBADF (%m)\n", sg_io->interface_id);
55
56	unsigned int *const piid = tail_alloc(sizeof(*piid));
57	*piid = (unsigned char) 'S';
58	ioctl(-1, SG_IO, piid);
59	printf("ioctl(-1, SG_IO, {interface_id='S', %p}) = -1 EBADF (%m)\n", piid + 1);
60
61	sg_io->interface_id = (unsigned char) 'S';
62	sg_io->dxfer_direction = -2;
63	sg_io->flags = -1U;
64	sg_io->info = -1U;
65	sg_io->dxferp = (void *) (unsigned long) 0xfacefeedfffffff1ULL;
66	sg_io->cmdp = (void *) (unsigned long) 0xfacefeedfffffff2ULL;
67	sg_io->sbp = (void *) (unsigned long) 0xfacefeedfffffff3ULL;
68
69	ioctl(-1, SG_IO, sg_io);
70	printf("ioctl(-1, SG_IO, {interface_id='S'"
71	       ", dxfer_direction=SG_DXFER_TO_DEV"
72	       ", cmd_len=%u"
73	       ", cmdp=%p"
74	       ", mx_sb_len=%u"
75	       ", iovec_count=%u"
76	       ", dxfer_len=%u"
77	       ", timeout=%u"
78	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_UNUSED_LUN_INHIBIT"
79	       "|SG_FLAG_MMAP_IO|SG_FLAG_NO_DXFER"
80	       "|SG_FLAG_Q_AT_TAIL|SG_FLAG_Q_AT_HEAD|0xfffeffc8"
81	       ", dxferp=%p"
82	       ", status=%#x"
83	       ", masked_status=%#x"
84	       ", msg_status=%#x"
85	       ", sb_len_wr=%u"
86	       ", sbp=%p"
87	       ", host_status=%#x"
88	       ", driver_status=%#x"
89	       ", resid=%d"
90	       ", duration=%u"
91	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xfffffff8"
92	       "}) = -1 EBADF (%m)\n",
93	       sg_io->cmd_len,
94	       sg_io->cmdp,
95	       sg_io->mx_sb_len,
96	       sg_io->iovec_count,
97	       sg_io->dxfer_len,
98	       sg_io->timeout,
99	       sg_io->dxferp,
100	       sg_io->status,
101	       sg_io->masked_status,
102	       sg_io->msg_status,
103	       sg_io->sb_len_wr,
104	       sg_io->sbp,
105	       sg_io->host_status,
106	       sg_io->driver_status,
107	       sg_io->resid,
108	       sg_io->duration);
109
110	sg_io->dxfer_direction = -3;
111
112	ioctl(-1, SG_IO, sg_io);
113	printf("ioctl(-1, SG_IO, {interface_id='S'"
114	       ", dxfer_direction=SG_DXFER_FROM_DEV"
115	       ", cmd_len=%u"
116	       ", cmdp=%p"
117	       ", mx_sb_len=%u"
118	       ", iovec_count=%u"
119	       ", dxfer_len=%u"
120	       ", timeout=%u"
121	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_UNUSED_LUN_INHIBIT"
122	       "|SG_FLAG_MMAP_IO|SG_FLAG_NO_DXFER"
123	       "|SG_FLAG_Q_AT_TAIL|SG_FLAG_Q_AT_HEAD|0xfffeffc8"
124	       ", dxferp=%p"
125	       ", status=%#x"
126	       ", masked_status=%#x"
127	       ", msg_status=%#x"
128	       ", sb_len_wr=%u"
129	       ", sbp=%p"
130	       ", host_status=%#x"
131	       ", driver_status=%#x"
132	       ", resid=%d"
133	       ", duration=%u"
134	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xfffffff8"
135	       "}) = -1 EBADF (%m)\n",
136	       sg_io->cmd_len,
137	       sg_io->cmdp,
138	       sg_io->mx_sb_len,
139	       sg_io->iovec_count,
140	       sg_io->dxfer_len,
141	       sg_io->timeout,
142	       sg_io->dxferp,
143	       sg_io->status,
144	       sg_io->masked_status,
145	       sg_io->msg_status,
146	       sg_io->sb_len_wr,
147	       sg_io->sbp,
148	       sg_io->host_status,
149	       sg_io->driver_status,
150	       sg_io->resid,
151	       sg_io->duration);
152
153	const struct iovec iov[] = {
154		{
155			.iov_base = (void *) efault - 2,
156			.iov_len = 2
157		}, {
158			.iov_base = (void *) efault - 3,
159			.iov_len = 4
160		}
161	};
162	struct iovec *const t_iov = tail_memdup(iov, sizeof(iov));
163
164	sg_io->flags = 0x24;
165	sg_io->info = 1;
166	sg_io->dxfer_direction = -2;
167
168	sg_io->iovec_count = ARRAY_SIZE(iov);
169	sg_io->dxfer_len = iov[0].iov_len + iov[1].iov_len - 1;
170	sg_io->dxferp = t_iov;
171
172	ioctl(-1, SG_IO, sg_io);
173	printf("ioctl(-1, SG_IO, {interface_id='S'"
174	       ", dxfer_direction=SG_DXFER_TO_DEV"
175	       ", cmd_len=%u"
176	       ", cmdp=%p"
177	       ", mx_sb_len=%u"
178	       ", iovec_count=%u"
179	       ", dxfer_len=%u"
180	       ", timeout=%u"
181	       ", flags=SG_FLAG_MMAP_IO|SG_FLAG_Q_AT_HEAD"
182	       ", dxferp=[{iov_base=\"\\%o\\%o\", iov_len=%u}"
183	       ", {iov_base=\"\\%o\\%o\\%o\", iov_len=%u}]"
184	       ", status=%#x"
185	       ", masked_status=%#x"
186	       ", msg_status=%#x"
187	       ", sb_len_wr=%u"
188	       ", sbp=%p"
189	       ", host_status=%#x"
190	       ", driver_status=%#x"
191	       ", resid=%d"
192	       ", duration=%u"
193	       ", info=SG_INFO_CHECK"
194	       "}) = -1 EBADF (%m)\n",
195	       sg_io->cmd_len,
196	       sg_io->cmdp,
197	       sg_io->mx_sb_len,
198	       sg_io->iovec_count,
199	       sg_io->dxfer_len,
200	       sg_io->timeout,
201	       * (unsigned char *) (iov[0].iov_base + 0),
202	       * (unsigned char *) (iov[0].iov_base + 1),
203	       (unsigned int) iov[0].iov_len,
204	       * (unsigned char *) (iov[1].iov_base + 0),
205	       * (unsigned char *) (iov[1].iov_base + 1),
206	       * (unsigned char *) (iov[1].iov_base + 2),
207	       (unsigned int) iov[1].iov_len,
208	       sg_io->status,
209	       sg_io->masked_status,
210	       sg_io->msg_status,
211	       sg_io->sb_len_wr,
212	       sg_io->sbp,
213	       sg_io->host_status,
214	       sg_io->driver_status,
215	       sg_io->resid,
216	       sg_io->duration);
217
218	sg_io->flags = 0x11;
219	sg_io->dxfer_direction = -3;
220	sg_io->resid = sg_io->dxfer_len + 1;
221
222	ioctl(-1, SG_IO, sg_io);
223	printf("ioctl(-1, SG_IO, {interface_id='S'"
224	       ", dxfer_direction=SG_DXFER_FROM_DEV"
225	       ", cmd_len=%u"
226	       ", cmdp=%p"
227	       ", mx_sb_len=%u"
228	       ", iovec_count=%u"
229	       ", dxfer_len=%u"
230	       ", timeout=%u"
231	       ", flags=SG_FLAG_DIRECT_IO|SG_FLAG_Q_AT_TAIL"
232	       ", dxferp=[{iov_base=\"\\%o\\%o\", iov_len=%u}"
233	       ", {iov_base=\"\\%o\\%o\\%o\", iov_len=%u}]"
234	       ", status=%#x"
235	       ", masked_status=%#x"
236	       ", msg_status=%#x"
237	       ", sb_len_wr=%u"
238	       ", sbp=%p"
239	       ", host_status=%#x"
240	       ", driver_status=%#x"
241	       ", resid=%d"
242	       ", duration=%u"
243	       ", info=SG_INFO_CHECK"
244	       "}) = -1 EBADF (%m)\n",
245	       sg_io->cmd_len,
246	       sg_io->cmdp,
247	       sg_io->mx_sb_len,
248	       sg_io->iovec_count,
249	       sg_io->dxfer_len,
250	       sg_io->timeout,
251	       * (unsigned char *) (iov[0].iov_base + 0),
252	       * (unsigned char *) (iov[0].iov_base + 1),
253	       (unsigned int) iov[0].iov_len,
254	       * (unsigned char *) (iov[1].iov_base + 0),
255	       * (unsigned char *) (iov[1].iov_base + 1),
256	       * (unsigned char *) (iov[1].iov_base + 2),
257	       (unsigned int) iov[1].iov_len,
258	       sg_io->status,
259	       sg_io->masked_status,
260	       sg_io->msg_status,
261	       sg_io->sb_len_wr,
262	       sg_io->sbp,
263	       sg_io->host_status,
264	       sg_io->driver_status,
265	       sg_io->resid,
266	       sg_io->duration);
267
268	sg_io->flags = 0x10000;
269	sg_io->info = 0xdeadbeef;
270	sg_io->iovec_count = 0;
271	sg_io->dxfer_len = 5;
272	sg_io->resid = 1;
273	sg_io->dxferp = (void *) efault - (sg_io->dxfer_len - sg_io->resid);
274
275	ioctl(-1, SG_IO, sg_io);
276	printf("ioctl(-1, SG_IO, {interface_id='S'"
277	       ", dxfer_direction=SG_DXFER_FROM_DEV"
278	       ", cmd_len=%u"
279	       ", cmdp=%p"
280	       ", mx_sb_len=%u"
281	       ", iovec_count=%u"
282	       ", dxfer_len=%u"
283	       ", timeout=%u"
284	       ", flags=SG_FLAG_NO_DXFER"
285	       ", dxferp=\"\\x%x\\x%x\\x%x\\x%x\""
286	       ", status=%#x"
287	       ", masked_status=%#x"
288	       ", msg_status=%#x"
289	       ", sb_len_wr=%u"
290	       ", sbp=%p"
291	       ", host_status=%#x"
292	       ", driver_status=%#x"
293	       ", resid=%d"
294	       ", duration=%u"
295	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
296	       "}) = -1 EBADF (%m)\n",
297	       sg_io->cmd_len,
298	       sg_io->cmdp,
299	       sg_io->mx_sb_len,
300	       sg_io->iovec_count,
301	       sg_io->dxfer_len,
302	       sg_io->timeout,
303	       * (unsigned char *) (sg_io->dxferp + 0),
304	       * (unsigned char *) (sg_io->dxferp + 1),
305	       * (unsigned char *) (sg_io->dxferp + 2),
306	       * (unsigned char *) (sg_io->dxferp + 3),
307	       sg_io->status,
308	       sg_io->masked_status,
309	       sg_io->msg_status,
310	       sg_io->sb_len_wr,
311	       sg_io->sbp,
312	       sg_io->host_status,
313	       sg_io->driver_status,
314	       sg_io->resid,
315	       sg_io->duration);
316
317	sg_io->flags = 2;
318	sg_io->dxfer_direction = -4;
319	sg_io->dxfer_len = 3;
320	sg_io->resid = 1;
321	sg_io->dxferp = (void *) efault - sg_io->dxfer_len;
322
323	ioctl(-1, SG_IO, sg_io);
324	printf("ioctl(-1, SG_IO, {interface_id='S'"
325	       ", dxfer_direction=SG_DXFER_TO_FROM_DEV"
326	       ", cmd_len=%u"
327	       ", cmdp=%p"
328	       ", mx_sb_len=%u"
329	       ", iovec_count=%u"
330	       ", dxfer_len=%u"
331	       ", timeout=%u"
332	       ", flags=SG_FLAG_UNUSED_LUN_INHIBIT"
333	       ", dxferp=\"\\x%x\\x%x\\x%x\" => dxferp=\"\\x%x\\x%x\""
334	       ", status=%#x"
335	       ", masked_status=%#x"
336	       ", msg_status=%#x"
337	       ", sb_len_wr=%u"
338	       ", sbp=%p"
339	       ", host_status=%#x"
340	       ", driver_status=%#x"
341	       ", resid=%d"
342	       ", duration=%u"
343	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
344	       "}) = -1 EBADF (%m)\n",
345	       sg_io->cmd_len,
346	       sg_io->cmdp,
347	       sg_io->mx_sb_len,
348	       sg_io->iovec_count,
349	       sg_io->dxfer_len,
350	       sg_io->timeout,
351	       * (unsigned char *) (sg_io->dxferp + 0),
352	       * (unsigned char *) (sg_io->dxferp + 1),
353	       * (unsigned char *) (sg_io->dxferp + 2),
354	       * (unsigned char *) (sg_io->dxferp + 0),
355	       * (unsigned char *) (sg_io->dxferp + 1),
356	       sg_io->status,
357	       sg_io->masked_status,
358	       sg_io->msg_status,
359	       sg_io->sb_len_wr,
360	       sg_io->sbp,
361	       sg_io->host_status,
362	       sg_io->driver_status,
363	       sg_io->resid,
364	       sg_io->duration);
365
366	sg_io->flags = 0;
367	sg_io->resid = sg_io->dxfer_len;
368
369	ioctl(-1, SG_IO, sg_io);
370	printf("ioctl(-1, SG_IO, {interface_id='S'"
371	       ", dxfer_direction=SG_DXFER_TO_FROM_DEV"
372	       ", cmd_len=%u"
373	       ", cmdp=%p"
374	       ", mx_sb_len=%u"
375	       ", iovec_count=%u"
376	       ", dxfer_len=%u"
377	       ", timeout=%u"
378	       ", flags=0"
379	       ", dxferp=\"\\x%x\\x%x\\x%x\""
380	       ", status=%#x"
381	       ", masked_status=%#x"
382	       ", msg_status=%#x"
383	       ", sb_len_wr=%u"
384	       ", sbp=%p"
385	       ", host_status=%#x"
386	       ", driver_status=%#x"
387	       ", resid=%d"
388	       ", duration=%u"
389	       ", info=SG_INFO_CHECK|SG_INFO_DIRECT_IO|SG_INFO_MIXED_IO|0xdeadbee8"
390	       "}) = -1 EBADF (%m)\n",
391	       sg_io->cmd_len,
392	       sg_io->cmdp,
393	       sg_io->mx_sb_len,
394	       sg_io->iovec_count,
395	       sg_io->dxfer_len,
396	       sg_io->timeout,
397	       * (unsigned char *) (sg_io->dxferp + 0),
398	       * (unsigned char *) (sg_io->dxferp + 1),
399	       * (unsigned char *) (sg_io->dxferp + 2),
400	       sg_io->status,
401	       sg_io->masked_status,
402	       sg_io->msg_status,
403	       sg_io->sb_len_wr,
404	       sg_io->sbp,
405	       sg_io->host_status,
406	       sg_io->driver_status,
407	       sg_io->resid,
408	       sg_io->duration);
409
410	puts("+++ exited with 0 +++");
411	return 0;
412}
413
414#else
415
416SKIP_MAIN_UNDEFINED("HAVE_SCSI_SG_H")
417
418#endif
419