static void print_all_devices_pt(struct fdisk_context *cxt) { FILE *f; char line[128 + 1]; f = fopen(_PATH_PROC_PARTITIONS, "r"); if (!f) { warn(_("cannot open %s"), _PATH_PROC_PARTITIONS); return; } DBG(FRONTEND, dbgprint("reading "_PATH_PROC_PARTITIONS)); while (fgets(line, sizeof(line), f)) { char ptname[128 + 1], devname[256]; if (sscanf(line, " %*d %*d %*d %128[^\n ]", ptname) != 1) continue; snprintf(devname, sizeof(devname), "/dev/%s", ptname); DBG(FRONTEND, dbgprint("listing %s", devname)); if (is_whole_disk(devname)) { char *cn = canonicalize_path(devname); if (cn) { if (!is_ide_cdrom_or_tape(cn)) print_device_pt(cxt, cn); free(cn); } } } fclose(f); }
int partition_type_is_lvm(struct dev_mgr *dm, struct device *d) { int pt; pt = _get_partition_type(dm, d); if (!pt) { if (is_whole_disk(dm, d)) /* FIXME: Overloaded pt=0 in error cases */ return 1; else { log_error ("%s: missing partition table " "on partitioned device", d->name); return 0; } } if (is_whole_disk(dm, d)) { log_error("%s: looks to possess partition table", d->name); return 0; } /* check part type */ if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) { log_error("%s: invalid partition type 0x%x " "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION); return 0; } if (pt == LVM_PARTITION) { log_error ("%s: old LVM partition type found - please change to 0x%x", d->name, LVM_NEW_PARTITION); return 0; } return 1; }
/* * try all things in /proc/partitions that look like a full disk * Taken from util-linux-2.19.1/fdisk/fdisk.c tryprocpt() */ static void dev_list_build(DC_DevList *dc_devlist) { int is_whole_disk(const char *name) { // taken from util-linux-2.19.1/lib/wholedisk.c while (*name) name++; return !isdigit(name[-1]); } FILE *procpt; char line[128], ptname[128]; int ma, mi; unsigned long long sz; int ret; procpt = fopen("/proc/partitions", "r"); if (procpt == NULL) { dc_log(DC_LOG_FATAL, "cannot open /proc/partitions\n"); return; } while (fgets(line, sizeof(line), procpt)) { if (sscanf (line, " %d %d %llu %128[^\n ]", &ma, &mi, &sz, ptname) != 4) continue; if (is_whole_disk(ptname)) { DC_Dev *dc_dev = calloc(1, sizeof(*dc_dev)); assert(dc_dev); dc_dev->dev_fs_name = strdup(ptname); assert(dc_dev->dev_fs_name); ret = asprintf(&dc_dev->dev_path, "/dev/%s", ptname); assert(ret != -1 && dc_dev->dev_path); dc_dev->capacity = sz * 1024; dc_dev->next = dc_devlist->arr; dc_devlist->arr = dc_dev; dc_devlist->arr_size++; } } fclose(procpt); }
int _get_partition_type(struct dev_mgr *dm, struct device *d) { int pv_handle = -1; struct device *primary; ssize_t read_ret; ssize_t bytes_read = 0; char *buffer; unsigned short *s_buffer; struct partition *part; loff_t offset = 0; loff_t extended_offset = 0; int part_sought; int part_found = 0; int first_partition = 1; int extended_partition = 0; int p; if (!(primary = dev_primary(dm, d))) { log_error ("Failed to find main device containing partition %s", d->name); return 0; } if (!(buffer = dm_malloc(SECTOR_SIZE))) { log_error("Failed to allocate partition table buffer"); return 0; } /* Get partition table */ if ((pv_handle = open(primary->name, O_RDONLY)) < 0) { log_error("%s: open failed: %s", primary->name, strerror(errno)); return 0; } s_buffer = (unsigned short *) buffer; part = (struct partition *) (buffer + 0x1be); part_sought = MINOR_PART(dm, d); do { bytes_read = 0; if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) { log_error("%s: llseek failed: %s", primary->name, strerror(errno)); return 0; } while ((bytes_read < SECTOR_SIZE) && (read_ret = read(pv_handle, buffer + bytes_read, SECTOR_SIZE - bytes_read)) != -1) bytes_read += read_ret; if (read_ret == -1) { log_error("%s: read failed: %s", primary->name, strerror(errno)); return 0; } if (s_buffer[255] == 0xAA55) { if (is_whole_disk(dm, d)) return -1; } else return 0; extended_partition = 0; /* Loop through primary partitions */ for (p = 0; p < 4; p++) { if (part[p].sys_ind == DOS_EXTENDED_PARTITION || part[p].sys_ind == LINUX_EXTENDED_PARTITION || part[p].sys_ind == WIN98_EXTENDED_PARTITION) { extended_partition = 1; offset = extended_offset + part[p].start_sect; if (extended_offset == 0) extended_offset = part[p].start_sect; if (first_partition == 1) part_found++; } else if (first_partition == 1) { if (p == part_sought) { if (part[p].sys_ind == 0) { /* missing primary? */ return 0; } } else part_found++; } else if (!part[p].sys_ind) part_found++; if (part_sought == part_found) return part[p].sys_ind; } first_partition = 0; } while (extended_partition == 1); return 0; }
/* * Create a leaf vdev. Determine if this is a file or a device. If it's a * device, fill in the device id to make a complete nvlist. Valid forms for a * leaf vdev are: * * /dev/dsk/xxx Complete disk path * /xxx Full path to file * xxx Shorthand for /dev/dsk/xxx */ nvlist_t * make_leaf_vdev(const char *arg) { char path[MAXPATHLEN]; struct stat statbuf; nvlist_t *vdev = NULL; char *type = NULL; boolean_t wholedisk = B_FALSE; /* * Determine what type of vdev this is, and put the full path into * 'path'. We detect whether this is a device of file afterwards by * checking the st_mode of the file. */ if (arg[0] == '/') { /* * Complete device or file path. Exact type is determined by * examining the file descriptor afterwards. */ if (is_whole_disk(arg, &statbuf)) { wholedisk = B_TRUE; } else if (stat(arg, &statbuf) != 0) { (void) fprintf(stderr, gettext("cannot open '%s': %s\n"), arg, strerror(errno)); return (NULL); } (void) strlcpy(path, arg, sizeof (path)); } else { /* * This may be a short path for a device, or it could be total * gibberish. Check to see if it's a known device in * /dev/dsk/. As part of this check, see if we've been given a * an entire disk (minus the slice number). */ (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, arg); if (is_whole_disk(path, &statbuf)) { wholedisk = B_TRUE; } else if (stat(path, &statbuf) != 0) { /* * If we got ENOENT, then the user gave us * gibberish, so try to direct them with a * reasonable error message. Otherwise, * regurgitate strerror() since it's the best we * can do. */ if (errno == ENOENT) { (void) fprintf(stderr, gettext("cannot open '%s': no such " "device in %s\n"), arg, DISK_ROOT); (void) fprintf(stderr, gettext("must be a full path or " "shorthand device name\n")); return (NULL); } else { (void) fprintf(stderr, gettext("cannot open '%s': %s\n"), path, strerror(errno)); return (NULL); } } } /* * Determine whether this is a device or a file. */ if (S_ISBLK(statbuf.st_mode)) { type = VDEV_TYPE_DISK; } else if (S_ISREG(statbuf.st_mode)) { type = VDEV_TYPE_FILE; } else { (void) fprintf(stderr, gettext("cannot use '%s': must be a " "block device or regular file\n"), path); return (NULL); } /* * Finally, we have the complete device or file, and we know that it is * acceptable to use. Construct the nvlist to describe this vdev. All * vdevs have a 'path' element, and devices also have a 'devid' element. */ verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0); verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0); verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0); if (strcmp(type, VDEV_TYPE_DISK) == 0) verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, (uint64_t)wholedisk) == 0); /* * For a whole disk, defer getting its devid until after labeling it. */ if (S_ISBLK(statbuf.st_mode) && !wholedisk) { /* * Get the devid for the device. */ int fd; ddi_devid_t devid; char *minor = NULL, *devid_str = NULL; if ((fd = open(path, O_RDONLY)) < 0) { (void) fprintf(stderr, gettext("cannot open '%s': " "%s\n"), path, strerror(errno)); nvlist_free(vdev); return (NULL); } if (devid_get(fd, &devid) == 0) { if (devid_get_minor_name(fd, &minor) == 0 && (devid_str = devid_str_encode(devid, minor)) != NULL) { verify(nvlist_add_string(vdev, ZPOOL_CONFIG_DEVID, devid_str) == 0); } if (devid_str != NULL) devid_str_free(devid_str); if (minor != NULL) devid_str_free(minor); devid_free(devid); } (void) close(fd); } return (vdev); }