diff options
-rw-r--r-- | toys/other/lsattr.c | 108 |
1 files changed, 75 insertions, 33 deletions
diff --git a/toys/other/lsattr.c b/toys/other/lsattr.c index 2dff4f99..76db649f 100644 --- a/toys/other/lsattr.c +++ b/toys/other/lsattr.c @@ -7,14 +7,14 @@ * * TODO cleanup -USE_LSATTR(NEWTOY(lsattr, "vldaR", TOYFLAG_BIN)) +USE_LSATTR(NEWTOY(lsattr, "vpldaR", TOYFLAG_BIN)) USE_CHATTR(NEWTOY(chattr, NULL, TOYFLAG_BIN)) config LSATTR bool "lsattr" default y help - usage: lsattr [-Radlv] [file...] + usage: lsattr [-Radlpv] [file...] List file attributes on a Linux second extended file system. Flag letters are defined in chattr help. @@ -23,17 +23,19 @@ config LSATTR -a List all files in directories, including files that start with '.' -d List directories like other files, rather than listing their contents -l List long flag names + -p List the file's project number -v List the file's version/generation number config CHATTR bool "chattr" default y help - usage: chattr [-R] [-+=AacDdijsStTu] [-v version] [file...] + usage: chattr [-R] [-+=AacDdijsStTu] [-p projid] [-v version] [file...] Change file attributes on a Linux second extended file system. -R Recurse + -p Set the file's project number -v Set the file's version/generation number Operators: @@ -64,29 +66,47 @@ config CHATTR #define FS_PROJINHERT_FL 0x20000000 // Linux 4.5 #define FS_CASEFOLD_FL 0x40000000 // Linux 5.4 +#define FS_VERITY_FL 0x00100000 // Linux 5.4 + +// Linux 4.5 +struct fsxattr_4_5 { + unsigned fsx_xflags; + unsigned fsx_extsize; + unsigned fsx_nextents; + unsigned fsx_projid; + unsigned fsx_cowextsize; + char fsx_pad[8]; +}; +#define FS_IOC_FSGETXATTR_4_5 _IOR('X', 31, struct fsxattr_4_5) +#define FS_IOC_FSSETXATTR_4_5 _IOW('X', 32, struct fsxattr_4_5) static struct ext2_attr { char *name; unsigned long flag; char opt; } e2attrs[] = { - {"No_Atime", FS_NOATIME_FL, 'A'}, - {"Append_Only", FS_APPEND_FL, 'a'}, - {"No_COW", FS_NOCOW_FL, 'C'}, - {"Compression_Requested", FS_COMPR_FL, 'c'}, + // Do not sort! These are in the order that lsattr outputs them. + {"Secure_Deletion", FS_SECRM_FL, 's'}, + {"Undelete", FS_UNRM_FL, 'u'}, + {"Synchronous_Updates", FS_SYNC_FL, 'S'}, {"Synchronous_Directory_Updates", FS_DIRSYNC_FL, 'D'}, - {"No_Dump", FS_NODUMP_FL, 'd'}, - {"Casefold", FS_CASEFOLD_FL, 'F'}, - {"Indexed_directory", FS_INDEX_FL, 'I'}, {"Immutable", FS_IMMUTABLE_FL, 'i'}, + {"Append_Only", FS_APPEND_FL, 'a'}, + {"No_Dump", FS_NODUMP_FL, 'd'}, + {"No_Atime", FS_NOATIME_FL, 'A'}, + {"Compression_Requested", FS_COMPR_FL, 'c'}, + {"Encrypted", FS_ENCRYPT_FL, 'E'}, {"Journaled_Data", FS_JOURNAL_DATA_FL, 'j'}, - {"Project_Hierarchy", FS_PROJINHERIT_FL, 'P'}, - {"Synchronous_Updates", FS_SYNC_FL, 'S'}, - {"Secure_Deletion", FS_SECRM_FL, 's'}, - {"Top_of_Directory_Hierarchies", FS_TOPDIR_FL, 'T'}, + {"Indexed_directory", FS_INDEX_FL, 'I'}, {"No_Tailmerging", FS_NOTAIL_FL, 't'}, - {"Undelete", FS_UNRM_FL, 'u'}, - {NULL, -1, 0}, + {"Top_of_Directory_Hierarchies", FS_TOPDIR_FL, 'T'}, + {"Extents", FS_EXTENT_FL, 'e'}, + {"No_COW", FS_NOCOW_FL, 'C'}, + {"Casefold", FS_CASEFOLD_FL, 'F'}, + {"Inline_Data", FS_INLINE_DATA_FL, 'N'}, + {"Project_Hierarchy", FS_PROJINHERIT_FL, 'P'}, + {"Verity", FS_VERITY_FL, 'V'}, + {NULL, 0, 0}, }; // Get file flags on a Linux second extended file system. @@ -111,9 +131,15 @@ static void print_file_attr(char *path) } if (-1 == (fd=open(path, O_RDONLY | O_NONBLOCK))) goto LABEL1; + if (FLAG(p)) { + struct fsxattr_4_5 fsx; + + if (ioctl(fd, FS_IOC_FSGETXATTR_4_5, &fsx)) goto LABEL2; + xprintf("%5u ", fsx.fsx_projid); + } if (FLAG(v)) { if (ioctl(fd, FS_IOC_GETVERSION, (void*)&version) < 0) goto LABEL2; - xprintf("%5lu ", version); + xprintf("%-10lu ", version); } if (ext2_getflag(fd, &sb, &flag) < 0) perror_msg("reading flags '%s'", path); @@ -152,12 +178,12 @@ LABEL1: perror_msg("reading '%s'", path); static int retell_dir(struct dirtree *root) { char *fpath = NULL; - + if (root->again) { xputc('\n'); return 0; } - if (S_ISDIR(root->st.st_mode) && !root->parent) + if (S_ISDIR(root->st.st_mode) && !root->parent) return (DIRTREE_RECURSE | DIRTREE_COMEAGAIN); fpath = dirtree_path(root, NULL); @@ -194,8 +220,8 @@ void lsattr_main(void) #include "generated/flags.h" static struct _chattr { - unsigned long add, rm, set, version; - unsigned char vflag, recursive; + unsigned long add, rm, set, projid, version; + unsigned char pflag, vflag, recursive; } chattr; // Set file flags on a Linux second extended file system. @@ -229,16 +255,20 @@ static void parse_cmdline_arg(char ***argv) if (*ptr == 'R') { chattr.recursive = 1; continue; - } else if (*ptr == 'v') {// get version from next argv. - char *endptr; + } else if (*ptr == 'p' || *ptr == 'v') { + unsigned val; - errno = 0; arg = *(*argv += 1); - if (!arg) help_exit("bad -v"); - if (*arg == '-') perror_exit("Invalid Number '%s'", arg); - chattr.version = strtoul(arg, &endptr, 0); - if (errno || *endptr) perror_exit("bad version '%s'", arg); - chattr.vflag = 1; + if (!arg) help_exit("missing arg to -%c", *ptr); + + val = atolx_range(arg, 0, UINT_MAX); + if (*ptr == 'v') { + chattr.version = val; + chattr.vflag = 1; + } else { + chattr.projid = val; + chattr.pflag = 1; + } continue; } else chattr.rm |= get_flag_val(*ptr); } @@ -297,12 +327,24 @@ static int update_attr(struct dirtree *root) if (ext2_setflag(fd, &(root->st), fval) < 0) perror_msg("setting flags '%s'", fpath); } - // set file version + + // (FS_IOC_SETVERSION works all the way back to 2.6, but FS_IOC_FSSETXATTR + // isn't available until 4.5.) if (chattr.vflag && (ioctl(fd, FS_IOC_SETVERSION, &chattr.version)<0)) perror_msg("while setting version on '%s'", fpath); + + if (chattr.pflag) { + struct fsxattr_4_5 fsx; + + if (ioctl(fd, FS_IOC_FSGETXATTR_4_5, &fsx)) + perror_exit("%s: FS_IOC_FSGETXATTR failed", fpath); + fsx.fsx_projid = chattr.projid; + if (ioctl(fd, FS_IOC_FSSETXATTR_4_5, &fsx)) + perror_exit("%s: FS_IOC_FSSETXATTR failed", fpath); + } + free(fpath); xclose(fd); - return (S_ISDIR(root->st.st_mode) && chattr.recursive) ? DIRTREE_RECURSE : 0; } @@ -316,8 +358,8 @@ void chattr_main(void) if (chattr.set && (chattr.add || chattr.rm)) error_exit("no '=' with '-' or '+'"); if (chattr.rm & chattr.add) error_exit("set/unset same flag"); - if (!(chattr.add || chattr.rm || chattr.set || chattr.vflag)) - error_exit("need '-v', '=', '-' or '+'"); + if (!(chattr.add || chattr.rm || chattr.set || chattr.pflag || chattr.vflag)) + error_exit("need '-p', '-v', '=', '-', or '+'"); for (; *argv; argv++) dirtree_read(*argv, update_attr); toys.exitval = 0; //always set success at this point. } |