Home | History | Annotate | Download | only in misc
      1 /*
      2  * e2image.c --- Program which writes an image file backing up
      3  * critical metadata for the filesystem.
      4  *
      5  * Copyright 2000, 2001 by Theodore Ts'o.
      6  *
      7  * %Begin-Header%
      8  * This file may be redistributed under the terms of the GNU Public
      9  * License.
     10  * %End-Header%
     11  */
     12 
     13 #define _LARGEFILE_SOURCE
     14 #define _LARGEFILE64_SOURCE
     15 
     16 #include <fcntl.h>
     17 #include <grp.h>
     18 #ifdef HAVE_GETOPT_H
     19 #include <getopt.h>
     20 #else
     21 extern char *optarg;
     22 extern int optind;
     23 #endif
     24 #include <pwd.h>
     25 #include <stdio.h>
     26 #ifdef HAVE_STDLIB_H
     27 #include <stdlib.h>
     28 #endif
     29 #include <string.h>
     30 #include <time.h>
     31 #include <unistd.h>
     32 #include <fcntl.h>
     33 #include <errno.h>
     34 #include <sys/stat.h>
     35 #include <sys/types.h>
     36 
     37 #include "ext2fs/ext2_fs.h"
     38 #include "ext2fs/ext2fs.h"
     39 #include "et/com_err.h"
     40 #include "uuid/uuid.h"
     41 #include "e2p/e2p.h"
     42 #include "ext2fs/e2image.h"
     43 
     44 #include "../version.h"
     45 #include "nls-enable.h"
     46 
     47 const char * program_name = "e2image";
     48 char * device_name = NULL;
     49 
     50 static void usage(void)
     51 {
     52 	fprintf(stderr, _("Usage: %s [-rsI] device image_file\n"),
     53 		program_name);
     54 	exit (1);
     55 }
     56 
     57 static void write_header(int fd, struct ext2_image_hdr *hdr, int blocksize)
     58 {
     59 	char *header_buf;
     60 	int actual;
     61 
     62 	header_buf = malloc(blocksize);
     63 	if (!header_buf) {
     64 		fputs(_("Couldn't allocate header buffer\n"), stderr);
     65 		exit(1);
     66 	}
     67 
     68 	if (lseek(fd, 0, SEEK_SET) < 0) {
     69 		perror("lseek while writing header");
     70 		exit(1);
     71 	}
     72 	memset(header_buf, 0, blocksize);
     73 
     74 	if (hdr)
     75 		memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr));
     76 
     77 	actual = write(fd, header_buf, blocksize);
     78 	if (actual < 0) {
     79 		perror("write header");
     80 		exit(1);
     81 	}
     82 	if (actual != blocksize) {
     83 		fprintf(stderr, _("short write (only %d bytes) for "
     84 				  "writing image header"), actual);
     85 		exit(1);
     86 	}
     87 	free(header_buf);
     88 }
     89 
     90 static void write_image_file(ext2_filsys fs, int fd)
     91 {
     92 	struct ext2_image_hdr	hdr;
     93 	struct stat		st;
     94 	errcode_t		retval;
     95 
     96 	write_header(fd, NULL, fs->blocksize);
     97 	memset(&hdr, 0, sizeof(struct ext2_image_hdr));
     98 
     99 	hdr.offset_super = lseek(fd, 0, SEEK_CUR);
    100 	retval = ext2fs_image_super_write(fs, fd, 0);
    101 	if (retval) {
    102 		com_err(program_name, retval, _("while writing superblock"));
    103 		exit(1);
    104 	}
    105 
    106 	hdr.offset_inode = lseek(fd, 0, SEEK_CUR);
    107 	retval = ext2fs_image_inode_write(fs, fd,
    108 				  (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
    109 	if (retval) {
    110 		com_err(program_name, retval, _("while writing inode table"));
    111 		exit(1);
    112 	}
    113 
    114 	hdr.offset_blockmap = lseek(fd, 0, SEEK_CUR);
    115 	retval = ext2fs_image_bitmap_write(fs, fd, 0);
    116 	if (retval) {
    117 		com_err(program_name, retval, _("while writing block bitmap"));
    118 		exit(1);
    119 	}
    120 
    121 	hdr.offset_inodemap = lseek(fd, 0, SEEK_CUR);
    122 	retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
    123 	if (retval) {
    124 		com_err(program_name, retval, _("while writing inode bitmap"));
    125 		exit(1);
    126 	}
    127 
    128 	hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE;
    129 	strcpy(hdr.magic_descriptor, "Ext2 Image 1.0");
    130 	gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname));
    131 	strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1);
    132 	hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0;
    133 	hdr.fs_blocksize = fs->blocksize;
    134 
    135 	if (stat(device_name, &st) == 0)
    136 		hdr.fs_device = st.st_rdev;
    137 
    138 	if (fstat(fd, &st) == 0) {
    139 		hdr.image_device = st.st_dev;
    140 		hdr.image_inode = st.st_ino;
    141 	}
    142 	memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid));
    143 
    144 	hdr.image_time = time(0);
    145 	write_header(fd, &hdr, fs->blocksize);
    146 }
    147 
    148 /*
    149  * These set of functions are used to write a RAW image file.
    150  */
    151 ext2fs_block_bitmap meta_block_map;
    152 ext2fs_block_bitmap scramble_block_map;	/* Directory blocks to be scrambled */
    153 
    154 struct process_block_struct {
    155 	ext2_ino_t	ino;
    156 	int		is_dir;
    157 };
    158 
    159 /*
    160  * These subroutines short circuits ext2fs_get_blocks and
    161  * ext2fs_check_directory; we use them since we already have the inode
    162  * structure, so there's no point in letting the ext2fs library read
    163  * the inode again.
    164  */
    165 static ino_t stashed_ino = 0;
    166 static struct ext2_inode *stashed_inode;
    167 
    168 static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
    169 				 ext2_ino_t ino,
    170 				 blk_t *blocks)
    171 {
    172 	int	i;
    173 
    174 	if ((ino != stashed_ino) || !stashed_inode)
    175 		return EXT2_ET_CALLBACK_NOTHANDLED;
    176 
    177 	for (i=0; i < EXT2_N_BLOCKS; i++)
    178 		blocks[i] = stashed_inode->i_block[i];
    179 	return 0;
    180 }
    181 
    182 static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
    183 				      ext2_ino_t ino)
    184 {
    185 	if ((ino != stashed_ino) || !stashed_inode)
    186 		return EXT2_ET_CALLBACK_NOTHANDLED;
    187 
    188 	if (!LINUX_S_ISDIR(stashed_inode->i_mode))
    189 		return EXT2_ET_NO_DIRECTORY;
    190 	return 0;
    191 }
    192 
    193 static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
    194 				 ext2_ino_t ino,
    195 				 struct ext2_inode *inode)
    196 {
    197 	if ((ino != stashed_ino) || !stashed_inode)
    198 		return EXT2_ET_CALLBACK_NOTHANDLED;
    199 	*inode = *stashed_inode;
    200 	return 0;
    201 }
    202 
    203 static void use_inode_shortcuts(ext2_filsys fs, int bool)
    204 {
    205 	if (bool) {
    206 		fs->get_blocks = meta_get_blocks;
    207 		fs->check_directory = meta_check_directory;
    208 		fs->read_inode = meta_read_inode;
    209 		stashed_ino = 0;
    210 	} else {
    211 		fs->get_blocks = 0;
    212 		fs->check_directory = 0;
    213 		fs->read_inode = 0;
    214 	}
    215 }
    216 
    217 static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
    218 			     blk_t *block_nr,
    219 			     e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
    220 			     blk_t ref_block EXT2FS_ATTR((unused)),
    221 			     int ref_offset EXT2FS_ATTR((unused)),
    222 			     void *priv_data EXT2FS_ATTR((unused)))
    223 {
    224 	struct process_block_struct *p;
    225 
    226 	p = (struct process_block_struct *) priv_data;
    227 
    228 	ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
    229 	if (scramble_block_map && p->is_dir && blockcnt >= 0)
    230 		ext2fs_mark_block_bitmap(scramble_block_map, *block_nr);
    231 	return 0;
    232 }
    233 
    234 static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)),
    235 			      blk_t *block_nr,
    236 			      e2_blkcnt_t blockcnt,
    237 			      blk_t ref_block EXT2FS_ATTR((unused)),
    238 			      int ref_offset EXT2FS_ATTR((unused)),
    239 			      void *priv_data EXT2FS_ATTR((unused)))
    240 {
    241 	if (blockcnt < 0) {
    242 		ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
    243 	}
    244 	return 0;
    245 }
    246 
    247 static void mark_table_blocks(ext2_filsys fs)
    248 {
    249 	blk_t	first_block, b;
    250 	unsigned int	i,j;
    251 
    252 	first_block = fs->super->s_first_data_block;
    253 	/*
    254 	 * Mark primary superblock
    255 	 */
    256 	ext2fs_mark_block_bitmap(meta_block_map, first_block);
    257 
    258 	/*
    259 	 * Mark the primary superblock descriptors
    260 	 */
    261 	for (j = 0; j < fs->desc_blocks; j++) {
    262 		ext2fs_mark_block_bitmap(meta_block_map,
    263 			 ext2fs_descriptor_block_loc(fs, first_block, j));
    264 	}
    265 
    266 	for (i = 0; i < fs->group_desc_count; i++) {
    267 		/*
    268 		 * Mark the blocks used for the inode table
    269 		 */
    270 		if (fs->group_desc[i].bg_inode_table) {
    271 			for (j = 0, b = fs->group_desc[i].bg_inode_table;
    272 			     j < (unsigned) fs->inode_blocks_per_group;
    273 			     j++, b++)
    274 				ext2fs_mark_block_bitmap(meta_block_map, b);
    275 		}
    276 
    277 		/*
    278 		 * Mark block used for the block bitmap
    279 		 */
    280 		if (fs->group_desc[i].bg_block_bitmap) {
    281 			ext2fs_mark_block_bitmap(meta_block_map,
    282 				     fs->group_desc[i].bg_block_bitmap);
    283 		}
    284 
    285 		/*
    286 		 * Mark block used for the inode bitmap
    287 		 */
    288 		if (fs->group_desc[i].bg_inode_bitmap) {
    289 			ext2fs_mark_block_bitmap(meta_block_map,
    290 				 fs->group_desc[i].bg_inode_bitmap);
    291 		}
    292 	}
    293 }
    294 
    295 /*
    296  * This function returns 1 if the specified block is all zeros
    297  */
    298 static int check_zero_block(char *buf, int blocksize)
    299 {
    300 	char	*cp = buf;
    301 	int	left = blocksize;
    302 
    303 	while (left > 0) {
    304 		if (*cp++)
    305 			return 0;
    306 		left--;
    307 	}
    308 	return 1;
    309 }
    310 
    311 static void write_block(int fd, char *buf, int sparse_offset,
    312 			int blocksize, blk_t block)
    313 {
    314 	int		count;
    315 	errcode_t	err;
    316 
    317 	if (sparse_offset) {
    318 #ifdef HAVE_LSEEK64
    319 		if (lseek64(fd, sparse_offset, SEEK_CUR) < 0)
    320 			perror("lseek");
    321 #else
    322 		if (lseek(fd, sparse_offset, SEEK_CUR) < 0)
    323 			perror("lseek");
    324 #endif
    325 	}
    326 	if (blocksize) {
    327 		count = write(fd, buf, blocksize);
    328 		if (count != blocksize) {
    329 			if (count == -1)
    330 				err = errno;
    331 			else
    332 				err = 0;
    333 			com_err(program_name, err, "error writing block %u",
    334 				block);
    335 			exit(1);
    336 		}
    337 	}
    338 }
    339 
    340 int name_id[256];
    341 
    342 #define EXT4_MAX_REC_LEN		((1<<16)-1)
    343 
    344 static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
    345 {
    346 	char *p, *end, *cp;
    347 	struct ext2_dir_entry_2 *dirent;
    348 	unsigned int rec_len;
    349 	int id, len;
    350 
    351 	end = buf + fs->blocksize;
    352 	for (p = buf; p < end-8; p += rec_len) {
    353 		dirent = (struct ext2_dir_entry_2 *) p;
    354 		rec_len = dirent->rec_len;
    355 #ifdef WORDS_BIGENDIAN
    356 		rec_len = ext2fs_swab16(rec_len);
    357 #endif
    358 		if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
    359 			rec_len = fs->blocksize;
    360 		else
    361 			rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
    362 #if 0
    363 		printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
    364 #endif
    365 		if (rec_len < 8 || (rec_len % 4) ||
    366 		    (p+rec_len > end)) {
    367 			printf("Corrupt directory block %lu: "
    368 			       "bad rec_len (%d)\n", (unsigned long) blk,
    369 			       rec_len);
    370 			rec_len = end - p;
    371 			(void) ext2fs_set_rec_len(fs, rec_len,
    372 					(struct ext2_dir_entry *) dirent);
    373 #ifdef WORDS_BIGENDIAN
    374 			dirent->rec_len = ext2fs_swab16(dirent->rec_len);
    375 #endif
    376 			continue;
    377 		}
    378 		if (dirent->name_len + 8 > rec_len) {
    379 			printf("Corrupt directory block %lu: "
    380 			       "bad name_len (%d)\n", (unsigned long) blk,
    381 			       dirent->name_len);
    382 			dirent->name_len = rec_len - 8;
    383 			continue;
    384 		}
    385 		cp = p+8;
    386 		len = rec_len - dirent->name_len - 8;
    387 		if (len > 0)
    388 			memset(cp+dirent->name_len, 0, len);
    389 		if (dirent->name_len==1 && cp[0] == '.')
    390 			continue;
    391 		if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
    392 			continue;
    393 
    394 		memset(cp, 'A', dirent->name_len);
    395 		len = dirent->name_len;
    396 		id = name_id[len]++;
    397 		while ((len > 0) && (id > 0)) {
    398 			*cp += id % 26;
    399 			id = id / 26;
    400 			cp++;
    401 			len--;
    402 		}
    403 	}
    404 }
    405 
    406 static void output_meta_data_blocks(ext2_filsys fs, int fd)
    407 {
    408 	errcode_t	retval;
    409 	blk_t		blk;
    410 	char		*buf, *zero_buf;
    411 	int		sparse = 0;
    412 
    413 	buf = malloc(fs->blocksize);
    414 	if (!buf) {
    415 		com_err(program_name, ENOMEM, "while allocating buffer");
    416 		exit(1);
    417 	}
    418 	zero_buf = malloc(fs->blocksize);
    419 	if (!zero_buf) {
    420 		com_err(program_name, ENOMEM, "while allocating buffer");
    421 		exit(1);
    422 	}
    423 	memset(zero_buf, 0, fs->blocksize);
    424 	for (blk = 0; blk < fs->super->s_blocks_count; blk++) {
    425 		if ((blk >= fs->super->s_first_data_block) &&
    426 		    ext2fs_test_block_bitmap(meta_block_map, blk)) {
    427 			retval = io_channel_read_blk(fs->io, blk, 1, buf);
    428 			if (retval) {
    429 				com_err(program_name, retval,
    430 					"error reading block %u", blk);
    431 			}
    432 			if (scramble_block_map &&
    433 			    ext2fs_test_block_bitmap(scramble_block_map, blk))
    434 				scramble_dir_block(fs, blk, buf);
    435 			if ((fd != 1) && check_zero_block(buf, fs->blocksize))
    436 				goto sparse_write;
    437 			write_block(fd, buf, sparse, fs->blocksize, blk);
    438 			sparse = 0;
    439 		} else {
    440 		sparse_write:
    441 			if (fd == 1) {
    442 				write_block(fd, zero_buf, 0,
    443 					    fs->blocksize, blk);
    444 				continue;
    445 			}
    446 			sparse += fs->blocksize;
    447 			if (sparse >= 1024*1024) {
    448 				write_block(fd, 0, sparse, 0, 0);
    449 				sparse = 0;
    450 			}
    451 		}
    452 	}
    453 	if (sparse)
    454 		write_block(fd, zero_buf, sparse-1, 1, -1);
    455 	free(zero_buf);
    456 	free(buf);
    457 }
    458 
    459 static void write_raw_image_file(ext2_filsys fs, int fd, int scramble_flag)
    460 {
    461 	struct process_block_struct	pb;
    462 	struct ext2_inode		inode;
    463 	ext2_inode_scan			scan;
    464 	ext2_ino_t			ino;
    465 	errcode_t			retval;
    466 	char *				block_buf;
    467 
    468 	retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
    469 					      &meta_block_map);
    470 	if (retval) {
    471 		com_err(program_name, retval, "while allocating block bitmap");
    472 		exit(1);
    473 	}
    474 
    475 	if (scramble_flag) {
    476 		retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
    477 						      &scramble_block_map);
    478 		if (retval) {
    479 			com_err(program_name, retval,
    480 				"while allocating scramble block bitmap");
    481 			exit(1);
    482 		}
    483 	}
    484 
    485 	mark_table_blocks(fs);
    486 
    487 	retval = ext2fs_open_inode_scan(fs, 0, &scan);
    488 	if (retval) {
    489 		com_err(program_name, retval, _("while opening inode scan"));
    490 		exit(1);
    491 	}
    492 
    493 	block_buf = malloc(fs->blocksize * 3);
    494 	if (!block_buf) {
    495 		com_err(program_name, 0, "Can't allocate block buffer");
    496 		exit(1);
    497 	}
    498 
    499 	use_inode_shortcuts(fs, 1);
    500 	stashed_inode = &inode;
    501 	while (1) {
    502 		retval = ext2fs_get_next_inode(scan, &ino, &inode);
    503 		if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
    504 			continue;
    505 		if (retval) {
    506 			com_err(program_name, retval,
    507 				_("while getting next inode"));
    508 			exit(1);
    509 		}
    510 		if (ino == 0)
    511 			break;
    512 		if (!inode.i_links_count)
    513 			continue;
    514 		if (inode.i_file_acl) {
    515 			ext2fs_mark_block_bitmap(meta_block_map,
    516 						 inode.i_file_acl);
    517 		}
    518 		if (!ext2fs_inode_has_valid_blocks(&inode))
    519 			continue;
    520 
    521 		stashed_ino = ino;
    522 		pb.ino = ino;
    523 		pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
    524 		if (LINUX_S_ISDIR(inode.i_mode) ||
    525 		    (LINUX_S_ISLNK(inode.i_mode) &&
    526 		     ext2fs_inode_has_valid_blocks(&inode)) ||
    527 		    ino == fs->super->s_journal_inum) {
    528 			retval = ext2fs_block_iterate2(fs, ino,
    529 					BLOCK_FLAG_READ_ONLY, block_buf,
    530 					process_dir_block, &pb);
    531 			if (retval) {
    532 				com_err(program_name, retval,
    533 					"while iterating over inode %u",
    534 					ino);
    535 				exit(1);
    536 			}
    537 		} else {
    538 			if ((inode.i_flags & EXT4_EXTENTS_FL) ||
    539 			    inode.i_block[EXT2_IND_BLOCK] ||
    540 			    inode.i_block[EXT2_DIND_BLOCK] ||
    541 			    inode.i_block[EXT2_TIND_BLOCK]) {
    542 				retval = ext2fs_block_iterate2(fs,
    543 				       ino, BLOCK_FLAG_READ_ONLY, block_buf,
    544 				       process_file_block, &pb);
    545 				if (retval) {
    546 					com_err(program_name, retval,
    547 					"while iterating over inode %u", ino);
    548 					exit(1);
    549 				}
    550 			}
    551 		}
    552 	}
    553 	use_inode_shortcuts(fs, 0);
    554 	output_meta_data_blocks(fs, fd);
    555 	free(block_buf);
    556 }
    557 
    558 static void install_image(char *device, char *image_fn, int raw_flag)
    559 {
    560 	errcode_t retval;
    561 	ext2_filsys fs;
    562 	int open_flag = EXT2_FLAG_IMAGE_FILE;
    563 	int fd = 0;
    564 	io_manager	io_ptr;
    565 	io_channel	io, image_io;
    566 
    567 	if (raw_flag) {
    568 		com_err(program_name, 0, "Raw images cannot be installed");
    569 		exit(1);
    570 	}
    571 
    572 #ifdef CONFIG_TESTIO_DEBUG
    573 	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
    574 		io_ptr = test_io_manager;
    575 		test_io_backing_manager = unix_io_manager;
    576 	} else
    577 #endif
    578 		io_ptr = unix_io_manager;
    579 
    580 	retval = ext2fs_open (image_fn, open_flag, 0, 0,
    581 			      io_ptr, &fs);
    582         if (retval) {
    583 		com_err (program_name, retval, _("while trying to open %s"),
    584 			 image_fn);
    585 		exit(1);
    586 	}
    587 
    588 	retval = ext2fs_read_bitmaps (fs);
    589 	if (retval) {
    590 		com_err(program_name, retval, "error reading bitmaps");
    591 		exit(1);
    592 	}
    593 
    594 #ifdef HAVE_OPEN64
    595 	fd = open64(image_fn, O_RDONLY);
    596 #else
    597 	fd = open(image_fn, O_RDONLY);
    598 #endif
    599 	if (fd < 0) {
    600 		perror(image_fn);
    601 		exit(1);
    602 	}
    603 
    604 	retval = io_ptr->open(device, IO_FLAG_RW, &io);
    605 	if (retval) {
    606 		com_err(device, 0, "while opening device file");
    607 		exit(1);
    608 	}
    609 
    610 	image_io = fs->io;
    611 
    612 	ext2fs_rewrite_to_io(fs, io);
    613 
    614 	if (lseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) {
    615 		perror("lseek");
    616 		exit(1);
    617 	}
    618 
    619 	retval = ext2fs_image_inode_read(fs, fd, 0);
    620 	if (retval) {
    621 		com_err(image_fn, 0, "while restoring the image table");
    622 		exit(1);
    623 	}
    624 
    625 	ext2fs_close (fs);
    626 	exit (0);
    627 }
    628 
    629 int main (int argc, char ** argv)
    630 {
    631 	int c;
    632 	errcode_t retval;
    633 	ext2_filsys fs;
    634 	char *image_fn;
    635 	int open_flag = 0;
    636 	int raw_flag = 0;
    637 	int install_flag = 0;
    638 	int scramble_flag = 0;
    639 	int fd = 0;
    640 
    641 #ifdef ENABLE_NLS
    642 	setlocale(LC_MESSAGES, "");
    643 	setlocale(LC_CTYPE, "");
    644 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    645 	textdomain(NLS_CAT_NAME);
    646 #endif
    647 	fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
    648 		 E2FSPROGS_DATE);
    649 	if (argc && *argv)
    650 		program_name = *argv;
    651 	add_error_table(&et_ext2_error_table);
    652 	while ((c = getopt (argc, argv, "rsI")) != EOF)
    653 		switch (c) {
    654 		case 'r':
    655 			raw_flag++;
    656 			break;
    657 		case 's':
    658 			scramble_flag++;
    659 			break;
    660 		case 'I':
    661 			install_flag++;
    662 			break;
    663 		default:
    664 			usage();
    665 		}
    666 	if (optind != argc - 2 )
    667 		usage();
    668 	device_name = argv[optind];
    669 	image_fn = argv[optind+1];
    670 
    671 	if (install_flag) {
    672 		install_image(device_name, image_fn, raw_flag);
    673 		exit (0);
    674 	}
    675 
    676 	retval = ext2fs_open (device_name, open_flag, 0, 0,
    677 			      unix_io_manager, &fs);
    678         if (retval) {
    679 		com_err (program_name, retval, _("while trying to open %s"),
    680 			 device_name);
    681 		fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
    682 		exit(1);
    683 	}
    684 
    685 	if (strcmp(image_fn, "-") == 0)
    686 		fd = 1;
    687 	else {
    688 #ifdef HAVE_OPEN64
    689 		fd = open64(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
    690 #else
    691 		fd = open(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
    692 #endif
    693 		if (fd < 0) {
    694 			com_err(program_name, errno,
    695 				_("while trying to open %s"), argv[optind+1]);
    696 			exit(1);
    697 		}
    698 	}
    699 
    700 	if (raw_flag)
    701 		write_raw_image_file(fs, fd, scramble_flag);
    702 	else
    703 		write_image_file(fs, fd);
    704 
    705 	ext2fs_close (fs);
    706 	remove_error_table(&et_ext2_error_table);
    707 	exit (0);
    708 }
    709