3 * Copyright (c) International Business Machines Corp., 2000
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <sys/ioctl.h>
30 #include <sys/types.h>
35 int fsim_rw_diskblocks( int, int64_t, int32_t, void *, int );
36 void set_mkfs_options( option_array_t *, char **, logical_volume_t *, char * );
37 void set_fsck_options( option_array_t *, char **, logical_volume_t * );
39 /* Vector of plugin record ptrs that we export for the EVMS Engine. */
40 plugin_record_t *evms_plugin_records[] = {
45 static plugin_record_t * pMyPluginRecord = &ext2_plugrec;
47 /*-------------------------------------------------------------------------------------+
51 +--------------------------------------------------------------------------------------*/
55 * Get the size limits for this volume.
57 int fsim_get_volume_limits( struct ext2_super_block * sb,
58 sector_count_t * fs_min_size,
59 sector_count_t * fs_max_size,
60 sector_count_t * vol_max_size)
65 blk_to_sect = (1 + sb->s_log_block_size);
66 *fs_min_size = (sb->s_blocks_count - sb->s_free_blocks_count) << blk_to_sect;
67 *fs_max_size = (sector_count_t) 1 << (32+blk_to_sect);
68 *vol_max_size = 0xffffffffff;
76 * Un-Format the volume.
78 int fsim_unmkfs( logical_volume_t * volume )
85 fd = open(EVMS_GET_DEVNAME(volume), O_RDWR|O_EXCL, 0);
86 if (fd < 0) return -1;
88 if ( volume->private_data ) {
89 /* clear private data */
90 memset( (void *) volume->private_data, 0, SIZE_OF_SUPER );
91 /* zero primary superblock */
92 rc = fsim_rw_diskblocks( fd, EXT2_SUPER_LOC, SIZE_OF_SUPER,
93 volume->private_data, PUT );
108 int fsim_mkfs(logical_volume_t * volume, option_array_t * options )
111 char *argv[MKFS_EXT2_OPTIONS_COUNT + 6];
112 char logsize[sizeof(unsigned int) + 1];
118 /* Fork and execute the correct program. */
119 switch (pidm = fork()) {
127 set_mkfs_options( options, argv, volume, logsize );
129 /* close stderr, stdout to suppress mke2fs output */
132 open("/dev/null", O_WRONLY);
133 open("/dev/null", O_WRONLY);
135 (void) execvp(argv[0], argv);
136 /* using exit() can hang GUI, use _exit */
141 /* wait for child to complete */
143 rc = waitpid( pidm, &status, 0 );
152 if ( WIFEXITED(status) ) {
153 /* get mke2fs exit code */
154 rc = WEXITSTATUS(status);
156 LOG("mke2fs exited with status %d", rc);
158 if (WIFSIGNALED(status))
159 LOG("mke2fs died with signal %d",
172 * NAME: set_mkfs_options
174 * FUNCTION: Build options array (argv) for mkfs.ext2
177 * options - options array passed from EVMS engine
178 * argv - mkfs options array
179 * vol_name - volume name on which program will be executed
182 void set_mkfs_options( option_array_t * options,
184 logical_volume_t * volume,
187 int i, bufsize, opt_count = 2;
197 /* the following is a big hack to make sure that we don't use a block */
198 /* size smaller than hardsector size since this does not work. */
199 /* would be nice if the ext2/3 utilities (mkfs) handled this themselves */
200 /* also, eventually we will implement this as a user option to manually */
202 if (volume->object->geometry.bytes_per_sector != EVMS_VSECTOR_SIZE) {
203 switch (volume->object->geometry.bytes_per_sector) {
213 /* not one we expect, just skip it */
218 for ( i=0; i<options->count; i++ ) {
220 if ( options->option[i].is_number_based ) {
222 switch (options->option[i].number) {
224 case MKFS_CHECKBB_INDEX:
225 /* 'check for bad blocks' option */
226 if ( options->option[i].value.bool == TRUE ) {
227 argv[opt_count++] = "-c";
231 case MKFS_CHECKRW_INDEX:
232 /* 'check for r/w bad blocks' option */
233 if ( options->option[i].value.bool == TRUE ) {
234 argv[opt_count++] = "-cc";
238 case MKFS_JOURNAL_INDEX:
239 /* 'create ext3 journal' option */
240 if ( options->option[i].value.bool == TRUE ) {
241 argv[opt_count++] = "-j";
245 case MKFS_SETVOL_INDEX:
246 /* 'set volume name' option */
247 if ( options->option[i].value.s ) {
248 argv[opt_count++] = "-L";
249 argv[opt_count++] = options->option[i].value.s;
259 if ( !strcmp(options->option[i].name, "badblocks") ) {
260 /* 'check for bad blocks' option */
261 if ( options->option[i].value.bool == TRUE ) {
262 argv[opt_count++] = "-c";
266 if ( !strcmp(options->option[i].name, "badblocks_rw") ) {
267 /* 'check for r/w bad blocks' option */
268 if ( options->option[i].value.bool == TRUE ) {
269 argv[opt_count++] = "-cc";
273 if ( !strcmp(options->option[i].name, "journal") ) {
274 /* 'create ext3 journal' option */
275 if ( options->option[i].value.bool == TRUE ) {
276 argv[opt_count++] = "-j";
280 if ( !strcmp(options->option[i].name, "vollabel") ) {
281 /* 'check for bad blocks' option */
282 if ( options->option[i].value.s ) {
283 argv[opt_count++] = "-L";
284 argv[opt_count++] = options->option[i].value.s;
290 argv[opt_count++] = EVMS_GET_DEVNAME(volume);
291 argv[opt_count] = NULL;
294 for (i=0; argv[i]; i++)
295 bufsize += strlen(argv[i]) + 5;
296 buf = malloc(bufsize+1);
300 for (i=0; argv[i]; i++) {
301 strcat(buf, argv[i]);
304 EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
305 "mke2fs command: %s\n", buf);
314 * Run fsck on the volume.
316 int fsim_fsck(logical_volume_t * volume, option_array_t * options,
320 char *argv[FSCK_EXT2_OPTIONS_COUNT + 3];
322 int status, bytes_read;
329 /* open pipe, alloc buffer for collecting fsck.jfs output */
334 if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) {
338 /* Fork and execute the correct program. */
339 switch (pidf = fork()) {
347 set_fsck_options( options, argv, volume );
349 /* pipe stderr, stdout */
350 dup2(fds2[1],1); /* fds2[1] replaces stdout */
351 dup2(fds2[1],2); /* fds2[1] replaces stderr */
352 close(fds2[0]); /* don't need this here */
354 execvp( argv[0], argv );
355 /* should never get here */
356 _exit(8); /* FSCK_ERROR -- operational error */
362 /* wait for child to complete */
363 fcntl(fds2[0], F_SETFL, fcntl(fds2[0], F_GETFL,0) | O_NONBLOCK);
364 while (!(waitpid( pidf, &status, WNOHANG ))) {
365 /* read e2fsck output */
366 bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
367 if (bytes_read > 0) {
368 /* display e2fsck output */
370 MESSAGE("e2fsck output:");
372 MESSAGE("%s",buffer);
373 memset(buffer,0,bytes_read); /* clear out message */
375 usleep(10000); /* don't hog all the cpu */
378 /* do final read, just in case we missed some */
379 bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
380 if (bytes_read > 0) {
382 MESSAGE("e2fsck output:");
383 MESSAGE("%s",buffer);
385 if ( WIFEXITED(status) ) {
386 /* get e2fsck exit code */
387 *ret_status = WEXITSTATUS(status);
388 LOG("e2fsck completed with exit code %d\n",
392 if (WIFSIGNALED(status))
393 LOG("e2fsck died with signal %d",
400 EngFncs->engine_free(buffer);
411 * NAME: set_fsck_options
413 * FUNCTION: Build options array (argv) for e2fsck
416 * options - options array passed from EVMS engine
417 * argv - fsck options array
418 * volume - volume on which program will be executed
421 void set_fsck_options( option_array_t * options, char ** argv, logical_volume_t * volume )
423 int i, bufsize, num_opts, opt_count = 1;
432 num_opts = options->count;
434 /* No options, assume force (for resizing) */
435 argv[opt_count++] = "-f";
439 for ( i=0; i < num_opts; i++) {
441 if ( options->option[i].is_number_based ) {
443 /* 'force check' option */
444 if ( (options->option[i].number == FSCK_FORCE_INDEX) &&
445 (options->option[i].value.bool == TRUE) ) {
446 argv[opt_count++] = "-f";
449 /* 'check read only' option or mounted */
450 if ((options->option[i].number == FSCK_READONLY_INDEX) &&
451 ((options->option[i].value.bool == TRUE) ||
452 EVMS_IS_MOUNTED(volume))) {
453 argv[opt_count++] = "-n";
457 /* 'bad blocks check' option and NOT mounted */
458 if ( (options->option[i].number == FSCK_CHECKBB_INDEX) &&
459 (options->option[i].value.bool == TRUE) &&
460 !EVMS_IS_MOUNTED(volume) ) {
461 argv[opt_count++] = "-c";
465 /* 'bad blocks check' option and NOT mounted */
466 if ( (options->option[i].number == FSCK_CHECKRW_INDEX) &&
467 (options->option[i].value.bool == TRUE) &&
468 !EVMS_IS_MOUNTED(volume) ) {
469 argv[opt_count++] = "-cc";
474 if ( (options->option[i].number == FSCK_TIMING_INDEX) &&
475 (options->option[i].value.bool == TRUE) ) {
476 argv[opt_count++] = "-tt";
481 /* 'force check' option selected and NOT mounted */
482 if ( !strcmp(options->option[i].name, "force") &&
483 (options->option[i].value.bool == TRUE) &&
484 !EVMS_IS_MOUNTED(volume) ) {
485 argv[opt_count++] = "-f";
488 /* 'check read only' option selected or mounted */
489 if ((!strcmp(options->option[i].name, "readonly")) &&
490 ((options->option[i].value.bool == TRUE) ||
491 EVMS_IS_MOUNTED(volume))) {
492 argv[opt_count++] = "-n";
496 /* 'check badblocks' option selected and NOT mounted */
497 if (!strcmp(options->option[i].name, "badblocks") &&
498 (options->option[i].value.bool == TRUE) &&
499 !EVMS_IS_MOUNTED(volume)) {
500 argv[opt_count++] = "-c";
504 /* 'check r/w badblocks' option selected and NOT mounted */
505 if (!strcmp(options->option[i].name, "badblocks_rw") &&
506 (options->option[i].value.bool == TRUE) &&
507 !EVMS_IS_MOUNTED(volume)) {
508 argv[opt_count++] = "-cc";
512 /* 'timing' option selected */
513 if (!strcmp(options->option[i].name, "badblocks") &&
514 (options->option[i].value.bool == TRUE)) {
515 argv[opt_count++] = "-tt";
521 argv[opt_count++] = "-p";
522 argv[opt_count++] = EVMS_GET_DEVNAME(volume);
523 argv[opt_count] = NULL;
526 for (i=0; argv[i]; i++)
527 bufsize += strlen(argv[i]) + 5;
528 buf = malloc(bufsize+1);
532 for (i=0; argv[i]; i++) {
533 strcat(buf, argv[i]);
536 EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
537 "fsck command: %s\n", buf);
544 * NAME:ext2fs_swap_super
546 * FUNCTION: Swap all fields in the super block to CPU format.
549 * sb - pointer to superblock
554 static void ext2fs_swap_super(struct ext2_super_block * sb)
557 sb->s_inodes_count = DISK_TO_CPU32(sb->s_inodes_count);
558 sb->s_blocks_count = DISK_TO_CPU32(sb->s_blocks_count);
559 sb->s_r_blocks_count = DISK_TO_CPU32(sb->s_r_blocks_count);
560 sb->s_free_blocks_count = DISK_TO_CPU32(sb->s_free_blocks_count);
561 sb->s_free_inodes_count = DISK_TO_CPU32(sb->s_free_inodes_count);
562 sb->s_first_data_block = DISK_TO_CPU32(sb->s_first_data_block);
563 sb->s_log_block_size = DISK_TO_CPU32(sb->s_log_block_size);
564 sb->s_log_frag_size = DISK_TO_CPU32(sb->s_log_frag_size);
565 sb->s_blocks_per_group = DISK_TO_CPU32(sb->s_blocks_per_group);
566 sb->s_frags_per_group = DISK_TO_CPU32(sb->s_frags_per_group);
567 sb->s_inodes_per_group = DISK_TO_CPU32(sb->s_inodes_per_group);
568 sb->s_mtime = DISK_TO_CPU32(sb->s_mtime);
569 sb->s_wtime = DISK_TO_CPU32(sb->s_wtime);
570 sb->s_mnt_count = DISK_TO_CPU16(sb->s_mnt_count);
571 sb->s_max_mnt_count = DISK_TO_CPU16(sb->s_max_mnt_count);
572 sb->s_magic = DISK_TO_CPU16(sb->s_magic);
573 sb->s_state = DISK_TO_CPU16(sb->s_state);
574 sb->s_errors = DISK_TO_CPU16(sb->s_errors);
575 sb->s_minor_rev_level = DISK_TO_CPU16(sb->s_minor_rev_level);
576 sb->s_lastcheck = DISK_TO_CPU32(sb->s_lastcheck);
577 sb->s_checkinterval = DISK_TO_CPU32(sb->s_checkinterval);
578 sb->s_creator_os = DISK_TO_CPU32(sb->s_creator_os);
579 sb->s_rev_level = DISK_TO_CPU32(sb->s_rev_level);
580 sb->s_def_resuid = DISK_TO_CPU16(sb->s_def_resuid);
581 sb->s_def_resgid = DISK_TO_CPU16(sb->s_def_resgid);
582 sb->s_first_ino = DISK_TO_CPU32(sb->s_first_ino);
583 sb->s_inode_size = DISK_TO_CPU16(sb->s_inode_size);
584 sb->s_block_group_nr = DISK_TO_CPU16(sb->s_block_group_nr);
585 sb->s_feature_compat = DISK_TO_CPU32(sb->s_feature_compat);
586 sb->s_feature_incompat = DISK_TO_CPU32(sb->s_feature_incompat);
587 sb->s_feature_ro_compat = DISK_TO_CPU32(sb->s_feature_ro_compat);
588 sb->s_algorithm_usage_bitmap = DISK_TO_CPU32(sb->s_algorithm_usage_bitmap);
589 sb->s_journal_inum = DISK_TO_CPU32(sb->s_journal_inum);
590 sb->s_journal_dev = DISK_TO_CPU32(sb->s_journal_dev);
591 sb->s_last_orphan = DISK_TO_CPU32(sb->s_last_orphan);
597 * NAME: fsim_get_ext2_superblock
599 * FUNCTION: Get and validate a ext2/3 superblock
602 * volume - pointer to volume from which to get the superblock
603 * sb_ptr - pointer to superblock
610 int fsim_get_ext2_superblock( logical_volume_t *volume, struct ext2_super_block *sb_ptr )
617 fd = open(EVMS_GET_DEVNAME(volume), O_RDONLY, 0);
624 /* get primary superblock */
625 rc = fsim_rw_diskblocks( fd, EXT2_SUPER_LOC, SIZE_OF_SUPER, sb_ptr, GET );
628 ext2fs_swap_super(sb_ptr);
629 /* see if superblock is ext2/3 */
630 if (( sb_ptr->s_magic != EXT2_SUPER_MAGIC ) ||
631 ( sb_ptr->s_rev_level > 1 ))
643 * NAME: fsim_rw_diskblocks
645 * FUNCTION: Read or write specific number of bytes for an opened device.
648 * dev_ptr - file handle of an opened device to read/write
649 * disk_offset - byte offset from beginning of device for start of disk
651 * disk_count - number of bytes to read/write
652 * data_buffer - On read this will be filled in with data read from
653 * disk; on write this contains data to be written
654 * mode - GET (read) or PUT (write)
657 * FSIM_SUCCESS (0) for success
658 * ERROR (-1) can't lseek
663 int fsim_rw_diskblocks( int dev_ptr,
669 off_t Actual_Location;
670 size_t Bytes_Transferred;
675 Actual_Location = lseek(dev_ptr,disk_offset, SEEK_SET);
676 if ( ( Actual_Location < 0 ) || ( Actual_Location != disk_offset ) )
681 Bytes_Transferred = read(dev_ptr,data_buffer,disk_count);
684 Bytes_Transferred = write(dev_ptr,data_buffer,disk_count);
693 if ( Bytes_Transferred != disk_count ) {
705 * Test e2fsprogs version.
707 * We don't bother since we don't need any special functionality that
708 * hasn't been around for *years*
710 int fsim_test_version( )