scfga_ret_t make_dyncomp( di_node_t node, const char *physpath, char **dyncompp, int *l_errnop) { char *devlink = NULL; scfga_ret_t ret; di_minor_t minor; char *path; char pathbuf[MAXPATHLEN]; int match_minor; if (*dyncompp != NULL) { return (SCFGA_LIB_ERR); } /* tag on minor name */ minor = di_minor_next(node, DI_MINOR_NIL); if (minor == DI_MINOR_NIL) { match_minor = 0; path = (char *)physpath; } else { match_minor = 1; (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath, di_minor_name(minor)); path = pathbuf; } /* Get the corresponding devlink from the physical path */ ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor); if (ret == SCFGA_OK) { assert(devlink != NULL); /* Create dynamic component. */ ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop); S_FREE(devlink); if (ret == SCFGA_OK) { assert(*dyncompp != NULL); return (SCFGA_OK); } /* * Failed to get devlink based dynamic component. * Try driver and instance */ } ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop); assert(ret != SCFGA_OK || *dyncompp != NULL); return (ret); }
static scfga_ret_t get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop) { size_t len; scfga_ret_t ret; int match_minor = 1; ret = physpath_to_devlink((char *)hba_phys, hba_logpp, l_errnop, match_minor); if (ret != SCFGA_OK) { return (ret); } assert(*hba_logpp != NULL); /* Remove the "/dev/cfg/" prefix */ len = strlen(CFGA_DEV_DIR SLASH); (void) memmove(*hba_logpp, *hba_logpp + len, strlen(*hba_logpp + len) + 1); return (SCFGA_OK); }
/*ARGSUSED*/ cfga_err_t cfga_list_ext( const char *ap_id, cfga_list_data_t **ap_id_list, int *nlistp, const char *options, const char *listopts, char **errstring, cfga_flags_t flags) { int l_errno; char *ap_id_log = NULL; size_t size; nvlist_t *user_nvlist = NULL; devctl_hdl_t devctl_hdl = NULL; cfga_sata_ret_t rv = CFGA_SATA_OK; devctl_ap_state_t devctl_ap_state; char *pdyn; if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) { (void) cfga_help(NULL, options, flags); goto bailout; } /* We do not care here about dynamic AP name component */ if ((pdyn = GET_DYN(ap_id)) != NULL) { *pdyn = '\0'; } if (ap_id_list == NULL || nlistp == NULL) { rv = CFGA_SATA_DATA_ERROR; (void) cfga_help(NULL, options, flags); goto bailout; } /* Get ap status */ if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist, DC_RDONLY)) != CFGA_SATA_OK) { goto bailout; } /* will call dc_cmd to send IOCTL to kernel */ if (devctl_ap_getstate(devctl_hdl, user_nvlist, &devctl_ap_state) == -1) { cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); rv = CFGA_SATA_IOCTL; goto bailout; } cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); /* * Create cfga_list_data_t struct. */ if ((*ap_id_list = (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) { rv = CFGA_SATA_ALLOC_FAIL; goto bailout; } *nlistp = 1; /* * Rest of the code fills in the cfga_list_data_t struct. */ /* Get /dev/cfg path to corresponding to the physical ap_id */ /* Remember ap_id_log must be freed */ rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id, &ap_id_log, &l_errno); if (rv != 0) { rv = CFGA_SATA_DEVLINK; goto bailout; } /* Get logical ap_id corresponding to the physical */ if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) { rv = CFGA_SATA_DEVLINK; goto bailout; } (void) strlcpy((*ap_id_list)->ap_log_id, /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1, sizeof ((*ap_id_list)->ap_log_id)); free(ap_id_log); ap_id_log = NULL; (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id, sizeof ((*ap_id_list)->ap_phys_id)); switch (devctl_ap_state.ap_rstate) { case AP_RSTATE_EMPTY: (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY; break; case AP_RSTATE_DISCONNECTED: (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED; break; case AP_RSTATE_CONNECTED: (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED; break; default: rv = CFGA_SATA_STATE; goto bailout; } switch (devctl_ap_state.ap_ostate) { case AP_OSTATE_CONFIGURED: (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED; break; case AP_OSTATE_UNCONFIGURED: (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED; break; default: rv = CFGA_SATA_STATE; goto bailout; } switch (devctl_ap_state.ap_condition) { case AP_COND_OK: (*ap_id_list)->ap_cond = CFGA_COND_OK; break; case AP_COND_FAILING: (*ap_id_list)->ap_cond = CFGA_COND_FAILING; break; case AP_COND_FAILED: (*ap_id_list)->ap_cond = CFGA_COND_FAILED; break; case AP_COND_UNUSABLE: (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE; break; case AP_COND_UNKNOWN: (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN; break; default: rv = CFGA_SATA_STATE; goto bailout; } (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */ (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition; (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change; (*ap_id_list)->ap_info[0] = NULL; if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) { char *str_p; int skip, i; /* * Fill in the 'Information' field for the -v option * Model (MOD:) */ if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO, NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { (void) printf( "SATA_CFGA_GET_MODULE_INFO ioctl failed\n"); goto bailout; } /* drop leading and trailing spaces */ skip = strspn(str_p, " "); for (i = size - 1; i >= 0; i--) { if (str_p[i] == '\040') str_p[i] = '\0'; else if (str_p[i] != '\0') break; } (void) strlcpy((*ap_id_list)->ap_info, "Mod: ", sizeof ((*ap_id_list)->ap_info)); (void) strlcat((*ap_id_list)->ap_info, str_p + skip, sizeof ((*ap_id_list)->ap_info)); free(str_p); /* * Fill in the 'Information' field for the -v option * Firmware revision (FREV:) */ if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_REVFIRMWARE_INFO, NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { (void) printf( "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n"); goto bailout; } /* drop leading and trailing spaces */ skip = strspn(str_p, " "); for (i = size - 1; i >= 0; i--) { if (str_p[i] == '\040') str_p[i] = '\0'; else if (str_p[i] != '\0') break; } (void) strlcat((*ap_id_list)->ap_info, " FRev: ", sizeof ((*ap_id_list)->ap_info)); (void) strlcat((*ap_id_list)->ap_info, str_p + skip, sizeof ((*ap_id_list)->ap_info)); free(str_p); /* * Fill in the 'Information' field for the -v option * Serial Number (SN:) */ if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_SERIALNUMBER_INFO, NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { (void) printf( "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n"); goto bailout; } /* drop leading and trailing spaces */ skip = strspn(str_p, " "); for (i = size - 1; i >= 0; i--) { if (str_p[i] == '\040') str_p[i] = '\0'; else if (str_p[i] != '\0') break; } (void) strlcat((*ap_id_list)->ap_info, " SN: ", sizeof ((*ap_id_list)->ap_info)); (void) strlcat((*ap_id_list)->ap_info, str_p + skip, sizeof ((*ap_id_list)->ap_info)); free(str_p); /* Fill in ap_type which is collected from HBA driver */ /* call do_control_ioctl TBD */ if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { (void) printf( "SATA_CFGA_GET_AP_TYPE ioctl failed\n"); goto bailout; } (void) strlcpy((*ap_id_list)->ap_type, str_p, sizeof ((*ap_id_list)->ap_type)); free(str_p); if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED) { char *dyncomp = NULL; /* * This is the case where we need to generate * a dynamic component of the ap_id, i.e. device. */ rv = sata_make_dyncomp(ap_id, &dyncomp); if (rv != CFGA_SATA_OK) goto bailout; if (dyncomp != NULL) { (void) strcat((*ap_id_list)->ap_log_id, DYN_SEP); (void) strlcat((*ap_id_list)->ap_log_id, dyncomp, sizeof ((*ap_id_list)->ap_log_id)); free(dyncomp); } } } else { /* Change it when port multiplier is supported */ (void) strlcpy((*ap_id_list)->ap_type, "sata-port", sizeof ((*ap_id_list)->ap_type)); } return (sata_err_msg(errstring, rv, ap_id, errno)); bailout: if (*ap_id_list != NULL) { free(*ap_id_list); } if (ap_id_log != NULL) { free(ap_id_log); } return (sata_err_msg(errstring, rv, ap_id, errno)); }
static cfga_sata_ret_t physpath_to_devlink(const char *basedir, const char *node_path, char **logpp, int *l_errnop) { char *linkpath; char *buf; char *real_path; DIR *dp; struct dirent *dep, *newdep; int deplen; boolean_t found = B_FALSE; int err = 0; struct stat sb; char *p; cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR; /* * Using libdevinfo for this is overkill and kills performance * when multiple consumers of libcfgadm are executing * concurrently. */ if ((dp = opendir(basedir)) == NULL) { *l_errnop = errno; return (CFGA_SATA_INTERNAL_ERROR); } linkpath = malloc(PATH_MAX); buf = malloc(PATH_MAX); real_path = malloc(PATH_MAX); deplen = pathconf(basedir, _PC_NAME_MAX) + sizeof (struct dirent); dep = (struct dirent *)malloc(deplen); if (dep == NULL || linkpath == NULL || buf == NULL || real_path == NULL) { *l_errnop = ENOMEM; rv = CFGA_SATA_ALLOC_FAIL; goto pp_cleanup; } *logpp = NULL; while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 && newdep != NULL) { assert(newdep == dep); if (strcmp(dep->d_name, ".") == 0 || strcmp(dep->d_name, "..") == 0) continue; (void) snprintf(linkpath, MAXPATHLEN, "%s/%s", basedir, dep->d_name); if (lstat(linkpath, &sb) < 0) continue; if (S_ISDIR(sb.st_mode)) { if ((rv = physpath_to_devlink(linkpath, node_path, logpp, l_errnop)) != CFGA_SATA_OK) { goto pp_cleanup; } if (*logpp != NULL) found = B_TRUE; } else if (S_ISLNK(sb.st_mode)) { bzero(buf, PATH_MAX); if (readlink(linkpath, buf, PATH_MAX) < 0) continue; /* * realpath() is too darn slow, so fake * it, by using what we know about /dev * links: they are always of the form: * <"../">+/devices/<path> */ p = buf; while (strncmp(p, "../", 3) == 0) p += 3; if (p != buf) p--; /* back up to get a slash */ assert (*p == '/'); if (strcmp(p, node_path) == 0) { *logpp = strdup(linkpath); if (*logpp == NULL) { rv = CFGA_SATA_ALLOC_FAIL; goto pp_cleanup; } found = B_TRUE; } } } free(linkpath); free(buf); free(real_path); free(dep); (void) closedir(dp); if (err != 0) { *l_errnop = err; return (CFGA_SATA_INTERNAL_ERROR); } return (CFGA_SATA_OK); pp_cleanup: if (dp) (void) closedir(dp); if (dep) free(dep); if (linkpath) free(linkpath); if (buf) free(buf); if (real_path) free(real_path); if (*logpp) { free(*logpp); *logpp = NULL; } return (rv); }
/* * The dynamic component buffer returned by this function has to be freed! */ int sata_make_dyncomp(const char *ap_id, char **dyncomp) { char *devpath = NULL; char *cp = NULL; int l_errno; char minor_path[MAXPATHLEN]; char name_part[MAXNAMELEN]; char *devlink = NULL; char *minor_portion = NULL; int deplen; int err; DIR *dp = NULL; struct stat sb; struct dirent *dep = NULL; struct dirent *newdep = NULL; char *p; assert(dyncomp != NULL); /* * Get target node path */ devpath = sata_get_devicepath(ap_id); if (devpath == NULL) { (void) printf("cfga_list_ext: cannot locate target device\n"); return (CFGA_SATA_DYNAMIC_AP); } else { cp = strrchr(devpath, *PATH_SEP); assert(cp != NULL); *cp = 0; /* terminate path for opendir() */ (void) strncpy(name_part, cp + 1, MAXNAMELEN); /* * Using libdevinfo for this is overkill and kills * performance when many consumers are using libcfgadm * concurrently. */ if ((dp = opendir(devpath)) == NULL) { goto bailout; } /* * deplen is large enough to fit the largest path- * struct dirent includes one byte (the terminator) * so we don't add 1 to the calculation here. */ deplen = pathconf(devpath, _PC_NAME_MAX) + sizeof (struct dirent); dep = (struct dirent *)malloc(deplen); if (dep == NULL) goto bailout; while ((err = readdir_r(dp, dep, &newdep)) == 0 && newdep != NULL) { assert(newdep == dep); if (strcmp(dep->d_name, ".") == 0 || strcmp(dep->d_name, "..") == 0 || (minor_portion = strchr(dep->d_name, *MINOR_SEP)) == NULL) continue; *minor_portion = 0; if (strcmp(dep->d_name, name_part) != 0) continue; *minor_portion = *MINOR_SEP; (void) snprintf(minor_path, MAXPATHLEN, "%s/%s", devpath, dep->d_name); if (stat(minor_path, &sb) < 0) continue; if (S_ISBLK(sb.st_mode)) break; } (void) closedir(dp); free(dep); free(devpath); dp = NULL; dep = NULL; devpath = NULL; /* * If there was an error, or we didn't exit the loop * by finding a block or character device, bail out. */ if (err != 0 || newdep == NULL) goto bailout; /* * Look for links to the physical path in /dev/dsk, * since we ONLY looked for BLOCK devices above. */ (void) physpath_to_devlink("/dev/dsk", minor_path, &devlink, &l_errno); /* postprocess and copy logical name here */ if (devlink != NULL) { /* * For disks, remove partition/slice info */ if ((cp = strstr(devlink, "dsk/")) != NULL) { /* cXtYdZ[(s[0..15])|(p[0..X])] */ if ((p = strchr(cp + 4, 'd')) != NULL) { p++; /* Skip the 'd' */ while (*p != 0 && isdigit(*p)) p++; *p = 0; } *dyncomp = strdup(cp); } free(devlink); } return (SATA_CFGA_OK); } bailout: if (dp) (void) closedir(dp); if (devpath) free(devpath); if (dep) free(dep); return (CFGA_SATA_DYNAMIC_AP); }