Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 2009, 2010 Jeff Mahoney <jeffm (at) suse.com>
      3  * All rights reserved.
      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 #ifdef LINUX
     30 #include <stdint.h>
     31 #include <inttypes.h>
     32 #include <linux/blkpg.h>
     33 #include <linux/fs.h>
     34 #include <linux/hdreg.h>
     35 
     36 /* ioctls <= 114 are present in Linux 2.4. The following ones have been
     37  * added since then and headers containing them may not be available on
     38  * every system. */
     39 
     40 #define BLKTRACE_BDEV_SIZE      32
     41 struct blk_user_trace_setup {
     42 	char name[BLKTRACE_BDEV_SIZE];	/* output */
     43 	uint16_t act_mask;		/* input */
     44 	uint32_t buf_size;		/* input */
     45 	uint32_t buf_nr;		/* input */
     46 	uint64_t start_lba;
     47 	uint64_t end_lba;
     48 	uint32_t pid;
     49 };
     50 
     51 #ifndef BLKTRACESETUP
     52 #define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup)
     53 #endif
     54 #ifndef BLKTRACESTART
     55 #define BLKTRACESTART _IO(0x12,116)
     56 #endif
     57 #ifndef BLKTRACESTART
     58 #define BLKTRACESTOP _IO(0x12,117)
     59 #endif
     60 #ifndef BLKTRACETEARDOWN
     61 #define BLKTRACETEARDOWN _IO(0x12,118)
     62 #endif
     63 #ifndef BLKDISCARD
     64 #define BLKDISCARD _IO(0x12,119)
     65 #endif
     66 #ifndef BLKIOMIN
     67 #define BLKIOMIN _IO(0x12,120)
     68 #endif
     69 #ifndef BLKIOOPT
     70 #define BLKIOOPT _IO(0x12,121)
     71 #endif
     72 #ifndef BLKALIGNOFF
     73 #define BLKALIGNOFF _IO(0x12,122)
     74 #endif
     75 #ifndef BLKPBSZGET
     76 #define BLKPBSZGET _IO(0x12,123)
     77 #endif
     78 #ifndef BLKDISCARDZEROES
     79 #define BLKDISCARDZEROES _IO(0x12,124)
     80 #endif
     81 #ifndef BLKSECDISCARD
     82 #define BLKSECDISCARD _IO(0x12,125)
     83 #endif
     84 
     85 static const struct xlat blkpg_ops[] = {
     86 	{ BLKPG_ADD_PARTITION,	"BLKPG_ADD_PARTITION", },
     87 	{ BLKPG_DEL_PARTITION,	"BLKPG_DEL_PARTITION", },
     88 	{ 0,			NULL },
     89 };
     90 
     91 static void
     92 print_blkpg_req(struct tcb *tcp, struct blkpg_ioctl_arg *blkpg)
     93 {
     94 	struct blkpg_partition p;
     95 
     96 	tprintf("{");
     97 	printxval(blkpg_ops, blkpg->op, "BLKPG_???");
     98 
     99 	tprintf(", flags=%d, datalen=%d, ",
    100 		blkpg->flags, blkpg->datalen);
    101 
    102 	if (umove(tcp, (long) blkpg->data, &p) < 0)
    103 		tprintf("%#lx}", (long) blkpg->data);
    104 	else
    105 		tprintf("{start=%lld, length=%lld, pno=%d, "
    106 			"devname=\"%.*s\", volname=\"%.*s\"}}",
    107 			p.start, p.length, p.pno,
    108 			(int) sizeof(p.devname), p.devname,
    109 			(int) sizeof(p.volname), p.volname);
    110 }
    111 
    112 int
    113 block_ioctl(struct tcb *tcp, long code, long arg)
    114 {
    115 	switch (code) {
    116 	/* take arg as a value, not as a pointer */
    117 	case BLKRASET:
    118 	case BLKFRASET:
    119 		if (entering(tcp))
    120 			tprintf(", %ld", arg);
    121 		break;
    122 
    123 	/* take a signed int */
    124 	case BLKROSET:
    125 	case BLKBSZSET:
    126 		if (entering(tcp)) {
    127 			int val;
    128 			if (umove(tcp, arg, &val) < 0)
    129 				tprintf(", %#lx", arg);
    130 			else
    131 				tprintf(", %d", val);
    132 		}
    133 		break;
    134 
    135 	/* returns an unsigned short */
    136 	case BLKSECTGET:
    137 		if (exiting(tcp)) {
    138 			unsigned short val;
    139 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    140 				tprintf(", %#lx", arg);
    141 			else
    142 				tprintf(", %hu", val);
    143 		}
    144 		break;
    145 
    146 	/* return a signed int */
    147 	case BLKROGET:
    148 	case BLKBSZGET:
    149 	case BLKSSZGET:
    150 	case BLKALIGNOFF:
    151 		if (exiting(tcp)) {
    152 			int val;
    153 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    154 				tprintf(", %#lx", arg);
    155 			else
    156 				tprintf(", %d", val);
    157 		}
    158 		break;
    159 
    160 	/* return an unsigned int */
    161 	case BLKPBSZGET:
    162 	case BLKIOMIN:
    163 	case BLKIOOPT:
    164 	case BLKDISCARDZEROES:
    165 		if (exiting(tcp)) {
    166 			unsigned int val;
    167 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    168 				tprintf(", %#lx", arg);
    169 			else
    170 				tprintf(", %u", val);
    171 		}
    172 		break;
    173 
    174 	/* return a signed long */
    175 	case BLKRAGET:
    176 	case BLKFRAGET:
    177 		if (exiting(tcp)) {
    178 			long val;
    179 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    180 				tprintf(", %#lx", arg);
    181 			else
    182 				tprintf(", %ld", val);
    183 		}
    184 		break;
    185 
    186 	/* returns an unsigned long */
    187 	case BLKGETSIZE:
    188 		if (exiting(tcp)) {
    189 			unsigned long val;
    190 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    191 				tprintf(", %#lx", arg);
    192 			else
    193 				tprintf(", %lu", val);
    194 			}
    195 		break;
    196 
    197 	/* return an uint64_t */
    198 	case BLKGETSIZE64:
    199 		if (exiting(tcp)) {
    200 			uint64_t val;
    201 			if (syserror(tcp) || umove(tcp, arg, &val) < 0)
    202 				tprintf(", %#lx", arg);
    203 			else
    204 				tprintf(", %" PRIu64, val);
    205 		}
    206 		break;
    207 
    208 	/* More complex types */
    209 	case BLKDISCARD:
    210 	case BLKSECDISCARD:
    211 		if (entering(tcp)) {
    212 			uint64_t range[2];
    213 			if (umove(tcp, arg, range) < 0)
    214 				tprintf(", %#lx", arg);
    215 			else
    216 				tprintf(", {%" PRIx64 ", %" PRIx64 "}",
    217 					range[0], range[1]);
    218 		}
    219 		break;
    220 
    221 	case HDIO_GETGEO:
    222 		if (exiting(tcp)) {
    223 			struct hd_geometry geo;
    224 			if (syserror(tcp) || umove(tcp, arg, &geo) < 0)
    225 				tprintf(", %#lx", arg);
    226 			else
    227 				tprintf(", {heads=%hhu, sectors=%hhu, "
    228 					"cylinders=%hu, start=%lu}",
    229 					geo.heads, geo.sectors,
    230 					geo.cylinders, geo.start);
    231 		}
    232 		break;
    233 
    234 	case BLKPG:
    235 		if (entering(tcp)) {
    236 			struct blkpg_ioctl_arg blkpg;
    237 			if (umove(tcp, arg, &blkpg) < 0)
    238 				tprintf(", %#lx", arg);
    239 			else {
    240 				tprintf(", ");
    241 				print_blkpg_req(tcp, &blkpg);
    242 			}
    243 		}
    244 		break;
    245 
    246 	case BLKTRACESETUP:
    247 		if (entering(tcp)) {
    248 			struct blk_user_trace_setup buts;
    249 			if (umove(tcp, arg, &buts) < 0)
    250 				tprintf(", %#lx", arg);
    251 			else
    252 				tprintf(", {act_mask=%hu, buf_size=%u, "
    253 					"buf_nr=%u, start_lba=%" PRIu64 ", "
    254 					"end_lba=%" PRIu64 ", pid=%u}",
    255 					buts.act_mask, buts.buf_size,
    256 					buts.buf_nr, buts.start_lba,
    257 					buts.end_lba, buts.pid);
    258 		}
    259 		if (exiting(tcp)) {
    260 			struct blk_user_trace_setup buts;
    261 			if (syserror(tcp) || umove(tcp, arg, &buts) < 0)
    262 				tprintf(", %#lx", arg);
    263 			else
    264 				tprintf(", {name=\"%.*s\"}",
    265 					(int) sizeof(buts.name), buts.name);
    266 		}
    267 		break;
    268 
    269 	/* No arguments or unhandled */
    270 	case BLKTRACESTART:
    271 	case BLKTRACESTOP:
    272 	case BLKTRACETEARDOWN:
    273 	case BLKFLSBUF: /* Requires driver knowlege */
    274 	case BLKRRPART: /* No args */
    275 	default:
    276 		if (entering(tcp))
    277 			tprintf(", %#lx", arg);
    278 		break;
    279 
    280 	};
    281 	return 1;
    282 }
    283 #endif /* LINUX */
    284