+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
+ 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,
+ };
+ 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 = '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 = '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 = "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 },
+/* 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 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:v",
+ 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(&t, xtime, optarg);
+ if (rc == INT_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 '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':
+ 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;
+ break;
+ case 'n':
+ param.fp_pattern = (char *)optarg;
+ param.fp_exclude_pattern = !!neg_opt;
+ break;
+ case 'N':
+ if (optarg[0] == '+') {
+ param.fp_mirror_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_mirror_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_mirror_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "error: bad mirror count '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_mirror_count = 1;
+ param.fp_exclude_mirror_count = !!neg_opt;
+ break;
+ case 'm':
+ case 'i':
+ case 'O': {
+ char *buf, *token, *next, *p;
+ int len = 1;
+ void *tmp;
+
+ buf = strdup(optarg);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ param.fp_exclude_obd = !!neg_opt;
+
+ token = buf;
+ while (token && *token) {
+ token = strchr(token, ',');
+ if (token) {
+ len++;
+ token++;
+ }
+ }
+ if (c == 'm') {
+ param.fp_exclude_mdt = !!neg_opt;
+ param.fp_num_alloc_mdts += len;
+ tmp = realloc(param.fp_mdt_uuid,
+ param.fp_num_alloc_mdts *
+ sizeof(*param.fp_mdt_uuid));
+ if (tmp == NULL) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ param.fp_mdt_uuid = tmp;
+ } else {
+ param.fp_exclude_obd = !!neg_opt;
+ param.fp_num_alloc_obds += len;
+ tmp = realloc(param.fp_obd_uuid,
+ param.fp_num_alloc_obds *
+ sizeof(*param.fp_obd_uuid));
+ if (tmp == NULL) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ param.fp_obd_uuid = tmp;
+ }
+ for (token = buf; token && *token; token = next) {
+ struct obd_uuid *puuid;
+ if (c == 'm') {
+ puuid =
+ ¶m.fp_mdt_uuid[param.fp_num_mdts++];
+ } else {
+ puuid =
+ ¶m.fp_obd_uuid[param.fp_num_obds++];
+ }
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+
+ if (strlen(token) > sizeof(puuid->uuid) - 1) {
+ ret = -E2BIG;
+ goto err_free;
+ }
+
+ strncpy(puuid->uuid, token,
+ sizeof(puuid->uuid));
+ }
+err_free:
+ if (buf)
+ free(buf);
+ break;
+ }
+#if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
+ case 'p':
+#endif
+ case LFS_POOL_OPT:
+ if (strlen(optarg) > LOV_MAXPOOLNAME) {
+ fprintf(stderr,
+ "Pool name %s is too long (max %d)\n",
+ optarg, LOV_MAXPOOLNAME);
+ ret = -1;
+ goto err;
+ }
+ /*
+ * We do check for empty pool because empty pool
+ * is used to find V1 LOV attributes
+ */
+ strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
+ param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
+ param.fp_exclude_pool = !!neg_opt;
+ param.fp_check_pool = 1;
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
+ case 'p': /* want this for --pool, to match getstripe/find */
+ fprintf(stderr,
+ "warning: -p deprecated, use --print0 or -0\n");
+#endif
+ case '0':
+ param.fp_zero_end = 1;
+ break;
+ case 'P': /* we always print, this option is a no-op */
+ break;
+ case LFS_PROJID_OPT:
+ rc = name2projid(¶m.fp_projid, optarg);
+ if (rc) {
+ param.fp_projid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Invalid project ID: %s",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_projid = !!neg_opt;
+ param.fp_check_projid = 1;
+ break;
+ case 's':
+ if (optarg[0] == '+') {
+ param.fp_size_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_size_sign = 1;
+ optarg++;
+ }
+
+ ret = llapi_parse_size(optarg, ¶m.fp_size,
+ ¶m.fp_size_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad file size '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_size = 1;
+ param.fp_exclude_size = !!neg_opt;
+ break;
+ case 'S':
+ if (optarg[0] == '+') {
+ param.fp_stripe_size_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_stripe_size_sign = 1;
+ optarg++;
+ }
+
+ ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
+ ¶m.fp_stripe_size_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad stripe_size '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_stripe_size = 1;
+ param.fp_exclude_stripe_size = !!neg_opt;
+ break;
+ case 't':
+ param.fp_exclude_type = !!neg_opt;
+ switch (optarg[0]) {
+ case 'b':
+ param.fp_type = S_IFBLK;
+ break;
+ case 'c':
+ param.fp_type = S_IFCHR;
+ break;
+ case 'd':
+ param.fp_type = S_IFDIR;
+ break;
+ case 'f':
+ param.fp_type = S_IFREG;
+ break;
+ case 'l':
+ param.fp_type = S_IFLNK;
+ break;
+ case 'p':
+ param.fp_type = S_IFIFO;
+ break;
+ case 's':
+ param.fp_type = S_IFSOCK;
+ break;
+ default:
+ fprintf(stderr, "error: %s: bad type '%s'\n",
+ argv[0], optarg);
+ ret = CMD_HELP;
+ goto err;
+ };
+ break;
+ case 'T':
+ if (optarg[0] == '+') {
+ param.fp_mdt_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_mdt_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_mdt_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: bad mdt_count '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_mdt_count = 1;
+ param.fp_exclude_mdt_count = !!neg_opt;
+ break;
+ default:
+ ret = CMD_HELP;
+ goto err;
+ };
+ }
+
+ if (pathstart == -1) {
+ fprintf(stderr, "error: %s: no filename|pathname\n",
+ argv[0]);
+ ret = CMD_HELP;
+ goto err;
+ } else if (pathend == -1) {
+ /* no options */
+ pathend = argc;
+ }
+
+ do {
+ rc = llapi_find(argv[pathstart], ¶m);
+ if (rc != 0 && ret == 0)
+ ret = rc;
+ } while (++pathstart < pathend);
+
+ if (ret)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+err:
+ if (param.fp_obd_uuid && param.fp_num_alloc_obds)
+ free(param.fp_obd_uuid);
+
+ if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
+ free(param.fp_mdt_uuid);
+
+ return ret;
+}
+
+static int lfs_getstripe_internal(int argc, char **argv,
+ struct find_param *param)
+{
+ struct option long_opts[] = {
+/* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/
+/* find { .val = 'b', .name = "blocks", .has_arg = required_argument }*/
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "comp-count", .has_arg = no_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "component-count", .has_arg = no_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "comp-flags", .has_arg = optional_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "component-flags", .has_arg = optional_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "comp-start", .has_arg = optional_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "component-start", .has_arg = optional_argument },
+ { .val = LFS_MIRROR_INDEX_OPT,
+ .name = "mirror-index", .has_arg = required_argument },
+ { .val = LFS_MIRROR_ID_OPT,
+ .name = "mirror-id", .has_arg = required_argument },
+ { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
+ { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
+/* find { .val = 'C', .name = "ctime", .has_arg = required_argument }*/
+ { .val = 'd', .name = "directory", .has_arg = no_argument },
+ { .val = 'D', .name = "default", .has_arg = no_argument },
+ { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
+ { .val = 'E', .name = "component-end", .has_arg = optional_argument },
+ { .val = 'F', .name = "fid", .has_arg = no_argument },
+ { .val = 'g', .name = "generation", .has_arg = no_argument },
+/* find { .val = 'G', .name = "group", .has_arg = required_argument }*/
+/* dirstripe { .val = 'H', .name = "mdt-hash", .has_arg = required_argument }*/
+ { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
+ { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
+ { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
+ { .val = 'I', .name = "component-id", .has_arg = optional_argument },
+ { .val = 'L', .name = "layout", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
+/* find { .val = 'M', .name = "mtime", .has_arg = required_argument }*/
+/* find { .val = 'n', .name = "name", .has_arg = required_argument }*/
+ { .val = 'N', .name = "mirror-count", .has_arg = no_argument },
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'O', .name = "ost", .has_arg = required_argument },
+ { .val = 'p', .name = "pool", .has_arg = no_argument },
+/* find { .val = 'P', .name = "print", .has_arg = no_argument }, */
+ { .val = 'q', .name = "quiet", .has_arg = no_argument },
+ { .val = 'r', .name = "recursive", .has_arg = no_argument },
+ { .val = 'R', .name = "raw", .has_arg = no_argument },
+ { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
+ { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
+/* find { .val = 't', .name = "type", .has_arg = required_argument }*/
+/* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
+/* find { .val = 'u', .name = "uid", .has_arg = required_argument }*/
+/* find { .val = 'U', .name = "user", .has_arg = required_argument }*/
+ { .val = 'v', .name = "verbose", .has_arg = no_argument },
+ { .val = 'y', .name = "yaml", .has_arg = no_argument },
+ { .name = NULL } };
+ int c, rc;
+ int neg_opt = 0;
+ int pathstart = -1, pathend = -1;
+ int isoption;
+ char *end, *tmp;
+
+ while ((c = getopt_long(argc, argv,
+ "-cdDE::FghiI::LmMNoO:pqrRsSvy",
+ long_opts, NULL)) != -1) {
+ if (neg_opt)
+ --neg_opt;
+
+ /* '!' is part of option */
+ isoption = (c != 1) || (strcmp(optarg, "!") == 0);
+ if (!isoption && pathend != -1) {
+ fprintf(stderr,
+ "error: %s: filename|dirname must either precede options or follow options\n",
+ argv[0]);
+ return CMD_HELP;
+ }
+ if (!isoption && pathstart == -1)
+ pathstart = optind - 1;
+ if (isoption && pathstart != -1 && pathend == -1)
+ pathend = optind - 2;
+
+ switch (c) {
+ case 1:
+ /* unknown: opt is "!" */
+ if (strcmp(optarg, "!") == 0)
+ neg_opt = 2;
+ break;
+ case 'c':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_COUNT;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case LFS_COMP_COUNT_OPT:
+ param->fp_verbose |= VERBOSE_COMP_COUNT;
+ param->fp_max_depth = 0;
+ break;
+ case LFS_COMP_FLAGS_OPT:
+ if (optarg != NULL) {
+ rc = comp_str2flags(optarg,
+ ¶m->fp_comp_flags,
+ ¶m->fp_comp_neg_flags);
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component flags '%s'.\n",
+ argv[0], optarg);
+ return CMD_HELP;
+ }
+ param->fp_check_comp_flags = 1;
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_FLAGS;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case LFS_COMP_START_OPT:
+ if (optarg != NULL) {
+ tmp = optarg;
+ if (tmp[0] == '+') {
+ param->fp_comp_start_sign = -1;
+ tmp++;
+ } else if (tmp[0] == '-') {
+ param->fp_comp_start_sign = 1;
+ tmp++;
+ }
+ rc = llapi_parse_size(tmp,
+ ¶m->fp_comp_start,
+ ¶m->fp_comp_start_units, 0);
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component start '%s'.\n",
+ argv[0], tmp);
+ return CMD_HELP;
+ } else {
+ param->fp_check_comp_start = 1;
+ }
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_START;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case LFS_MIRROR_INDEX_OPT:
+ if (optarg[0] == '+') {
+ param->fp_mirror_index_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param->fp_mirror_index_sign = 1;
+ optarg++;
+ }
+
+ param->fp_mirror_index = strtoul(optarg, &end, 0);
+ if (*end != '\0' || (param->fp_mirror_index == 0 &&
+ param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
+ fprintf(stderr,
+ "%s %s: invalid mirror index '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+ if (param->fp_mirror_id != 0) {
+ fprintf(stderr,
+ "%s %s: can't specify both mirror index and mirror ID\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+ param->fp_check_mirror_index = 1;
+ param->fp_exclude_mirror_index = !!neg_opt;
+ break;
+ case LFS_MIRROR_ID_OPT:
+ if (optarg[0] == '+') {
+ param->fp_mirror_id_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param->fp_mirror_id_sign = 1;
+ optarg++;
+ }
+
+ param->fp_mirror_id = strtoul(optarg, &end, 0);
+ if (*end != '\0' || (param->fp_mirror_id == 0 &&
+ param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
+ fprintf(stderr,
+ "%s %s: invalid mirror ID '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+ if (param->fp_mirror_index != 0) {
+ fprintf(stderr,
+ "%s %s: can't specify both mirror index and mirror ID\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+ param->fp_check_mirror_id = 1;
+ param->fp_exclude_mirror_id = !!neg_opt;
+ break;
+ case 'd':
+ param->fp_max_depth = 0;
+ break;
+ case 'D':
+ param->fp_get_default_lmv = 1;
+ break;
+ case 'E':
+ if (optarg != NULL) {
+ tmp = optarg;
+ if (tmp[0] == '+') {
+ param->fp_comp_end_sign = -1;
+ tmp++;
+ } else if (tmp[0] == '-') {
+ param->fp_comp_end_sign = 1;
+ tmp++;
+ }
+
+ if (arg_is_eof(tmp)) {
+ param->fp_comp_end = LUSTRE_EOF;
+ param->fp_comp_end_units = 1;
+ rc = 0;
+ } else {
+ rc = llapi_parse_size(tmp,
+ ¶m->fp_comp_end,
+ ¶m->fp_comp_end_units, 0);
+ }
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component end '%s'.\n",
+ argv[0], tmp);
+ return CMD_HELP;
+ }
+ param->fp_check_comp_end = 1;
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_END;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'F':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_DFID;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'g':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_GENERATION;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'i':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'I':
+ if (optarg != NULL) {
+ param->fp_comp_id = strtoul(optarg, &end, 0);
+ if (*end != '\0' || param->fp_comp_id == 0 ||
+ param->fp_comp_id > LCME_ID_MAX) {
+ fprintf(stderr, "error: %s bad "
+ "component id '%s'\n",
+ argv[0], optarg);
+ return CMD_HELP;
+ } else {
+ param->fp_check_comp_id = 1;
+ }
+ } else {
+ param->fp_max_depth = 0;
+ param->fp_verbose |= VERBOSE_COMP_ID;
+ }
+ break;
+ case 'L':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_PATTERN;
+ param->fp_max_depth = 0;
+ }
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 'M':
+ fprintf(stderr, "warning: '-M' deprecated"
+ ", use '--mdt-index' or '-m' instead\n");
+#endif
+ case 'm':
+ if (!(param->fp_verbose & VERBOSE_DETAIL))
+ param->fp_max_depth = 0;
+ param->fp_verbose |= VERBOSE_MDTINDEX;
+ break;
+ case 'N':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_MIRROR_COUNT;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'O':
+ if (param->fp_obd_uuid) {
+ fprintf(stderr,
+ "error: %s: only one obduuid allowed",
+ argv[0]);
+ return CMD_HELP;
+ }
+ param->fp_obd_uuid = (struct obd_uuid *)optarg;
+ break;
+ case 'p':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_POOL;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'q':
+ param->fp_quiet++;
+ break;
+ case 'r':
+ param->fp_recursive = 1;
+ break;
+ case 'R':
+ param->fp_raw = 1;
+ break;
+ case 'S':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_STRIPE_SIZE;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'v':
+ param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
+ break;
+ case 'y':
+ param->fp_yaml = 1;
+ break;
+ default:
+ return CMD_HELP;
+ }
+ }
+
+ if (pathstart == -1) {
+ fprintf(stderr, "error: %s: no filename|pathname\n",
+ argv[0]);
+ return CMD_HELP;
+ } else if (pathend == -1) {
+ /* no options */
+ pathend = argc;
+ }
+
+ if (pathend > argc)
+ return CMD_HELP;
+
+ if (param->fp_recursive)
+ param->fp_max_depth = -1;
+ else if (param->fp_verbose & VERBOSE_DETAIL)
+ param->fp_max_depth = 1;
+
+ if (!param->fp_verbose)
+ param->fp_verbose = VERBOSE_DEFAULT;
+ if (param->fp_quiet)
+ param->fp_verbose = VERBOSE_OBJID;
+
+ do {
+ rc = llapi_getstripe(argv[pathstart], param);
+ } while (++pathstart < pathend && !rc);
+
+ if (rc)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+ return rc;
+}
+
+static int lfs_tgts(int argc, char **argv)
+{
+ char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
+ struct find_param param;
+ int index = 0, rc=0;
+
+ if (argc > 2)
+ return CMD_HELP;
+
+ if (argc == 2 && !realpath(argv[1], path)) {
+ rc = -errno;
+ fprintf(stderr, "error: invalid path '%s': %s\n",
+ argv[1], strerror(-rc));
+ return rc;
+ }
+
+ while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
+ /* Check if we have a mount point */
+ if (mntdir[0] == '\0')
+ continue;
+
+ memset(¶m, 0, sizeof(param));
+ if (!strcmp(argv[0], "mdts"))
+ param.fp_get_lmv = 1;
+
+ rc = llapi_ostlist(mntdir, ¶m);
+ if (rc) {
+ fprintf(stderr, "error: %s: failed on %s\n",
+ argv[0], mntdir);
+ }
+ if (path[0] != '\0')
+ break;
+ memset(mntdir, 0, PATH_MAX);
+ }
+
+ return rc;
+}
+
+static int lfs_getstripe(int argc, char **argv)
+{
+ struct find_param param = { 0 };
+
+ param.fp_max_depth = 1;
+ return lfs_getstripe_internal(argc, argv, ¶m);
+}
+
+/* functions */
+static int lfs_getdirstripe(int argc, char **argv)
+{
+ struct find_param param = { 0 };
+ struct option long_opts[] = {
+ { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
+ { .val = 'D', .name = "default", .has_arg = no_argument },
+ { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
+ { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'r', .name = "recursive", .has_arg = no_argument },
+ { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
+ { .val = 'y', .name = "yaml", .has_arg = no_argument },
+ { .name = NULL } };
+ int c, rc;
+
+ param.fp_get_lmv = 1;
+
+ while ((c = getopt_long(argc, argv,
+ "cDHimO:rtTy", long_opts, NULL)) != -1)
+ {
+ switch (c) {
+ case 'c':
+ case 'T':
+ param.fp_verbose |= VERBOSE_COUNT;
+ break;
+ case 'D':
+ param.fp_get_default_lmv = 1;
+ break;
+ case 'i':
+ case 'm':
+ param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 't':
+ fprintf(stderr, "warning: '-t' deprecated, "
+ "use '--mdt-hash' or '-H' instead\n");
+#endif
+ case 'H':
+ param.fp_verbose |= VERBOSE_HASH_TYPE;
+ break;
+ case 'O':
+ if (param.fp_obd_uuid) {
+ fprintf(stderr,
+ "error: %s: only one obduuid allowed",
+ argv[0]);
+ return CMD_HELP;
+ }
+ param.fp_obd_uuid = (struct obd_uuid *)optarg;
+ break;
+ case 'r':
+ param.fp_recursive = 1;
+ break;
+ case 'y':
+ param.fp_yaml = 1;
+ break;
+ default:
+ return CMD_HELP;
+ }
+ }
+
+ if (optind >= argc)
+ return CMD_HELP;
+
+ if (param.fp_recursive)
+ param.fp_max_depth = -1;
+
+ if (!param.fp_verbose)
+ param.fp_verbose = VERBOSE_DEFAULT;
+
+ do {
+ rc = llapi_getstripe(argv[optind], ¶m);
+ } while (++optind < argc && !rc);
+
+ if (rc)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+ return rc;
+}
+
+enum mntdf_flags {
+ MNTDF_INODES = 0x0001,
+ MNTDF_COOKED = 0x0002,
+ MNTDF_LAZY = 0x0004,
+ MNTDF_VERBOSE = 0x0008,
+ MNTDF_SHOW = 0x0010,
+};
+
+#define COOK(value) \
+({ \
+ int radix = 0; \
+ while (value > 1024) { \
+ value /= 1024; \
+ radix++; \
+ } \
+ radix; \
+})
+#define UUF "%-20s"
+#define CSF "%11s"
+#define CDF "%11llu"
+#define HDF "%8.1f%c"
+#define RSF "%4s"
+#define RDF "%3d%%"
+
+static inline int obd_statfs_ratio(const struct obd_statfs *st)
+{
+ double avail, used, ratio = 0;
+
+ avail = st->os_bavail;
+ used = st->os_blocks - st->os_bfree;
+ if (avail + used > 0)
+ ratio = used / (used + avail) * 100 + 0.5;
+
+ return (int)ratio;
+}
+
+static int showdf(char *mntdir, struct obd_statfs *stat,
+ char *uuid, enum mntdf_flags flags,
+ char *type, int index, int rc)
+{
+ long long avail, used, total;
+ int ratio = 0;
+ char *suffix = "KMGTPEZY";
+ /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
+ char tbuf[3 * sizeof(__u64)];
+ char ubuf[3 * sizeof(__u64)];
+ char abuf[3 * sizeof(__u64)];
+ char rbuf[3 * sizeof(__u64)];
+
+ if (!uuid || !stat)
+ return -EINVAL;
+
+ switch (rc) {
+ case 0:
+ if (flags & MNTDF_INODES) {
+ avail = stat->os_ffree;
+ used = stat->os_files - stat->os_ffree;
+ total = stat->os_files;
+ } else {
+ int shift = flags & MNTDF_COOKED ? 0 : 10;
+
+ avail = (stat->os_bavail * stat->os_bsize) >> shift;
+ used = ((stat->os_blocks - stat->os_bfree) *
+ stat->os_bsize) >> shift;
+ total = (stat->os_blocks * stat->os_bsize) >> shift;
+ }
+
+ ratio = obd_statfs_ratio(stat);
+
+ if (flags & MNTDF_COOKED) {
+ int i;
+ double cook_val;
+
+ cook_val = (double)total;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(tbuf, sizeof(tbuf), CDF, total);
+
+ cook_val = (double)used;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(ubuf, sizeof(ubuf), CDF, used);
+
+ cook_val = (double)avail;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(abuf, sizeof(abuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(abuf, sizeof(abuf), CDF, avail);
+ } else {
+ snprintf(tbuf, sizeof(tbuf), CDF, total);
+ snprintf(ubuf, sizeof(tbuf), CDF, used);
+ snprintf(abuf, sizeof(tbuf), CDF, avail);
+ }
+
+ sprintf(rbuf, RDF, ratio);
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
+ uuid, tbuf, ubuf, abuf, rbuf, mntdir);
+ if (type)
+ printf("[%s:%d]", type, index);
+
+ if (stat->os_state) {
+ /*
+ * Each character represents the matching
+ * OS_STATE_* bit.
+ */
+ const char state_names[] = "DRSI";
+ __u32 state;
+ __u32 i;
+
+ printf(" ");
+ for (i = 0, state = stat->os_state;
+ state && i < sizeof(state_names); i++) {
+ if (!(state & (1 << i)))
+ continue;
+ printf("%c", state_names[i]);
+ state ^= 1 << i;
+ }
+ }
+
+ printf("\n");
+ break;
+ case -ENODATA:
+ printf(UUF": inactive device\n", uuid);
+ break;
+ default:
+ printf(UUF": %s\n", uuid, strerror(-rc));
+ break;
+ }
+
+ return 0;
+}
+
+struct ll_stat_type {
+ int st_op;
+ char *st_name;
+};
+
+#define LL_STATFS_MAX LOV_MAX_STRIPE_COUNT
+
+struct ll_statfs_data {
+ int sd_index;
+ struct obd_statfs sd_st;
+};
+
+struct ll_statfs_buf {
+ int sb_count;
+ struct ll_statfs_data sb_buf[LL_STATFS_MAX];
+};
+
+static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
+ int ops, struct ll_statfs_buf *lsb)
+{
+ struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
+ struct obd_uuid uuid_buf;
+ char *poolname = NULL;
+ struct ll_stat_type types[] = {
+ { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
+ { .st_op = LL_STATFS_LOV, .st_name = "OST" },
+ { .st_name = NULL } };
+ struct ll_stat_type *tp;
+ __u64 ost_ffree = 0;
+ __u32 index;
+ __u32 type;
+ int fd;
+ int rc = 0;
+ int rc2;
+
+ if (pool) {
+ poolname = strchr(pool, '.');
+ if (poolname != NULL) {
+ if (strncmp(fsname, pool, strlen(fsname))) {
+ fprintf(stderr, "filesystem name incorrect\n");
+ return -ENODEV;
+ }
+ poolname++;
+ } else
+ poolname = pool;
+ }
+
+ fd = open(mntdir, O_RDONLY);
+ if (fd < 0) {
+ rc = -errno;
+ fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
+ strerror(errno));
+ return rc;
+ }
+
+ if (flags & MNTDF_SHOW) {
+ if (flags & MNTDF_INODES)
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
+ "UUID", "Inodes", "IUsed", "IFree",
+ "IUse%", "Mounted on");
+ else
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
+ "UUID",
+ flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
+ "Used", "Available", "Use%", "Mounted on");
+ }
+
+ for (tp = types; tp->st_name != NULL; tp++) {
+ bool have_ost = false;
+
+ if (!(tp->st_op & ops))
+ continue;
+
+ for (index = 0; ; index++) {
+ memset(&stat_buf, 0, sizeof(struct obd_statfs));
+ memset(&uuid_buf, 0, sizeof(struct obd_uuid));
+ type = flags & MNTDF_LAZY ?
+ tp->st_op | LL_STATFS_NODELAY : tp->st_op;
+ rc2 = llapi_obd_fstatfs(fd, type, index,
+ &stat_buf, &uuid_buf);
+ if (rc2 == -ENODEV)
+ break;
+ if (rc2 == -EAGAIN)
+ continue;
+ if (rc2 == -ENODATA) { /* Inactive device, OK. */
+ if (!(flags & MNTDF_VERBOSE))
+ continue;
+ } else if (rc2 < 0 && rc == 0) {
+ rc = rc2;
+ }
+
+ /* If we have OSTs then don't report MDT block counts.
+ * For MDT-only filesystems the expectation is that all
+ * layouts have a DoM component. For filesystems with
+ * OSTs, files are not necessarily going to store data
+ * on MDTs, and MDT space is limited to a fraction of
+ * OST space, so don't include it in the summary.
+ */
+ if (tp->st_op == LL_STATFS_LOV && !have_ost) {
+ have_ost = true;
+ sum.os_blocks = 0;
+ sum.os_bfree = 0;
+ sum.os_bavail = 0;
+ }
+
+ if (poolname && tp->st_op == LL_STATFS_LOV &&
+ llapi_search_ost(fsname, poolname,
+ obd_uuid2str(&uuid_buf)) != 1)
+ continue;
+
+ /* the llapi_obd_statfs() call may have returned with
+ * an error, but if it filled in uuid_buf we will at
+ * lease use that to print out a message for that OBD.
+ * If we didn't get anything in the uuid_buf, then fill
+ * it in so that we can print an error message. */
+ if (uuid_buf.uuid[0] == '\0')
+ snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
+ "%s%04x", tp->st_name, index);
+ if (!rc && lsb) {
+ lsb->sb_buf[lsb->sb_count].sd_index = index;
+ lsb->sb_buf[lsb->sb_count].sd_st = stat_buf;
+ lsb->sb_count++;
+ }
+ if (flags & MNTDF_SHOW)
+ showdf(mntdir, &stat_buf,
+ obd_uuid2str(&uuid_buf), flags,
+ tp->st_name, index, rc2);
+
+ if (rc2)
+ continue;
+
+ if (tp->st_op == LL_STATFS_LMV) {
+ sum.os_ffree += stat_buf.os_ffree;
+ sum.os_files += stat_buf.os_files;
+ } else /* if (tp->st_op == LL_STATFS_LOV) */ {
+ ost_ffree += stat_buf.os_ffree;
+ }
+ sum.os_blocks += stat_buf.os_blocks *
+ stat_buf.os_bsize;
+ sum.os_bfree += stat_buf.os_bfree *
+ stat_buf.os_bsize;
+ sum.os_bavail += stat_buf.os_bavail *
+ stat_buf.os_bsize;
+ }
+ }
+
+ close(fd);
+
+ /* If we don't have as many objects free on the OST as inodes
+ * on the MDS, we reduce the total number of inodes to
+ * compensate, so that the "inodes in use" number is correct.
+ * Matches ll_statfs_internal() so the results are consistent. */
+ if (ost_ffree < sum.os_ffree) {
+ sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
+ sum.os_ffree = ost_ffree;
+ }
+ if (flags & MNTDF_SHOW) {
+ printf("\n");
+ showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
+ printf("\n");
+ }
+
+ return rc;
+}
+
+static int ll_statfs_data_comp(const void *sd1, const void *sd2)
+{
+ const struct obd_statfs *st1 = &((const struct ll_statfs_data *)sd1)->
+ sd_st;
+ const struct obd_statfs *st2 = &((const struct ll_statfs_data *)sd2)->
+ sd_st;
+ int r1 = obd_statfs_ratio(st1);
+ int r2 = obd_statfs_ratio(st2);
+ int64_t result = r1 - r2;
+
+ /* if both space usage are above 90, compare free inodes */
+ if (r1 > 90 && r2 > 90)
+ result = st2->os_ffree - st1->os_ffree;
+
+ if (result < 0)
+ return -1;
+ else if (result == 0)
+ return 0;
+ else
+ return 1;
+}
+
+/* functions */
+static int lfs_setdirstripe(int argc, char **argv)
+{
+ char *dname;
+ int result;
+ struct lfs_setstripe_args lsa = { 0 };
+ struct llapi_stripe_param *param = NULL;
+ __u32 mdts[LMV_MAX_STRIPE_COUNT] = { 0 };
+ char *end;
+ int c;
+ char *mode_opt = NULL;
+ bool default_stripe = false;
+ mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
+ mode_t previous_mode = 0;
+ bool delete = false;
+ struct ll_statfs_buf *lsb = NULL;
+ char mntdir[PATH_MAX] = "";
+ bool auto_distributed = false;
+
+ struct option long_opts[] = {
+ { .val = 'c', .name = "count", .has_arg = required_argument },
+ { .val = 'c', .name = "mdt-count", .has_arg = required_argument },
+ { .val = 'd', .name = "delete", .has_arg = no_argument },
+ { .val = 'D', .name = "default", .has_arg = no_argument },
+ { .val = 'D', .name = "default_stripe", .has_arg = no_argument },
+ { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
+ { .val = 'i', .name = "mdt-index", .has_arg = required_argument },
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ { .val = 'i', .name = "index", .has_arg = required_argument },
+#endif
+ { .val = 'o', .name = "mode", .has_arg = required_argument },
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ { .val = 't', .name = "hash-type", .has_arg = required_argument },
+#endif
+ { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
+/* setstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */
+ { .name = NULL } };
+
+ setstripe_args_init(&lsa);
+
+ while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:", long_opts,
+ NULL)) >= 0) {
+ switch (c) {
+ case 0:
+ /* Long options. */
+ break;
+ case 'c':
+ case 'T':
+ lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s %s: invalid stripe count '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+ break;
+ case 'd':
+ delete = true;
+ default_stripe = true;
+ break;
+ case 'D':
+ default_stripe = true;
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 't':
+ fprintf(stderr, "warning: '--hash-type' and '-t' "
+ "deprecated, use '--mdt-hash' or '-H' instead\n");
+#endif
+ case 'H':
+ lsa.lsa_pattern = check_hashtype(optarg);
+ if (lsa.lsa_pattern == 0) {
+ fprintf(stderr,
+ "%s %s: bad stripe hash type '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+ break;
+ case 'i':
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ if (strcmp(argv[optind - 1], "--index") == 0)
+ fprintf(stderr,
+ "%s %s: warning: '--index' deprecated, use '--mdt-index' instead\n",
+ progname, argv[0]);
+#endif
+ lsa.lsa_nr_tgts = parse_targets(mdts,
+ sizeof(mdts) / sizeof(__u32),
+ lsa.lsa_nr_tgts, optarg);
+ 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 = mdts;
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
+ lsa.lsa_stripe_off = mdts[0];
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+ case 'm':
+ fprintf(stderr, "warning: '-m' is deprecated, "
+ "use '--mode' or '-o' instead\n");
+#endif
+ case 'o':
+ mode_opt = optarg;
+ break;
+ default:
+ fprintf(stderr, "%s %s: unrecognized option '%s'\n",
+ progname, argv[0], argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+
+ if (optind == argc) {
+ fprintf(stderr, "%s %s: DIR must be specified\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+
+ if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
+ lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT) {
+ fprintf(stderr,
+ "%s %s: stripe offset and count must be specified\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+
+ if (delete &&
+ (lsa.lsa_stripe_off != LLAPI_LAYOUT_DEFAULT ||
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)) {
+ fprintf(stderr,
+ "%s %s: cannot specify -d with -c or -i options\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+
+ if (mode_opt != NULL) {
+ mode = strtoul(mode_opt, &end, 8);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s %s: bad MODE '%s'\n",
+ progname, argv[0], mode_opt);
+ return CMD_HELP;
+ }
+ previous_mode = umask(0);
+ }
+
+ /*
+ * initialize stripe parameters, in case param is converted to specific,
+ * i.e, 'lfs mkdir -i -1 -c N', always allocate space for lsp_tgts.
+ */
+ param = calloc(1, offsetof(typeof(*param),
+ lsp_tgts[lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT ?
+ lsa.lsa_stripe_count : lsa.lsa_nr_tgts]));
+ if (param == NULL) {
+ fprintf(stderr,
+ "%s %s: cannot allocate memory for parameters: %s\n",
+ progname, argv[0], strerror(ENOMEM));
+ return CMD_HELP;
+ }
+
+ if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT)
+ 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;
+ if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
+ param->lsp_stripe_pattern = lsa.lsa_pattern;
+ else
+ param->lsp_stripe_pattern = LMV_HASH_TYPE_FNV_1A_64;
+ param->lsp_pool = lsa.lsa_pool_name;
+ param->lsp_is_specific = false;
+ if (lsa.lsa_nr_tgts > 1) {
+ 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",
+ argv[0], lsa.lsa_stripe_count, lsa.lsa_nr_tgts);
+ free(param);
+ return CMD_HELP;
+ }
+
+ param->lsp_is_specific = true;
+ param->lsp_stripe_count = lsa.lsa_nr_tgts;
+ memcpy(param->lsp_tgts, mdts, sizeof(*mdts) * lsa.lsa_nr_tgts);
+ }
+
+ dname = argv[optind];
+ do {
+ if (default_stripe) {
+ result = llapi_dir_set_default_lmv(dname, param);
+ } else {
+ /* if current \a dname isn't under the same \a mntdir
+ * as the last one, and the last one was
+ * auto-distributed, restore \a param.
+ */
+ if (mntdir[0] != '\0' &&
+ strncmp(dname, mntdir, strlen(mntdir)) &&
+ auto_distributed) {
+ param->lsp_is_specific = false;
+ param->lsp_stripe_offset = -1;
+ auto_distributed = false;
+ }
+
+ if (!param->lsp_is_specific &&
+ param->lsp_stripe_offset == -1) {
+ char path[PATH_MAX] = "";
+
+ if (!lsb) {
+ lsb = malloc(sizeof(*lsb));
+ if (!lsb) {
+ result = -ENOMEM;
+ break;
+ }
+ }
+ lsb->sb_count = 0;
+
+ /* use mntdir for dirname() temporarily */
+ strncpy(mntdir, dname, sizeof(mntdir));
+ if (!realpath(dirname(mntdir), path)) {
+ result = -errno;
+ fprintf(stderr,
+ "error: invalid path '%s': %s\n",
+ argv[optind], strerror(errno));
+ break;
+ }
+ mntdir[0] = '\0';
+
+ result = llapi_search_mounts(path, 0, mntdir,
+ NULL);
+ if (result < 0 || mntdir[0] == '\0') {
+ fprintf(stderr,
+ "No suitable Lustre mount found\n");
+ break;
+ }
+
+ result = mntdf(mntdir, NULL, NULL, 0,
+ LL_STATFS_LMV, lsb);
+ if (result < 0)
+ break;
+
+ if (param->lsp_stripe_count > lsb->sb_count) {
+ fprintf(stderr,
+ "error: stripe count %d is too big\n",
+ param->lsp_stripe_count);
+ result = -ERANGE;
+ break;
+ }
+
+ qsort(lsb->sb_buf, lsb->sb_count,
+ sizeof(struct ll_statfs_data),
+ ll_statfs_data_comp);
+
+ auto_distributed = true;
+ }
+
+ if (auto_distributed) {
+ int r;
+ int nr = MAX(param->lsp_stripe_count,
+ lsb->sb_count / 2);
+
+ /* don't use server whose usage is above 90% */
+ while (nr != param->lsp_stripe_count &&
+ obd_statfs_ratio(&lsb->sb_buf[nr].sd_st)
+ > 90)
+ nr = MAX(param->lsp_stripe_count,
+ nr / 2);
+
+ /* get \a r between [0, nr) */
+ r = rand() % nr;
+
+ param->lsp_stripe_offset =
+ lsb->sb_buf[r].sd_index;
+ if (param->lsp_stripe_count > 1) {
+ int i = 0;
+
+ param->lsp_is_specific = true;
+ for (; i < param->lsp_stripe_count; i++)
+ param->lsp_tgts[(i + r) % nr] =
+ lsb->sb_buf[i].sd_index;
+ }
+ }
+
+ result = llapi_dir_create(dname, mode, param);
+ }
+
+ if (result) {
+ fprintf(stderr,
+ "%s setdirstripe: cannot create stripe dir '%s': %s\n",
+ progname, dname, strerror(-result));
+ break;
+ }
+ dname = argv[++optind];
+ } while (dname != NULL);
+
+ if (mode_opt != NULL)
+ umask(previous_mode);
+
+ free(lsb);
+ free(param);
+ return result;
+}
+
+/* functions */
+static int lfs_rmentry(int argc, char **argv)
+{
+ char *dname;
+ int index;
+ int result = 0;
+
+ if (argc <= 1) {
+ fprintf(stderr, "error: %s: missing dirname\n",
+ argv[0]);
+ return CMD_HELP;
+ }
+
+ index = 1;
+ dname = argv[index];
+ while (dname != NULL) {
+ result = llapi_direntry_remove(dname);
+ if (result) {
+ fprintf(stderr, "error: %s: remove dir entry '%s' "
+ "failed\n", argv[0], dname);
+ break;
+ }
+ dname = argv[++index];
+ }
+ return result;
+}
+
+static int lfs_mv(int argc, char **argv)
+{
+ struct lmv_user_md lmu = { LMV_USER_MAGIC };
+ struct find_param param = {
+ .fp_max_depth = -1,
+ .fp_mdt_index = -1,
+ };
+ char *end;
+ int c;
+ int rc = 0;
+ struct option long_opts[] = {
+ { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
+ { .val = 'v', .name = "verbose", .has_arg = no_argument },
+ { .name = NULL } };
+
+ while ((c = getopt_long(argc, argv, "m:M:v", long_opts, NULL)) != -1) {
+ switch (c) {
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 'M':
+ fprintf(stderr, "warning: '-M' deprecated"
+ ", use '--mdt-index' or '-m' instead\n");
+#endif
+ case 'm':
+ lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "%s mv: bad MDT index '%s'\n",
+ progname, optarg);
+ return CMD_HELP;
+ }
+ break;
+ case 'v':
+ param.fp_verbose = VERBOSE_DETAIL;
+ break;
+ default:
+ fprintf(stderr, "%s mv: unrecognized option '%s'\n",
+ progname, argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+
+ if (lmu.lum_stripe_offset == -1) {
+ fprintf(stderr, "%s mv: MDT index must be specified\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "%s mv: DIR must be specified\n", progname);
+ return CMD_HELP;
+ }
+
+
+ /* initialize migrate mdt parameters */
+ param.fp_lmv_md = &lmu;
+ param.fp_migrate = 1;
+ rc = llapi_migrate_mdt(argv[optind], ¶m);
+ if (rc != 0)
+ fprintf(stderr, "%s mv: cannot migrate '%s' to MDT%04x: %s\n",
+ progname, argv[optind], param.fp_mdt_index,
+ strerror(-rc));
+ return rc;
+}
+
+static int lfs_osts(int argc, char **argv)
+{
+ return lfs_tgts(argc, argv);
+}
+
+static int lfs_mdts(int argc, char **argv)
+{
+ return lfs_tgts(argc, argv);
+}
+
+static int lfs_df(int argc, char **argv)
+{
+ char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
+ enum mntdf_flags flags = MNTDF_SHOW;
+ int ops = LL_STATFS_LMV | LL_STATFS_LOV;
+ int c, rc = 0, index = 0;
+ char fsname[PATH_MAX] = "", *pool_name = NULL;
+ struct option long_opts[] = {
+ { .val = 'h', .name = "human-readable",
+ .has_arg = no_argument },
+ { .val = 'i', .name = "inodes", .has_arg = no_argument },
+ { .val = 'l', .name = "lazy", .has_arg = no_argument },
+ { .val = 'p', .name = "pool", .has_arg = required_argument },
+ { .val = 'v', .name = "verbose", .has_arg = no_argument },
+ { .name = NULL} };
+
+ while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ flags |= MNTDF_COOKED;
+ break;
+ case 'i':
+ flags |= MNTDF_INODES;
+ break;
+ case 'l':
+ flags |= MNTDF_LAZY;
+ break;
+ case 'p':
+ pool_name = optarg;
+ break;
+ case 'v':
+ flags |= MNTDF_VERBOSE;
+ break;
+ default:
+ return CMD_HELP;
+ }
+ }
+ if (optind < argc && !realpath(argv[optind], path)) {
+ rc = -errno;
+ fprintf(stderr, "error: invalid path '%s': %s\n",
+ argv[optind], strerror(-rc));
+ return rc;
+ }
+
+ while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
+ /* Check if we have a mount point */
+ if (mntdir[0] == '\0')
+ continue;
+
+ rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL);
+ if (rc || path[0] != '\0')
+ break;
+ fsname[0] = '\0'; /* avoid matching in next loop */
+ mntdir[0] = '\0'; /* avoid matching in next loop */
+ }
+
+ return rc;
+}
+
+static int lfs_getname(int argc, char **argv)
+{
+ char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
+ int rc = 0, index = 0, c;
+ char buf[sizeof(struct obd_uuid)];
+
+ while ((c = getopt(argc, argv, "h")) != -1)
+ return CMD_HELP;
+
+ if (optind == argc) { /* no paths specified, get all paths. */
+ while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
+ rc = llapi_getname(mntdir, buf, sizeof(buf));
+ if (rc < 0) {
+ fprintf(stderr,
+ "cannot get name for `%s': %s\n",
+ mntdir, strerror(-rc));
+ break;
+ }
+
+ printf("%s %s\n", buf, mntdir);
+
+ path[0] = fsname[0] = mntdir[0] = 0;
+ }
+ } else { /* paths specified, only attempt to search these. */
+ for (; optind < argc; optind++) {
+ rc = llapi_getname(argv[optind], buf, sizeof(buf));
+ if (rc < 0) {
+ fprintf(stderr,
+ "cannot get name for `%s': %s\n",
+ argv[optind], strerror(-rc));
+ break;
+ }
+
+ printf("%s %s\n", buf, argv[optind]);
+ }
+ }
+ return rc;
+}
+
+static int lfs_check(int argc, char **argv)
+{
+ int rc;
+ char mntdir[PATH_MAX] = {'\0'};
+ int num_types = 1;
+ char *obd_types[2];
+ char obd_type1[4];
+ char obd_type2[4];
+
+ if (argc != 2) {
+ fprintf(stderr, "%s check: server type must be specified\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ obd_types[0] = obd_type1;
+ obd_types[1] = obd_type2;
+
+ if (strcmp(argv[1], "osts") == 0) {
+ strcpy(obd_types[0], "osc");
+ } else if (strcmp(argv[1], "mds") == 0) {
+ strcpy(obd_types[0], "mdc");
+ } else if (strcmp(argv[1], "servers") == 0) {
+ num_types = 2;
+ strcpy(obd_types[0], "osc");
+ strcpy(obd_types[1], "mdc");
+ } else {
+ fprintf(stderr, "%s check: unrecognized option '%s'\n",
+ progname, argv[1]);
+ return CMD_HELP;
+ }
+
+ rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
+ if (rc < 0 || mntdir[0] == '\0') {
+ fprintf(stderr,
+ "%s check: cannot find mounted Lustre filesystem: %s\n",
+ progname, (rc < 0) ? strerror(-rc) : strerror(ENODEV));
+ return rc;
+ }
+
+ rc = llapi_target_check(num_types, obd_types, mntdir);
+ if (rc)
+ fprintf(stderr, "%s check: cannot check target '%s': %s\n",
+ progname, argv[1], strerror(-rc));
+
+ return rc;
+
+}
+
+#ifdef HAVE_SYS_QUOTA_H
+#define ARG2INT(nr, str, msg) \
+do { \
+ char *endp; \
+ nr = strtol(str, &endp, 0); \
+ if (*endp != '\0') { \
+ fprintf(stderr, "%s: bad %s '%s'\n", \
+ progname, msg, str); \
+ return CMD_HELP; \
+ } \
+} while (0)
+
+#define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
+
+/* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
+ * returns the value or ULONG_MAX on integer overflow or incorrect format
+ * Notes:
+ * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
+ * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
+ * 3. empty integer value is interpreted as 0
+ */
+static unsigned long str2sec(const char* timestr)
+{
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long val = 0;
+ char *tail;
+
+ if (strpbrk(timestr, spec) == NULL) {
+ /* no specifiers inside the time string,
+ should treat it as an integer value */
+ val = strtoul(timestr, &tail, 10);
+ return *tail ? ULONG_MAX : val;
+ }
+
+ /* format string is XXwXXdXXhXXmXXs */
+ while (*timestr) {
+ unsigned long v;
+ int ind;
+ char* ptr;
+
+ v = strtoul(timestr, &tail, 10);
+ if (v == ULONG_MAX || *tail == '\0')
+ /* value too large (ULONG_MAX or more)
+ or missing specifier */
+ goto error;
+
+ ptr = strchr(spec, *tail);
+ if (ptr == NULL)
+ /* unknown specifier */
+ goto error;
+
+ ind = ptr - spec;
+
+ /* check if product will overflow the type */
+ if (!(v < ULONG_MAX / mult[ind]))
+ goto error;
+
+ ADD_OVERFLOW(val, mult[ind] * v);
+ if (val == ULONG_MAX)
+ goto error;
+
+ timestr = tail + 1;
+ }
+
+ return val;
+
+error:
+ return ULONG_MAX;
+}
+
+#define ARG2ULL(nr, str, def_units) \
+do { \
+ unsigned long long limit, units = def_units; \
+ int rc; \
+ \
+ rc = llapi_parse_size(str, &limit, &units, 1); \
+ if (rc < 0) { \
+ fprintf(stderr, "%s: invalid limit '%s'\n", \
+ progname, str); \
+ return CMD_HELP; \
+ } \
+ nr = limit; \
+} while (0)
+
+static inline int has_times_option(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (!strcmp(argv[i], "-t"))
+ return 1;
+
+ return 0;
+}
+
+int lfs_setquota_times(int argc, char **argv)
+{
+ int c, rc;
+ struct if_quotactl qctl;
+ char *mnt, *obd_type = (char *)qctl.obd_type;
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
+ struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
+ struct option long_opts[] = {
+ { .val = 'b', .name = "block-grace", .has_arg = required_argument },
+ { .val = 'g', .name = "group", .has_arg = no_argument },
+ { .val = 'i', .name = "inode-grace", .has_arg = required_argument },
+ { .val = 'p', .name = "projid", .has_arg = no_argument },
+ { .val = 't', .name = "times", .has_arg = no_argument },
+ { .val = 'u', .name = "user", .has_arg = no_argument },
+ { .name = NULL } };
+ int qtype;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_SETINFO;
+ qctl.qc_type = ALLQUOTA;
+
+ while ((c = getopt_long(argc, argv, "b:gi:ptu",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'u':
+ qtype = USRQUOTA;
+ goto quota_type;
+ case 'g':
+ qtype = GRPQUOTA;
+ goto quota_type;
+ case 'p':
+ qtype = PRJQUOTA;
+quota_type:
+ if (qctl.qc_type != ALLQUOTA) {
+ fprintf(stderr, "error: -u/g/p can't be used "
+ "more than once\n");
+ return CMD_HELP;
+ }
+ qctl.qc_type = qtype;
+ break;
+ case 'b':
+ if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
+ fprintf(stderr, "error: bad block-grace: %s\n",
+ optarg);
+ return CMD_HELP;
+ }
+ dqb->dqb_valid |= QIF_BTIME;
+ break;
+ case 'i':
+ if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
+ fprintf(stderr, "error: bad inode-grace: %s\n",
+ optarg);
+ return CMD_HELP;
+ }
+ dqb->dqb_valid |= QIF_ITIME;
+ break;
+ case 't': /* Yes, of course! */
+ break;
+ default: /* getopt prints error message for us when opterr != 0 */
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type == ALLQUOTA) {
+ fprintf(stderr, "error: neither -u, -g nor -p specified\n");
+ return CMD_HELP;
+ }
+
+ if (optind != argc - 1) {
+ fprintf(stderr, "error: unexpected parameters encountered\n");
+ return CMD_HELP;
+ }
+
+ if ((dqb->dqb_valid | QIF_BTIME && dqi->dqi_bgrace >= UINT_MAX) ||
+ (dqb->dqb_valid | QIF_ITIME && dqi->dqi_igrace >= UINT_MAX)) {
+ fprintf(stderr, "error: grace time is too large\n");
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ return 0;
+}
+
+#define BSLIMIT (1 << 0)
+#define BHLIMIT (1 << 1)
+#define ISLIMIT (1 << 2)
+#define IHLIMIT (1 << 3)
+
+int lfs_setquota(int argc, char **argv)
+{
+ int c, rc = 0;
+ struct if_quotactl qctl;
+ char *mnt, *obd_type = (char *)qctl.obd_type;
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
+ struct option long_opts[] = {
+ { .val = 'b', .name = "block-softlimit",
+ .has_arg = required_argument },
+ { .val = 'B', .name = "block-hardlimit",
+ .has_arg = required_argument },
+ { .val = 'd', .name = "default", .has_arg = no_argument },
+ { .val = 'g', .name = "group", .has_arg = required_argument },
+ { .val = 'G', .name = "default-grp", .has_arg = no_argument },
+ { .val = 'i', .name = "inode-softlimit",
+ .has_arg = required_argument },
+ { .val = 'I', .name = "inode-hardlimit",
+ .has_arg = required_argument },
+ { .val = 'p', .name = "projid", .has_arg = required_argument },
+ { .val = 'P', .name = "default-prj", .has_arg = no_argument },
+ { .val = 'u', .name = "user", .has_arg = required_argument },
+ { .val = 'U', .name = "default-usr", .has_arg = no_argument },
+ { .name = NULL } };
+ unsigned limit_mask = 0;
+ char *endptr;
+ bool use_default = false;
+ int qtype;
+
+ if (has_times_option(argc, argv))
+ return lfs_setquota_times(argc, argv);
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
+ qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
+ * so it can be used as a marker that qc_type
+ * isn't reinitialized from command line */
+
+ while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:U",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'U':
+ qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
+ qtype = USRQUOTA;
+ qctl.qc_id = 0;
+ goto quota_type_def;
+ case 'u':
+ qtype = USRQUOTA;
+ rc = name2uid(&qctl.qc_id, optarg);
+ goto quota_type;
+ case 'G':
+ qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
+ qtype = GRPQUOTA;
+ qctl.qc_id = 0;
+ goto quota_type_def;
+ case 'g':
+ qtype = GRPQUOTA;
+ rc = name2gid(&qctl.qc_id, optarg);
+ goto quota_type;
+ case 'P':
+ qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
+ qtype = PRJQUOTA;
+ qctl.qc_id = 0;
+ goto quota_type_def;
+ case 'p':
+ qtype = PRJQUOTA;
+ rc = name2projid(&qctl.qc_id, optarg);
+quota_type:
+ if (rc) {
+ qctl.qc_id = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "%s setquota: invalid"
+ " id '%s'\n", progname, optarg);
+ return -1;
+ }
+ }
+
+ if (qctl.qc_id == 0) {
+ fprintf(stderr, "%s setquota: can't set quota"
+ " for root usr/group/project.\n",
+ progname);
+ return -1;
+ }
+
+quota_type_def:
+ if (qctl.qc_type != ALLQUOTA) {
+ fprintf(stderr,
+ "%s setquota: only one of -u, -U, -g,"
+ " -G, -p or -P may be specified\n",
+ progname);
+ return CMD_HELP;
+ }
+ qctl.qc_type = qtype;
+ break;
+ case 'd':
+ qctl.qc_cmd = LUSTRE_Q_SETDEFAULT;
+ use_default = true;
+ break;
+ case 'b':
+ ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
+ dqb->dqb_bsoftlimit >>= 10;
+ limit_mask |= BSLIMIT;
+ if (dqb->dqb_bsoftlimit &&
+ dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
+ fprintf(stderr,
+ "%s setquota: warning: block softlimit '%llu' smaller than minimum qunit size\n"
+ "See '%s help setquota' or Lustre manual for details\n",
+ progname, dqb->dqb_bsoftlimit,
+ progname);
+ break;
+ case 'B':
+ ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
+ dqb->dqb_bhardlimit >>= 10;
+ limit_mask |= BHLIMIT;
+ if (dqb->dqb_bhardlimit &&
+ dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
+ fprintf(stderr,
+ "%s setquota: warning: block hardlimit '%llu' smaller than minimum qunit size\n"
+ "See '%s help setquota' or Lustre manual for details\n",
+ progname, dqb->dqb_bhardlimit,
+ progname);
+ break;
+ case 'i':
+ ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
+ limit_mask |= ISLIMIT;
+ if (dqb->dqb_isoftlimit &&
+ dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
+ fprintf(stderr,
+ "%s setquota: warning: inode softlimit '%llu' smaller than minimum qunit size\n"
+ "See '%s help setquota' or Lustre manual for details\n",
+ progname, dqb->dqb_isoftlimit,
+ progname);
+ break;
+ case 'I':
+ ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
+ limit_mask |= IHLIMIT;
+ if (dqb->dqb_ihardlimit &&
+ dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
+ fprintf(stderr,
+ "%s setquota: warning: inode hardlimit '%llu' smaller than minimum qunit size\n"
+ "See '%s help setquota' or Lustre manual for details\n",
+ progname, dqb->dqb_ihardlimit,
+ progname);
+ break;
+ default:
+ fprintf(stderr,
+ "%s setquota: unrecognized option '%s'\n",
+ progname, argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type == ALLQUOTA) {
+ fprintf(stderr,
+ "%s setquota: either -u or -g must be specified\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ if (!use_default && limit_mask == 0) {
+ fprintf(stderr,
+ "%s setquota: at least one limit must be specified\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ if (use_default && limit_mask != 0) {
+ fprintf(stderr,
+ "%s setquota: limits should not be specified when"
+ " using default quota\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ if (use_default && qctl.qc_id == 0) {
+ fprintf(stderr,
+ "%s setquota: can not set default quota for root"
+ " user/group/project\n",
+ progname);
+ return CMD_HELP;
+ }
+
+ if (optind != argc - 1) {
+ fprintf(stderr,
+ "%s setquota: filesystem not specified or unexpected argument '%s'\n",
+ progname, argv[optind]);
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+
+ if (use_default) {
+ dqb->dqb_bhardlimit = 0;
+ dqb->dqb_bsoftlimit = 0;
+ dqb->dqb_ihardlimit = 0;
+ dqb->dqb_isoftlimit = 0;
+ dqb->dqb_itime = 0;
+ dqb->dqb_btime = 0;
+ dqb->dqb_valid |= QIF_LIMITS | QIF_TIMES;
+ } else if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
+ (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
+ /* sigh, we can't just set blimits/ilimits */
+ struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
+ .qc_type = qctl.qc_type,
+ .qc_id = qctl.qc_id};
+
+ rc = llapi_quotactl(mnt, &tmp_qctl);
+ if (rc < 0)
+ return rc;
+
+ if (!(limit_mask & BHLIMIT))
+ dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
+ if (!(limit_mask & BSLIMIT))
+ dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
+ if (!(limit_mask & IHLIMIT))
+ dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
+ if (!(limit_mask & ISLIMIT))
+ dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
+
+ /* Keep grace times if we have got no softlimit arguments */
+ if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
+ dqb->dqb_valid |= QIF_BTIME;
+ dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
+ }
+
+ if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
+ dqb->dqb_valid |= QIF_ITIME;
+ dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
+ }
+ }
+
+ dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
+ dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr,
+ "%s setquota: cannot quotactl '%s' '%s': %s",
+ progname, obd_type,
+ obd_uuid2str(&qctl.obd_uuid), strerror(-rc));
+ return rc;
+ }
+
+ return 0;
+}
+
+/* Converts seconds value into format string
+ * result is returned in buf
+ * Notes:
+ * 1. result is in descenting order: 1w2d3h4m5s
+ * 2. zero fields are not filled (except for p. 3): 5d1s
+ * 3. zero seconds value is presented as "0s"
+ */
+static char * __sec2str(time_t seconds, char *buf)
+{
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long c;
+ char *tail = buf;
+ int i;
+
+ for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
+ c = seconds / mult[i];
+
+ if (c > 0 || (i == 0 && buf == tail))
+ tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
+
+ seconds %= mult[i];
+ }
+
+ return tail;
+}
+
+static void sec2str(time_t seconds, char *buf, int rc)
+{
+ char *tail = buf;
+
+ if (rc)
+ *tail++ = '[';
+
+ tail = __sec2str(seconds, tail);
+
+ if (rc && tail - buf < 39) {
+ *tail++ = ']';
+ *tail++ = 0;
+ }
+}
+
+static void diff2str(time_t seconds, char *buf, time_t now)
+{
+
+ buf[0] = 0;
+ if (!seconds)
+ return;
+ if (seconds <= now) {
+ strcpy(buf, "none");
+ return;
+ }
+ __sec2str(seconds - now, buf);
+}
+
+static void print_quota_title(char *name, struct if_quotactl *qctl,
+ bool human_readable, bool show_default)
+{
+ if (show_default) {
+ printf("Disk default %s quota:\n", qtype_name(qctl->qc_type));
+ printf("%15s %8s%8s%8s %8s%8s%8s\n",
+ "Filesystem", "bquota", "blimit", "bgrace",
+ "iquota", "ilimit", "igrace");
+ } else {
+ printf("Disk quotas for %s %s (%cid %u):\n",
+ qtype_name(qctl->qc_type), name,
+ *qtype_name(qctl->qc_type), qctl->qc_id);
+ printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
+ "Filesystem", human_readable ? "used" : "kbytes",
+ "quota", "limit", "grace",
+ "files", "quota", "limit", "grace");
+ }
+}
+
+static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
+{
+ if (!h) {
+ snprintf(buf, buflen, "%ju", (uintmax_t)num);
+ } else {
+ if (num >> 40)
+ snprintf(buf, buflen, "%5.4gP",
+ (double)num / ((__u64)1 << 40));
+ else if (num >> 30)
+ snprintf(buf, buflen, "%5.4gT",
+ (double)num / (1 << 30));
+ else if (num >> 20)
+ snprintf(buf, buflen, "%5.4gG",
+ (double)num / (1 << 20));
+ else if (num >> 10)
+ snprintf(buf, buflen, "%5.4gM",
+ (double)num / (1 << 10));
+ else
+ snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
+ }
+}
+
+#define STRBUF_LEN 32
+static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
+ int rc, bool h, bool show_default)
+{
+ time_t now;
+
+ time(&now);
+
+ if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA ||
+ qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) {
+ int bover = 0, iover = 0;
+ struct obd_dqblk *dqb = &qctl->qc_dqblk;
+ char numbuf[3][STRBUF_LEN];
+ char timebuf[40];
+ char strbuf[STRBUF_LEN];
+
+ if (dqb->dqb_bhardlimit &&
+ lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
+ bover = 1;
+ } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
+ if (dqb->dqb_btime > now) {
+ bover = 2;
+ } else {
+ bover = 3;
+ }
+ }
+
+ if (dqb->dqb_ihardlimit &&
+ dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
+ iover = 1;
+ } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
+ if (dqb->dqb_itime > now) {
+ iover = 2;
+ } else {
+ iover = 3;
+ }
+ }
+
+
+ if (strlen(mnt) > 15)
+ printf("%s\n%15s", mnt, "");
+ else
+ printf("%15s", mnt);
+
+ if (bover)
+ diff2str(dqb->dqb_btime, timebuf, now);
+ else if (show_default)
+ snprintf(timebuf, sizeof(timebuf), "%llu",
+ dqb->dqb_btime);
+
+ kbytes2str(lustre_stoqb(dqb->dqb_curspace),
+ strbuf, sizeof(strbuf), h);
+ if (rc == -EREMOTEIO)
+ sprintf(numbuf[0], "%s*", strbuf);
+ else
+ sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
+ "%s" : "[%s]", strbuf);
+
+ kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
+ if (type == QC_GENERAL)
+ sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
+ "%s" : "[%s]", strbuf);
+ else
+ sprintf(numbuf[1], "%s", "-");
+
+ kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
+ sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
+ "%s" : "[%s]", strbuf);
+
+ if (show_default)
+ printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
+ else
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], bover ? '*' : ' ', numbuf[1],
+ numbuf[2], bover > 1 ? timebuf : "-");
+
+
+ if (iover)
+ diff2str(dqb->dqb_itime, timebuf, now);
+ else if (show_default)
+ snprintf(timebuf, sizeof(timebuf), "%llu",
+ dqb->dqb_itime);
+
+ snprintf(numbuf[0], sizeof(numbuf),
+ (dqb->dqb_valid & QIF_INODES) ? "%ju" : "[%ju]",
+ (uintmax_t)dqb->dqb_curinodes);
+
+ if (type == QC_GENERAL)
+ sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
+ "%ju" : "[%ju]",
+ (uintmax_t)dqb->dqb_isoftlimit);
+ else
+ sprintf(numbuf[1], "%s", "-");
+
+ sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
+ "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
+
+ if (show_default)
+ printf(" %6s %7s %7s", numbuf[1], numbuf[2], timebuf);
+ else if (type != QC_OSTIDX)
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], iover ? '*' : ' ', numbuf[1],
+ numbuf[2], iover > 1 ? timebuf : "-");
+ else
+ printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
+ printf("\n");
+
+ } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
+ qctl->qc_cmd == Q_GETOINFO) {
+ char bgtimebuf[40];
+ char igtimebuf[40];
+
+ sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
+ sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
+ printf("Block grace time: %s; Inode grace time: %s\n",
+ bgtimebuf, igtimebuf);
+ }
+}
+
+static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
+ bool h, __u64 *total)
+{
+ int rc = 0, rc1 = 0, count = 0;
+ __u32 valid = qctl->qc_valid;
+
+ rc = llapi_get_obd_count(mnt, &count, is_mdt);
+ if (rc) {
+ fprintf(stderr, "can not get %s count: %s\n",
+ is_mdt ? "mdt": "ost", strerror(-rc));
+ return rc;
+ }
+
+ for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
+ qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ /* It is remote client case. */
+ if (rc == -EOPNOTSUPP) {
+ rc = 0;
+ goto out;
+ }
+
+ if (!rc1)
+ rc1 = rc;
+ fprintf(stderr, "quotactl %s%d failed.\n",
+ is_mdt ? "mdt": "ost", qctl->qc_idx);
+ continue;
+ }
+
+ print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
+ qctl->qc_valid, 0, h, false);
+ *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
+ qctl->qc_dqblk.dqb_bhardlimit;
+ }
+out:
+ qctl->qc_valid = valid;
+ return rc ? : rc1;
+}
+
+static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
+ int verbose, int quiet, bool human_readable,
+ bool show_default)
+{
+ int rc1 = 0, rc2 = 0, rc3 = 0;
+ char *obd_type = (char *)qctl->obd_type;
+ char *obd_uuid = (char *)qctl->obd_uuid.uuid;
+ __u64 total_ialloc = 0, total_balloc = 0;
+ bool use_default_for_blk = false;
+ bool use_default_for_file = false;
+ int inacc;
+
+ rc1 = llapi_quotactl(mnt, qctl);
+ if (rc1 < 0) {
+ switch (rc1) {
+ case -ESRCH:
+ fprintf(stderr, "%s quotas are not enabled.\n",
+ qtype_name(qctl->qc_type));
+ goto out;
+ case -EPERM:
+ fprintf(stderr, "Permission denied.\n");
+ case -ENODEV:
+ case -ENOENT:
+ /* We already got error message. */
+ goto out;
+ default:
+ fprintf(stderr, "Unexpected quotactl error: %s\n",
+ strerror(-rc1));
+ }
+ }
+
+ if (!show_default && qctl->qc_id == 0) {
+ qctl->qc_dqblk.dqb_bhardlimit = 0;
+ qctl->qc_dqblk.dqb_bsoftlimit = 0;
+ qctl->qc_dqblk.dqb_ihardlimit = 0;
+ qctl->qc_dqblk.dqb_isoftlimit = 0;
+ qctl->qc_dqblk.dqb_btime = 0;
+ qctl->qc_dqblk.dqb_itime = 0;
+ qctl->qc_dqblk.dqb_valid |= QIF_LIMITS | QIF_TIMES;
+ }
+
+ if (qctl->qc_dqblk.dqb_valid & QIF_BTIME &&
+ LQUOTA_FLAG(qctl->qc_dqblk.dqb_btime) & LQUOTA_FLAG_DEFAULT) {
+ use_default_for_blk = true;
+ qctl->qc_dqblk.dqb_btime &= LQUOTA_GRACE_MASK;
+ }
+
+ if (qctl->qc_dqblk.dqb_valid & QIF_ITIME &&
+ LQUOTA_FLAG(qctl->qc_dqblk.dqb_itime) & LQUOTA_FLAG_DEFAULT) {
+ use_default_for_file = true;
+ qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
+ }
+
+ if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
+ qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
+ print_quota_title(name, qctl, human_readable, show_default);
+
+ if (rc1 && *obd_type)
+ fprintf(stderr, "%s %s ", obd_type, obd_uuid);