NEWERXY_MAX,
};
+enum lfs_find_perm {
+ LFS_FIND_PERM_EXACT = -2,
+ LFS_FIND_PERM_ANY = -1,
+ LFS_FIND_PERM_OFF = 0,
+ LFS_FIND_PERM_ALL = 1,
+};
+
struct find_param {
unsigned int fp_max_depth;
dev_t fp_dev;
mode_t fp_type; /* S_IFIFO,... */
uid_t fp_uid;
gid_t fp_gid;
+ mode_t fp_perm;
time_t fp_atime;
time_t fp_mtime;
time_t fp_ctime;
fp_mdt_count_sign:2,
fp_blocks_sign:2,
fp_ext_size_sign:2,
- fp_unused1_sign:2, /* Fields available to use*/
+ fp_perm_sign:2,
fp_unused2_sign:2, /* Once used we must add */
fp_unused3_sign:2, /* a separate flag field */
fp_unused4_sign:2; /* at end of the struct. */
fp_lazy:1,
fp_newerxy:1,
fp_exclude_btime:1,
- fp_unused_bit3:1, /* All of these unused bit */
- fp_unused_bit4:1, /* fields available to use.*/
- fp_unused_bit5:1, /* Once all unused fields */
- fp_unused_bit6:1, /* are used we need to add */
- fp_unused_bit7:1; /* a separate flag field at*/
- /* the end of the struct. */
+ fp_exclude_perm:1,
+ fp_unused_bit4:1, /* Once all unused fields */
+ fp_unused_bit5:1, /* are used we need to add */
+ fp_unused_bit6:1, /* a separate flag field at*/
+ fp_unused_bit7:1; /* the end of the struct. */
enum llapi_layout_verbose fp_verbose;
int fp_quiet;
}
run_test 56ab "lfs find --blocks"
+# LU-11188
+test_56aca() {
+ local dir="$DIR/$tdir"
+ local perms=(001 002 003 004 005 006 007
+ 010 020 030 040 050 060 070
+ 100 200 300 400 500 600 700
+ 111 222 333 444 555 666 777)
+ local perm_minus=(8 8 4 8 4 4 2
+ 8 8 4 8 4 4 2
+ 8 8 4 8 4 4 2
+ 4 4 2 4 2 2 1)
+ local perm_slash=(8 8 12 8 12 12 14
+ 8 8 12 8 12 12 14
+ 8 8 12 8 12 12 14
+ 16 16 24 16 24 24 28)
+
+ test_mkdir "$dir"
+ for perm in ${perms[*]}; do
+ touch "$dir/$tfile.$perm"
+ chmod $perm "$dir/$tfile.$perm"
+ done
+
+ for ((i = 0; i < ${#perms[*]}; i++)); do
+ local num=$($LFS find $dir -perm ${perms[i]} | wc -l)
+ (( $num == 1 )) ||
+ error "lfs find -perm ${perms[i]}:"\
+ "$num != 1"
+
+ num=$($LFS find $dir -perm -${perms[i]} -type f| wc -l)
+ (( $num == ${perm_minus[i]} )) ||
+ error "lfs find -perm -${perms[i]}:"\
+ "$num != ${perm_minus[i]}"
+
+ num=$($LFS find $dir -perm /${perms[i]} -type f| wc -l)
+ (( $num == ${perm_slash[i]} )) ||
+ error "lfs find -perm /${perms[i]}:"\
+ "$num != ${perm_slash[i]}"
+ done
+}
+run_test 56aca "check lfs find -perm with octal representation"
+
+test_56acb() {
+ local dir=$DIR/$tdir
+ # p is the permission of write and execute for user, group and other
+ # without the umask. It is used to test +wx.
+ local p=$(printf "%o" "$((0333 & ~$(umask)))")
+ local perms=(1000 000 2000 4000 $p 644 111 110 100 004)
+ local symbolic=(+t a+t u+t g+t o+t
+ g+s u+s o+s +s o+sr
+ o=r,ug+o,u+w
+ u+ g+ o+ a+ ugo+
+ u- g- o- a- ugo-
+ u= g= o= a= ugo=
+ o=r,ug+o,u+w u=r,a+u,u+w
+ g=r,ugo=g,u+w u+x,+X +X
+ u+x,u+X u+X u+x,g+X o+r,+X
+ u+x,go+X +wx +rwx)
+
+ test_mkdir $dir
+ for perm in ${perms[*]}; do
+ touch "$dir/$tfile.$perm"
+ chmod $perm "$dir/$tfile.$perm"
+ done
+
+ for (( i = 0; i < ${#symbolic[*]}; i++ )); do
+ local num=$($LFS find $dir -perm ${symbolic[i]} | wc -l)
+
+ (( $num == 1 )) ||
+ error "lfs find $dir -perm ${symbolic[i]}: $num != 1"
+ done
+}
+run_test 56acb "check lfs find -perm with symbolic representation"
+
+test_56acc() {
+ local dir=$DIR/$tdir
+ local tests="17777 787 789 abcd
+ ug=uu ug=a ug=gu uo=ou urw
+ u+xg+x a=r,u+x,"
+
+ test_mkdir $dir
+ for err in $tests; do
+ if $LFS find $dir -perm $err 2>/dev/null; then
+ error "lfs find -perm $err: parsing should have failed"
+ fi
+ done
+}
+run_test 56acc "check parsing error for lfs find -perm"
+
test_56ba() {
[ $MDS1_VERSION -lt $(version_code 2.10.50) ] &&
skip "Need MDS version at least 2.10.50"
" [[!] --newer[XY] <reference>] [[!] --blocks|-b N]\n"
" [--maxdepth|-D N] [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
" [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
- " [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n"
+ " [[!] --perm [/-]mode] [[!] --pool <pool>] [--print|-P]\n"
+ " [--print0|-0] [[!] --projid <projid>]\n"
+ " [[!] --size|-s [+-]N[bkMGTPE]]\n"
" [[!] --stripe-count|-c [+-]<stripes>]\n"
" [[!] --stripe-index|-i <index,...>]\n"
" [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
" [[!] --extension-size|--ext-size|-z [+-]N[kMGT]]\n"
" [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
- " [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
- " [[!] --projid <projid>]\n"
+ " [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
" [[!] --layout|-L released,raid0,mdt]\n"
" [[!] --foreign[=<foreign_type>]]\n"
" [[!] --component-count [+-]<comp_cnt>]\n"
LFS_MODE_OPT,
LFS_NEWERXY_OPT,
LFS_INHERIT_RR_OPT,
+ LFS_FIND_PERM,
};
/* functions */
return 0;
}
+static int parse_symbolic(const char *input, mode_t *outmode, const char **end)
+{
+ int loop;
+ int user, group, other;
+ int who, all;
+ char c, op;
+ mode_t perm;
+ mode_t usermask;
+ mode_t previous_flags;
+
+ user = group = other = 0;
+ all = 0;
+ loop = 1;
+ perm = 0;
+ previous_flags = 0;
+ *end = input;
+ usermask = 0;
+
+ while (loop) {
+ switch (*input) {
+ case 'u':
+ user = 1;
+ break;
+ case 'g':
+ group = 1;
+ break;
+ case 'o':
+ other = 1;
+ break;
+ case 'a':
+ user = group = other = 1;
+ all = 1;
+ break;
+ default:
+ loop = 0;
+ }
+
+ if (loop)
+ input++;
+ }
+
+ who = user || group || other;
+ if (!who) {
+ /* get the umask */
+ usermask = umask(0022);
+ umask(usermask);
+ usermask &= 07777;
+ }
+
+ if (*input == '-' || *input == '+' || *input == '=')
+ op = *input++;
+ else
+ /* operation is required */
+ return -1;
+
+ /* get the flags in *outmode */
+ switch (*input) {
+ case 'u':
+ previous_flags = (*outmode & 0700);
+ perm |= user ? previous_flags : 0;
+ perm |= group ? (previous_flags >> 3) : 0;
+ perm |= other ? (previous_flags >> 6) : 0;
+ input++;
+ goto write_perm;
+ case 'g':
+ previous_flags = (*outmode & 0070);
+ perm |= user ? (previous_flags << 3) : 0;
+ perm |= group ? previous_flags : 0;
+ perm |= other ? (previous_flags >> 3) : 0;
+ input++;
+ goto write_perm;
+ case 'o':
+ previous_flags = (*outmode & 0007);
+ perm |= user ? (previous_flags << 6) : 0;
+ perm |= group ? (previous_flags << 3) : 0;
+ perm |= other ? previous_flags : 0;
+ input++;
+ goto write_perm;
+ default:
+ break;
+ }
+
+ /* this part is optional,
+ * if empty perm = 0 and *outmode is not modified
+ */
+ loop = 1;
+ while (loop) {
+ c = *input;
+ switch (c) {
+ case 'r':
+ perm |= user ? 0400 : 0;
+ perm |= group ? 0040 : 0;
+ perm |= other ? 0004 : 0;
+ /* set read permission for uog except for umask's
+ * permissions
+ */
+ perm |= who ? 0 : (0444 & ~usermask);
+ break;
+ case 'w':
+ perm |= user ? 0200 : 0;
+ perm |= group ? 0020 : 0;
+ perm |= other ? 0002 : 0;
+ /* set write permission for uog except for umask'
+ * permissions
+ */
+ perm |= who ? 0 : (0222 & ~usermask);
+ break;
+ case 'x':
+ perm |= user ? 0100 : 0;
+ perm |= group ? 0010 : 0;
+ perm |= other ? 0001 : 0;
+ /* set execute permission for uog except for umask'
+ * permissions
+ */
+ perm |= who ? 0 : (0111 & ~usermask);
+ break;
+ case 'X':
+ /*
+ * Adds execute permission to 'u', 'g' and/or 'g' if
+ * specified and either 'u', 'g' or 'o' already has
+ * execute permissions.
+ */
+ if ((*outmode & 0111) != 0) {
+ perm |= user ? 0100 : 0;
+ perm |= group ? 0010 : 0;
+ perm |= other ? 0001 : 0;
+ perm |= !who ? 0111 : 0;
+ }
+ break;
+ case 's':
+ /* s is ignored if o is given, but it's not an error */
+ if (other && !group && !user)
+ break;
+ perm |= user ? S_ISUID : 0;
+ perm |= group ? S_ISGID : 0;
+ break;
+ case 't':
+ /* 't' should be used when 'a' is given
+ * or who is empty
+ */
+ perm |= (!who || all) ? S_ISVTX : 0;
+ /* using ugo with t is not an error */
+ break;
+ default:
+ loop = 0;
+ break;
+ }
+ if (loop)
+ input++;
+ }
+
+write_perm:
+ /* uog flags should be only one character long */
+ if (previous_flags && (*input != '\0' && *input != ','))
+ return -1;
+
+ switch (op) {
+ case '-':
+ /* remove the flags from outmode */
+ *outmode &= ~perm;
+ break;
+ case '+':
+ /* add the flags to outmode */
+ *outmode |= perm;
+ break;
+ case '=':
+ /* set the flags of outmode to perm */
+ if (perm != 0)
+ *outmode = perm;
+ break;
+ }
+
+ *end = input;
+ return 0;
+}
+
+static int str2mode_t(const char *input, mode_t *outmode)
+{
+ int ret;
+ const char *iter;
+
+ ret = 0;
+
+ if (*input >= '0' && *input <= '7') {
+ /* parse octal representation */
+ char *end;
+
+ iter = input;
+
+ /* look for invalid digits in octal representation */
+ while (isdigit(*iter))
+ if (*iter++ > '7')
+ return -1;
+
+ errno = 0;
+ *outmode = strtoul(input, &end, 8);
+
+ if (errno != 0 || *outmode > 07777) {
+ *outmode = 0;
+ ret = -1;
+ }
+
+ } else if (*input == '8' || *input == '9') {
+ /* error: invalid octal number */
+ ret = -1;
+ } else {
+ /* parse coma seperated list of symbolic representation */
+ int rc;
+ const char *end;
+
+ *outmode = 0;
+ rc = 0;
+ end = NULL;
+
+ do {
+ rc = parse_symbolic(input, outmode, &end);
+ if (rc)
+ return -1;
+
+ input = end+1;
+ } while (*end == ',');
+
+ if (*end != '\0')
+ ret = -1;
+ }
+ return ret;
+}
+
static int lfs_find(int argc, char **argv)
{
int c, rc;
{ .val = 'S', .name = "stripe-size", .has_arg = required_argument },
{ .val = 'S', .name = "stripe_size", .has_arg = required_argument },
{ .val = 't', .name = "type", .has_arg = required_argument },
+ { .val = LFS_FIND_PERM,
+ .name = "perm", .has_arg = required_argument },
{ .val = 'T', .name = "mdt-count", .has_arg = required_argument },
{ .val = 'u', .name = "uid", .has_arg = required_argument },
{ .val = 'U', .name = "user", .has_arg = required_argument },
goto err;
};
break;
+ case LFS_FIND_PERM:
+ param.fp_exclude_perm = !!neg_opt;
+ param.fp_perm_sign = LFS_FIND_PERM_EXACT;
+ if (*optarg == '/') {
+ param.fp_perm_sign = LFS_FIND_PERM_ANY;
+ optarg++;
+ } else if (*optarg == '-') {
+ param.fp_perm_sign = LFS_FIND_PERM_ALL;
+ optarg++;
+ }
+
+ if (str2mode_t(optarg, ¶m.fp_perm)) {
+ fprintf(stderr, "error: invalid mode '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ break;
case 'T':
if (optarg[0] == '+') {
param.fp_mdt_count_sign = -1;
return 0;
}
+/*
+ * Check that the file's permissions in *st matches the one in find_param
+ */
+static int check_file_permissions(const struct find_param *param,
+ const lstat_t *st)
+{
+ const mode_t st_mode = st->st_mode & 07777;
+ int decision = 0;
+
+ switch (param->fp_perm_sign) {
+ case LFS_FIND_PERM_EXACT:
+ decision = (st_mode == param->fp_perm);
+ break;
+ case LFS_FIND_PERM_ALL:
+ decision = ((st_mode & param->fp_perm) == param->fp_perm);
+ break;
+ case LFS_FIND_PERM_ANY:
+ decision = ((st_mode & param->fp_perm) != 0);
+ break;
+ }
+
+ if ((param->fp_exclude_perm && decision)
+ || (!param->fp_exclude_perm && !decision))
+ return -1;
+ else
+ return 1;
+}
+
static int cb_find_init(char *path, int p, int *dp,
void *data, struct dirent64 *de)
{
param->fp_check_size || param->fp_check_blocks ||
find_check_lmm_info(param) ||
param->fp_check_mdt_count || param->fp_hash_type ||
- param->fp_check_hash_flag)
+ param->fp_check_hash_flag || param->fp_perm_sign)
decision = 0;
if (param->fp_type != 0 && checked_type == 0)
(param->fp_lazy && flags & OBD_MD_FLLAZYBLOCKS)))
decision = 0;
+ if (param->fp_perm_sign)
+ decision = 0;
+
/*
* If file still fits the request, ask ost for updated info.
* The regular stat is almost of the same speed as some new
goto out;
}
}
+
+ /* Check the file permissions from the stat info */
+ if (param->fp_perm_sign) {
+ decision = check_file_permissions(param, &st);
+ if (decision == -1)
+ goto decided;
+ }
}
if (param->fp_check_size) {