• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
usage(void)50 static void usage(void)
51 {
52 	fprintf(stderr, _("Usage: %s [-rsI] device image_file\n"),
53 		program_name);
54 	exit (1);
55 }
56 
write_header(int fd,struct ext2_image_hdr * hdr,int blocksize)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 
write_image_file(ext2_filsys fs,int fd)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 
meta_get_blocks(ext2_filsys fs EXT2FS_ATTR ((unused)),ext2_ino_t ino,blk_t * blocks)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 
meta_check_directory(ext2_filsys fs EXT2FS_ATTR ((unused)),ext2_ino_t ino)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 
meta_read_inode(ext2_filsys fs EXT2FS_ATTR ((unused)),ext2_ino_t ino,struct ext2_inode * inode)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 
use_inode_shortcuts(ext2_filsys fs,int bool)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 
process_dir_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk_t * block_nr,e2_blkcnt_t blockcnt EXT2FS_ATTR ((unused)),blk_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data EXT2FS_ATTR ((unused)))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 
process_file_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk_t * block_nr,e2_blkcnt_t blockcnt,blk_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data EXT2FS_ATTR ((unused)))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 
mark_table_blocks(ext2_filsys fs)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  */
check_zero_block(char * buf,int blocksize)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 
write_block(int fd,char * buf,int sparse_offset,int blocksize,blk_t block)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 
scramble_dir_block(ext2_filsys fs,blk_t blk,char * buf)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 
output_meta_data_blocks(ext2_filsys fs,int fd)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 
write_raw_image_file(ext2_filsys fs,int fd,int scramble_flag)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 
install_image(char * device,char * image_fn,int raw_flag)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 
main(int argc,char ** argv)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