Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * zap.c --- zap block
      3  *
      4  * Copyright (C) 2012 Theodore Ts'o.  This file may be redistributed
      5  * under the terms of the GNU Public License.
      6  */
      7 
      8 #include "config.h"
      9 #include <stdio.h>
     10 #include <unistd.h>
     11 #include <stdlib.h>
     12 #include <ctype.h>
     13 #include <string.h>
     14 #include <time.h>
     15 #ifdef HAVE_ERRNO_H
     16 #include <errno.h>
     17 #endif
     18 #include <sys/types.h>
     19 #ifdef HAVE_GETOPT_H
     20 #include <getopt.h>
     21 #else
     22 extern int optind;
     23 extern char *optarg;
     24 #endif
     25 
     26 #include "debugfs.h"
     27 
     28 void do_zap_block(int argc, char *argv[])
     29 {
     30 	unsigned long	pattern = 0;
     31 	unsigned char	*buf;
     32 	ext2_ino_t	inode;
     33 	errcode_t	errcode;
     34 	blk64_t		block;
     35 	char		*file = NULL;
     36 	int		c, err;
     37 	int		offset = -1;
     38 	int		length = -1;
     39 	int		bit = -1;
     40 
     41 	if (check_fs_open(argv[0]))
     42 		return;
     43 	if (check_fs_read_write(argv[0]))
     44 		return;
     45 
     46 	reset_getopt();
     47 	while ((c = getopt (argc, argv, "b:f:l:o:p:")) != EOF) {
     48 		switch (c) {
     49 		case 'f':
     50 			file = optarg;
     51 			break;
     52 		case 'b':
     53 			bit = parse_ulong(optarg, argv[0],
     54 					  "bit", &err);
     55 			if (err)
     56 				return;
     57 			if (bit >= (int) current_fs->blocksize * 8) {
     58 				com_err(argv[0], 0, "The bit to flip "
     59 					"must be within a %d block\n",
     60 					current_fs->blocksize);
     61 				return;
     62 			}
     63 			break;
     64 		case 'p':
     65 			pattern = parse_ulong(optarg, argv[0],
     66 					      "pattern", &err);
     67 			if (err)
     68 				return;
     69 			if (pattern >= 256) {
     70 				com_err(argv[0], 0, "The fill pattern must "
     71 					"be an 8-bit value\n");
     72 				return;
     73 			}
     74 			break;
     75 		case 'o':
     76 			offset = parse_ulong(optarg, argv[0],
     77 					     "offset", &err);
     78 			if (err)
     79 				return;
     80 			if (offset >= (int) current_fs->blocksize) {
     81 				com_err(argv[0], 0, "The offset must be "
     82 					"within a %d block\n",
     83 					current_fs->blocksize);
     84 				return;
     85 			}
     86 			break;
     87 
     88 			break;
     89 		case 'l':
     90 			length = parse_ulong(optarg, argv[0],
     91 					     "length", &err);
     92 			if (err)
     93 				return;
     94 			break;
     95 		default:
     96 			goto print_usage;
     97 		}
     98 	}
     99 
    100 	if (bit > 0 && offset > 0) {
    101 		com_err(argv[0], 0, "The -o and -b options can not be mixed.");
    102 		return;
    103 	}
    104 
    105 	if (offset < 0)
    106 		offset = 0;
    107 	if (length < 0)
    108 		length = current_fs->blocksize - offset;
    109 	if ((offset + length) > (int) current_fs->blocksize) {
    110 		com_err(argv[0], 0, "The specified length is too bug\n");
    111 		return;
    112 	}
    113 
    114 	if (argc != optind+1) {
    115 	print_usage:
    116 		com_err(0, 0, "Usage:\tzap_block [-f file] [-o offset] "
    117 			"[-l length] [-p pattern] block_num");
    118 		com_err(0, 0, "\tzap_block [-f file] [-b bit] "
    119 			"block_num");
    120 		return;
    121 	}
    122 
    123 	block = parse_ulonglong(argv[optind], argv[0], "block", &err);
    124 	if (err)
    125 		return;
    126 
    127 	if (file) {
    128 		inode = string_to_inode(file);
    129 		if (!inode)
    130 			return;
    131 		errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
    132 				       block, 0, &block);
    133 		if (errcode) {
    134 			com_err(argv[0], errcode,
    135 				"while mapping logical block %llu\n", block);
    136 			return;
    137 		}
    138 	}
    139 
    140 	buf = malloc(current_fs->blocksize);
    141 	if (!buf) {
    142 		com_err(argv[0], 0, "Couldn't allocate block buffer");
    143 		return;
    144 	}
    145 
    146 	errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
    147 	if (errcode) {
    148 		com_err(argv[0], errcode,
    149 			"while reading block %llu\n", block);
    150 		goto errout;
    151 	}
    152 
    153 	if (bit >= 0)
    154 		buf[bit >> 3] ^= 1 << (bit & 7);
    155 	else
    156 		memset(buf+offset, pattern, length);
    157 
    158 	errcode = io_channel_write_blk64(current_fs->io, block, 1, buf);
    159 	if (errcode) {
    160 		com_err(argv[0], errcode,
    161 			"while write block %llu\n", block);
    162 		goto errout;
    163 	}
    164 
    165 errout:
    166 	free(buf);
    167 	return;
    168 }
    169 
    170 void do_block_dump(int argc, char *argv[])
    171 {
    172 	unsigned char	*buf;
    173 	ext2_ino_t	inode;
    174 	errcode_t	errcode;
    175 	blk64_t		block;
    176 	char		*file = NULL;
    177 	int		c, err;
    178 
    179 	if (check_fs_open(argv[0]))
    180 		return;
    181 
    182 	reset_getopt();
    183 	while ((c = getopt (argc, argv, "f:")) != EOF) {
    184 		switch (c) {
    185 		case 'f':
    186 			file = optarg;
    187 			break;
    188 
    189 		default:
    190 			goto print_usage;
    191 		}
    192 	}
    193 
    194 	if (argc != optind + 1) {
    195 	print_usage:
    196 		com_err(0, 0, "Usage: block_dump [-f inode] block_num");
    197 		return;
    198 	}
    199 
    200 	block = parse_ulonglong(argv[optind], argv[0], "block", &err);
    201 	if (err)
    202 		return;
    203 
    204 	if (file) {
    205 		inode = string_to_inode(file);
    206 		if (!inode)
    207 			return;
    208 		errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
    209 				       block, 0, &block);
    210 		if (errcode) {
    211 			com_err(argv[0], errcode,
    212 				"while mapping logical block %llu\n", block);
    213 			return;
    214 		}
    215 	}
    216 
    217 	buf = malloc(current_fs->blocksize);
    218 	if (!buf) {
    219 		com_err(argv[0], 0, "Couldn't allocate block buffer");
    220 		return;
    221 	}
    222 
    223 	errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
    224 	if (errcode) {
    225 		com_err(argv[0], errcode,
    226 			"while reading block %llu\n", block);
    227 		goto errout;
    228 	}
    229 
    230 	do_byte_hexdump(stdout, buf, current_fs->blocksize);
    231 errout:
    232 	free(buf);
    233 }
    234 
    235 void do_byte_hexdump(FILE *fp, unsigned char *buf, size_t bufsize)
    236 {
    237 	size_t		i, j;
    238 	int		suppress = -1;
    239 
    240 	for (i = 0; i < bufsize; i += 16) {
    241 		if (suppress < 0) {
    242 			if (i && memcmp(buf + i, buf + i - 16, 16) == 0) {
    243 				suppress = i;
    244 				fprintf(fp, "*\n");
    245 				continue;
    246 			}
    247 		} else {
    248 			if (memcmp(buf + i, buf + suppress, 16) == 0)
    249 				continue;
    250 			suppress = -1;
    251 		}
    252 		fprintf(fp, "%04o  ", (unsigned int)i);
    253 		for (j = 0; j < 16; j++) {
    254 			fprintf(fp, "%02x", buf[i+j]);
    255 			if ((j % 2) == 1)
    256 				fprintf(fp, " ");
    257 		}
    258 		fprintf(fp, " ");
    259 		for (j = 0; j < 16; j++)
    260 			fprintf(fp, "%c", isprint(buf[i+j]) ? buf[i+j] : '.');
    261 		fprintf(fp, "\n");
    262 	}
    263 	fprintf(fp, "\n");
    264 }
    265