static int gather_pci_cap(LibHalContext *ctx, const char *udi, virNodeDevCapDataPtr d) { char *sysfs_path; if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) { char *p = strrchr(sysfs_path, '/'); if (p) { ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain)); ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus)); ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot)); ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function)); } if (nodeDeviceSysfsGetPCIRelatedDevCaps(sysfs_path, d) < 0) { VIR_FREE(sysfs_path); return -1; } VIR_FREE(sysfs_path); } (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name); return 0; }
static int gather_pci_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { char *sysfs_path; if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) { char *p = strrchr(sysfs_path, '/'); if (p) { (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function); } if (!pciGetPhysicalFunction(sysfs_path, &d->pci_dev.physical_function)) d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; if (!pciGetVirtualFunctions(sysfs_path, &d->pci_dev.virtual_functions, &d->pci_dev.num_virtual_functions) || d->pci_dev.num_virtual_functions > 0) d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; VIR_FREE(sysfs_path); } (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name); return 0; }
static int gather_pci_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { char *sysfs_path; if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) { char *p = strrchr(sysfs_path, '/'); if (p) { (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot); (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function); } get_physical_function(sysfs_path, d); get_virtual_functions(sysfs_path, d); VIR_FREE(sysfs_path); } (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor); if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0) (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name); (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product); if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0) (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name); return 0; }
static int gather_capabilities(LibHalContext *ctx, const char *udi, virNodeDevCapsDefPtr *caps_p) { char *bus_name = NULL; virNodeDevCapsDefPtr caps = NULL; char **hal_cap_names = NULL; int rv; size_t i; if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) { rv = gather_capability(ctx, udi, "system", &caps); if (rv != 0) goto failure; } if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0 || get_str_prop(ctx, udi, "linux.subsystem", &bus_name) == 0) { rv = gather_capability(ctx, udi, bus_name, &caps); if (rv != 0) goto failure; } hal_cap_names = libhal_device_get_property_strlist(ctx, udi, "info.capabilities", NULL); if (hal_cap_names) { for (i = 0; hal_cap_names[i]; i++) { if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) { rv = gather_capability(ctx, udi, hal_cap_names[i], &caps); if (rv != 0) goto failure; } } for (i = 0; hal_cap_names[i]; i++) VIR_FREE(hal_cap_names[i]); VIR_FREE(hal_cap_names); } VIR_FREE(bus_name); *caps_p = caps; return 0; failure: VIR_FREE(bus_name); if (hal_cap_names) { for (i = 0; hal_cap_names[i]; i++) VIR_FREE(hal_cap_names[i]); VIR_FREE(hal_cap_names); } while (caps) { virNodeDevCapsDefPtr next = caps->next; virNodeDevCapsDefFree(caps); caps = next; } return rv; }
static int gather_system_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { char *uuidstr; (void)get_str_prop(ctx, udi, "system.product", &d->system.product_name); (void)get_str_prop(ctx, udi, "system.hardware.vendor", &d->system.hardware.vendor_name); (void)get_str_prop(ctx, udi, "system.hardware.version", &d->system.hardware.version); (void)get_str_prop(ctx, udi, "system.hardware.serial", &d->system.hardware.serial); if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) { ignore_value(virUUIDParse(uuidstr, d->system.hardware.uuid)); VIR_FREE(uuidstr); } (void)get_str_prop(ctx, udi, "system.firmware.vendor", &d->system.firmware.vendor_name); (void)get_str_prop(ctx, udi, "system.firmware.version", &d->system.firmware.version); (void)get_str_prop(ctx, udi, "system.firmware.release_date", &d->system.firmware.release_date); return 0; }
static int gather_scsi_generic_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { (void)get_str_prop(ctx, udi, "scsi_generic.device", &d->sg.path); return 0; }
static int gather_net_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { unsigned long long dummy; (void)get_str_prop(ctx, udi, "net.interface", &d->net.ifname); (void)get_str_prop(ctx, udi, "net.address", &d->net.address); if (get_uint64_prop(ctx, udi, "net.80203.mac_address", &dummy) == 0) d->net.subtype = VIR_NODE_DEV_CAP_NET_80203; else if (get_uint64_prop(ctx, udi, "net.80211.mac_address", &dummy) == 0) d->net.subtype = VIR_NODE_DEV_CAP_NET_80211; else d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; return 0; }
static int gather_scsi_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { (void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host); (void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus); (void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target); (void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun); (void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type); return 0; }
static int gather_usb_device_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { (void)get_int_prop(ctx, udi, "usb_device.bus_number", (int *)&d->usb_dev.bus); (void)get_int_prop(ctx, udi, "usb_device.linux.device_number", (int *)&d->usb_dev.device); (void)get_int_prop(ctx, udi, "usb_device.vendor_id", (int *)&d->usb_dev.vendor); if (get_str_prop(ctx, udi, "usb_device.vendor", &d->usb_dev.vendor_name) != 0) (void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name); (void)get_int_prop(ctx, udi, "usb_device.product_id", (int *)&d->usb_dev.product); if (get_str_prop(ctx, udi, "usb_device.product", &d->usb_dev.product_name) != 0) (void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name); return 0; }
static int gather_storage_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { int val; (void)get_str_prop(ctx, udi, "block.device", &d->storage.block); (void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus); (void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type); (void)get_str_prop(ctx, udi, "storage.model", &d->storage.model); (void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor); (void)get_str_prop(ctx, udi, "storage.serial", &d->storage.serial); if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) { d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE; if (get_bool_prop(ctx, udi, "storage.removable.media_available", &val) == 0 && val) { d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; (void)get_uint64_prop(ctx, udi, "storage.removable.media_size", &d->storage.removable_media_size); } } else { (void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size); } if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val) d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE; return 0; }
static int gather_usb_cap(LibHalContext *ctx, const char *udi, union _virNodeDevCapData *d) { (void)get_int_prop(ctx, udi, "usb.interface.number", (int *)&d->usb_if.number); (void)get_int_prop(ctx, udi, "usb.interface.class", (int *)&d->usb_if._class); (void)get_int_prop(ctx, udi, "usb.interface.subclass", (int *)&d->usb_if.subclass); (void)get_int_prop(ctx, udi, "usb.interface.protocol", (int *)&d->usb_if.protocol); (void)get_str_prop(ctx, udi, "usb.interface.description", &d->usb_if.description); return 0; }
STATIC phandle DoFindNodeByType(char *type, phandle ph) { phandle res; if (ph == 0) { return(0); } if (strcmp(get_str_prop(ph, "device_type", NOALLOC), type) == 0) { return(ph); } res = DoFindNodeByType(type, OFChild(ph)); if (res != 0) { return(res); } return(DoFindNodeByType(type, OFPeer(ph))); }
static void dev_create(const char *udi) { LibHalContext *ctx; char *parent_key = NULL; virNodeDeviceObjPtr dev = NULL; virNodeDeviceDefPtr def = NULL; const char *name = hal_name(udi); int rv; char *privData; char *devicePath = NULL; if (VIR_STRDUP(privData, udi) < 0) return; nodeDeviceLock(driverState); ctx = DRV_STATE_HAL_CTX(driverState); if (VIR_ALLOC(def) < 0) goto failure; if (VIR_STRDUP(def->name, name) < 0) goto failure; if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) { if (VIR_STRDUP(def->parent, hal_name(parent_key)) < 0) { VIR_FREE(parent_key); goto failure; } VIR_FREE(parent_key); } rv = gather_capabilities(ctx, udi, &def->caps); if (rv != 0) goto failure; if (def->caps == NULL) goto cleanup; /* Some devices don't have a path in sysfs, so ignore failure */ (void)get_str_prop(ctx, udi, "linux.sysfs_path", &devicePath); dev = virNodeDeviceAssignDef(&driverState->devs, def); if (!dev) { VIR_FREE(devicePath); goto failure; } dev->privateData = privData; dev->privateFree = free_udi; dev->def->sysfs_path = devicePath; virNodeDeviceObjUnlock(dev); nodeDeviceUnlock(driverState); return; failure: VIR_DEBUG("FAILED TO ADD dev %s", name); cleanup: VIR_FREE(privData); virNodeDeviceDefFree(def); nodeDeviceUnlock(driverState); }
static disk_t * create_disk(char *deviceid, char *kernel_name, struct search_args *args) { disk_t *diskp; char *type; char *prod_id; char *vendor_id; if (dm_debug) { (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name); } diskp = calloc(1, sizeof (disk_t)); if (diskp == NULL) { return (NULL); } diskp->controllers = (controller_t **) calloc(1, sizeof (controller_t *)); if (diskp->controllers == NULL) { cache_free_disk(diskp); return (NULL); } diskp->controllers[0] = NULL; diskp->devid = NULL; if (deviceid != NULL) { if ((diskp->device_id = strdup(deviceid)) == NULL) { cache_free_disk(diskp); return (NULL); } (void) devid_str_decode(deviceid, &(diskp->devid), NULL); } if (kernel_name != NULL) { diskp->kernel_name = strdup(kernel_name); if (diskp->kernel_name == NULL) { cache_free_disk(diskp); return (NULL); } } diskp->paths = NULL; diskp->aliases = NULL; diskp->cd_rom = 0; diskp->rpm = 0; diskp->solid_state = -1; type = di_minor_nodetype(args->minor); prod_id = get_str_prop(PROD_ID_PROP, args->node); if (prod_id != NULL) { if ((diskp->product_id = strdup(prod_id)) == NULL) { cache_free_disk(diskp); return (NULL); } } else { prod_id = get_str_prop(PROD_ID_USB_PROP, args->node); if (prod_id != NULL) { if ((diskp->product_id = strdup(prod_id)) == NULL) { cache_free_disk(diskp); return (NULL); } } } vendor_id = get_str_prop(VENDOR_ID_PROP, args->node); if (vendor_id != NULL) { if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { cache_free_disk(diskp); return (NULL); } } else { vendor_id = get_str_prop(VENDOR_ID_USB_PROP, args->node); if (vendor_id != NULL) { if ((diskp->vendor_id = strdup(vendor_id)) == NULL) { cache_free_disk(diskp); return (NULL); } } } /* * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS. * We try to use uscsi later to determine the real type. * The cd_rom flag tells us that the kernel categorized the drive * as a CD-ROM. We leave the drv_type as UNKNOWN for now. * The combination of the cd_rom flag being set with the drv_type of * unknown is what triggers the uscsi probe in drive.c. */ if (disk_is_cdrom(type)) { diskp->drv_type = DM_DT_UNKNOWN; diskp->cd_rom = 1; diskp->removable = 1; } else if (libdiskmgt_str_eq(type, DDI_NT_FD)) { diskp->drv_type = DM_DT_FLOPPY; diskp->removable = 1; } else { /* not a CD-ROM or Floppy */ diskp->removable = get_prop(REMOVABLE_PROP, args->node); if (diskp->removable == -1) { diskp->removable = 0; diskp->drv_type = DM_DT_FIXED; } } diskp->next = args->disk_listp; args->disk_listp = diskp; return (diskp); }
static int add_devs(di_node_t node, di_minor_t minor, void *arg) { struct search_args *args; int result = DI_WALK_CONTINUE; args = (struct search_args *)arg; if (dm_debug > 1) { /* This is all just debugging code */ char *devpath; char dev_name[MAXPATHLEN]; devpath = di_devfs_path(node); (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath, di_minor_name(minor)); di_devfs_path_free((void *) devpath); (void) fprintf(stderr, "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n", dev_name, di_node_name(node), di_instance(node), di_minor_spectype(minor), (di_minor_nodetype(minor) != NULL ? di_minor_nodetype(minor) : "NULL")); } if (bus_type(node, minor, args->ph) != NULL) { if (add_bus(args, node, minor, NULL) == NULL) { args->dev_walk_status = ENOMEM; result = DI_WALK_TERMINATE; } } else if (is_ctrl(node, minor)) { if (add_controller(args, node, minor) == NULL) { args->dev_walk_status = ENOMEM; result = DI_WALK_TERMINATE; } } else if (di_minor_spectype(minor) == S_IFCHR && (is_drive(minor) || is_zvol(node, minor))) { char *devidstr; char kernel_name[MAXPATHLEN]; disk_t *diskp; (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", di_node_name(node), di_instance(node)); devidstr = get_str_prop(DEVICE_ID_PROP, node); args->node = node; args->minor = minor; /* * Check if we already got this disk and * this is another slice. */ if (!have_disk(args, devidstr, kernel_name, &diskp)) { args->dev_walk_status = 0; /* * This is a newly found disk, create the * disk structure. */ diskp = create_disk(devidstr, kernel_name, args); if (diskp == NULL) { args->dev_walk_status = ENOMEM; } if (diskp->drv_type != DM_DT_FLOPPY) { /* add the controller relationship */ if (args->dev_walk_status == 0) { if (add_disk2controller(diskp, args) != 0) { args->dev_walk_status = ENOMEM; } } } } if (is_zvol(node, minor)) { char zvdsk[MAXNAMELEN]; char *str; alias_t *ap; if (di_prop_lookup_strings(di_minor_devt(minor), node, "name", &str) == -1) return (DI_WALK_CONTINUE); (void) snprintf(zvdsk, MAXNAMELEN, "/dev/zvol/rdsk/%s", str); if ((ap = find_alias(diskp, kernel_name)) == NULL) { if (new_alias(diskp, kernel_name, zvdsk, args) != 0) { args->dev_walk_status = ENOMEM; } } else { /* * It is possible that we have already added * this devpath. * Do not add it again. new_devpath will * return a 0 if found, and not add the path. */ if (new_devpath(ap, zvdsk) != 0) { args->dev_walk_status = ENOMEM; } } } /* Add the devpaths for the drive. */ if (args->dev_walk_status == 0) { char *devpath; char slice_path[MAXPATHLEN]; char *pattern; /* * We will come through here once for each of * the raw slice device names. */ devpath = di_devfs_path(node); (void) snprintf(slice_path, sizeof (slice_path), "%s:%s", devpath, di_minor_name(minor)); di_devfs_path_free((void *) devpath); if (libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_NT_FD)) { pattern = DEVLINK_FLOPPY_REGEX; } else { pattern = DEVLINK_REGEX; } /* Walk the /dev tree to get the devlinks. */ (void) di_devlink_walk(args->handle, pattern, slice_path, DI_PRIMARY_LINK, arg, add_devpath); } if (args->dev_walk_status != 0) { result = DI_WALK_TERMINATE; } } return (result); }
static int add_devpath(di_devlink_t devlink, void *arg) { struct search_args *args; char *devidstr; disk_t *diskp; char kernel_name[MAXPATHLEN]; args = (struct search_args *)arg; /* * Get the diskp value from calling have_disk. Can either be found * by kernel name or devid. */ diskp = NULL; devidstr = get_str_prop(DEVICE_ID_PROP, args->node); (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", di_node_name(args->node), di_instance(args->node)); (void) have_disk(args, devidstr, kernel_name, &diskp); /* * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0. * For diskettes it is /dev/rdiskette*. * On Intel we would also get each fdisk partition as well * (e.g. /dev/rdsk/c0t0d0p0). */ if (diskp != NULL) { alias_t *ap; char *devlink_path; if (diskp->drv_type != DM_DT_FLOPPY) { /* * Add other controllers for multipath disks. * This will have no effect if the controller * relationship is already set up. */ if (add_disk2controller(diskp, args) != 0) { args->dev_walk_status = ENOMEM; } } (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d", di_node_name(args->node), di_instance(args->node)); devlink_path = (char *)di_devlink_path(devlink); if (dm_debug > 1) { (void) fprintf(stderr, "INFO: devpath %s\n", devlink_path); } if ((ap = find_alias(diskp, kernel_name)) == NULL) { if (new_alias(diskp, kernel_name, devlink_path, args) != 0) { args->dev_walk_status = ENOMEM; } } else { /* * It is possible that we have already added this * devpath. Do not add it again. new_devpath will * return a 0 if found, and not add the path. */ if (new_devpath(ap, devlink_path) != 0) { args->dev_walk_status = ENOMEM; } } } return (DI_WALK_CONTINUE); }