1 /*
2 * lvm topology
3 * -- this is fallback for old systems where the topology information is not
4 * exported by sysfs
5 *
6 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
7 *
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
10 *
11 */
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include "topology.h"
23
24 #ifndef LVM_BLK_MAJOR
25 # define LVM_BLK_MAJOR 58
26 #endif
27
28 static int is_lvm_device(dev_t devno)
29 {
30 if (major(devno) == LVM_BLK_MAJOR)
31 return 1;
32 return blkid_driver_has_major("lvm", major(devno));
33 }
34
35 static int probe_lvm_tp(blkid_probe pr,
36 const struct blkid_idmag *mag __attribute__((__unused__)))
37 {
38 const char * const paths[] = {
39 "/usr/local/sbin/lvdisplay",
40 "/usr/sbin/lvdisplay",
41 "/sbin/lvdisplay"
42 };
43 int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0;
44 FILE *stream = NULL;
45 char *cmd = NULL, *devname = NULL, buf[1024];
46 size_t i;
47 dev_t devno = blkid_probe_get_devno(pr);
48
49 if (!devno)
50 goto nothing; /* probably not a block device */
51 if (!is_lvm_device(devno))
52 goto nothing;
53
54 for (i = 0; i < ARRAY_SIZE(paths); i++) {
55 struct stat sb;
56 if (stat(paths[i], &sb) == 0) {
57 cmd = (char *) paths[i];
58 break;
59 }
60 }
61
62 if (!cmd)
63 goto nothing;
64
65 devname = blkid_devno_to_devname(devno);
66 if (!devname)
67 goto nothing;
68
69 if (pipe(lvpipe) < 0) {
70 DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno));
71 goto nothing;
72 }
73
74 switch (fork()) {
75 case 0:
76 {
77 char *lvargv[3];
78
79 /* Plumbing */
80 close(lvpipe[0]);
81
82 if (lvpipe[1] != STDOUT_FILENO)
83 dup2(lvpipe[1], STDOUT_FILENO);
84
85 if (drop_permissions() != 0)
86 exit(1);
87
88 lvargv[0] = cmd;
89 lvargv[1] = devname;
90 lvargv[2] = NULL;
91
92 execv(lvargv[0], lvargv);
93
94 DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno));
95 exit(1);
96 }
97 case -1:
98 DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno));
99 goto nothing;
100 default:
101 break;
102 }
103
104 stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR);
105 if (!stream)
106 goto nothing;
107
108 while (fgets(buf, sizeof(buf), stream) != NULL) {
109 if (!strncmp(buf, "Stripes", 7))
110 ignore_result( sscanf(buf, "Stripes %d", &stripes) );
111
112 if (!strncmp(buf, "Stripe size", 11))
113 ignore_result( sscanf(buf, "Stripe size (KByte) %d", &stripesize) );
114 }
115
116 if (!stripes)
117 goto nothing;
118
119 blkid_topology_set_minimum_io_size(pr, stripesize << 10);
120 blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10);
121
122 free(devname);
123 fclose(stream);
124 close(lvpipe[1]);
125 return 0;
126
127 nothing:
128 free(devname);
129 if (stream)
130 fclose(stream);
131 else if (lvpipe[0] != -1)
132 close(lvpipe[0]);
133 if (lvpipe[1] != -1)
134 close(lvpipe[1]);
135 return 1;
136 }
137
138 const struct blkid_idinfo lvm_tp_idinfo =
139 {
140 .name = "lvm",
141 .probefunc = probe_lvm_tp,
142 .magics = BLKID_NONE_MAGIC
143 };
144