#include <unistd.h>
#include <errno.h>
#include <plugin.h>
+#include <sys/wait.h>
#include "fsimext2.h"
static plugin_record_t *pMyPluginRecord = &ext2_plugrec;
* this here in case we do at a later date....
*/
rc = fsim_test_version();
+#if 0
if ( rc ) {
MESSAGE( "e2fsprogs must be version 1.XXX or later to function properly with this FSIM." );
MESSAGE( "Please get the current version of e2fsprogs from http://e2fsprogs.sourceforge.net" );
rc = ENOSYS;
}
-
+#endif
LOGEXIT();
return rc;
}
static int fs_expand( logical_volume_t * volume,
sector_count_t * new_size )
{
- /* unsupported at this time */
- int rc = ENOSYS;
+ struct ext2_super_block *sb;
+ int rc = 0;
+ char *argv[7];
+ pid_t pidf;
+ int status;
+ int fds1[2]; /* pipe for stdin 0=read 1=write */
+ int fds2[2]; /* pipe for stderr and stdout 0=-read,1=write */
+ int bytes_read;
+ char *buffer = NULL;
+ int banner = 0;
LOGENTRY();
+
+ /* get and validate current ext2/3 superblock */
+ sb = (struct ext2_super_block *) volume->private_data;
+ rc = fsim_get_ext2_superblock( volume, sb );
+ if ((sb->s_lastcheck < sb->s_mtime) ||
+ (sb->s_state & EXT2_ERROR_FS) ||
+ ((sb->s_state & EXT2_VALID_FS) == 0)) {
+ MESSAGE("Running fsck before expanding volume");
+ rc = fsim_fsck(volume, NULL );
+ if (rc)
+ goto errout;
+ }
+
+ /* don't expand if mounted */
+ if (EngFncs->is_mounted(volume->name, NULL)) {
+ rc = EBUSY;
+ goto errout;
+ }
+
+ if (pipe(fds1)) {
+ rc = errno;
+ goto errout;
+ }
+ if (pipe(fds2)) {
+ rc = errno;
+ goto errout;
+ }
+ if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) {
+ rc = ENOMEM;
+ goto errout;
+ }
+
+ /* Fork and execute the correct program. */
+ switch (pidf = fork()) {
+
+ /* error */
+ case -1:
+ return EIO;
+
+ /* child */
+ case 0:
+ argv[0] = "resize2fs";
+ SET_STRING_FIELD(argv[1], EVMS_GET_DEVNAME(volume));
+ argv[2] = NULL;
+
+ dup2(fds1[0],0); /* fds1[0] replaces stdin */
+ dup2(fds2[1],1); /* fds2[1] replaces stdout */
+ dup2(fds2[1],2); /* fds2[1] replaces stderr */
+ close(fds2[0]); /* don't need this here */
+ close(fds1[1]); /* don't need this here */
+
+ rc = execvp( argv[0], argv );
+
+ /* using exit() can hang GUI, use _exit */
+ _exit(errno);
+
+ /* parent */
+ default:
+ /*
+ * WARNING: Do Not close read handle of stdin or
+ * you will cause a SIGPIPE if you write after the
+ * child process has gone away.
+ */
+/* close(fds1[0]); */
+ close(fds2[1]);
+
+ /* wait for child to complete */
+ while (!(pidf = waitpid( pidf, &status, WNOHANG ))) {
+ bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+ if (bytes_read > 0) {
+ if (!banner)
+ MESSAGE("expand output:");
+ banner = 1;
+ MESSAGE("%s", buffer);
+ memset(buffer,0,bytes_read); /* clear out message */
+ }
+ usleep(10000); /* don't hog all the cpu */
+ }
+ /* do final read, just in case we missed some */
+ bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+ if (bytes_read > 0) {
+ if (!banner)
+ MESSAGE("expand output:");
+ MESSAGE("%s",buffer);
+ }
+ if ( WIFEXITED(status) ) {
+ /* get expand exit code */
+ LOG("Expand completed with rc = %d \n",status);
+ rc = WEXITSTATUS(status);
+ }
+ }
+ if (buffer) {
+ EngFncs->engine_free(buffer);
+ }
+ fs_get_fs_size(volume, new_size);
+errout:
LOGEXITRC();
return rc;
}
sector_count_t requested_size,
sector_count_t * new_size )
{
- /* unsupported at this time */
- int rc = ENOSYS;
+ int rc = 0;
+ char *argv[7];
+ pid_t pidf;
+ int status;
+ int fds1[2]; /* pipe for stdin 0=read 1=write */
+ int fds2[2]; /* pipe for stderr and stdout 0=-read,1=write */
+ int bytes_read;
+ char *buffer = NULL;
+ char size_buf[128];
+ struct ext2_super_block *sb;
+ int banner = 0;
LOGENTRY();
+
+ /* don't shrink if mounted */
+ if (EVMS_IS_MOUNTED(volume)) {
+ LOGEXITRC();
+ return EBUSY;
+ }
+
+ /* get and validate current ext2/3 superblock */
+ sb = (struct ext2_super_block *) volume->private_data;
+ rc = fsim_get_ext2_superblock( volume, sb );
+ requested_size = requested_size >> (1 + sb->s_log_block_size);
+ if ((sb->s_lastcheck < sb->s_mtime) ||
+ (sb->s_state & EXT2_ERROR_FS) ||
+ ((sb->s_state & EXT2_VALID_FS) == 0)) {
+ MESSAGE("Running fsck before shrinking volume");
+ rc = fsim_fsck(volume, NULL );
+ if (rc)
+ goto errout;
+ }
+
+ if (pipe(fds1)) {
+ rc = errno;
+ goto errout;
+ }
+ if (pipe(fds2)) {
+ rc = errno;
+ goto errout;
+ }
+ if (!(buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN))) {
+ rc = ENOMEM;
+ goto errout;
+ }
+
+ /* Fork and execute the correct program. */
+ switch (pidf = fork()) {
+
+ /* error */
+ case -1:
+ return EIO;
+
+ /* child */
+ case 0:
+ argv[0] = "resize2fs";
+ SET_STRING_FIELD(argv[1], EVMS_GET_DEVNAME(volume));
+ sprintf(size_buf,"%lld", (sector_count_t)requested_size);
+ argv[2] = size_buf;
+ argv[3] = NULL;
+
+ dup2(fds1[0],0); /* fds1[0] replaces stdin */
+ dup2(fds2[1],1); /* fds2[1] replaces stdout */
+ dup2(fds2[1],2); /* fds2[1] replaces stderr */
+ close(fds2[0]); /* don't need this here */
+ close(fds1[1]); /* don't need this here */
+
+ rc = execvp( argv[0], argv );
+
+ /* using exit() can hang GUI, use _exit */
+ _exit(errno);
+
+ /* parent */
+ default:
+ /*
+ * WARNING: Do Not close read handle of stdin or you
+ * will cause a SIGPIPE if you write after the child
+ * process has gone away.
+ */
+ /* close(fds1[0]); */
+ close(fds2[1]);
+ write(fds1[1], "Yes\n",4);
+
+ /* wait for child to complete */
+ while (!(pidf = waitpid( pidf, &status, WNOHANG ))) {
+ bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+ if (bytes_read > 0) {
+ if (!banner)
+ MESSAGE("Shrink output:");
+ banner = 1;
+ MESSAGE("%s", buffer);
+ memset(buffer,0,bytes_read); /* clear out message */
+ }
+ usleep(10000); /* don't hog all the cpu */
+ }
+ /* do final read, just in case we missed some */
+ bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+ if (bytes_read > 0) {
+ if (!banner)
+ MESSAGE("Shrink output:");
+ MESSAGE("%s",buffer);
+ }
+ if ( WIFEXITED(status) ) {
+ /* get shrink exit code */
+ LOG("Shrink completed with rc = %d \n",status);
+ rc = WEXITSTATUS(status);
+ }
+ }
+ if (buffer) {
+ EngFncs->engine_free(buffer);
+ }
+ fs_get_fs_size(volume, new_size);
+errout:
LOGEXITRC();
return rc;
}
task_effect_t * effect )
{
int rc = 0;
- int64_t log_size;
- unsigned int max_log_size;
- logical_volume_t * vol;
+ logical_volume_t * vol;
LOGENTRY();
if (info) {
if (descriptor_name == NULL) {
- *info = NULL; // init to no info returned
+ *info = NULL; /* init to no info returned */
Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + (8*sizeof(extended_info_t)) );
if (Info) {
iptr->collection_type = EVMS_Collection_None;
memset( &iptr->group, 0, sizeof(group_info_t));
-#ifdef VERSION
+#if defined(PACKAGE) && defined(VERSION)
iptr = &Info->info[Info->count++];
SET_STRING_FIELD( iptr->name, "E2fsprogs Version" );
SET_STRING_FIELD( iptr->title, "E2fsprogs Version" );
static int fs_can_expand_by(logical_volume_t * volume,
sector_count_t * delta)
{
- /* unsupported at this time */
- int rc = ENOSYS;
+ int rc = 0;
LOGENTRY();
+ if (EVMS_IS_MOUNTED(volume)) {
+ rc = EBUSY; /* If mounted, can't expand */
+ goto errout;
+ }
+ fs_get_fs_limits( volume, /* reset limits */
+ &volume->min_fs_size,
+ &volume->max_vol_size,
+ &volume->max_fs_size);
+ if (volume->fs_size + *delta > volume->max_fs_size) {
+ *delta = volume->max_fs_size - volume->fs_size;
+ }
+errout:
LOGEXITRC();
return rc;
-
}
static int fs_can_shrink_by(logical_volume_t * volume,
sector_count_t * delta)
{
- /* unsupported at this time */
- int rc = ENOSYS;
+ int rc = 0;
LOGENTRY();
+ if (EVMS_IS_MOUNTED(volume)) {
+ rc = EBUSY; /* If mounted, can't shrink */
+ goto errout;
+ }
+ fs_get_fs_limits( volume, /* reset limits */
+ &volume->min_fs_size,
+ &volume->max_vol_size,
+ &volume->max_fs_size);
+ if (volume->fs_size - *delta < volume->min_fs_size) {
+ *delta = volume->fs_size - volume->min_fs_size;
+ }
+ if (volume->min_fs_size >= volume->vol_size) {
+ rc = ENOSPC;
+ }
+errout:
LOGEXITRC();
return rc;
}
void set_mkfs_options( option_array_t *, char **, logical_volume_t *, char * );
void set_fsck_options( option_array_t *, char **, logical_volume_t * );
-// Vector of plugin record ptrs that we export for the EVMS Engine.
+/* Vector of plugin record ptrs that we export for the EVMS Engine. */
plugin_record_t *evms_plugin_records[] = {
&ext2_plugrec,
NULL
* Get the size limits for this volume.
*/
int fsim_get_volume_limits( struct ext2_super_block * sb,
- sector_count_t * min_size,
- sector_count_t * max_volume_size,
- sector_count_t * max_object_size)
+ sector_count_t * fs_min_size,
+ sector_count_t * fs_max_size,
+ sector_count_t * vol_max_size)
{
int rc = 0;
sector_count_t fs_size;
+ int blk_to_sect;
/*
* Since ext2/3 does not yet support shrink or expand,
* all values are actual file system size.
*/
- fs_size = sb->s_blocks_count << (1 + sb->s_log_block_size);
- *max_volume_size = fs_size;
- *max_object_size = fs_size;
- *min_size = fs_size;
+ blk_to_sect = (1 + sb->s_log_block_size);
+ fs_size = sb->s_blocks_count << blk_to_sect;
+ *fs_min_size = (sb->s_blocks_count - sb->s_free_blocks_count) << blk_to_sect;
+ *fs_max_size = (sector_count_t) 1 << (32+blk_to_sect);
+ *vol_max_size = 0xffffffff;
return rc;
}
logical_volume_t * volume,
char * logsize )
{
- int i, opt_count = 2;
+ int i, bufsize, opt_count = 2;
+ char *buf;
argv[0] = "mke2fs";
argv[opt_count++] = EVMS_GET_DEVNAME(volume);
argv[opt_count] = NULL;
- {
- FILE *f;
-
- f = fopen("/var/tmp/evms-log", "a");
- for ( i=0; argv[i]; i++) {
- fprintf(f, "'%s' ", argv[i]);
- }
- fprintf(f, "\n");
- fclose(f);
+ bufsize = 0;
+ for (i=0; argv[i]; i++)
+ bufsize += strlen(argv[i]) + 5;
+ buf = malloc(bufsize+1);
+ if (!buf)
+ return;
+ buf[0] = 0;
+ for (i=0; argv[i]; i++) {
+ strcat(buf, argv[i]);
+ strcat(buf, " ");
}
+ EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
+ "mke2fs command: %s\n", buf);
+ free(buf);
return;
}
if (bytes_read > 0) {
/* display e2fsck output */
if (!banner)
- MESSAGE("e2fsck output: \n\n%s",buffer);
- else
- banner = 1;
- memset(buffer,0,bytes_read); //clear out message
+ MESSAGE("e2fsck output:");
+ banner = 1;
+ MESSAGE("%s",buffer);
+ memset(buffer,0,bytes_read); /* clear out message */
}
usleep(10000); /* don't hog all the cpu */
}
- /* wait for child to complete */
- pidf = waitpid( pidf, &status, 0 );
+ /* do final read, just in case we missed some */
+ bytes_read = read(fds2[0],buffer,MAX_USER_MESSAGE_LEN);
+ if (bytes_read > 0) {
+ if (!banner)
+ MESSAGE("e2fsck output:");
+ MESSAGE("%s",buffer);
+ }
if ( WIFEXITED(status) ) {
/* get e2fsck exit code */
rc = WEXITSTATUS(status);
*/
void set_fsck_options( option_array_t * options, char ** argv, logical_volume_t * volume )
{
- int i, opt_count = 1;
+ int i, bufsize, num_opts, opt_count = 1;
int do_preen = 1;
+ char *buf;
argv[0] = "e2fsck";
- for ( i=0; i<options->count; i++) {
+ if (options)
+ num_opts = options->count;
+ else {
+ /* No options, assume force (for resizing) */
+ argv[opt_count++] = "-f";
+ num_opts = 0;
+ }
+
+ for ( i=0; i < num_opts; i++) {
if ( options->option[i].is_number_based ) {
argv[opt_count++] = EVMS_GET_DEVNAME(volume);
argv[opt_count] = NULL;
- {
- FILE *f;
-
- f = fopen("/var/tmp/evms-log", "a");
- for ( i=0; argv[i]; i++) {
- fprintf(f, "'%s' ", argv[i]);
- }
- fprintf(f, "\n");
- fclose(f);
+ bufsize = 0;
+ for (i=0; argv[i]; i++)
+ bufsize += strlen(argv[i]) + 5;
+ buf = malloc(bufsize+1);
+ if (!buf)
+ return;
+ buf[0] = 0;
+ for (i=0; argv[i]; i++) {
+ strcat(buf, argv[i]);
+ strcat(buf, " ");
}
+ EngFncs->write_log_entry(DEBUG, pMyPluginRecord,
+ "fsck command: %s\n", buf);
+ free(buf);
return;
}