| /* |
| * lvm topology |
| * -- this is fallback for old systems where the topology information is not |
| * exported by sysfs |
| * |
| * Copyright (C) 2009 Karel Zak <kzak@redhat.com> |
| * |
| * This file may be redistributed under the terms of the |
| * GNU Lesser General Public License. |
| * |
| */ |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "topology.h" |
| |
| #ifndef LVM_BLK_MAJOR |
| # define LVM_BLK_MAJOR 58 |
| #endif |
| |
| static int is_lvm_device(dev_t devno) |
| { |
| if (major(devno) == LVM_BLK_MAJOR) |
| return 1; |
| return blkid_driver_has_major("lvm", major(devno)); |
| } |
| |
| static int probe_lvm_tp(blkid_probe pr, |
| const struct blkid_idmag *mag __attribute__((__unused__))) |
| { |
| const char *paths[] = { |
| "/usr/local/sbin/lvdisplay", |
| "/usr/sbin/lvdisplay", |
| "/sbin/lvdisplay" |
| }; |
| int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0; |
| FILE *stream = NULL; |
| char *cmd = NULL, *devname = NULL, buf[1024]; |
| size_t i; |
| dev_t devno = blkid_probe_get_devno(pr); |
| |
| if (!devno) |
| goto nothing; /* probably not a block device */ |
| if (!is_lvm_device(devno)) |
| goto nothing; |
| |
| for (i = 0; i < ARRAY_SIZE(paths); i++) { |
| struct stat sb; |
| if (stat(paths[i], &sb) == 0) { |
| cmd = (char *) paths[i]; |
| break; |
| } |
| } |
| |
| if (!cmd) |
| goto nothing; |
| |
| devname = blkid_devno_to_devname(devno); |
| if (!devname) |
| goto nothing; |
| |
| if (pipe(lvpipe) < 0) { |
| DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); |
| goto nothing; |
| } |
| |
| switch (fork()) { |
| case 0: |
| { |
| char *lvargv[3]; |
| |
| /* Plumbing */ |
| close(lvpipe[0]); |
| |
| if (lvpipe[1] != STDOUT_FILENO) |
| dup2(lvpipe[1], STDOUT_FILENO); |
| |
| /* The libblkid library could linked with setuid programs */ |
| if (setgid(getgid()) < 0) |
| exit(1); |
| if (setuid(getuid()) < 0) |
| exit(1); |
| |
| lvargv[0] = cmd; |
| lvargv[1] = devname; |
| lvargv[2] = NULL; |
| |
| execv(lvargv[0], lvargv); |
| |
| DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); |
| exit(1); |
| } |
| case -1: |
| DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); |
| goto nothing; |
| default: |
| break; |
| } |
| |
| stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR); |
| if (!stream) |
| goto nothing; |
| |
| while (fgets(buf, sizeof(buf), stream) != NULL) { |
| if (!strncmp(buf, "Stripes", 7)) |
| sscanf(buf, "Stripes %d", &stripes); |
| |
| if (!strncmp(buf, "Stripe size", 11)) |
| sscanf(buf, "Stripe size (KByte) %d", &stripesize); |
| } |
| |
| if (!stripes) |
| goto nothing; |
| |
| blkid_topology_set_minimum_io_size(pr, stripesize << 10); |
| blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10); |
| |
| free(devname); |
| fclose(stream); |
| close(lvpipe[1]); |
| return 0; |
| |
| nothing: |
| free(devname); |
| if (stream) |
| fclose(stream); |
| else if (lvpipe[0] != -1) |
| close(lvpipe[0]); |
| if (lvpipe[1] != -1) |
| close(lvpipe[1]); |
| return 1; |
| } |
| |
| const struct blkid_idinfo lvm_tp_idinfo = |
| { |
| .name = "lvm", |
| .probefunc = probe_lvm_tp, |
| .magics = BLKID_NONE_MAGIC |
| }; |
| |