From 7b599e8fa775901fad4af49c6c4e8c6442095247 Mon Sep 17 00:00:00 2001 From: kalpak <kalpak> Date: Wed, 28 Nov 2007 10:46:14 +0000 Subject: [PATCH] b=13128 i=kalpak, rupesh (patch by adilger) add -type option to lfs find --- lustre/include/lustre/liblustreapi.h | 3 +- lustre/tests/sanity.sh | 69 ++++++++++++++++++ lustre/utils/lfs.c | 49 +++++++++---- lustre/utils/liblustreapi.c | 104 ++++++++++++++++++++------- 4 files changed, 183 insertions(+), 42 deletions(-) diff --git a/lustre/include/lustre/liblustreapi.h b/lustre/include/lustre/liblustreapi.h index 27433f7d9f..c812664852 100644 --- a/lustre/include/lustre/liblustreapi.h +++ b/lustre/include/lustre/liblustreapi.h @@ -29,8 +29,9 @@ struct find_param { int asign; int csign; int msign; + int type; - int zeroend:1, recursive:1, got_uuids:1, obds_printed:1, exclude_pattern:1; + unsigned zeroend:1, recursive:1, got_uuids:1, obds_printed:1, exclude_pattern:1, exclude_type:1; int verbose; int quiet; diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 48a3403ecd..cec9405ed3 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -2449,6 +2449,25 @@ setup_56() { fi } +setup_56_special() { + LOCAL_NUMFILES=$1 + LOCAL_NUMDIRS=$2 + TDIR=$DIR/${tdir}g + setup_56 $1 $2 + if [ ! -e "$TDIR/loop1b" ] ; then + for i in `seq 1 $LOCAL_NUMFILES` ; do + mknod $TDIR/loop${i}b b 7 $i + mknod $TDIR/null${i}c c 1 3 + ln -s $TDIR/file0 $TDIR/link${i}l + done + for i in `seq 1 $LOCAL_NUMDIRS` ; do + mknod $TDIR/dir$i/loop${i}b b 7 $i + mknod $TDIR/dir$i/null${i}c c 1 3 + ln -s $TDIR/dir$i/file0 $TDIR/dir$i/link${i}l + done + fi +} + test_56g() { $LSTRIPE -d $DIR @@ -2490,6 +2509,56 @@ test_56i() { } run_test 56i "check 'lfs find -ost UUID' skips directories =======" +test_56j() { + setup_56_special $NUMFILES $NUMDIRS + + EXPECTED=$((NUMDIRS+1)) + NUMS=`$LFIND -type d $DIR/${tdir}g | wc -l` + [ $NUMS -eq $EXPECTED ] || \ + error "lfs find -type d $DIR/${tdir}g wrong: found $NUMS, expected $EXPECTED" +} +run_test 56j "check lfs find -type d =============================" + +test_56k() { + setup_56_special $NUMFILES $NUMDIRS + + EXPECTED=$(((NUMDIRS+1) * NUMFILES)) + NUMS=`$LFIND -type f $DIR/${tdir}g | wc -l` + [ $NUMS -eq $EXPECTED ] || \ + error "lfs find -type f $DIR/${tdir}g wrong: found $NUMS, expected $EXPECTED" +} +run_test 56k "check lfs find -type f =============================" + +test_56l() { + setup_56_special $NUMFILES $NUMDIRS + + EXPECTED=$((NUMDIRS + NUMFILES)) + NUMS=`$LFIND -type b $DIR/${tdir}g | wc -l` + [ $NUMS -eq $EXPECTED ] || \ + error "lfs find -type b $DIR/${tdir}g wrong: found $NUMS, expected $EXPECTED" +} +run_test 56l "check lfs find -type b =============================" + +test_56m() { + setup_56_special $NUMFILES $NUMDIRS + + EXPECTED=$((NUMDIRS + NUMFILES)) + NUMS=`$LFIND -type c $DIR/${tdir}g | wc -l` + [ $NUMS -eq $EXPECTED ] || \ + error "lfs find -type c $DIR/${tdir}g wrong: found $NUMS, expected $EXPECTED" +} +run_test 56m "check lfs find -type c =============================" + +test_56n() { + setup_56_special $NUMFILES $NUMDIRS + + EXPECTED=$((NUMDIRS + NUMFILES)) + NUMS=`$LFIND -type l $DIR/${tdir}g | wc -l` + [ $NUMS -eq $EXPECTED ] || \ + error "lfs find -type l $DIR/${tdir}g wrong: found $NUMS, expected $EXPECTED" +} +run_test 56n "check lfs find -type l =============================" + test_57a() { # note test will not do anything if MDS is not local remote_mds && skip "remote MDS" && return diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 315cb7dcb4..79c3c27b1d 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -99,15 +99,12 @@ command_t cmdlist[] = { {"find", lfs_find, 0, "To find files that match given parameters recursively in a directory tree.\n" "usage: find <dir/file> ... \n" - " [[!] --atime|-A N] [[!] --mtime|-M N] [[!] --ctime|-C N] [--maxdepth|-D N]\n" - " [[!] --name|-n <pattern>] [--print0|-P] [--print|-p] [--obd|-O <uuid>]\n" - "\t !: used before --atime, --mtime, --ctime specifies the negative value\n" - "\t !: used before --name means find exclude the regular expression pattern\n" - "If one of the options below is provided, find works the same as 'getstripe':\n" - "To list the striping info for a given filename or files in a directory or\n" - "recursively.\n" - "OBSOLETE usage: find [--quiet | -q] [--verbose | -v]\n" - " [--recursive | -r] <dir|file> ..."}, + " [[!] --atime|-A [+-]N] [[!] --mtime|-M [+-]N] [[!] --ctime|-C [+-]N]\n" + " [--maxdepth|-D N] [[!] --name|-n <pattern>] [--print0|-P]\n" + " [--print|-p] [--obd|-O <uuid>] [[!] --type|-t <filetype>]\n" + "\t !: used before an option indicates 'NOT' the requested attribute\n" + "\t -: used before an value indicates 'AT MOST' the requested value\n" + "\t +: used before an option indicates 'AT LEAST' the requested value\n"}, {"check", lfs_check, 0, "Display the status of MDS or OSTs (as specified in the command)\n" "or all the servers (MDS and OSTs).\n" @@ -348,6 +345,7 @@ static int lfs_find(int argc, char **argv) /* Old find options. */ {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, + {"type", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} }; @@ -360,7 +358,7 @@ static int lfs_find(int argc, char **argv) time(&t); - while ((c = getopt_long_only(argc, argv, "-A:C:D:M:n:PpO:qrv", + while ((c = getopt_long_only(argc, argv, "-A:C:D:M:n:PpO:qrt:v", long_opts, NULL)) >= 0) { xtime = NULL; xsign = NULL; @@ -424,15 +422,13 @@ static int lfs_find(int argc, char **argv) *xsign = ret; break; case 'D': + new_fashion = 1; param.maxdepth = strtol(optarg, 0, 0); break; case 'n': new_fashion = 1; param.pattern = (char *)optarg; - if (neg_opt) - param.exclude_pattern = 1; - else - param.exclude_pattern = 0; + param.exclude_pattern = !!neg_opt; break; case 'O': if (param.obduuid) { @@ -444,6 +440,7 @@ static int lfs_find(int argc, char **argv) param.obduuid = (struct obd_uuid *)optarg; break; case 'p': + new_fashion = 1; param.zeroend = 1; break; case 'P': @@ -457,6 +454,24 @@ static int lfs_find(int argc, char **argv) new_fashion = 0; param.recursive = 1; break; + case 't': + param.exclude_type = !!neg_opt; + switch(optarg[0]) { + case 'b': param.type = S_IFBLK; break; + case 'c': param.type = S_IFCHR; break; + case 'd': param.type = S_IFDIR; break; + case 'f': param.type = S_IFREG; break; + case 'l': param.type = S_IFLNK; break; + case 'p': param.type = S_IFIFO; break; + case 's': param.type = S_IFSOCK; break; +#ifdef S_IFDOOR /* Solaris only */ + case 'D': param.type = S_IFDOOR; break; +#endif + default: fprintf(stderr, "error: %s: bad type '%s'\n", + argv[0], optarg); + return CMD_HELP; + }; + break; case 'v': new_fashion = 0; param.verbose++; @@ -483,6 +498,12 @@ static int lfs_find(int argc, char **argv) if (new_fashion) { param.quiet = 1; } else { + static int deprecated_warning; + if (!deprecated_warning) { + fprintf(stderr, "lfs find: -q, -r, -v options " + "deprecated. Use 'lfs getstripe' instead.\n"); + deprecated_warning = 1; + } if (!param.recursive && param.maxdepth == -1) param.maxdepth = 1; } diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 66b1604b49..cfafb4b356 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -158,7 +158,8 @@ int llapi_file_create(const char *name, unsigned long stripe_size, return 0; } -typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d, void *data); +typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d, + void *data, struct dirent64 *de); #define MAX_LOV_UUID_COUNT max(LOV_MAX_STRIPE_COUNT, 1000) #define OBD_NOT_FOUND (-1) @@ -527,7 +528,8 @@ static DIR *opendir_parent(char *path) static int llapi_semantic_traverse(char *path, int size, DIR *parent, semantic_func_t sem_init, - semantic_func_t sem_fini, void *data) + semantic_func_t sem_fini, void *data, + struct dirent64 *de) { struct dirent64 *dent; int len, ret; @@ -548,7 +550,7 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, GOTO(out, ret = -EINVAL); } - if (sem_init && (ret = sem_init(path, parent ?: p, d, data))) + if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de))) goto err; if (!d) @@ -582,19 +584,19 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent, break; case DT_DIR: ret = llapi_semantic_traverse(path, size, d, sem_init, - sem_fini, data); + sem_fini, data, dent); if (ret < 0) goto out; break; default: ret = 0; if (sem_init) { - ret = sem_init(path, d, NULL, data); + ret = sem_init(path, d, NULL, data, dent); if (ret < 0) goto out; } if (sem_fini && ret == 0) - sem_fini(path, d, NULL, data); + sem_fini(path, d, NULL, data, dent); } } @@ -602,7 +604,7 @@ out: path[len] = 0; if (sem_fini) - sem_fini(path, parent, d, data); + sem_fini(path, parent, d, data, de); err: if (d) closedir(d); @@ -701,28 +703,73 @@ static int find_time_check(lstat_t *st, struct find_param *param, int mds) return rc; } -static int cb_find_init(char *path, DIR *parent, DIR *dir, void *data) +static unsigned llapi_dir_filetype_table[] = { + [DT_UNKNOWN]= 0, + [DT_FIFO]= S_IFIFO, + [DT_CHR] = S_IFCHR, + [DT_DIR] = S_IFDIR, + [DT_BLK] = S_IFBLK, + [DT_REG] = S_IFREG, + [DT_LNK] = S_IFLNK, + [DT_SOCK]= S_IFSOCK, +#if defined(DT_DOOR) && defined(S_IFDOOR) + [DT_DOOR]= S_IFDOOR, +#endif +}; +#if defined(DT_DOOR) && defined(S_IFDOOR) +static const int DT_MAX = DT_DOOR; +#else +static const int DT_MAX = DT_SOCK; +#endif + +static int cb_find_init(char *path, DIR *parent, DIR *dir, + void *data, struct dirent64 *de) { struct find_param *param = (struct find_param *)data; int decision = 1; /* 1 is accepted; -1 is rejected. */ lstat_t *st = ¶m->lmd->lmd_st; int lustre_fs = 1; - int ret = 0; + int checked_type = 0; + int ret; LASSERT(parent != NULL || dir != NULL); param->lmd->lmd_lmm.lmm_stripe_count = 0; + /* If a regular expression is presented, make the initial decision */ + if (param->pattern != NULL) { + char *fname = strrchr(path, '/'); + fname = (fname == NULL ? path : fname + 1); + ret = fnmatch(param->pattern, fname, 0); + if ((ret == FNM_NOMATCH && !param->exclude_pattern) || + (ret == 0 && param->exclude_pattern)) + goto decided; + } + + /* See if we can check the file type from the dirent. */ + if (param->type && de != NULL && de->d_type != DT_UNKNOWN && + de->d_type < DT_MAX) { + checked_type = 1; + if (llapi_dir_filetype_table[de->d_type] == param->type) { + if (param->exclude_type) + goto decided; + } else { + if (!param->exclude_type) + goto decided; + } + } + + /* If a time or OST should be checked, the decision is not taken yet. */ if (param->atime || param->ctime || param->mtime || param->obduuid) decision = 0; /* Request MDS for the stat info. */ - if (!decision && dir) { + if (dir) { /* retrieve needed file info */ ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO, (void *)param->lmd); - } else if (!decision && parent) { + } else /* if (parent) LASSERT() above makes always true */ { char *fname = strrchr(path, '/'); fname = (fname == NULL ? path : fname + 1); @@ -755,6 +802,16 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir, void *data) } } + if (param->type && !checked_type) { + if ((st->st_mode & S_IFMT) == param->type) { + if (param->exclude_type) + goto decided; + } else { + if (!param->exclude_type) + goto decided; + } + } + /* Prepare odb. */ if (param->obduuid) { if (lustre_fs && param->got_uuids && @@ -777,16 +834,6 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir, void *data) } } - /* If a regular expression is presented, make the initial decision */ - if (param->pattern != NULL) { - char *fname = strrchr(path, '/'); - fname = (fname == NULL ? path : fname + 1); - ret = fnmatch(param->pattern, fname, 0); - if ((ret == FNM_NOMATCH && !param->exclude_pattern) || - (ret == 0 && param->exclude_pattern)) - decision = -1; - } - /* If an OBD UUID is specified but no one matches, skip this file. */ if (param->obduuid && param->obdindex == OBD_NOT_FOUND) decision = -1; @@ -894,7 +941,8 @@ decided: return 0; } -static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data) +static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data, + struct dirent64 *de) { struct find_param *param = (struct find_param *)data; param->depth--; @@ -926,14 +974,15 @@ int llapi_find(char *path, struct find_param *param) strncpy(buf, path, PATH_MAX + 1); ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init, - cb_common_fini, param); + cb_common_fini, param, NULL); find_param_fini(param); free(buf); return ret < 0 ? ret : 0; } -static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data) +static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data, + struct dirent64 *de) { struct find_param *param = (struct find_param *)data; int ret = 0; @@ -1015,7 +1064,7 @@ int llapi_getstripe(char *path, struct find_param *param) strncpy(buf, path, PATH_MAX + 1); ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe, - cb_common_fini, param); + cb_common_fini, param, NULL); find_param_fini(param); free(buf); return ret < 0 ? ret : 0; @@ -1272,7 +1321,8 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl) return rc; } -static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data) +static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data, + struct dirent64 *de) { struct find_param *param = (struct find_param *)data; lstat_t *st; @@ -1356,7 +1406,7 @@ int llapi_quotachown(char *path, int flag) strncpy(buf, path, PATH_MAX + 1); ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown, - NULL, ¶m); + NULL, ¶m, NULL); out: find_param_fini(¶m); free(buf); -- GitLab