free(ctrls->address);
free(ctrls->state);
free(ctrls->ana_state);
+ free(ctrls->subsysnqn);
+ free(ctrls->traddr);
+ free(ctrls->trsvcid);
+ free(ctrls->host_traddr);
+}
+
+static const char delim_space = ' ';
+const char *conarg_traddr = "traddr";
+const char *conarg_trsvcid = "trsvcid";
+const char *conarg_host_traddr = "host_traddr";
+
+/*
+ * parse strings with connect arguments to find a particular field.
+ * If field found, return string containing field value. If field
+ * not found, return an empty string.
+ */
+char *__parse_connect_arg(char *conargs, const char delim, const char *fieldnm)
+{
+ char *s, *e;
+ size_t cnt;
+
+ /*
+ * There are field name overlaps: traddr and host_traddr.
+ * By chance, both connect arg strings are set up to
+ * have traddr field followed by host_traddr field. Thus field
+ * name matching doesn't overlap in the searches. Technically,
+ * as is, the loop and delimiter checking isn't necessary.
+ * However, better to be prepared.
+ */
+ do {
+ s = strstr(conargs, fieldnm);
+ if (!s)
+ goto empty_field;
+ /* validate prior character is delimiter */
+ if (s == conargs || *(s - 1) == delim) {
+ /* match requires next character to be assignment */
+ s += strlen(fieldnm);
+ if (*s == '=')
+ /* match */
+ break;
+ }
+ /* field overlap: seek to delimiter and keep looking */
+ conargs = strchr(s, delim);
+ if (!conargs)
+ goto empty_field;
+ conargs++; /* skip delimiter */
+ } while (1);
+ s++; /* skip assignment character */
+ e = strchr(s, delim);
+ if (e)
+ cnt = e - s;
+ else
+ cnt = strlen(s);
+
+ return strndup(s, cnt);
+
+empty_field:
+ return strdup("\0");
}
static int get_nvme_ctrl_info(char *name, char *path,
if (nsid != NVME_NSID_ALL)
ctrl->ana_state = get_nvme_ctrl_path_ana_state(ctrl_path, nsid);
+ ctrl->subsysnqn = get_nvme_ctrl_attr(ctrl_path, "subsysnqn");
+ if (!ctrl->subsysnqn) {
+ fprintf(stderr, "%s: failed to get controller subsysnqn.\n",
+ ctrl->name);
+ goto free_ctrl_items;
+ }
+
+ ctrl->traddr = __parse_connect_arg(ctrl->address, delim_space,
+ conarg_traddr);
+ ctrl->trsvcid = __parse_connect_arg(ctrl->address, delim_space,
+ conarg_trsvcid);
+ ctrl->host_traddr = __parse_connect_arg(ctrl->address, delim_space,
+ conarg_host_traddr);
+
return 0; /* success */
free_ctrl_items: