aboutsummaryrefslogtreecommitdiff
path: root/e2fsprogs/lsattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsprogs/lsattr.c')
-rw-r--r--e2fsprogs/lsattr.c80
1 files changed, 57 insertions, 23 deletions
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c
index ed7b67c6f..d82861e14 100644
--- a/e2fsprogs/lsattr.c
+++ b/e2fsprogs/lsattr.c
@@ -22,7 +22,7 @@
22 22
23//usage:#define lsattr_trivial_usage 23//usage:#define lsattr_trivial_usage
24//usage: IF_NOT_PLATFORM_MINGW32( 24//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "[-Radlv] [FILE]..." 25//usage: "[-Radlpv] [FILE]..."
26//usage: ) 26//usage: )
27//usage: IF_PLATFORM_MINGW32( 27//usage: IF_PLATFORM_MINGW32(
28//usage: "[-Radl] [FILE]..." 28//usage: "[-Radl] [FILE]..."
@@ -30,10 +30,12 @@
30//usage:#define lsattr_full_usage "\n\n" 30//usage:#define lsattr_full_usage "\n\n"
31//usage: "List ext2 file attributes\n" 31//usage: "List ext2 file attributes\n"
32//usage: "\n -R Recurse" 32//usage: "\n -R Recurse"
33//usage: "\n -a Don't hide entries starting with ." 33//usage: "\n -a Include names starting with ."
34//usage: "\n -d List directory entries instead of contents" 34//usage: "\n -d List directory names, not contents"
35// -a,-d text should match ls --help
35//usage: "\n -l List long flag names" 36//usage: "\n -l List long flag names"
36//usage: IF_NOT_PLATFORM_MINGW32( 37//usage: IF_NOT_PLATFORM_MINGW32(
38//usage: "\n -p List project ID"
37//usage: "\n -v List version/generation number" 39//usage: "\n -v List version/generation number"
38//usage: ) 40//usage: )
39 41
@@ -41,43 +43,71 @@
41#include "e2fs_lib.h" 43#include "e2fs_lib.h"
42 44
43enum { 45enum {
44 OPT_RECUR = 0x1, 46 OPT_RECUR = 1 << 0,
45 OPT_ALL = 0x2, 47 OPT_ALL = 1 << 1,
46 OPT_DIRS_OPT = 0x4, 48 OPT_DIRS_OPT = 1 << 2,
47 OPT_PF_LONG = 0x8, 49 OPT_PF_LONG = 1 << 3,
48 OPT_GENERATION = 0x10, 50 OPT_GENERATION = 1 << 4,
51 OPT_PROJID = 1 << 5,
49}; 52};
50 53
51static void list_attributes(const char *name) 54static void list_attributes(const char *name)
52{ 55{
53 unsigned long fsflags; 56 unsigned fsflags;
54#if !ENABLE_PLATFORM_MINGW32 57#if !ENABLE_PLATFORM_MINGW32
55 unsigned long generation; 58 int fd, r;
56#endif 59
57 60 /* There is no way to run needed ioctls on a symlink.
58 if (fgetflags(name, &fsflags) != 0) 61 * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink,
59 goto read_err; 62 * but ioctls fail on such a fd (tried on 4.12.0 kernel).
63 * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks.
64 */
65 fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW);
66 if (fd < 0)
67 return;
68
69 if (option_mask32 & OPT_PROJID) {
70 struct ext2_fsxattr fsxattr;
71 r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
72 /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */
73 if (r != 0)
74 goto read_err;
75 printf("%5u ", (unsigned)fsxattr.fsx_projid);
76 }
60 77
61#if !ENABLE_PLATFORM_MINGW32
62 if (option_mask32 & OPT_GENERATION) { 78 if (option_mask32 & OPT_GENERATION) {
63 if (fgetversion(name, &generation) != 0) 79 unsigned generation;
80 r = ioctl(fd, EXT2_IOC_GETVERSION, &generation);
81 if (r != 0)
64 goto read_err; 82 goto read_err;
65 printf("%5lu ", generation); 83 printf("%-10u ", generation);
66 } 84 }
85
86 r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags);
87 if (r != 0)
88 goto read_err;
89
90 close(fd);
91#else /* ENABLE_PLATFORM_MINGW32 */
92 if (fgetflags(name, &fsflags) != 0)
93 goto read_err;
67#endif 94#endif
68 95
69 if (option_mask32 & OPT_PF_LONG) { 96 if (option_mask32 & OPT_PF_LONG) {
70 printf("%-28s ", name); 97 printf("%-28s ", name);
71 print_e2flags(stdout, fsflags, PFOPT_LONG); 98 print_e2flags_long(fsflags);
72 bb_putchar('\n'); 99 bb_putchar('\n');
73 } else { 100 } else {
74 print_e2flags(stdout, fsflags, 0); 101 print_e2flags(fsflags);
75 printf(" %s\n", name); 102 printf(" %s\n", name);
76 } 103 }
77 104
78 return; 105 return;
79 read_err: 106 read_err:
80 bb_perror_msg("reading %s", name); 107 bb_perror_msg("reading %s", name);
108#if !ENABLE_PLATFORM_MINGW32
109 close(fd);
110#endif
81} 111}
82 112
83static int FAST_FUNC lsattr_dir_proc(const char *dir_name, 113static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
@@ -90,9 +120,13 @@ static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
90 path = concat_path_file(dir_name, de->d_name); 120 path = concat_path_file(dir_name, de->d_name);
91 121
92 if (lstat(path, &st) != 0) 122 if (lstat(path, &st) != 0)
93 bb_perror_msg("stat %s", path); 123 bb_perror_msg("can't stat '%s'", path);
124
94 else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) { 125 else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) {
95 list_attributes(path); 126 /* Don't try to open device files, fifos etc */
127 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode))
128 list_attributes(path);
129
96 if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR) 130 if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR)
97 && !DOT_OR_DOTDOT(de->d_name) 131 && !DOT_OR_DOTDOT(de->d_name)
98 ) { 132 ) {
@@ -111,7 +145,7 @@ static void lsattr_args(const char *name)
111 struct stat st; 145 struct stat st;
112 146
113 if (lstat(name, &st) == -1) { 147 if (lstat(name, &st) == -1) {
114 bb_perror_msg("stat %s", name); 148 bb_perror_msg("can't stat '%s'", name);
115 } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) { 149 } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) {
116 iterate_on_dir(name, lsattr_dir_proc, NULL); 150 iterate_on_dir(name, lsattr_dir_proc, NULL);
117 } else { 151 } else {
@@ -125,7 +159,7 @@ int lsattr_main(int argc UNUSED_PARAM, char **argv)
125#if ENABLE_PLATFORM_MINGW32 159#if ENABLE_PLATFORM_MINGW32
126 getopt32(argv, "Radl"); 160 getopt32(argv, "Radl");
127#else 161#else
128 getopt32(argv, "Radlv"); 162 getopt32(argv, "Radlvp");
129#endif 163#endif
130 argv += optind; 164 argv += optind;
131 165