Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fslist: search by selinux labels #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 198 additions & 38 deletions action-fslist.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <regex.h>
#include <time.h>

enum {
Expand All @@ -22,25 +23,136 @@ enum {
FORMAT_NE2SCAN,
};

enum filter_type {
FIL_NONE = 0x0,
FIL_BEFORE = 0x1,
FIL_NEWER = 0x2,
FIL_CONTEXT = 0x4,
FIL_ALL = 0x7,
};

struct filter_elt;

typedef int (*filter_cb_t)(struct filter_elt *elt,
struct ext2_inode *i,
struct ea_info *ctx);

struct filter_elt {
filter_cb_t fe_cb;
int fe_not;
union {
time_t time;
regex_t regex;
char *str;
}fe_d;
};

#define MAX_FILTER_NUMBER 10
struct filter_array {
int fa_msk;
int fa_cnt;
struct filter_elt fa_array[MAX_FILTER_NUMBER];
};

static int fslist_format = FORMAT_NE2SCAN;
static const char *fsname = "UNKNOWN";
static const char *user_note = "";
static int show_dirs = 0;
static int show_fid = 0;
static int show_ctx = 0;
static int show_one = 0;
static const char *target_dev;
static time_t cutoff_time;
static int accessed_before;
static int newer_than;
static struct filter_array filters = { 0 };
static FILE *genhit;

static int add_to_filters(enum filter_type type, filter_cb_t cb, int not,
void *data, size_t len)
{
struct filter_elt *elt;

if (filters.fa_cnt >= MAX_FILTER_NUMBER || len > sizeof(elt->fe_d) ||
type > FIL_ALL)
return -1;

elt = &filters.fa_array[filters.fa_cnt];
elt->fe_cb = cb;
elt->fe_not = not;
memcpy(&elt->fe_d, data, len);

filters.fa_cnt++;
filters.fa_msk |= type;

return 0;
}

static int is_filters_match( struct ext2_inode *inode, struct ea_info *ctx)
{
int i;
int match = 0;
struct filter_elt *elt = &filters.fa_array[0];

for (i = 0; i < filters.fa_cnt; i++, elt++) {
match = elt->fe_cb(elt, inode, ctx);

if (elt->fe_not)
match = !match;
if (!match)
break;
}

return match;
}

static int filter_accessed_before(struct filter_elt *elt, struct ext2_inode *i,
struct ea_info *ctx)
{
time_t cutoff_time = elt->fe_d.time;

if (i->i_atime < cutoff_time &&
i->i_mtime < cutoff_time &&
i->i_ctime < cutoff_time)
return 1;

return 0;
}

static int filter_newer_than(struct filter_elt *elt, struct ext2_inode *i,
struct ea_info *ctx)
{
time_t cutoff_time = elt->fe_d.time;

if (i->i_mtime >= cutoff_time &&
i->i_ctime >= cutoff_time)
return 1;

return 0;
}

static int filter_context(struct filter_elt *elt, struct ext2_inode *i,
struct ea_info *ctx)
{
regex_t *reg = &elt->fe_d.regex;

if (!ctx)
return 0;

return regexec(reg, ctx->value, 0, NULL, 0) == 0;
}

static void report_fid(FILE *f, struct ea_info *lov)
{
struct lustre_mdt_attrs *lma = lov->value;
fprintf(f, "0x%lx:0x%x:0x%x", lma->lma_self_fid.f_seq,
lma->lma_self_fid.f_oid, lma->lma_self_fid.f_ver);
}

static void report_ctx(FILE *f, struct ea_info *ctx)
{
char *ctx_str = ctx->value;

fprintf(f, "%s", ctx_str);
}

static void report_osts(FILE *f, struct ea_info *lov)
{
struct lov_mds_md_v1 *lov1;
Expand Down Expand Up @@ -111,10 +223,13 @@ static void fslist_help(void)
fprintf(stderr, " show_dirs\t\tAlso show directory names\n");
fprintf(stderr, " show_fid\t\tAlso show FID in lov, ne2scan "
"format\n");
fprintf(stderr, " show_ctx\t\tAlso show selinux context, ne2scan "
"format\n");
fprintf(stderr, " note=MSG\t\tAdd MSG to ne2scan header\n");
fprintf(stderr, " fs=NAME\t\tName filesystem for ne2scan output\n");
fprintf(stderr, " newer=FILE\t\tFiles newer than FILE\n");
fprintf(stderr, " before=FILE\t\tFiles not accessed since FILE\n");
fprintf(stderr, " context=REGEX\t\tFiles match context regex\n");
fprintf(stderr, " genhit=FILE\t\tCopy entries matching newer/before "
"options to FILE\n");
fprintf(stderr, "\t\t\t (Main output will get all files, matching "
Expand All @@ -124,37 +239,72 @@ static void fslist_help(void)
static int fslist_init(const char *dev, int argc, const char **argv)
{
const char *genhit_name = NULL;
int rc;
target_dev = dev;

while (argc--) {
int not = 0;

if (!bcmp(*argv, "not_", 4)) {
not = 1;
*argv += 4;
}

if (!strcmp(*argv, "show_dirs"))
show_dirs = 1;
else if (!strcmp(*argv, "show_fid"))
show_fid = 1;
else if (!strcmp(*argv, "show_ctx"))
show_ctx = 1;
else if (!strcmp(*argv, "show_one"))
show_one = 1;
else if (!strncmp(*argv, "fs=", 3))
fsname = *argv + 3;
else if (!strncmp(*argv, "note=", 5))
user_note = *argv + 5;
else if (!strncmp(*argv, "newer=", 6)) {
if (newer_than || accessed_before) {
fprintf(stderr, "Only one newer= or before= "
"option allowed\n");
time_t f_time;

if (get_timestamp(*argv + 6, NULL, &f_time))
return 1;
}
if (get_timestamp(*argv + 6, NULL, &cutoff_time))

rc = add_to_filters(FIL_NEWER, filter_newer_than, not,
&f_time, sizeof(f_time));
if (rc) {
fprintf(stderr, "Fail to add filter '%s'\n",
*argv);
return 1;
newer_than = 1;
}

} else if (!strncmp(*argv, "before=", 7)) {
if (newer_than || accessed_before) {
fprintf(stderr, "Only one newer= or before= "
"option allowed\n");
time_t f_time;

if (get_timestamp(*argv + 7, NULL, &f_time))
return 1;

rc = add_to_filters(FIL_BEFORE, filter_accessed_before,
not, &f_time, sizeof(f_time));
if (rc) {
fprintf(stderr, "Fail to add filter '%s'\n",
*argv);
return 1;
}
} else if (!strncmp(*argv, "context=", 8)) {
const char *context_str = *argv + 8;
regex_t reg;

if (regcomp(&reg, context_str, REG_EXTENDED)) {
fprintf(stderr, "Could not compile context regex\n");
return 1;
}
if (get_timestamp(*argv + 7, &cutoff_time, NULL))

rc = add_to_filters(FIL_CONTEXT, filter_context, not,
&reg, sizeof(reg));
if (rc) {
fprintf(stderr, "Fail to add filter '%s'\n",
*argv);
return 1;
accessed_before = 1;
}
} else if (!strncmp(*argv, "format=", 7)) {
if (!strcmp(*argv, "format=ne2scan"))
fslist_format = FORMAT_NE2SCAN;
Expand Down Expand Up @@ -182,9 +332,9 @@ static int fslist_init(const char *dev, int argc, const char **argv)
}

if (genhit_name) {
if (!(newer_than || accessed_before)) {
fprintf(stderr, "genhit only makes sense with newer= "
"or before=\n");
if (!(filters.fa_msk & FIL_ALL)) {
fprintf(stderr, "genhit only makes sense with a filter"
"option\n");
return 1;
}

Expand Down Expand Up @@ -215,12 +365,7 @@ static int fslist_iscan(ext2_ino_t ino, struct ext2_inode *inode,
* Note, if we're sending data to a separate genhit file, then
* we actually want everything for the main file.
*/
if (!genhit && accessed_before && (inode->i_atime >= cutoff_time ||
inode->i_mtime >= cutoff_time ||
inode->i_ctime >= cutoff_time))
return ACTION_COMPLETE;
if (!genhit && newer_than && inode->i_ctime < cutoff_time &&
inode->i_mtime < cutoff_time)
if (!genhit && is_filters_match(inode, NULL))
return ACTION_COMPLETE;

return ACTION_WANT_PATH | ACTION_WANT_INODE;
Expand Down Expand Up @@ -255,7 +400,8 @@ static int fslist_dscan_begin(void)

static int fslist_output(FILE *f, ext2_ino_t ino, struct ext2_inode *inode,
int offset, const char *name, int namelen,
struct ea_info *lov, struct ea_info *lma)
struct ea_info *lov, struct ea_info *lma,
struct ea_info *ctx)
{
if (fslist_format > FORMAT_INUM) {
fprintf(f, "%u|%u|%u|%u|%u|%o|%lu|%u", inode->i_atime,
Expand All @@ -276,6 +422,12 @@ static int fslist_output(FILE *f, ext2_ino_t ino, struct ext2_inode *inode,
report_fid(f, lma);
}

if (show_ctx) {
fprintf(f, "|");
if (ctx)
report_ctx(f, ctx);
}

fprintf(f, "|");
} else if (fslist_format == FORMAT_INUM) {
fprintf(f, "%lu ", ino);
Expand All @@ -288,17 +440,34 @@ static int fslist_dscan(ext2_ino_t ino, struct ext2_inode *inode,
struct dentry *parent, const char *name, int namelen,
struct ea_info *eas)
{
int need_ctx = show_ctx || (filters.fa_msk | FIL_CONTEXT);
struct ea_info *lov = NULL;
struct ea_info *lma = NULL;
struct ea_info *ctx = NULL;
struct ea_info *ea;
int requested = 0;
int offset;

if (!inode)
return ACTION_WANT_INODE | ACTION_WANT_ATTRS;

if (fslist_format >= FORMAT_LUSTRE) {
if (fslist_format >= FORMAT_LUSTRE || need_ctx) {
for (ea = eas; ea->name; ea++) {
if (need_ctx &&
ea->index == EXT2_XATTR_INDEX_SECURITY &&
ea->name_len == 7 &&
!strncmp(ea->name, "selinux", 7)) {
char *ctx_str = ea->value;

ctx = ea;
if (!ctx_str) {
ea->requested = 1;
requested++;
} else {
ctx_str[ctx->value_len - 1] = '\0';
}
}

if (ea->index != EXT2_XATTR_INDEX_TRUSTED &&
ea->index != EXT2_XATTR_INDEX_LUSTRE)
continue;
Expand Down Expand Up @@ -327,20 +496,11 @@ static int fslist_dscan(ext2_ino_t ino, struct ext2_inode *inode,
return ACTION_WANT_READ_ATTRS;

offset = build_path(parent, 0);
fslist_output(outfile, ino, inode, offset, name, namelen, lov, lma);
fslist_output(outfile, ino, inode, offset, name, namelen, lov, lma, ctx);

if (genhit) {
if (accessed_before && (inode->i_atime < cutoff_time &&
inode->i_mtime < cutoff_time &&
inode->i_ctime < cutoff_time)) {
fslist_output(genhit, ino, inode, offset, name,
namelen, lov, lma);
} else if (newer_than && (inode->i_ctime >= cutoff_time ||
inode->i_mtime >= cutoff_time)) {
fslist_output(genhit, ino, inode, offset, name,
namelen, lov, lma);
}
}
if (genhit && is_filters_match(inode, ctx))
fslist_output(genhit, ino, inode, offset, name,
namelen, lov, lma, ctx);

if (show_one)
return ACTION_COMPLETE | ACTION_IGNORE_FILE;
Expand Down
3 changes: 3 additions & 0 deletions lustre_lov.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#ifndef EXT2_XATTR_INDEX_LUSTRE
#define EXT2_XATTR_INDEX_LUSTRE 5
#endif
#ifndef EXT2_XATTR_INDEX_SECURITY
#define EXT2_XATTR_INDEX_SECURITY 6
#endif

/* From lustre_idl.h */
#define LOV_MAGIC_V1 0x0BD10BD0
Expand Down