+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
+ return rc;
+ }
+
+ *count = is_mdt;
+ rc = ioctl(dirfd(root), LL_IOC_GETOBDCOUNT, count);
+ if (rc < 0)
+ rc = -errno;
+
+ closedir(root);
+ return rc;
+}
+
+/* Check if user specified value matches a real uuid. Ignore _UUID,
+ * -osc-4ba41334, other trailing gunk in comparison.
+ * @param real_uuid ends in "_UUID"
+ * @param search_uuid may or may not end in "_UUID"
+ */
+int llapi_uuid_match(char *real_uuid, char *search_uuid)
+{
+ int cmplen = strlen(real_uuid);
+ int searchlen = strlen(search_uuid);
+
+ if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
+ cmplen -= 5;
+ if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
+ searchlen -= 5;
+
+ /* The UUIDs may legitimately be different lengths, if
+ * the system was upgraded from an older version. */
+ if (cmplen != searchlen)
+ return 0;
+
+ return (strncmp(search_uuid, real_uuid, cmplen) == 0);
+}
+
+/* Here, param->obduuid points to a single obduuid, the index of which is
+ * returned in param->obdindex */
+static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
+{
+ struct obd_uuid obd_uuid;
+ char uuid[sizeof(struct obd_uuid)];
+ char buf[1024];
+ FILE *fp;
+ int rc = 0, index;
+
+ if (param->got_uuids)
+ return rc;
+
+ /* Get the lov/lmv name */
+ if (param->get_lmv)
+ rc = llapi_file_fget_lmv_uuid(dirfd(dir), &obd_uuid);
+ else
+ rc = llapi_file_fget_lov_uuid(dirfd(dir), &obd_uuid);
+ if (rc) {
+ if (rc != -ENOTTY) {
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "error: can't get lov name: %s", dname);
+ } else {
+ rc = 0;
+ }
+ return rc;
+ }
+
+ param->got_uuids = 1;
+
+ /* Now get the ost uuids from /proc */
+ snprintf(buf, sizeof(buf), "/proc/fs/lustre/%s/%s/target_obd",
+ param->get_lmv ? "lmv" : "lov", obd_uuid.uuid);
+ fp = fopen(buf, "r");
+ if (fp == NULL) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", buf);
+ return rc;
+ }
+
+ if (!param->obduuid && !param->quiet && !param->obds_printed)
+ llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
+ param->get_lmv ? "MDTS" : "OBDS:");
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (sscanf(buf, "%d: %s", &index, uuid) < 2)
+ break;
+
+ if (param->obduuid) {
+ if (llapi_uuid_match(uuid, param->obduuid->uuid)) {
+ param->obdindex = index;
+ break;
+ }
+ } else if (!param->quiet && !param->obds_printed) {
+ /* Print everything */
+ llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
+ }
+ }
+ param->obds_printed = 1;
+
+ fclose(fp);
+
+ if (param->obduuid && (param->obdindex == OBD_NOT_FOUND)) {
+ llapi_err_noerrno(LLAPI_MSG_ERROR,
+ "error: %s: unknown obduuid: %s",
+ __func__, param->obduuid->uuid);
+ rc = -EINVAL;
+ }
+
+ return (rc);
+}
+
+/* In this case, param->obduuid will be an array of obduuids and
+ * obd index for all these obduuids will be returned in
+ * param->obdindexes */
+static int setup_indexes(DIR *dir, char *path, struct obd_uuid *obduuids,
+ int num_obds, int **obdindexes, int *obdindex,
+ enum tgt_type type)
+{
+ int ret, obdcount, obd_valid = 0, obdnum, i;
+ struct obd_uuid *uuids = NULL;
+ char buf[16];
+ int *indexes;
+
+ if (type == LOV_TYPE)
+ ret = get_param_lov(path, "numobd", buf, sizeof(buf));
+ else
+ ret = get_param_lmv(path, "numobd", buf, sizeof(buf));
+ if (ret != 0)
+ return ret;
+
+ obdcount = atoi(buf);
+ uuids = (struct obd_uuid *)malloc(obdcount *
+ sizeof(struct obd_uuid));
+ if (uuids == NULL)
+ return -ENOMEM;
+
+retry_get_uuids:
+ ret = llapi_get_target_uuids(dirfd(dir), uuids, &obdcount, type);
+ if (ret) {
+ struct obd_uuid *uuids_temp;
+
+ if (ret == -EOVERFLOW) {
+ uuids_temp = realloc(uuids, obdcount *
+ sizeof(struct obd_uuid));
+ if (uuids_temp != NULL) {
+ uuids = uuids_temp;
+ goto retry_get_uuids;
+ }
+ else
+ ret = -ENOMEM;
+ }
+
+ llapi_error(LLAPI_MSG_ERROR, ret, "get ost uuid failed");
+ goto out_free;
+ }
+
+ indexes = malloc(num_obds * sizeof(*obdindex));
+ if (indexes == NULL) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ for (obdnum = 0; obdnum < num_obds; obdnum++) {
+ char *end = NULL;
+
+ /* The user may have specified a simple index */
+ i = strtol(obduuids[obdnum].uuid, &end, 0);
+ if (end && *end == '\0' && i < obdcount) {
+ indexes[obdnum] = i;
+ obd_valid++;
+ } else {
+ for (i = 0; i < obdcount; i++) {
+ if (llapi_uuid_match(uuids[i].uuid,
+ obduuids[obdnum].uuid)) {
+ indexes[obdnum] = i;
+ obd_valid++;
+ break;
+ }
+ }
+ }
+ if (i >= obdcount) {
+ indexes[obdnum] = OBD_NOT_FOUND;
+ llapi_err_noerrno(LLAPI_MSG_ERROR,
+ "error: %s: unknown obduuid: %s",
+ __func__, obduuids[obdnum].uuid);
+ ret = -EINVAL;
+ }
+ }
+
+ if (obd_valid == 0)
+ *obdindex = OBD_NOT_FOUND;
+ else
+ *obdindex = obd_valid;
+
+ *obdindexes = indexes;
+out_free:
+ if (uuids)
+ free(uuids);
+
+ return ret;
+}
+
+static int setup_target_indexes(DIR *dir, char *path, struct find_param *param)
+{
+ int ret = 0;
+
+ if (param->mdtuuid) {
+ ret = setup_indexes(dir, path, param->mdtuuid, param->num_mdts,
+ ¶m->mdtindexes, ¶m->mdtindex, LMV_TYPE);
+ if (ret)
+ return ret;
+ }
+ if (param->obduuid) {
+ ret = setup_indexes(dir, path, param->obduuid, param->num_obds,
+ ¶m->obdindexes, ¶m->obdindex, LOV_TYPE);
+ if (ret)
+ return ret;
+ }
+ param->got_uuids = 1;
+ return ret;
+}
+
+int llapi_ostlist(char *path, struct find_param *param)
+{
+ DIR *dir;
+ int ret;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return -errno;
+
+ ret = setup_obd_uuid(dir, path, param);
+ closedir(dir);
+
+ return ret;
+}
+
+/*
+ * Given a filesystem name, or a pathname of a file on a lustre filesystem,
+ * tries to determine the path to the filesystem's clilov directory under /proc
+ *
+ * fsname is limited to MTI_NAME_MAXLEN in lustre_idl.h
+ * The NUL terminator is compensated by the additional "%s" bytes. */
+#define LOV_LEN (sizeof("/proc/fs/lustre/lov/%s-clilov-*") + MTI_NAME_MAXLEN)
+static int clilovpath(const char *fsname, const char *const pathname,
+ char *clilovpath)
+{
+ int rc;
+ char pattern[LOV_LEN];
+ char buffer[PATH_MAX + 1];
+
+ if (fsname == NULL) {
+ rc = llapi_search_fsname(pathname, buffer);
+ if (rc != 0)
+ return rc;
+ fsname = buffer;
+ }
+
+ snprintf(pattern, sizeof(pattern), "/proc/fs/lustre/lov/%s-clilov-*",
+ fsname);
+
+ rc = first_match(pattern, buffer);
+ if (rc != 0)
+ return rc;
+
+ strncpy(clilovpath, buffer, sizeof(buffer));
+
+ return 0;
+}
+
+/*
+ * Given the path to a stripe attribute proc file, tries to open and
+ * read the attribute and return the value using the attr parameter
+ */
+static int sattr_read_attr(const char *const fpath,
+ unsigned int *attr)
+{
+
+ FILE *f;
+ char line[PATH_MAX + 1];
+ int rc = 0;
+
+ f = fopen(fpath, "r");
+ if (f == NULL) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "Cannot open '%s'", fpath);
+ return rc;