xref: /dflybsd-src/contrib/lvm2/dist/lib/device/device.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*	$NetBSD: device.c,v 1.1.1.2 2009/12/02 00:26:34 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include <libgen.h> /* dirname, basename */
19*86d7f5d3SJohn Marino #include "lib.h"
20*86d7f5d3SJohn Marino #include "lvm-types.h"
21*86d7f5d3SJohn Marino #include "device.h"
22*86d7f5d3SJohn Marino #include "metadata.h"
23*86d7f5d3SJohn Marino #include "filter.h"
24*86d7f5d3SJohn Marino #include "xlate.h"
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino /* See linux/genhd.h and fs/partitions/msdos */
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino #define PART_MAGIC 0xAA55
29*86d7f5d3SJohn Marino #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
30*86d7f5d3SJohn Marino #define PART_OFFSET UINT64_C(0x1BE)
31*86d7f5d3SJohn Marino 
32*86d7f5d3SJohn Marino struct partition {
33*86d7f5d3SJohn Marino 	uint8_t boot_ind;
34*86d7f5d3SJohn Marino 	uint8_t head;
35*86d7f5d3SJohn Marino 	uint8_t sector;
36*86d7f5d3SJohn Marino 	uint8_t cyl;
37*86d7f5d3SJohn Marino 	uint8_t sys_ind;	/* partition type */
38*86d7f5d3SJohn Marino 	uint8_t end_head;
39*86d7f5d3SJohn Marino 	uint8_t end_sector;
40*86d7f5d3SJohn Marino 	uint8_t end_cyl;
41*86d7f5d3SJohn Marino 	uint32_t start_sect;
42*86d7f5d3SJohn Marino 	uint32_t nr_sects;
43*86d7f5d3SJohn Marino } __attribute__((packed));
44*86d7f5d3SJohn Marino 
_is_partitionable(struct device * dev)45*86d7f5d3SJohn Marino static int _is_partitionable(struct device *dev)
46*86d7f5d3SJohn Marino {
47*86d7f5d3SJohn Marino 	int parts = max_partitions(MAJOR(dev->dev));
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino 	/* All MD devices are partitionable via blkext (as of 2.6.28) */
50*86d7f5d3SJohn Marino 	if (MAJOR(dev->dev) == md_major())
51*86d7f5d3SJohn Marino 		return 1;
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino 	if ((parts <= 1) || (MINOR(dev->dev) % parts))
54*86d7f5d3SJohn Marino 		return 0;
55*86d7f5d3SJohn Marino 
56*86d7f5d3SJohn Marino 	return 1;
57*86d7f5d3SJohn Marino }
58*86d7f5d3SJohn Marino 
_has_partition_table(struct device * dev)59*86d7f5d3SJohn Marino static int _has_partition_table(struct device *dev)
60*86d7f5d3SJohn Marino {
61*86d7f5d3SJohn Marino 	int ret = 0;
62*86d7f5d3SJohn Marino 	unsigned p;
63*86d7f5d3SJohn Marino 	uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
64*86d7f5d3SJohn Marino 	uint16_t *part_magic;
65*86d7f5d3SJohn Marino 	struct partition *part;
66*86d7f5d3SJohn Marino 
67*86d7f5d3SJohn Marino 	if (!dev_open(dev)) {
68*86d7f5d3SJohn Marino 		stack;
69*86d7f5d3SJohn Marino 		return -1;
70*86d7f5d3SJohn Marino 	}
71*86d7f5d3SJohn Marino 
72*86d7f5d3SJohn Marino 	if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf))
73*86d7f5d3SJohn Marino 		goto_out;
74*86d7f5d3SJohn Marino 
75*86d7f5d3SJohn Marino 	/* FIXME Check for other types of partition table too */
76*86d7f5d3SJohn Marino 
77*86d7f5d3SJohn Marino 	/* Check for msdos partition table */
78*86d7f5d3SJohn Marino 	part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
79*86d7f5d3SJohn Marino 	if ((*part_magic == xlate16(PART_MAGIC))) {
80*86d7f5d3SJohn Marino 		part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
81*86d7f5d3SJohn Marino 		for (p = 0; p < 4; p++, part++) {
82*86d7f5d3SJohn Marino 			/* Table is invalid if boot indicator not 0 or 0x80 */
83*86d7f5d3SJohn Marino 			if ((part->boot_ind & 0x7f)) {
84*86d7f5d3SJohn Marino 				ret = 0;
85*86d7f5d3SJohn Marino 				break;
86*86d7f5d3SJohn Marino 			}
87*86d7f5d3SJohn Marino 			/* Must have at least one non-empty partition */
88*86d7f5d3SJohn Marino 			if (part->nr_sects)
89*86d7f5d3SJohn Marino 				ret = 1;
90*86d7f5d3SJohn Marino 		}
91*86d7f5d3SJohn Marino 	}
92*86d7f5d3SJohn Marino 
93*86d7f5d3SJohn Marino       out:
94*86d7f5d3SJohn Marino 	if (!dev_close(dev))
95*86d7f5d3SJohn Marino 		stack;
96*86d7f5d3SJohn Marino 
97*86d7f5d3SJohn Marino 	return ret;
98*86d7f5d3SJohn Marino }
99*86d7f5d3SJohn Marino 
is_partitioned_dev(struct device * dev)100*86d7f5d3SJohn Marino int is_partitioned_dev(struct device *dev)
101*86d7f5d3SJohn Marino {
102*86d7f5d3SJohn Marino 	if (!_is_partitionable(dev))
103*86d7f5d3SJohn Marino 		return 0;
104*86d7f5d3SJohn Marino 
105*86d7f5d3SJohn Marino 	return _has_partition_table(dev);
106*86d7f5d3SJohn Marino }
107*86d7f5d3SJohn Marino 
108*86d7f5d3SJohn Marino #if 0
109*86d7f5d3SJohn Marino #include <sys/stat.h>
110*86d7f5d3SJohn Marino #include <sys/mman.h>
111*86d7f5d3SJohn Marino #include <stdio.h>
112*86d7f5d3SJohn Marino #include <unistd.h>
113*86d7f5d3SJohn Marino #include <fcntl.h>
114*86d7f5d3SJohn Marino #include <ctype.h>
115*86d7f5d3SJohn Marino 
116*86d7f5d3SJohn Marino #include <errno.h>
117*86d7f5d3SJohn Marino #include <sys/ioctl.h>
118*86d7f5d3SJohn Marino #include <linux/fs.h>
119*86d7f5d3SJohn Marino #include <linux/major.h>
120*86d7f5d3SJohn Marino #include <linux/genhd.h>
121*86d7f5d3SJohn Marino 
122*86d7f5d3SJohn Marino int _get_partition_type(struct dev_filter *filter, struct device *d);
123*86d7f5d3SJohn Marino 
124*86d7f5d3SJohn Marino #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino int is_extended_partition(struct device *d)
127*86d7f5d3SJohn Marino {
128*86d7f5d3SJohn Marino 	return (MINOR_PART(d) > 4) ? 1 : 0;
129*86d7f5d3SJohn Marino }
130*86d7f5d3SJohn Marino 
131*86d7f5d3SJohn Marino struct device *dev_primary(struct dev_mgr *dm, struct device *d)
132*86d7f5d3SJohn Marino {
133*86d7f5d3SJohn Marino 	struct device *ret;
134*86d7f5d3SJohn Marino 
135*86d7f5d3SJohn Marino 	ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
136*86d7f5d3SJohn Marino 	/* FIXME: Needs replacing with a 'refresh' */
137*86d7f5d3SJohn Marino 	if (!ret) {
138*86d7f5d3SJohn Marino 		init_dev_scan(dm);
139*86d7f5d3SJohn Marino 		ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
140*86d7f5d3SJohn Marino 	}
141*86d7f5d3SJohn Marino 
142*86d7f5d3SJohn Marino 	return ret;
143*86d7f5d3SJohn Marino 
144*86d7f5d3SJohn Marino }
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino int partition_type_is_lvm(struct dev_mgr *dm, struct device *d)
147*86d7f5d3SJohn Marino {
148*86d7f5d3SJohn Marino 	int pt;
149*86d7f5d3SJohn Marino 
150*86d7f5d3SJohn Marino 	pt = _get_partition_type(dm, d);
151*86d7f5d3SJohn Marino 
152*86d7f5d3SJohn Marino 	if (!pt) {
153*86d7f5d3SJohn Marino 		if (is_whole_disk(dm, d))
154*86d7f5d3SJohn Marino 			/* FIXME: Overloaded pt=0 in error cases */
155*86d7f5d3SJohn Marino 			return 1;
156*86d7f5d3SJohn Marino 		else {
157*86d7f5d3SJohn Marino 			log_error
158*86d7f5d3SJohn Marino 			    ("%s: missing partition table "
159*86d7f5d3SJohn Marino 			     "on partitioned device", d->name);
160*86d7f5d3SJohn Marino 			return 0;
161*86d7f5d3SJohn Marino 		}
162*86d7f5d3SJohn Marino 	}
163*86d7f5d3SJohn Marino 
164*86d7f5d3SJohn Marino 	if (is_whole_disk(dm, d)) {
165*86d7f5d3SJohn Marino 		log_error("%s: looks to possess partition table", d->name);
166*86d7f5d3SJohn Marino 		return 0;
167*86d7f5d3SJohn Marino 	}
168*86d7f5d3SJohn Marino 
169*86d7f5d3SJohn Marino 	/* check part type */
170*86d7f5d3SJohn Marino 	if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) {
171*86d7f5d3SJohn Marino 		log_error("%s: invalid partition type 0x%x "
172*86d7f5d3SJohn Marino 			  "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION);
173*86d7f5d3SJohn Marino 		return 0;
174*86d7f5d3SJohn Marino 	}
175*86d7f5d3SJohn Marino 
176*86d7f5d3SJohn Marino 	if (pt == LVM_PARTITION) {
177*86d7f5d3SJohn Marino 		log_error
178*86d7f5d3SJohn Marino 		    ("%s: old LVM partition type found - please change to 0x%x",
179*86d7f5d3SJohn Marino 		     d->name, LVM_NEW_PARTITION);
180*86d7f5d3SJohn Marino 		return 0;
181*86d7f5d3SJohn Marino 	}
182*86d7f5d3SJohn Marino 
183*86d7f5d3SJohn Marino 	return 1;
184*86d7f5d3SJohn Marino }
185*86d7f5d3SJohn Marino 
186*86d7f5d3SJohn Marino int _get_partition_type(struct dev_mgr *dm, struct device *d)
187*86d7f5d3SJohn Marino {
188*86d7f5d3SJohn Marino 	int pv_handle = -1;
189*86d7f5d3SJohn Marino 	struct device *primary;
190*86d7f5d3SJohn Marino 	ssize_t read_ret;
191*86d7f5d3SJohn Marino 	ssize_t bytes_read = 0;
192*86d7f5d3SJohn Marino 	char *buffer;
193*86d7f5d3SJohn Marino 	unsigned short *s_buffer;
194*86d7f5d3SJohn Marino 	struct partition *part;
195*86d7f5d3SJohn Marino 	loff_t offset = 0;
196*86d7f5d3SJohn Marino 	loff_t extended_offset = 0;
197*86d7f5d3SJohn Marino 	int part_sought;
198*86d7f5d3SJohn Marino 	int part_found = 0;
199*86d7f5d3SJohn Marino 	int first_partition = 1;
200*86d7f5d3SJohn Marino 	int extended_partition = 0;
201*86d7f5d3SJohn Marino 	int p;
202*86d7f5d3SJohn Marino 
203*86d7f5d3SJohn Marino 	if (!(primary = dev_primary(dm, d))) {
204*86d7f5d3SJohn Marino 		log_error
205*86d7f5d3SJohn Marino 		    ("Failed to find main device containing partition %s",
206*86d7f5d3SJohn Marino 		     d->name);
207*86d7f5d3SJohn Marino 		return 0;
208*86d7f5d3SJohn Marino 	}
209*86d7f5d3SJohn Marino 
210*86d7f5d3SJohn Marino 	if (!(buffer = dm_malloc(SECTOR_SIZE))) {
211*86d7f5d3SJohn Marino 		log_error("Failed to allocate partition table buffer");
212*86d7f5d3SJohn Marino 		return 0;
213*86d7f5d3SJohn Marino 	}
214*86d7f5d3SJohn Marino 
215*86d7f5d3SJohn Marino 	/* Get partition table */
216*86d7f5d3SJohn Marino 	if ((pv_handle = open(primary->name, O_RDONLY)) < 0) {
217*86d7f5d3SJohn Marino 		log_error("%s: open failed: %s", primary->name,
218*86d7f5d3SJohn Marino 			  strerror(errno));
219*86d7f5d3SJohn Marino 		return 0;
220*86d7f5d3SJohn Marino 	}
221*86d7f5d3SJohn Marino 
222*86d7f5d3SJohn Marino 	s_buffer = (unsigned short *) buffer;
223*86d7f5d3SJohn Marino 	part = (struct partition *) (buffer + 0x1be);
224*86d7f5d3SJohn Marino 	part_sought = MINOR_PART(dm, d);
225*86d7f5d3SJohn Marino 
226*86d7f5d3SJohn Marino 	do {
227*86d7f5d3SJohn Marino 		bytes_read = 0;
228*86d7f5d3SJohn Marino 
229*86d7f5d3SJohn Marino 		if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) {
230*86d7f5d3SJohn Marino 			log_error("%s: llseek failed: %s",
231*86d7f5d3SJohn Marino 				  primary->name, strerror(errno));
232*86d7f5d3SJohn Marino 			return 0;
233*86d7f5d3SJohn Marino 		}
234*86d7f5d3SJohn Marino 
235*86d7f5d3SJohn Marino 		while ((bytes_read < SECTOR_SIZE) &&
236*86d7f5d3SJohn Marino 		       (read_ret =
237*86d7f5d3SJohn Marino 			read(pv_handle, buffer + bytes_read,
238*86d7f5d3SJohn Marino 			     SECTOR_SIZE - bytes_read)) != -1)
239*86d7f5d3SJohn Marino 			bytes_read += read_ret;
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino 		if (read_ret == -1) {
242*86d7f5d3SJohn Marino 			log_error("%s: read failed: %s", primary->name,
243*86d7f5d3SJohn Marino 				  strerror(errno));
244*86d7f5d3SJohn Marino 			return 0;
245*86d7f5d3SJohn Marino 		}
246*86d7f5d3SJohn Marino 
247*86d7f5d3SJohn Marino 		if (s_buffer[255] == 0xAA55) {
248*86d7f5d3SJohn Marino 			if (is_whole_disk(dm, d))
249*86d7f5d3SJohn Marino 				return -1;
250*86d7f5d3SJohn Marino 		} else
251*86d7f5d3SJohn Marino 			return 0;
252*86d7f5d3SJohn Marino 
253*86d7f5d3SJohn Marino 		extended_partition = 0;
254*86d7f5d3SJohn Marino 
255*86d7f5d3SJohn Marino 		/* Loop through primary partitions */
256*86d7f5d3SJohn Marino 		for (p = 0; p < 4; p++) {
257*86d7f5d3SJohn Marino 			if (part[p].sys_ind == DOS_EXTENDED_PARTITION ||
258*86d7f5d3SJohn Marino 			    part[p].sys_ind == LINUX_EXTENDED_PARTITION
259*86d7f5d3SJohn Marino 			    || part[p].sys_ind == WIN98_EXTENDED_PARTITION) {
260*86d7f5d3SJohn Marino 				extended_partition = 1;
261*86d7f5d3SJohn Marino 				offset = extended_offset + part[p].start_sect;
262*86d7f5d3SJohn Marino 				if (extended_offset == 0)
263*86d7f5d3SJohn Marino 					extended_offset = part[p].start_sect;
264*86d7f5d3SJohn Marino 				if (first_partition == 1)
265*86d7f5d3SJohn Marino 					part_found++;
266*86d7f5d3SJohn Marino 			} else if (first_partition == 1) {
267*86d7f5d3SJohn Marino 				if (p == part_sought) {
268*86d7f5d3SJohn Marino 					if (part[p].sys_ind == 0) {
269*86d7f5d3SJohn Marino 						/* missing primary? */
270*86d7f5d3SJohn Marino 						return 0;
271*86d7f5d3SJohn Marino 					}
272*86d7f5d3SJohn Marino 				} else
273*86d7f5d3SJohn Marino 					part_found++;
274*86d7f5d3SJohn Marino 			} else if (!part[p].sys_ind)
275*86d7f5d3SJohn Marino 				part_found++;
276*86d7f5d3SJohn Marino 
277*86d7f5d3SJohn Marino 			if (part_sought == part_found)
278*86d7f5d3SJohn Marino 				return part[p].sys_ind;
279*86d7f5d3SJohn Marino 
280*86d7f5d3SJohn Marino 		}
281*86d7f5d3SJohn Marino 		first_partition = 0;
282*86d7f5d3SJohn Marino 	}
283*86d7f5d3SJohn Marino 	while (extended_partition == 1);
284*86d7f5d3SJohn Marino 
285*86d7f5d3SJohn Marino 	return 0;
286*86d7f5d3SJohn Marino }
287*86d7f5d3SJohn Marino #endif
288*86d7f5d3SJohn Marino 
289*86d7f5d3SJohn Marino #ifdef linux
290*86d7f5d3SJohn Marino 
get_primary_dev(const char * sysfs_dir,struct device * dev,dev_t * result)291*86d7f5d3SJohn Marino int get_primary_dev(const char *sysfs_dir,
292*86d7f5d3SJohn Marino 		    struct device *dev, dev_t *result)
293*86d7f5d3SJohn Marino {
294*86d7f5d3SJohn Marino 	char path[PATH_MAX+1];
295*86d7f5d3SJohn Marino 	char temp_path[PATH_MAX+1];
296*86d7f5d3SJohn Marino 	char buffer[64];
297*86d7f5d3SJohn Marino 	struct stat info;
298*86d7f5d3SJohn Marino 	FILE *fp;
299*86d7f5d3SJohn Marino 	uint32_t pri_maj, pri_min;
300*86d7f5d3SJohn Marino 	int ret = 0;
301*86d7f5d3SJohn Marino 
302*86d7f5d3SJohn Marino 	/* check if dev is a partition */
303*86d7f5d3SJohn Marino 	if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
304*86d7f5d3SJohn Marino 			sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
305*86d7f5d3SJohn Marino 		log_error("dm_snprintf partition failed");
306*86d7f5d3SJohn Marino 		return ret;
307*86d7f5d3SJohn Marino 	}
308*86d7f5d3SJohn Marino 
309*86d7f5d3SJohn Marino 	if (stat(path, &info) == -1) {
310*86d7f5d3SJohn Marino 		if (errno != ENOENT)
311*86d7f5d3SJohn Marino 			log_sys_error("stat", path);
312*86d7f5d3SJohn Marino 		return ret;
313*86d7f5d3SJohn Marino 	}
314*86d7f5d3SJohn Marino 
315*86d7f5d3SJohn Marino 	/*
316*86d7f5d3SJohn Marino 	 * extract parent's path from the partition's symlink, e.g.:
317*86d7f5d3SJohn Marino 	 * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
318*86d7f5d3SJohn Marino 	 * - dirname ../../block/md0/md0p1 = ../../block/md0
319*86d7f5d3SJohn Marino 	 * - basename ../../block/md0/md0  = md0
320*86d7f5d3SJohn Marino 	 * Parent's 'dev' sysfs attribute  = /sys/block/md0/dev
321*86d7f5d3SJohn Marino 	 */
322*86d7f5d3SJohn Marino 	if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
323*86d7f5d3SJohn Marino 		log_sys_error("readlink", path);
324*86d7f5d3SJohn Marino 		return ret;
325*86d7f5d3SJohn Marino 	}
326*86d7f5d3SJohn Marino 
327*86d7f5d3SJohn Marino 	if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
328*86d7f5d3SJohn Marino 			sysfs_dir, basename(dirname(temp_path))) < 0) {
329*86d7f5d3SJohn Marino 		log_error("dm_snprintf dev failed");
330*86d7f5d3SJohn Marino 		return ret;
331*86d7f5d3SJohn Marino 	}
332*86d7f5d3SJohn Marino 
333*86d7f5d3SJohn Marino 	/* finally, parse 'dev' attribute and create corresponding dev_t */
334*86d7f5d3SJohn Marino 	if (stat(path, &info) == -1) {
335*86d7f5d3SJohn Marino 		if (errno == ENOENT)
336*86d7f5d3SJohn Marino 			log_error("sysfs file %s does not exist", path);
337*86d7f5d3SJohn Marino 		else
338*86d7f5d3SJohn Marino 			log_sys_error("stat", path);
339*86d7f5d3SJohn Marino 		return ret;
340*86d7f5d3SJohn Marino 	}
341*86d7f5d3SJohn Marino 
342*86d7f5d3SJohn Marino 	fp = fopen(path, "r");
343*86d7f5d3SJohn Marino 	if (!fp) {
344*86d7f5d3SJohn Marino 		log_sys_error("fopen", path);
345*86d7f5d3SJohn Marino 		return ret;
346*86d7f5d3SJohn Marino 	}
347*86d7f5d3SJohn Marino 
348*86d7f5d3SJohn Marino 	if (!fgets(buffer, sizeof(buffer), fp)) {
349*86d7f5d3SJohn Marino 		log_sys_error("fgets", path);
350*86d7f5d3SJohn Marino 		goto out;
351*86d7f5d3SJohn Marino 	}
352*86d7f5d3SJohn Marino 
353*86d7f5d3SJohn Marino 	if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
354*86d7f5d3SJohn Marino 		log_error("sysfs file %s not in expected MAJ:MIN format: %s",
355*86d7f5d3SJohn Marino 			  path, buffer);
356*86d7f5d3SJohn Marino 		goto out;
357*86d7f5d3SJohn Marino 	}
358*86d7f5d3SJohn Marino 	*result = MKDEV(pri_maj, pri_min);
359*86d7f5d3SJohn Marino 	ret = 1;
360*86d7f5d3SJohn Marino 
361*86d7f5d3SJohn Marino out:
362*86d7f5d3SJohn Marino 	if (fclose(fp))
363*86d7f5d3SJohn Marino 		log_sys_error("fclose", path);
364*86d7f5d3SJohn Marino 
365*86d7f5d3SJohn Marino 	return ret;
366*86d7f5d3SJohn Marino }
367*86d7f5d3SJohn Marino 
_dev_topology_attribute(const char * attribute,const char * sysfs_dir,struct device * dev)368*86d7f5d3SJohn Marino static unsigned long _dev_topology_attribute(const char *attribute,
369*86d7f5d3SJohn Marino 					     const char *sysfs_dir,
370*86d7f5d3SJohn Marino 					     struct device *dev)
371*86d7f5d3SJohn Marino {
372*86d7f5d3SJohn Marino 	const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s";
373*86d7f5d3SJohn Marino 	char path[PATH_MAX+1], buffer[64];
374*86d7f5d3SJohn Marino 	FILE *fp;
375*86d7f5d3SJohn Marino 	struct stat info;
376*86d7f5d3SJohn Marino 	dev_t uninitialized_var(primary);
377*86d7f5d3SJohn Marino 	unsigned long result = 0UL;
378*86d7f5d3SJohn Marino 
379*86d7f5d3SJohn Marino 	if (!attribute || !*attribute)
380*86d7f5d3SJohn Marino 		return_0;
381*86d7f5d3SJohn Marino 
382*86d7f5d3SJohn Marino 	if (!sysfs_dir || !*sysfs_dir)
383*86d7f5d3SJohn Marino 		return_0;
384*86d7f5d3SJohn Marino 
385*86d7f5d3SJohn Marino 	if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
386*86d7f5d3SJohn Marino 			(int)MAJOR(dev->dev), (int)MINOR(dev->dev),
387*86d7f5d3SJohn Marino 			attribute) < 0) {
388*86d7f5d3SJohn Marino 		log_error("dm_snprintf %s failed", attribute);
389*86d7f5d3SJohn Marino 		return 0;
390*86d7f5d3SJohn Marino 	}
391*86d7f5d3SJohn Marino 
392*86d7f5d3SJohn Marino 	/*
393*86d7f5d3SJohn Marino 	 * check if the desired sysfs attribute exists
394*86d7f5d3SJohn Marino 	 * - if not: either the kernel doesn't have topology support
395*86d7f5d3SJohn Marino 	 *   or the device could be a partition
396*86d7f5d3SJohn Marino 	 */
397*86d7f5d3SJohn Marino 	if (stat(path, &info) == -1) {
398*86d7f5d3SJohn Marino 		if (errno != ENOENT) {
399*86d7f5d3SJohn Marino 			log_sys_error("stat", path);
400*86d7f5d3SJohn Marino 			return 0;
401*86d7f5d3SJohn Marino 		}
402*86d7f5d3SJohn Marino 		if (!get_primary_dev(sysfs_dir, dev, &primary))
403*86d7f5d3SJohn Marino 			return 0;
404*86d7f5d3SJohn Marino 
405*86d7f5d3SJohn Marino 		/* get attribute from partition's primary device */
406*86d7f5d3SJohn Marino 		if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
407*86d7f5d3SJohn Marino 				(int)MAJOR(primary), (int)MINOR(primary),
408*86d7f5d3SJohn Marino 				attribute) < 0) {
409*86d7f5d3SJohn Marino 			log_error("primary dm_snprintf %s failed", attribute);
410*86d7f5d3SJohn Marino 			return 0;
411*86d7f5d3SJohn Marino 		}
412*86d7f5d3SJohn Marino 		if (stat(path, &info) == -1) {
413*86d7f5d3SJohn Marino 			if (errno != ENOENT)
414*86d7f5d3SJohn Marino 				log_sys_error("stat", path);
415*86d7f5d3SJohn Marino 			return 0;
416*86d7f5d3SJohn Marino 		}
417*86d7f5d3SJohn Marino 	}
418*86d7f5d3SJohn Marino 
419*86d7f5d3SJohn Marino 	if (!(fp = fopen(path, "r"))) {
420*86d7f5d3SJohn Marino 		log_sys_error("fopen", path);
421*86d7f5d3SJohn Marino 		return 0;
422*86d7f5d3SJohn Marino 	}
423*86d7f5d3SJohn Marino 
424*86d7f5d3SJohn Marino 	if (!fgets(buffer, sizeof(buffer), fp)) {
425*86d7f5d3SJohn Marino 		log_sys_error("fgets", path);
426*86d7f5d3SJohn Marino 		goto out;
427*86d7f5d3SJohn Marino 	}
428*86d7f5d3SJohn Marino 
429*86d7f5d3SJohn Marino 	if (sscanf(buffer, "%lu", &result) != 1) {
430*86d7f5d3SJohn Marino 		log_error("sysfs file %s not in expected format: %s", path,
431*86d7f5d3SJohn Marino 			  buffer);
432*86d7f5d3SJohn Marino 		goto out;
433*86d7f5d3SJohn Marino 	}
434*86d7f5d3SJohn Marino 
435*86d7f5d3SJohn Marino 	log_very_verbose("Device %s %s is %lu bytes.",
436*86d7f5d3SJohn Marino 			 dev_name(dev), attribute, result);
437*86d7f5d3SJohn Marino 
438*86d7f5d3SJohn Marino out:
439*86d7f5d3SJohn Marino 	if (fclose(fp))
440*86d7f5d3SJohn Marino 		log_sys_error("fclose", path);
441*86d7f5d3SJohn Marino 
442*86d7f5d3SJohn Marino 	return result >> SECTOR_SHIFT;
443*86d7f5d3SJohn Marino }
444*86d7f5d3SJohn Marino 
dev_alignment_offset(const char * sysfs_dir,struct device * dev)445*86d7f5d3SJohn Marino unsigned long dev_alignment_offset(const char *sysfs_dir,
446*86d7f5d3SJohn Marino 				   struct device *dev)
447*86d7f5d3SJohn Marino {
448*86d7f5d3SJohn Marino 	return _dev_topology_attribute("alignment_offset",
449*86d7f5d3SJohn Marino 				       sysfs_dir, dev);
450*86d7f5d3SJohn Marino }
451*86d7f5d3SJohn Marino 
dev_minimum_io_size(const char * sysfs_dir,struct device * dev)452*86d7f5d3SJohn Marino unsigned long dev_minimum_io_size(const char *sysfs_dir,
453*86d7f5d3SJohn Marino 				  struct device *dev)
454*86d7f5d3SJohn Marino {
455*86d7f5d3SJohn Marino 	return _dev_topology_attribute("queue/minimum_io_size",
456*86d7f5d3SJohn Marino 				       sysfs_dir, dev);
457*86d7f5d3SJohn Marino }
458*86d7f5d3SJohn Marino 
dev_optimal_io_size(const char * sysfs_dir,struct device * dev)459*86d7f5d3SJohn Marino unsigned long dev_optimal_io_size(const char *sysfs_dir,
460*86d7f5d3SJohn Marino 				  struct device *dev)
461*86d7f5d3SJohn Marino {
462*86d7f5d3SJohn Marino 	return _dev_topology_attribute("queue/optimal_io_size",
463*86d7f5d3SJohn Marino 				       sysfs_dir, dev);
464*86d7f5d3SJohn Marino }
465*86d7f5d3SJohn Marino 
466*86d7f5d3SJohn Marino #else
467*86d7f5d3SJohn Marino 
get_primary_dev(const char * sysfs_dir,struct device * dev,dev_t * result)468*86d7f5d3SJohn Marino int get_primary_dev(const char *sysfs_dir,
469*86d7f5d3SJohn Marino 		    struct device *dev, dev_t *result)
470*86d7f5d3SJohn Marino {
471*86d7f5d3SJohn Marino 	return 0;
472*86d7f5d3SJohn Marino }
473*86d7f5d3SJohn Marino 
dev_alignment_offset(const char * sysfs_dir,struct device * dev)474*86d7f5d3SJohn Marino unsigned long dev_alignment_offset(const char *sysfs_dir,
475*86d7f5d3SJohn Marino 				   struct device *dev)
476*86d7f5d3SJohn Marino {
477*86d7f5d3SJohn Marino 	return 0UL;
478*86d7f5d3SJohn Marino }
479*86d7f5d3SJohn Marino 
dev_minimum_io_size(const char * sysfs_dir,struct device * dev)480*86d7f5d3SJohn Marino unsigned long dev_minimum_io_size(const char *sysfs_dir,
481*86d7f5d3SJohn Marino 				  struct device *dev)
482*86d7f5d3SJohn Marino {
483*86d7f5d3SJohn Marino 	return 0UL;
484*86d7f5d3SJohn Marino }
485*86d7f5d3SJohn Marino 
dev_optimal_io_size(const char * sysfs_dir,struct device * dev)486*86d7f5d3SJohn Marino unsigned long dev_optimal_io_size(const char *sysfs_dir,
487*86d7f5d3SJohn Marino 				  struct device *dev)
488*86d7f5d3SJohn Marino {
489*86d7f5d3SJohn Marino 	return 0UL;
490*86d7f5d3SJohn Marino }
491*86d7f5d3SJohn Marino 
492*86d7f5d3SJohn Marino #endif
493