+ case 'I':
+ comp_id = strtoul(optarg, &end, 0);
+ if (*end != '\0' || comp_id == 0 ||
+ comp_id > LCME_ID_MAX) {
+ fprintf(stderr,
+ "%s %s: invalid component ID '%s'\n",
+ progname, argv[0], optarg);
+ goto usage_error;
+ }
+ break;
+ case 'f':
+ if (opc != SO_MIRROR_EXTEND && opc != SO_MIRROR_SPLIT) {
+ fprintf(stderr,
+ "error: %s: invalid option: %s\n",
+ progname, argv[optopt + 1]);
+ goto usage_error;
+ }
+ if (opc == SO_MIRROR_EXTEND) {
+ if (last_mirror == NULL) {
+ fprintf(stderr,
+ "error: %s: '-N' must exist in front of '%s'\n",
+ progname, argv[optopt + 1]);
+ goto usage_error;
+ }
+ last_mirror->m_file = optarg;
+ last_mirror->m_count = 1;
+ } else {
+ /* mirror split */
+ if (mirror_list == NULL)
+ mirror_list = lfs_mirror_alloc();
+ mirror_list->m_file = optarg;
+ }
+ has_m_file = true;
+ break;
+ case 'L':
+ if (strcmp(argv[optind - 1], "mdt") == 0) {
+ /* Can be only the first component */
+ if (layout != NULL) {
+ result = -EINVAL;
+ fprintf(stderr, "error: 'mdt' layout "
+ "can be only the first one\n");
+ goto error;
+ }
+ if (lsa.lsa_comp_end > (1ULL << 30)) { /* 1Gb */
+ result = -EFBIG;
+ fprintf(stderr, "error: 'mdt' layout "
+ "size is too big\n");
+ goto error;
+ }
+ lsa.lsa_pattern = LLAPI_LAYOUT_MDT;
+ } else if (strcmp(argv[optind - 1], "raid0") != 0) {
+ result = -EINVAL;
+ fprintf(stderr, "error: layout '%s' is "
+ "unknown, supported layouts are: "
+ "'mdt', 'raid0'\n", argv[optind]);
+ goto error;
+ }
+ break;
+ case 'm':
+ if (!migrate_mode) {
+ fprintf(stderr,
+ "%s %s: -m|--mdt-index is valid only for migrate command\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+ migrate_mdt_mode = true;
+ lsa.lsa_nr_tgts = parse_targets(tgts,
+ sizeof(tgts) / sizeof(__u32),
+ lsa.lsa_nr_tgts, optarg, NULL);
+ if (lsa.lsa_nr_tgts < 0) {
+ fprintf(stderr,
+ "%s %s: invalid MDT target(s) '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+
+ lsa.lsa_tgts = tgts;
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
+ lsa.lsa_stripe_off = tgts[0];
+ break;
+ case 'n':
+ if (!migrate_mode) {
+ fprintf(stderr,
+ "%s %s: -n|--non-block valid only for migrate command\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+ migration_flags |= MIGRATION_NONBLOCK;
+ break;
+ case 'N':
+ if (opc == SO_SETSTRIPE) {
+ opc = SO_MIRROR_CREATE;
+ mirror_mode = true;
+ }
+ mirror_count = 1;
+ if (optarg != NULL) {
+ mirror_count = strtoul(optarg, &end, 0);
+ if (*end != '\0' || mirror_count == 0) {
+ fprintf(stderr,
+ "error: %s: bad mirror count: %s\n",
+ progname, optarg);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+ new_mirror = lfs_mirror_alloc();
+ new_mirror->m_count = mirror_count;
+
+ if (mirror_list == NULL)
+ mirror_list = new_mirror;
+
+ if (last_mirror != NULL) {
+ /* wrap up last mirror */
+ if (lsa.lsa_comp_end == 0)
+ lsa.lsa_comp_end = LUSTRE_EOF;
+
+ result = comp_args_to_layout(lpp, &lsa, true);
+ if (result) {
+ lfs_mirror_free(new_mirror);
+ goto error;
+ }
+
+ setstripe_args_init_inherit(&lsa);
+
+ last_mirror->m_next = new_mirror;
+ }
+
+ last_mirror = new_mirror;
+ lpp = &last_mirror->m_layout;
+ break;
+ case 'o':
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ if (strcmp(argv[optind - 1], "--ost-list") == 0)
+ fprintf(stderr, "warning: '--ost-list' is "
+ "deprecated, use '--ost' instead\n");
+#endif
+ /* -o allows overstriping, and must note it because
+ * parse_targets is shared with MDT striping, which
+ * does not allow duplicates
+ */
+ lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
+ lsa.lsa_nr_tgts = parse_targets(tgts,
+ sizeof(tgts) / sizeof(__u32),
+ lsa.lsa_nr_tgts, optarg,
+ &lsa.lsa_pattern);
+ if (lsa.lsa_nr_tgts < 0) {
+ fprintf(stderr,
+ "%s %s: invalid OST target(s) '%s'\n",
+ progname, argv[0], optarg);
+ goto usage_error;
+ }
+
+ lsa.lsa_tgts = tgts;
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
+ lsa.lsa_stripe_off = tgts[0];
+ break;
+ case 'p':
+ if (optarg == NULL)
+ goto usage_error;
+ lsa.lsa_pool_name = optarg;
+
+ if (strlen(lsa.lsa_pool_name) == 0 ||
+ strncmp(lsa.lsa_pool_name, "none",
+ LOV_MAXPOOLNAME) == 0)
+ lsa.lsa_pool_name = NULL;
+ break;
+ case 'S':
+ result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
+ &size_units, 0);
+ if (result) {
+ fprintf(stderr,
+ "%s %s: invalid stripe size '%s'\n",
+ progname, argv[0], optarg);
+ goto usage_error;
+ }
+ break;
+ case 'v':
+ if (!migrate_mode) {
+ fprintf(stderr,
+ "%s %s: -v|--verbose valid only for migrate command\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+ migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
+ migration_flags = MIGRATION_VERBOSE;
+ break;
+ case 'x':
+ xattr = optarg;
+ break;
+ case 'y':
+ from_yaml = true;
+ template = optarg;
+ break;
+ case 'z':
+ result = llapi_parse_size(optarg,
+ &lsa.lsa_extension_size,
+ &size_units, 0);
+ if (result) {
+ fprintf(stderr,
+ "%s %s: invalid extension size '%s'\n",
+ progname, argv[0], optarg);
+ goto usage_error;
+ }
+
+ lsa.lsa_extension_comp = true;
+ break;
+ default:
+ fprintf(stderr, "%s %s: unrecognized option '%s'\n",
+ progname, argv[0], argv[optind - 1]);
+ goto usage_error;
+ }
+ }
+
+ fname = argv[optind];
+
+ if (optind == argc) {
+ fprintf(stderr, "%s %s: FILE must be specified\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (xattr && !foreign_mode) {
+ /* only print a warning as this is harmless and will be ignored
+ */
+ fprintf(stderr,
+ "%s %s: xattr has been specified for non-foreign layout\n",
+ progname, argv[0]);
+ } else if (foreign_mode && !xattr) {
+ fprintf(stderr,
+ "%s %s: xattr must be provided in foreign mode\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
+ comp_set || comp_id || delete || from_copy ||
+ setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
+ lsa.lsa_tgts)) {
+ fprintf(stderr,
+ "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+
+ if (mirror_mode && mirror_count == 0) {
+ fprintf(stderr,
+ "error: %s: --mirror-count|-N option is required\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ }
+
+ if (mirror_mode) {
+ if (lsa.lsa_comp_end == 0)
+ lsa.lsa_comp_end = LUSTRE_EOF;
+ }
+
+ if (lsa.lsa_comp_end != 0) {
+ result = comp_args_to_layout(lpp, &lsa, true);
+ if (result) {
+ fprintf(stderr, "error: %s: invalid layout\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (mirror_flags & MF_NO_VERIFY) {
+ if (opc != SO_MIRROR_EXTEND) {
+ fprintf(stderr,
+ "error: %s: --no-verify is valid only for lfs mirror extend command\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ } else if (!has_m_file) {
+ fprintf(stderr,
+ "error: %s: --no-verify must be specified with -f <victim_file> option\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (comp_set && !comp_id) {
+ fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if ((delete + comp_set + comp_del + comp_add) > 1) {
+ fprintf(stderr,
+ "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
+ lsa.lsa_comp_flags != 0 || layout != NULL)) {
+ fprintf(stderr,
+ "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if ((comp_set || comp_del) &&
+ (setstripe_args_specified(&lsa) || layout != NULL)) {
+ fprintf(stderr,
+ "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
+ fprintf(stderr,
+ "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (comp_add || comp_del) {
+ struct stat st;
+
+ result = lstat(fname, &st);
+ if (result == 0 && S_ISDIR(st.st_mode)) {
+ fprintf(stderr,
+ "%s setstripe: cannot use --component-add or --component-del for directory\n",
+ progname);
+ goto usage_error;
+ }
+
+ if (mirror_mode) {
+ fprintf(stderr, "error: %s: can't use --component-add "
+ "or --component-del for mirror operation\n",
+ progname);
+ goto usage_error;
+ }
+ }
+
+ if (comp_add) {
+ if (layout == NULL) {
+ fprintf(stderr,
+ "%s %s: option -E must be specified with --component-add\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+ }
+
+ if (layout != NULL || mirror_list != NULL) {
+ if (mirror_list)
+ result = mirror_adjust_first_extents(mirror_list);
+ else
+ result = layout_adjust_first_extent(fname, layout,
+ comp_add);
+ if (result == -ENODATA)
+ comp_add = 0;
+ else if (result != 0) {
+ fprintf(stderr, "error: %s: invalid layout\n",
+ progname);
+ goto error;
+ }
+ }
+
+ if (from_yaml && from_copy) {
+ fprintf(stderr,
+ "%s: can't specify --yaml and --copy together\n",
+ progname);
+ goto error;
+ }
+
+ if ((from_yaml || from_copy) &&
+ (setstripe_args_specified(&lsa) || layout != NULL)) {
+ fprintf(stderr, "error: %s: can't specify --yaml with "
+ "-c, -S, -i, -o, -p or -E options.\n",
+ argv[0]);
+ goto error;
+ }
+
+ if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
+ fprintf(stderr,
+ "%s %s: options --non-block and --block are mutually exclusive\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (!comp_del && !comp_set && opc != SO_MIRROR_SPLIT &&
+ opc != SO_MIRROR_DELETE && comp_id != 0) {
+ fprintf(stderr,
+ "%s: option -I can only be used with --component-del or --component-set or lfs mirror split\n",
+ progname);
+ goto usage_error;
+ }
+
+ if (migrate_mdt_mode) {
+ struct lmv_user_md *lmu;
+
+ /* initialize migrate mdt parameters */
+ lmu = calloc(1, lmv_user_md_size(lsa.lsa_nr_tgts,
+ LMV_USER_MAGIC_SPECIFIC));
+ if (!lmu) {
+ fprintf(stderr,
+ "%s %s: cannot allocate memory for lmv_user_md: %s\n",
+ progname, argv[0], strerror(ENOMEM));
+ result = -ENOMEM;
+ goto error;
+ }
+ if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
+ lmu->lum_stripe_count = lsa.lsa_stripe_count;
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT) {
+ fprintf(stderr,
+ "%s %s: migrate should specify MDT index\n",
+ progname, argv[0]);
+ free(lmu);
+ goto usage_error;
+ }
+ lmu->lum_stripe_offset = lsa.lsa_stripe_off;
+ if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
+ lmu->lum_hash_type = lsa.lsa_pattern;
+ else
+ lmu->lum_hash_type = LMV_HASH_TYPE_DEFAULT;
+ if (lsa.lsa_pool_name) {
+ strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
+ sizeof(lmu->lum_pool_name) - 1);
+ lmu->lum_pool_name[sizeof(lmu->lum_pool_name) - 1] = 0;
+ }
+ if (lsa.lsa_nr_tgts > 1) {
+ int i;
+
+ if (lsa.lsa_stripe_count > 0 &&
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
+ lsa.lsa_stripe_count != lsa.lsa_nr_tgts) {
+ fprintf(stderr,
+ "error: %s: stripe count %lld doesn't match the number of MDTs: %d\n",
+ progname, lsa.lsa_stripe_count,
+ lsa.lsa_nr_tgts);
+ free(lmu);
+ goto usage_error;
+ }
+
+ lmu->lum_magic = LMV_USER_MAGIC_SPECIFIC;
+ lmu->lum_stripe_count = lsa.lsa_nr_tgts;
+ for (i = 0; i < lsa.lsa_nr_tgts; i++)
+ lmu->lum_objects[i].lum_mds = lsa.lsa_tgts[i];
+ } else {
+ lmu->lum_magic = LMV_USER_MAGIC;
+ }
+
+ migrate_mdt_param.fp_lmv_md = lmu;
+ migrate_mdt_param.fp_migrate = 1;
+ } else if (layout == NULL) {
+ /* initialize stripe parameters */
+ param = calloc(1, offsetof(typeof(*param),
+ lsp_osts[lsa.lsa_nr_tgts]));
+ if (param == NULL) {
+ fprintf(stderr,
+ "%s %s: cannot allocate memory for parameters: %s\n",
+ progname, argv[0], strerror(ENOMEM));
+ result = -ENOMEM;
+ goto error;
+ }
+
+ if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
+ param->lsp_stripe_size = lsa.lsa_stripe_size;
+ if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
+ if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
+ param->lsp_stripe_count = -1;
+ else
+ param->lsp_stripe_count = lsa.lsa_stripe_count;
+ }
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
+ param->lsp_stripe_offset = -1;
+ else
+ param->lsp_stripe_offset = lsa.lsa_stripe_off;
+ param->lsp_stripe_pattern =
+ llapi_pattern_to_lov(lsa.lsa_pattern);
+ if (param->lsp_stripe_pattern == EINVAL) {
+ fprintf(stderr, "error: %s: invalid stripe pattern\n",
+ argv[0]);
+ free(param);
+ goto usage_error;
+ }
+ param->lsp_pool = lsa.lsa_pool_name;
+ param->lsp_is_specific = false;
+ if (lsa.lsa_nr_tgts > 0) {
+ if (lsa.lsa_stripe_count > 0 &&
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
+ lsa.lsa_nr_tgts != lsa.lsa_stripe_count) {
+ fprintf(stderr,
+ "error: %s: stripe count %lld doesn't match the number of OSTs: %d\n",
+ argv[0], lsa.lsa_stripe_count,
+ lsa.lsa_nr_tgts);
+ free(param);
+ goto usage_error;
+ }
+
+ param->lsp_is_specific = true;
+ param->lsp_stripe_count = lsa.lsa_nr_tgts;
+ memcpy(param->lsp_osts, tgts,
+ sizeof(*tgts) * lsa.lsa_nr_tgts);
+ }
+ }
+
+ if (from_yaml) {
+ /* generate a layout from a YAML template */
+ result = lfs_comp_create_from_yaml(template, &layout,
+ &lsa, tgts);
+ if (result) {
+ fprintf(stderr, "error: %s: can't create composite "
+ "layout from template file %s\n",
+ argv[0], template);
+ goto error;
+ }
+ } else if (from_copy) {
+ layout = llapi_layout_get_by_path(template, 0);
+ if (layout == NULL) {
+ fprintf(stderr,
+ "%s: can't create composite layout from file %s.\n",
+ progname, template);
+ goto error;
+ }
+ }
+
+ for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
+ if (migrate_mdt_mode) {
+ result = llapi_migrate_mdt(fname, &migrate_mdt_param);
+ } else if (migrate_mode) {
+ result = lfs_migrate(fname, migration_flags, param,
+ layout);
+ } else if (comp_set != 0) {
+ result = lfs_component_set(fname, comp_id,
+ lsa.lsa_comp_flags,
+ lsa.lsa_comp_neg_flags);
+ } else if (comp_del != 0) {
+ result = lfs_component_del(fname, comp_id,
+ lsa.lsa_comp_flags,
+ lsa.lsa_comp_neg_flags);
+ } else if (comp_add != 0) {
+ result = lfs_component_add(fname, layout);
+ } else if (opc == SO_MIRROR_CREATE) {
+ result = mirror_create(fname, mirror_list);
+ } else if (opc == SO_MIRROR_EXTEND) {
+ result = mirror_extend(fname, mirror_list,
+ mirror_flags);
+ } else if (opc == SO_MIRROR_SPLIT || opc == SO_MIRROR_DELETE) {
+ if (!mirror_id && !comp_id && !lsa.lsa_pool_name) {
+ fprintf(stderr,
+ "%s: no mirror specified to delete from '%s'\n",
+ progname, fname);
+ goto usage_error;
+ }
+ if (lsa.lsa_pool_name)
+ mirror_flags |= MF_COMP_POOL;
+ else if (mirror_id != 0)
+ comp_id = mirror_id;
+ else
+ mirror_flags |= MF_COMP_ID;
+ result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
+ mirror_flags,
+ has_m_file ? mirror_list->m_file :
+ NULL);
+ } else if (layout != NULL) {
+ result = lfs_component_create(fname, O_CREAT | O_WRONLY,
+ mode, layout);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ } else if (foreign_mode) {
+ result = llapi_file_create_foreign(fname, mode, type,
+ flags, xattr);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ } else {
+ result = llapi_file_open_param(fname,
+ O_CREAT | O_WRONLY,
+ mode, param);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ }
+ if (result) {
+ /* Save the first error encountered. */
+ if (result2 == 0)
+ result2 = result;
+ continue;
+ }
+ }
+
+ if (mode_opt != NULL)
+ umask(previous_umask);
+
+ free(param);
+ free(migrate_mdt_param.fp_lmv_md);
+ llapi_layout_free(layout);
+ lfs_mirror_list_free(mirror_list);
+ return result2;
+usage_error:
+ result = CMD_HELP;
+error:
+ llapi_layout_free(layout);
+ lfs_mirror_list_free(mirror_list);
+ return result;
+}
+
+static int lfs_poollist(int argc, char **argv)
+{
+ if (argc != 2)
+ return CMD_HELP;
+
+ return llapi_poollist(argv[1]);
+}
+
+static time_t set_time(struct find_param *param, time_t *time, time_t *set,
+ char *str)
+{
+ long long t = 0;
+ int res = 0;
+ char *endptr = "AD";
+ char *timebuf;
+
+ if (str[0] == '+')
+ res = 1;
+ else if (str[0] == '-')
+ res = -1;
+
+ if (res)
+ str++;
+
+ for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
+ long long val = strtoll(timebuf, &endptr, 0);
+ int unit = 1;
+
+ switch (*endptr) {
+ case 'y':
+ unit *= 52; /* 52 weeks + 1 day below */
+ case 'w': /* fallthrough */
+ unit *= 7;
+ case '\0': /* days are default unit if none used */
+ case 'd': /* fallthrough */
+ unit = (unit + (*endptr == 'y')) * 24;
+ case 'h': /* fallthrough */
+ unit *= 60;
+ case 'm': /* fallthrough */
+ unit *= 60;
+ case 's': /* fallthrough */
+ break;
+ /* don't need to multiply by 1 for seconds */
+ default:
+ fprintf(stderr,
+ "%s find: bad time string '%s': %s\n",
+ progname, timebuf, strerror(EINVAL));
+ return LONG_MAX;
+ }
+
+ if (param->fp_time_margin == 0 ||
+ (*endptr && unit < param->fp_time_margin))
+ param->fp_time_margin = unit;
+
+ t += val * unit;
+ }
+ if (*time < t) {
+ if (res != 0)
+ str--;
+ fprintf(stderr, "%s find: bad time '%s': too large\n",
+ progname, str);
+ return LONG_MAX;
+ }
+
+ *set = *time - t;
+
+ return res;
+}
+
+static int name2uid(unsigned int *id, const char *name)
+{
+ struct passwd *passwd;
+
+ passwd = getpwnam(name);
+ if (passwd == NULL)
+ return -ENOENT;
+ *id = passwd->pw_uid;
+
+ return 0;
+}
+
+static int name2gid(unsigned int *id, const char *name)
+{
+ struct group *group;
+
+ group = getgrnam(name);
+ if (group == NULL)
+ return -ENOENT;
+ *id = group->gr_gid;
+
+ return 0;
+}
+
+static inline int name2projid(unsigned int *id, const char *name)
+{
+ return -ENOTSUP;
+}
+
+static int uid2name(char **name, unsigned int id)
+{
+ struct passwd *passwd;
+
+ passwd = getpwuid(id);
+ if (passwd == NULL)
+ return -ENOENT;
+ *name = passwd->pw_name;
+
+ return 0;
+}
+
+static inline int gid2name(char **name, unsigned int id)
+{
+ struct group *group;
+
+ group = getgrgid(id);
+ if (group == NULL)
+ return -ENOENT;
+ *name = group->gr_name;
+
+ return 0;
+}
+
+static int name2layout(__u32 *layout, char *name)
+{
+ char *ptr, *layout_name;
+
+ *layout = 0;
+ for (ptr = name; ; ptr = NULL) {
+ layout_name = strtok(ptr, ",");
+ if (layout_name == NULL)
+ break;
+ if (strcmp(layout_name, "released") == 0)
+ *layout |= LOV_PATTERN_F_RELEASED;
+ else if (strcmp(layout_name, "raid0") == 0)
+ *layout |= LOV_PATTERN_RAID0;
+ else if (strcmp(layout_name, "mdt") == 0)
+ *layout |= LOV_PATTERN_MDT;
+ else if (strcmp(layout_name, "overstriping") == 0)
+ *layout |= LOV_PATTERN_OVERSTRIPING;
+ else
+ return -1;
+ }
+ return 0;
+}
+
+static int lfs_find(int argc, char **argv)
+{
+ int c, rc;
+ int ret = 0;
+ time_t t;
+ struct find_param param = {
+ .fp_max_depth = -1,
+ .fp_quiet = 1,
+ .fp_time_margin = 24 * 60 * 60,
+ };
+ struct option long_opts[] = {
+ { .val = 'A', .name = "atime", .has_arg = required_argument },
+ { .val = 'b', .name = "blocks", .has_arg = required_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "comp-count", .has_arg = required_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "component-count",
+ .has_arg = required_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "comp-flags", .has_arg = required_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "component-flags",
+ .has_arg = required_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "comp-start", .has_arg = required_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "component-start",
+ .has_arg = required_argument },
+ { .val = LFS_MIRROR_STATE_OPT,
+ .name = "mirror-state", .has_arg = required_argument },
+ { .val = LFS_LAYOUT_FOREIGN_OPT,
+ .name = "foreign", .has_arg = optional_argument},
+ { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
+ { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
+ { .val = 'C', .name = "ctime", .has_arg = required_argument },
+/* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
+ { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
+ { .val = 'E', .name = "comp-end", .has_arg = required_argument },
+ { .val = 'E', .name = "component-end",
+ .has_arg = required_argument },
+/* find { .val = 'F', .name = "fid", .has_arg = no_argument }, */
+ { .val = LFS_LAYOUT_FOREIGN_OPT,
+ .name = "foreign", .has_arg = optional_argument},
+ { .val = 'g', .name = "gid", .has_arg = required_argument },
+ { .val = 'G', .name = "group", .has_arg = required_argument },
+ { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
+ { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
+ { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
+/* getstripe { .val = 'I', .name = "comp-id", .has_arg = required_argument }*/
+ { .val = 'l', .name = "lazy", .has_arg = no_argument },
+ { .val = 'L', .name = "layout", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
+ { .val = 'M', .name = "mtime", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .val = 'N', .name = "mirror-count", .has_arg = required_argument },
+/* find { .val = 'o' .name = "or", .has_arg = no_argument }, like find(1) */
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'O', .name = "ost", .has_arg = required_argument },
+ /* no short option for pool yet, can be 'p' after 2.18 */
+ { .val = LFS_POOL_OPT,
+ .name = "pool", .has_arg = required_argument },
+ { .val = '0', .name = "print0", .has_arg = no_argument },
+ { .val = 'P', .name = "print", .has_arg = no_argument },
+ { .val = LFS_PROJID_OPT,
+ .name = "projid", .has_arg = required_argument },
+/* getstripe { .val = 'q', .name = "quiet", .has_arg = no_argument }, */
+/* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
+/* getstripe { .val = 'R', .name = "raw", .has_arg = no_argument }, */
+ { .val = 's', .name = "size", .has_arg = required_argument },
+ { .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 = 'T', .name = "mdt-count", .has_arg = required_argument },
+ { .val = 'u', .name = "uid", .has_arg = required_argument },
+ { .val = 'U', .name = "user", .has_arg = required_argument },
+ { .val = 'z', .name = "extension-size",
+ .has_arg = required_argument },
+ { .val = 'z', .name = "ext-size", .has_arg = required_argument },
+/* getstripe { .val = 'v', .name = "verbose", .has_arg = no_argument }, */
+/* getstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */
+ { .name = NULL } };
+ int pathstart = -1;
+ int pathend = -1;
+ int pathbad = -1;
+ int neg_opt = 0;
+ time_t *xtime;
+ int *xsign;
+ int isoption;
+ char *endptr;
+
+ time(&t);
+
+ /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
+ while ((c = getopt_long_only(argc, argv,
+ "-0A:b:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:vz:",
+ long_opts, NULL)) >= 0) {
+ xtime = NULL;
+ xsign = NULL;
+ if (neg_opt)
+ --neg_opt;
+ /* '!' is part of option */
+ /* when getopt_long_only() finds a string which is not
+ * an option nor a known option argument it returns 1
+ * in that case if we already have found pathstart and pathend
+ * (i.e. we have the list of pathnames),
+ * the only supported value is "!"
+ */
+ isoption = (c != 1) || (strcmp(optarg, "!") == 0);
+ if (!isoption && pathend != -1) {
+ fprintf(stderr, "err: %s: filename|dirname must either "
+ "precede options or follow options\n",
+ argv[0]);
+ ret = CMD_HELP;
+ goto err;
+ }
+ if (!isoption && pathstart == -1)
+ pathstart = optind - 1;
+ if (isoption && pathstart != -1 && pathend == -1)
+ pathend = optind - 2;
+ switch (c) {
+ case 0:
+ /* Long options. */
+ break;
+ case 1:
+ /* unknown; opt is "!" or path component,
+ * checking done above.
+ */
+ if (strcmp(optarg, "!") == 0)
+ neg_opt = 2;
+ break;
+ case 'A':
+ xtime = ¶m.fp_atime;
+ xsign = ¶m.fp_asign;
+ param.fp_exclude_atime = !!neg_opt;
+ /* no break, this falls through to 'C' for ctime */
+ case 'C':
+ if (c == 'C') {
+ xtime = ¶m.fp_ctime;
+ xsign = ¶m.fp_csign;
+ param.fp_exclude_ctime = !!neg_opt;
+ }
+ /* no break, this falls through to 'M' for mtime */
+ case 'M':
+ if (c == 'M') {
+ xtime = ¶m.fp_mtime;
+ xsign = ¶m.fp_msign;
+ param.fp_exclude_mtime = !!neg_opt;
+ }
+ rc = set_time(¶m, &t, xtime, optarg);
+ if (rc == LONG_MAX) {
+ ret = -1;
+ goto err;
+ }
+ if (rc)
+ *xsign = rc;
+ break;
+ case 'b':
+ if (optarg[0] == '+') {
+ param.fp_blocks_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_blocks_sign = 1;
+ optarg++;
+ }
+
+ param.fp_blocks_units = 1024;
+ ret = llapi_parse_size(optarg, ¶m.fp_blocks,
+ ¶m.fp_blocks_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad blocks '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_blocks = 1;
+ param.fp_exclude_blocks = !!neg_opt;
+ break;
+ case LFS_COMP_COUNT_OPT:
+ if (optarg[0] == '+') {
+ param.fp_comp_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_comp_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: bad component count "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_count = 1;
+ param.fp_exclude_comp_count = !!neg_opt;
+ break;
+ case LFS_COMP_FLAGS_OPT:
+ rc = comp_str2flags(optarg, ¶m.fp_comp_flags,
+ ¶m.fp_comp_neg_flags);
+ if (rc) {
+ fprintf(stderr, "error: bad component flags "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_flags = 1;
+ if (neg_opt) {
+ __u32 flags = param.fp_comp_neg_flags;
+ param.fp_comp_neg_flags = param.fp_comp_flags;
+ param.fp_comp_flags = flags;
+ }
+ break;
+ case LFS_COMP_START_OPT:
+ if (optarg[0] == '+') {
+ param.fp_comp_start_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_start_sign = 1;
+ optarg++;
+ }
+
+ rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
+ ¶m.fp_comp_start_units, 0);
+ if (rc) {
+ fprintf(stderr, "error: bad component start "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_start = 1;
+ param.fp_exclude_comp_start = !!neg_opt;
+ break;
+ case LFS_MIRROR_STATE_OPT:
+ rc = mirror_str2state(optarg, ¶m.fp_mirror_state,
+ ¶m.fp_mirror_neg_state);
+ if (rc) {
+ fprintf(stderr,
+ "error: bad mirrored file state '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_mirror_state = 1;
+ if (neg_opt) {
+ __u16 state = param.fp_mirror_neg_state;
+ param.fp_mirror_neg_state =
+ param.fp_mirror_state;
+ param.fp_mirror_state = state;
+ }
+ break;
+ case 'c':
+ if (optarg[0] == '+') {
+ param.fp_stripe_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_stripe_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_stripe_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,"error: bad stripe_count '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_stripe_count = 1;
+ param.fp_exclude_stripe_count = !!neg_opt;
+ break;
+ case 'D':
+ param.fp_max_depth = strtol(optarg, 0, 0);
+ break;
+ case 'E':
+ if (optarg[0] == '+') {
+ param.fp_comp_end_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_end_sign = 1;
+ optarg++;
+ }
+
+ if (arg_is_eof(optarg)) {
+ param.fp_comp_end = LUSTRE_EOF;
+ param.fp_comp_end_units = 1;
+ rc = 0;
+ } else {
+ rc = llapi_parse_size(optarg,
+ ¶m.fp_comp_end,
+ ¶m.fp_comp_end_units, 0);
+ }
+ if (rc) {
+ fprintf(stderr, "error: bad component end "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_end = 1;
+ param.fp_exclude_comp_end = !!neg_opt;
+ break;
+ case LFS_LAYOUT_FOREIGN_OPT: {
+ /* all types by default */
+ uint32_t type = LU_FOREIGN_TYPE_UNKNOWN;
+
+ if (optarg != NULL) {
+ /* check pure numeric */
+ type = strtoul(optarg, &endptr, 0);
+ if (*endptr) {
+ /* check name */
+ type = check_foreign_type_name(optarg);
+ if (type == LU_FOREIGN_TYPE_UNKNOWN) {
+ fprintf(stderr,
+ "%s %s: unknown foreign type '%s'\n",
+ progname, argv[0],
+ optarg);
+ return CMD_HELP;
+ }
+ }
+ }
+ param.fp_foreign_type = type;
+ param.fp_check_foreign = 1;
+ param.fp_exclude_foreign = !!neg_opt;
+ break;
+ }
+ case 'g':
+ case 'G':
+ rc = name2gid(¶m.fp_gid, optarg);
+ if (rc) {
+ param.fp_gid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Group/GID: %s cannot "
+ "be found.\n", optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_gid = !!neg_opt;
+ param.fp_check_gid = 1;
+ break;
+ case 'H':
+ param.fp_hash_type = check_hashtype(optarg);
+ if (param.fp_hash_type == 0) {
+ fprintf(stderr, "error: bad hash_type '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_hash_type = 1;
+ param.fp_exclude_hash_type = !!neg_opt;
+ break;
+ case 'l':
+ param.fp_lazy = 1;
+ break;
+ case 'L':
+ ret = name2layout(¶m.fp_layout, optarg);
+ if (ret)
+ goto err;
+ param.fp_exclude_layout = !!neg_opt;
+ param.fp_check_layout = 1;
+ break;
+ case 'u':
+ case 'U':
+ rc = name2uid(¶m.fp_uid, optarg);
+ if (rc) {
+ param.fp_uid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "User/UID: %s cannot "
+ "be found.\n", optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_uid = !!neg_opt;
+ param.fp_check_uid = 1;