busybox/e2fsprogs/lsattr.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * lsattr.c             - List file attributes on an ext2 file system
   4 *
   5 * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
   6 *                           Laboratoire MASI, Institut Blaise Pascal
   7 *                           Universite Pierre et Marie Curie (Paris VI)
   8 *
   9 * This file can be redistributed under the terms of the GNU General
  10 * Public License
  11 */
  12//config:config LSATTR
  13//config:       bool "lsattr (5.5 kb)"
  14//config:       default y
  15//config:       help
  16//config:       lsattr lists the file attributes on a second extended file system.
  17
  18//applet:IF_LSATTR(APPLET_NOEXEC(lsattr, lsattr, BB_DIR_BIN, BB_SUID_DROP, lsattr))
  19/* ls is NOEXEC, so we should be too! ;) */
  20
  21//kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
  22
  23//usage:#define lsattr_trivial_usage
  24//usage:       "[-Radlpv] [FILE]..."
  25//usage:#define lsattr_full_usage "\n\n"
  26//usage:       "List ext2 file attributes\n"
  27//usage:     "\n        -R      Recurse"
  28//usage:     "\n        -a      Include names starting with ."
  29//usage:     "\n        -d      List directory names, not contents"
  30// -a,-d text should match ls --help
  31//usage:     "\n        -l      List long flag names"
  32//usage:     "\n        -p      List project ID"
  33//usage:     "\n        -v      List version/generation number"
  34
  35#include "libbb.h"
  36#include "e2fs_lib.h"
  37
  38enum {
  39        OPT_RECUR      = 1 << 0,
  40        OPT_ALL        = 1 << 1,
  41        OPT_DIRS_OPT   = 1 << 2,
  42        OPT_PF_LONG    = 1 << 3,
  43        OPT_GENERATION = 1 << 4,
  44        OPT_PROJID     = 1 << 5,
  45};
  46
  47static void list_attributes(const char *name)
  48{
  49        unsigned fsflags;
  50        int fd, r;
  51
  52        /* There is no way to run needed ioctls on a symlink.
  53         * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink,
  54         * but ioctls fail on such a fd (tried on 4.12.0 kernel).
  55         * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks.
  56         */
  57        fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW);
  58        if (fd < 0)
  59                return;
  60
  61        if (option_mask32 & OPT_PROJID) {
  62                struct ext2_fsxattr fsxattr;
  63                r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
  64                /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */
  65                if (r != 0)
  66                        goto read_err;
  67                printf("%5u ", (unsigned)fsxattr.fsx_projid);
  68        }
  69
  70        if (option_mask32 & OPT_GENERATION) {
  71                unsigned generation;
  72                r = ioctl(fd, EXT2_IOC_GETVERSION, &generation);
  73                if (r != 0)
  74                        goto read_err;
  75                printf("%-10u ", generation);
  76        }
  77
  78        r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags);
  79        if (r != 0)
  80                goto read_err;
  81
  82        close(fd);
  83
  84        if (option_mask32 & OPT_PF_LONG) {
  85                printf("%-28s ", name);
  86                print_e2flags_long(fsflags);
  87                bb_putchar('\n');
  88        } else {
  89                print_e2flags(fsflags);
  90                printf(" %s\n", name);
  91        }
  92
  93        return;
  94 read_err:
  95        bb_perror_msg("reading %s", name);
  96        close(fd);
  97}
  98
  99static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
 100                struct dirent *de,
 101                void *private UNUSED_PARAM)
 102{
 103        struct stat st;
 104        char *path;
 105
 106        path = concat_path_file(dir_name, de->d_name);
 107
 108        if (lstat(path, &st) != 0)
 109                bb_perror_msg("can't stat '%s'", path);
 110
 111        else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) {
 112                /* Don't try to open device files, fifos etc */
 113                if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode))
 114                        list_attributes(path);
 115
 116                if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR)
 117                 && !DOT_OR_DOTDOT(de->d_name)
 118                ) {
 119                        printf("\n%s:\n", path);
 120                        iterate_on_dir(path, lsattr_dir_proc, NULL);
 121                        bb_putchar('\n');
 122                }
 123        }
 124
 125        free(path);
 126        return 0;
 127}
 128
 129static void lsattr_args(const char *name)
 130{
 131        struct stat st;
 132
 133        if (lstat(name, &st) == -1) {
 134                bb_perror_msg("can't stat '%s'", name);
 135        } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) {
 136                iterate_on_dir(name, lsattr_dir_proc, NULL);
 137        } else {
 138                list_attributes(name);
 139        }
 140}
 141
 142int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 143int lsattr_main(int argc UNUSED_PARAM, char **argv)
 144{
 145        getopt32(argv, "Radlvp");
 146        argv += optind;
 147
 148        if (!*argv)
 149                *--argv = (char*)".";
 150        do lsattr_args(*argv++); while (*argv);
 151
 152        return EXIT_SUCCESS;
 153}
 154