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 = &param->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, &param);
+                                      NULL, &param, NULL);
 out:
         find_param_fini(&param);
         free(buf);
-- 
GitLab