diff --git a/lib/e2p/e2p.h b/lib/e2p/e2p.h
index 4a68dd9..1fbbe1b 100644
--- a/lib/e2p/e2p.h
+++ b/lib/e2p/e2p.h
@@ -26,6 +26,24 @@
 /* `options' for print_flags() */
 
 #define PFOPT_LONG  1 /* Must be 1 for compatibility with `int long_format'. */
+#define PFOPT_SNAPSHOT  2 /* list/control snapshot flags */
+#define PFOPT_SNAPSHOT_X 4 /* -X option for 'Snapshot' flags */
+
+/*
+ * snapshot status/control flags for lsattr/chattr -X.
+ * reusing compression flags on the GET/SETFLAGS ioctl for snapshot control API.
+ * all the flags below are either read-only on-disk inode flags (deleted and
+ * shrunk) or in-memory inode status flags (the rest).
+ * TODO: implement new ioctls for snapshot status/control.
+ */
+#define NEXT3_SNAPFILE_LIST_FL		0x00000100 /* snapshot is on list */
+#define NEXT3_SNAPFILE_ENABLED_FL	0x00000200 /* snapshot is enabled */
+#define NEXT3_SNAPFILE_ACTIVE_FL	0x00000400 /* snapshot is active */
+#define NEXT3_SNAPFILE_INUSE_FL		0x00000800 /* snapshot is in-use */
+#define NEXT3_SNAPFILE_DELETED_FL	0x04000000 /* snapshot is deleted */
+#define NEXT3_SNAPFILE_SHRUNK_FL	0x08000000 /* snapshot is shrunk */
+#define NEXT3_SNAPFILE_OPEN_FL		0x10000000 /* snapshot is mounted */
+#define NEXT3_SNAPFILE_TAGGED_FL	0x20000000 /* snapshot is tagged */
 
 
 int fgetflags (const char * name, unsigned long * flags);
diff --git a/lib/e2p/pf.c b/lib/e2p/pf.c
index f34a5cc..063bf2a 100644
--- a/lib/e2p/pf.c
+++ b/lib/e2p/pf.c
@@ -48,16 +48,47 @@ static struct flags_name flags_array[] = {
 	{ EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
 	{ EXT4_EXTENTS_FL, "e", "Extents" },
 	{ EXT4_HUGE_FILE_FL, "h", "Huge_file" },
+	{ EXT4_SNAPFILE_FL, "x", "Snapshot_File" },
+	{ 0, NULL, NULL }
+};
+
+/* Traditional snapshot flags */
+static struct flags_name snapshot_flags_array[] = {
+	{ NEXT3_SNAPFILE_LIST_FL, "l", "on_List" },
+	{ NEXT3_SNAPFILE_ENABLED_FL, "e", "Enabled" },
+	{ NEXT3_SNAPFILE_ACTIVE_FL, "a", "Active" },
+	{ NEXT3_SNAPFILE_INUSE_FL, "i", "Inuse_by_previous" },
+	{ NEXT3_SNAPFILE_DELETED_FL, "d", "Deleted" },
+	{ NEXT3_SNAPFILE_SHRUNK_FL, "s", "Shrunk" },
+	{ NEXT3_SNAPFILE_OPEN_FL, "m", "Mounted" },
+	{ NEXT3_SNAPFILE_TAGGED_FL, "t", "Tagged" },
+	{ 0, NULL, NULL }
+};
+
+/* Cool 'Snapshot' flags */
+static struct flags_name snapshot_X_flags_array[] = {
+	{ NEXT3_SNAPFILE_LIST_FL, "S", "on_liSt" },
+	{ NEXT3_SNAPFILE_ENABLED_FL, "n", "eNabled" },
+	{ NEXT3_SNAPFILE_ACTIVE_FL, "a", "Active" },
+	{ NEXT3_SNAPFILE_INUSE_FL, "p", "inuse_by_Previous" },
+	{ NEXT3_SNAPFILE_DELETED_FL, "s", "Deleted" },
+	{ NEXT3_SNAPFILE_SHRUNK_FL, "h", "sHrunk" },
+	{ NEXT3_SNAPFILE_OPEN_FL, "o", "mOunted" },
+	{ NEXT3_SNAPFILE_TAGGED_FL, "t", "Tagged" },
 	{ 0, NULL, NULL }
 };
 
 void print_flags (FILE * f, unsigned long flags, unsigned options)
 {
+	struct flags_name *array = ((options & PFOPT_SNAPSHOT_X) ?
+			snapshot_X_flags_array :
+			((options & PFOPT_SNAPSHOT) ?
+			 snapshot_flags_array : flags_array));
 	int long_opt = (options & PFOPT_LONG);
 	struct flags_name *fp;
 	int	first = 1;
 
-	for (fp = flags_array; fp->flag != 0; fp++) {
+	for (fp = array; fp->flag != 0; fp++) {
 		if (flags & fp->flag) {
 			if (long_opt) {
 				if (first)
diff --git a/misc/chattr.c b/misc/chattr.c
index de33b08..449101f 100644
--- a/misc/chattr.c
+++ b/misc/chattr.c
@@ -56,6 +56,8 @@
 
 static const char * program_name = "chattr";
 
+static int chsnap;
+
 static int add;
 static int rem;
 static int set;
@@ -81,8 +83,12 @@ static unsigned long sf;
 
 static void usage(void)
 {
+	fprintf(stderr, chsnap ?
+		_("Usage: %s [-+=let] snapshot files...\n") :
+		_("Usage: %s [-RVf] [-+=AacDdeijsSux] [-v version] files...\n"),
+		program_name);
 	fprintf(stderr,
-		_("Usage: %s [-RVf] [-+=AacDdeijsSu] [-v version] files...\n"),
+		_("Usage: %s -X [-+=Snt] snapshot files...\n"),
 		program_name);
 	exit(1);
 }
@@ -92,7 +98,7 @@ struct flags_char {
 	char 		optchar;
 };
 
-static const struct flags_char flags_array[] = {
+static const struct flags_char ext2_flags_array[] = {
 	{ EXT2_NOATIME_FL, 'A' },
 	{ EXT2_SYNC_FL, 'S' },
 	{ EXT2_DIRSYNC_FL, 'D' },
@@ -106,6 +112,25 @@ static const struct flags_char flags_array[] = {
 	{ EXT2_UNRM_FL, 'u' },
 	{ EXT2_NOTAIL_FL, 't' },
 	{ EXT2_TOPDIR_FL, 'T' },
+	{ EXT4_SNAPFILE_FL, 'x' },
+	{ 0, 0 }
+};
+
+static const struct flags_char *flags_array = ext2_flags_array;
+
+/* Traditional snapshot flags */
+static struct flags_char snapshot_flags_array[] = {
+	{ NEXT3_SNAPFILE_LIST_FL, 'l' },
+	{ NEXT3_SNAPFILE_ENABLED_FL, 'e' },
+	{ NEXT3_SNAPFILE_TAGGED_FL, 't' },
+	{ 0, 0 }
+};
+
+/* Cool 'Snapshot' flags */
+static struct flags_char snapshot_X_flags_array[] = {
+	{ NEXT3_SNAPFILE_LIST_FL, 'S' },
+	{ NEXT3_SNAPFILE_ENABLED_FL, 'n' },
+	{ NEXT3_SNAPFILE_TAGGED_FL, 't' },
 	{ 0, 0 }
 };
 
@@ -131,6 +156,10 @@ static int decode_arg (int * i, int argc, char ** argv)
 	{
 	case '-':
 		for (p = &argv[*i][1]; *p; p++) {
+			if (*p == 'X') {
+				flags_array = snapshot_X_flags_array;
+				continue;
+			}
 			if (*p == 'R') {
 				recursive = 1;
 				continue;
@@ -303,6 +332,11 @@ int main (int argc, char ** argv)
 #endif
 	if (argc && *argv)
 		program_name = *argv;
+	i = strlen(program_name);
+	if (i >= 6 && !strcmp(program_name + i - 6, "chsnap")) {
+		flags_array = snapshot_flags_array;
+		chsnap = 1;
+	}
 	i = 1;
 	while (i < argc && !end_arg) {
 		/* '--' arg should end option processing */
diff --git a/misc/lsattr.c b/misc/lsattr.c
index 15b17ad..3885628 100644
--- a/misc/lsattr.c
+++ b/misc/lsattr.c
@@ -70,7 +70,7 @@ static int generation_opt;
 
 static void usage(void)
 {
-	fprintf(stderr, _("Usage: %s [-RVadlv] [files...]\n"), program_name);
+	fprintf(stderr, _("Usage: %s [-XRVadlv] [files...]\n"), program_name);
 	exit(1);
 }
 
@@ -169,9 +169,16 @@ int main (int argc, char ** argv)
 #endif
 	if (argc && *argv)
 		program_name = *argv;
-	while ((c = getopt (argc, argv, "RVadlv")) != EOF)
+	i = strlen(program_name);
+	if (i >= 6 && !strcmp(program_name + i - 6, "lssnap"))
+		pf_options |= PFOPT_SNAPSHOT;
+
+	while ((c = getopt (argc, argv, "XRVadlv")) != EOF)
 		switch (c)
 		{
+			case 'X':
+				pf_options |= PFOPT_SNAPSHOT_X;
+				break;
 			case 'R':
 				recursive = 1;
 				break;
@@ -185,7 +192,7 @@ int main (int argc, char ** argv)
 				dirs_opt = 1;
 				break;
 			case 'l':
-				pf_options = PFOPT_LONG;
+				pf_options |= PFOPT_LONG;
 				break;
 			case 'v':
 				generation_opt = 1;
