/*
* 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/sysmacros.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
};