+/**
+ * return a parameter string for a specific device type or mountpoint
+ *
+ * \param param_path the path to the file containing parameter data
+ * \param result buffer for parameter value string
+ * \param result_size size of buffer for return value
+ *
+ * The \param param_path is appended to /proc/{fs,sys}/{lnet,lustre} to
+ * complete the absolute path to the file containing the parameter data
+ * the user is requesting. If that file exist then the data is read from
+ * the file and placed into the \param result buffer that is passed by
+ * the user. Data is only copied up to the \param result_size to prevent
+ * overflow of the array.
+ *
+ * Return 0 for success, with a NUL-terminated string in \param result.
+ * Return -ve value for error.
+ */
+static int get_param(const char *param_path, char *result,
+ unsigned int result_size)
+{
+ char file[PATH_MAX + 1], pattern[PATH_MAX + 1], buf[result_size];
+ FILE *fp = NULL;
+ int rc = 0;
+
+ snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
+ param_path);
+ rc = first_match(pattern, file);
+ if (rc)
+ return rc;
+
+ fp = fopen(file, "r");
+ if (fp != NULL) {
+ while (fgets(buf, result_size, fp) != NULL)
+ strcpy(result, buf);
+ fclose(fp);
+ } else {
+ rc = -errno;
+ }
+ return rc;
+}
+
+#define DEVICES_LIST "/proc/fs/lustre/devices"
+
+/**
+ * return a parameter string for a specific device type or mountpoint
+ *
+ * \param fsname Lustre filesystem name (optional)
+ * \param file_path path to file in filesystem (optional, if fsname unset)
+ * \param obd_type Lustre OBD device type
+ * \param param_name parameter name to fetch
+ * \param value return buffer for parameter value string
+ * \param val_len size of buffer for return value
+ *
+ * If fsname is specified then the parameter will be from that filesystem
+ * (if it exists). If file_path is given and it is in a mounted Lustre
+ * filesystem, then the parameter will be otherwise the value may be
+ * from any mounted filesystem (if there is more than one).
+ *
+ * If "obd_type" matches a Lustre device then the first matching device
+ * (as with "lctl dl", constrained by \param fsname or \param mount_path)
+ * will be used to provide the return value, otherwise the first such
+ * device found will be used.
+ *
+ * Return 0 for success, with a NUL-terminated string in \param buffer.
+ * Return -ve value for error.
+ */
+static int get_param_obdvar(const char *fsname, const char *file_path,
+ const char *obd_type, const char *param_name,
+ char *value, unsigned int val_len)
+{
+ char devices[PATH_MAX + 1], dev[PATH_MAX + 1] = "*", fs[PATH_MAX + 1];
+ FILE *fp = fopen(DEVICES_LIST, "r");
+ int rc = 0;
+
+ if (!fsname && file_path) {
+ rc = llapi_search_fsname(file_path, fs);
+ if (rc) {
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "'%s' is not on a Lustre filesystem",
+ file_path);
+ if (fp != NULL)
+ fclose(fp);
+ return rc;
+ }
+ } else if (fsname) {
+ strcpy(fs, fsname);
+ }
+
+ if (fp == NULL) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "error: opening "DEVICES_LIST);
+ return rc;
+ }
+
+ while (fgets(devices, sizeof(devices), fp) != NULL) {
+ char *bufp = devices, *tmp;
+
+ while (bufp[0] == ' ')
+ ++bufp;
+
+ tmp = strstr(bufp, obd_type);
+ if (tmp) {
+ tmp += strlen(obd_type) + 1;
+ if (strcmp(tmp, fs))
+ continue;
+ strcpy(dev, tmp);
+ tmp = strchr(dev, ' ');
+ *tmp = '\0';
+ break;
+ }
+ }
+
+ if (dev[0] == '*' && strlen(fs))
+ snprintf(dev, PATH_MAX, "%s-*", fs);
+ snprintf(devices, PATH_MAX, "%s/%s/%s", obd_type, dev, param_name);
+ fclose(fp);
+ return get_param(devices, value, val_len);
+}
+
+/*
+ * TYPE one of llite, lmv, lov.
+ * /proc/fs/lustre/TYPE/INST the directory of interest.
+ */
+static int get_param_cli(const char *type, const char *inst,
+ const char *param, char *buf, size_t buf_size)
+{
+ char param_path[PATH_MAX + 1];
+ FILE *param_file = NULL;
+ int rc;
+
+ snprintf(param_path, sizeof(param_path),
+ "/proc/fs/lustre/%s/%s/%s", type, inst, param);
+
+ param_file = fopen(param_path, "r");
+ if (param_file == NULL) {
+ rc = -errno;
+ goto out;
+ }
+
+ if (fgets(buf, buf_size, param_file) == NULL) {
+ rc = -errno;
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (param_file != NULL)
+ fclose(param_file);
+
+ return rc;
+}
+
+static int get_param_llite(const char *path,
+ const char *param, char *buf, size_t buf_size)
+{
+ char inst[80];
+ int rc;
+
+ rc = llapi_getname(path, inst, sizeof(inst));
+ if (rc != 0)
+ return rc;
+
+ return get_param_cli("llite", inst, param, buf, buf_size);
+}
+
+static int get_param_lov(const char *path,
+ const char *param, char *buf, size_t buf_size)
+{
+ struct obd_uuid uuid;
+ int rc;
+
+ rc = llapi_file_get_lov_uuid(path, &uuid);
+ if (rc != 0)
+ return rc;
+
+ return get_param_cli("lov", uuid.uuid, param, buf, buf_size);
+}
+
+static int get_param_lmv(const char *path,
+ const char *param, char *buf, size_t buf_size)
+{
+ struct obd_uuid uuid;
+ int rc;
+
+ rc = llapi_file_get_lmv_uuid(path, &uuid);
+ if (rc != 0)
+ return rc;
+
+ return get_param_cli("lmv", uuid.uuid, param, buf, buf_size);
+}
+
+static int get_mds_md_size(const char *path)
+{
+ int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
+ char buf[80];
+ int rc;
+
+ /* Get the max ea size from llite proc. */
+ rc = get_param_llite(path, "max_easize", buf, sizeof(buf));
+ if (rc != 0)
+ goto out;
+
+ rc = atoi(buf);
+ if (rc > 0)
+ md_size = rc;
+
+out:
+ return md_size;
+}
+