ChangeLog, Makefile.in, mke2fs.8.in, mke2fs.c, tune2fs.8.in, tune2fs.c:
  tune2fs.c (main): Add a new option -O which allows the user to set and
  	clear certain "safe" filsystem feature flags.  Currently, the only
  	ones which are supported for modification are sparse_superblock and
  	filetype.
  mke2fs.c (PRS): Add new option -O which allows the user to request
  	filesystems with specific filesystem options.  By default on 2.2 and
  	later systems, create filesystems that have both file type information
  	and sparse superblocks.

diff --git a/misc/ChangeLog b/misc/ChangeLog
index 78cd6f6..e266b85 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,15 @@
+1999-10-22    <tytso@valinux.com>
+
+	* tune2fs.c (main): Add a new option -O which allows the user to
+		set and clear certain "safe" filsystem feature flags.
+		Currently, the only ones which are supported for
+		modification are sparse_superblock and filetype.
+
+	* mke2fs.c (PRS): Add new option -O which allows the user to
+		request filesystems with specific filesystem options.  By
+		default on 2.2 and later systems, create filesystems that
+		have both file type information and sparse superblocks.
+
 1999-10-21    <tytso@valinux.com>
 
 	* badblocks.8.in, chattr.1.in, dumpe2fs.8.in, e2label.8.in,
diff --git a/misc/Makefile.in b/misc/Makefile.in
index f7387cb..b14cb7c 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -60,12 +60,12 @@
 mklost+found: $(MKLPF_OBJS)
 	$(CC) $(ALL_LDFLAGS) -o mklost+found $(MKLPF_OBJS)
 
-mke2fs: $(MKE2FS_OBJS) $(DEPLIBS) $(LIBUUID)
-	$(CC) $(ALL_LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS) $(LIBUUID)
+mke2fs: $(MKE2FS_OBJS) $(DEPLIBS) $(LIBE2P) $(LIBUUID)
+	$(CC) $(ALL_LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS) $(LIBE2P) $(LIBUUID)
 
-mke2fs.static: $(MKE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBUUID)
+mke2fs.static: $(MKE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(STATIC_LIBUUID)
 	$(CC) $(ALL_LDFLAGS) -static -o mke2fs.static $(MKE2FS_OBJS) \
-		$(STATIC_LIBS) $(STATIC_LIBUUID)
+		$(STATIC_LIBS) $(STATIC_LIBE2P) $(STATIC_LIBUUID)
 
 resize2fs: resize2fs.o $(DEPLIBS)
 	$(CC) $(ALL_LDFLAGS) -o resize2fs resize2fs.o $(LIBS)
diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 07d8861..2e8ae4a 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -44,6 +44,10 @@
 .I creator-os
 ]
 [
+.B \-O 
+.IR feature [,...]
+]
+[
 .B \-q
 ]
 [
@@ -137,6 +141,27 @@
 ratio).  This allows the user to specify the number 
 of desired inodes directly.
 .TP
+.BI \-O " feature\fR[,...]"
+Create the filesystem with the listed set of features 
+(filesystem options).  The following features are supported: 
+.IR sparse ,
+which cause the filesystem to use sparse superblocks, and
+.IR filetype ,
+which will cause the filesystem to store file type information in 
+directory entries.   Currently, both features are turned on by default
+unless 
+.B mke2fs
+is run on a system with a pre-2.2 Linux kernel.
+.B Warning:
+Pre-2.2 Linux kernels do not properly 
+support the filesystems that use either of these two features.   Filesystems 
+that may need to mounted on pre-2.2 kernels should be created with 
+.B -O
+.I none
+which will disable both of these features, even if 
+.B mke2fs 
+is run on a system which can support these features.
+.TP
 .BI \-l " filename"
 Read the bad blocks list from
 .I filename.
@@ -166,15 +191,10 @@
 If 
 .I sparse-super-flag
 is 1, then turn on the sparse superblock flag in the superblock.  
-If 0, then turn off the sparse superblock flag in the superblock.  
-(Currently, the sparse 
-superblock flag is off by default if the kernel version is less than 
-2.2; otherwise it defaults to on.)  
-.B Warning:
-The Linux 2.0 kernel (and some Linux 2.1 kernel) does not properly 
-support sparse superblocks.  Filesystems that may need to mounted
-on pre-2.2 kernels should not be created with the sparse superblocks 
-feature.
+.B Note:
+This option is deprecated; use the 
+.B \-O
+option instead.
 .TP
 .B \-v
 Verbose execution.
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 0aad8e5..bf604e4 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -52,6 +52,7 @@
 
 #include "et/com_err.h"
 #include "uuid/uuid.h"
+#include "e2p/e2p.h"
 #include "ext2fs/ext2fs.h"
 #include "../version.h"
 
@@ -699,6 +700,11 @@
 	}
 }	
 
+static __u32 ok_features[3] = {
+	0,					/* Compat */
+	EXT2_FEATURE_INCOMPAT_FILETYPE,		/* Incompat */
+	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	/* R/O compat */
+};
 
 
 static void PRS(int argc, char *argv[])
@@ -712,11 +718,12 @@
 	int	reserved_ratio = 5;
 	ino_t	num_inodes = 0;
 	errcode_t	retval;
-	int	sparse_option = 1;
+	int	sparse_option = 0;
 	char	*oldpath = getenv("PATH");
 	struct ext2fs_sb *param_ext2 = (struct ext2fs_sb *) &param;
 	char	*raid_opts = 0;
 	char	*fs_type = 0;
+	char	*feature_set = "filetype,sparse_super";
 	blk_t	dev_size;
 #ifdef linux
 	struct utsname ut;
@@ -725,9 +732,10 @@
 		perror("uname");
 		exit(1);
 	}
-	if (ut.release[0] == '2' && ut.release[1] == '.' &&
-	    ut.release[2] < '2' && ut.release[3] == '.')
-		sparse_option = 0;
+	if ((ut.release[0] == '1') ||
+	    (ut.release[0] == '2' && ut.release[1] == '.' &&
+	     ut.release[2] < '2' && ut.release[3] == '.'))
+		feature_set = 0;
 #endif
 	/* Update our PATH to include /sbin  */
 	if (oldpath) {
@@ -753,7 +761,7 @@
 	if (argc && *argv)
 		program_name = *argv;
 	while ((c = getopt (argc, argv,
-			    "b:cf:g:i:l:m:no:qr:R:s:tvI:ST:FL:M:N:V")) != EOF)
+		    "b:cf:g:i:l:m:no:qr:R:s:tvI:ST:FL:M:N:O:V")) != EOF)
 		switch (c) {
 		case 'b':
 			blocksize = strtoul(optarg, &tmp, 0);
@@ -857,6 +865,9 @@
 		case 'M':
 			mount_dir = optarg;
 			break;
+		case 'O':
+			feature_set = optarg;
+			break;
 		case 'R':
 			raid_opts = optarg;
 			break;
@@ -953,6 +964,15 @@
 		param_ext2->s_feature_ro_compat |=
 			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
 #endif
+	if (feature_set && !strncasecmp(feature_set, "none", 4))
+		feature_set = 0;
+	if (feature_set && e2p_edit_feature(feature_set,
+					    &param_ext2->s_feature_compat,
+					    ok_features)) {
+		fprintf(stderr, "Invalid filesystem option set: %s\n",
+			feature_set);
+		exit(1);
+	}
 }
 					
 int main (int argc, char *argv[])
diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in
index bbac87b..5840448 100644
--- a/misc/tune2fs.8.in
+++ b/misc/tune2fs.8.in
@@ -55,6 +55,10 @@
 .I last-mounted-directory
 ]
 [
+.B \-O 
+\fR[^]\fIfeature\fR[,...]
+]
+[
 .B \-U
 .I UUID
 ]
@@ -130,6 +134,17 @@
 .BI \-M " last-mounted-directory"
 set the last-mounted directory for the filesystem.
 .TP
+.BI \-O " \fR[^]\fIfeature\fR[,...]"
+set or clear the indicated filesystem features (options) in the filesystem.
+.I Feature
+can be one of the following supported filesystem options: 
+.IR sparse ,
+which cause the filesystem to use sparse superblocks, and
+.IR filetype ,
+which will cause the filesystem to store file type information in 
+directory entries.  After setting or clearing either filesystem feature,
+e2fsck must be run on the filesystem.
+.TP
 .BI \-U " UUID"
 set the UUID of the filesystem.  A sample UUID looks like this: 
 "c1b9d5a2-f162-11cf-9ece-0020afc76f16".  The uuid may also be
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 4e9f853..66db3a4 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -96,11 +96,19 @@
 		 "[-g group]\n"
 		 "\t[-i interval[d|m|w]] [-l] [-s] [-m reserved-blocks-percent]\n"
 		 "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
-		 "\t[-L volume-label] [-M last-mounted-dir] [-U UUID] "
-		 "device\n", program_name);
+		 "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n"
+		 "\t[-O [-]feature[,...]] device\n", program_name);
 	exit (1);
 }
 
+static __u32 ok_features[3] = {
+	0,					/* Compat */
+	EXT2_FEATURE_INCOMPAT_FILETYPE,		/* Incompat */
+	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	/* R/O compat */
+};
+
+static const char *please_fsck = "Please run e2fsck on the filesystem.\n";
+
 int main (int argc, char ** argv)
 {
 	int c;
@@ -111,6 +119,7 @@
 	struct group * gr;
 	struct passwd * pw;
 	int open_flag = 0;
+	char *features_cmd = 0;
 
 	fprintf (stderr, "tune2fs %s, %s for EXT2 FS %s, %s\n",
 		 E2FSPROGS_VERSION, E2FSPROGS_DATE,
@@ -118,7 +127,7 @@
 	if (argc && *argv)
 		program_name = *argv;
 	initialize_ext2_error_table();
-	while ((c = getopt (argc, argv, "c:e:g:i:lm:r:s:u:C:L:M:U:")) != EOF)
+	while ((c = getopt (argc, argv, "c:e:g:i:lm:r:s:u:C:L:M:O:U:")) != EOF)
 		switch (c)
 		{
 			case 'c':
@@ -235,6 +244,10 @@
 				M_flag = 1;
 				open_flag = EXT2_FLAG_RW;
 				break;
+			case 'O':
+				features_cmd = optarg;
+				open_flag = EXT2_FLAG_RW;
+				break;
 			case 'r':
 				reserved_blocks = strtoul (optarg, &tmp, 0);
 				if (*tmp) {
@@ -356,8 +369,8 @@
 				EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
 			fs->super->s_state &= ~EXT2_VALID_FS;
 			ext2fs_mark_super_dirty(fs);
-			printf("\nSparse superblock flag set.  "
-			       "Please run e2fsck on the filesystem.\n");
+			printf("\nSparse superblock flag set.  %s",
+			       please_fsck);
 		}
 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
 		com_err (program_name, 0,
@@ -377,8 +390,8 @@
 			fs->super->s_state &= ~EXT2_VALID_FS;
 			fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
 			ext2fs_mark_super_dirty(fs);
-			printf("\nSparse superblock flag cleared.  "
-			       "Please run e2fsck on the filesystem.\n");
+			printf("\nSparse superblock flag cleared.  %s",
+			       please_fsck);
 		}
 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
 		com_err (program_name, 0,
@@ -414,6 +427,31 @@
 			sizeof(sb->s_last_mounted));
 		ext2fs_mark_super_dirty(fs);
 	}
+	if (features_cmd) {
+		int sparse, old_sparse, filetype, old_filetype;
+
+		old_sparse = sb->s_feature_ro_compat &
+			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+		old_filetype = sb->s_feature_incompat &
+			EXT2_FEATURE_INCOMPAT_FILETYPE;
+		if (e2p_edit_feature(features_cmd,
+				     &sb->s_feature_compat,
+				     ok_features)) {
+			fprintf(stderr, "Invalid filesystem option set: %s\n",
+				features_cmd);
+			exit(1);
+		}
+		sparse = sb->s_feature_ro_compat &
+			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+		filetype = sb->s_feature_incompat &
+			EXT2_FEATURE_INCOMPAT_FILETYPE;
+		if ((sparse != old_sparse) ||
+		    (filetype != old_filetype)) {
+			fs->super->s_state &= ~EXT2_VALID_FS;
+			printf("\n%s\n", please_fsck);
+		}
+		ext2fs_mark_super_dirty(fs);
+	}
 	if (U_flag) {
 		if (strcasecmp(new_UUID, "null") == 0) {
 			uuid_clear(sb->s_uuid);