OSDN Git Service

linux: clean up device naming code (no semantic change)
[android-x86/external-parted.git] / libparted / arch / linux.c
1 /* libparted - a library for manipulating disk partitions
2     Copyright (C) 1999-2011 Free Software Foundation, Inc.
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 3 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define PROC_DEVICES_BUFSIZ 16384
19
20 #include <config.h>
21 #include <arch/linux.h>
22 #include <linux/blkpg.h>
23 #include <parted/parted.h>
24 #include <parted/debug.h>
25 #if defined __s390__ || defined __s390x__
26 #include <parted/fdasd.h>
27 #endif
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <libgen.h>
33 #include <stdio.h>
34 #include <syscall.h>
35 #include <unistd.h>
36 #include <stdbool.h>
37 #include <dirent.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/utsname.h>        /* for uname() */
42 #include <scsi/scsi.h>
43 #include <assert.h>
44 #ifdef ENABLE_DEVICE_MAPPER
45 #include <libdevmapper.h>
46 #endif
47
48 #include "../architecture.h"
49 #include "dirname.h"
50 #include "xstrtol.h"
51
52 #if ENABLE_NLS
53 #  include <libintl.h>
54 #  define _(String) dgettext (PACKAGE, String)
55 #else
56 #  define _(String) (String)
57 #endif /* ENABLE_NLS */
58
59 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
60
61 #ifndef __NR__llseek
62 #define __NR__llseek 140
63 #endif
64
65 #ifndef SCSI_IOCTL_SEND_COMMAND
66 #define SCSI_IOCTL_SEND_COMMAND 1
67 #endif
68
69 /* from <linux/hdreg.h> */
70 #define HDIO_GETGEO             0x0301  /* get device geometry */
71 #define HDIO_GET_IDENTITY       0x030d  /* get IDE identification info */
72
73 #define RD_MODE (O_RDONLY)
74 #define WR_MODE (O_WRONLY)
75 #define RW_MODE (O_RDWR)
76
77 struct hd_geometry {
78         unsigned char heads;
79         unsigned char sectors;
80         unsigned short cylinders;
81         unsigned long start;
82 };
83
84 struct ata7_sectinfo {
85         int valid1:1;
86         int valid2:1;
87         int rsv:26;
88         int multiplier:4;
89 };
90
91 /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
92 struct hd_driveid {
93         unsigned short  config;         /* lots of obsolete bit flags */
94         unsigned short  cyls;           /* "physical" cyls */
95         unsigned short  reserved2;      /* reserved (word 2) */
96         unsigned short  heads;          /* "physical" heads */
97         unsigned short  track_bytes;    /* unformatted bytes per track */
98         unsigned short  sector_bytes;   /* unformatted bytes per sector */
99         unsigned short  sectors;        /* "physical" sectors per track */
100         unsigned short  vendor0;        /* vendor unique */
101         unsigned short  vendor1;        /* vendor unique */
102         unsigned short  vendor2;        /* vendor unique */
103         unsigned char   serial_no[20];  /* 0 = not_specified */
104         unsigned short  buf_type;
105         unsigned short  buf_size;       /* 512 byte increments;
106                                                          0 = not_specified */
107         unsigned short  ecc_bytes;      /* for r/w long cmds;
108                                                          0 = not_specified */
109         unsigned char   fw_rev[8];      /* 0 = not_specified */
110         char            model[40];      /* 0 = not_specified */
111         unsigned char   max_multsect;   /* 0=not_implemented */
112         unsigned char   vendor3;        /* vendor unique */
113         unsigned short  dword_io;       /* 0=not_implemented; 1=implemented */
114         unsigned char   vendor4;        /* vendor unique */
115         unsigned char   capability;     /* bits 0:DMA 1:LBA 2:IORDYsw
116                                                 3:IORDYsup*/
117         unsigned short  reserved50;     /* reserved (word 50) */
118         unsigned char   vendor5;        /* vendor unique */
119         unsigned char   tPIO;           /* 0=slow, 1=medium, 2=fast */
120         unsigned char   vendor6;        /* vendor unique */
121         unsigned char   tDMA;           /* 0=slow, 1=medium, 2=fast */
122         unsigned short  field_valid;    /* bits 0:cur_ok 1:eide_ok */
123         unsigned short  cur_cyls;       /* logical cylinders */
124         unsigned short  cur_heads;      /* logical heads */
125         unsigned short  cur_sectors;    /* logical sectors per track */
126         unsigned short  cur_capacity0;  /* logical total sectors on drive */
127         unsigned short  cur_capacity1;  /*  (2 words, misaligned int)     */
128         unsigned char   multsect;       /* current multiple sector count */
129         unsigned char   multsect_valid; /* when (bit0==1) multsect is ok */
130         unsigned int    lba_capacity;   /* total number of sectors */
131         unsigned short  dma_1word;      /* single-word dma info */
132         unsigned short  dma_mword;      /* multiple-word dma info */
133         unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
134         unsigned short  eide_dma_min;   /* min mword dma cycle time (ns) */
135         unsigned short  eide_dma_time;  /* recommended mword dma cycle
136                                            time (ns) */
137         unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
138         unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
139         unsigned short  words69_70[2];  /* reserved words 69-70 */
140         /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
141         unsigned short  words71_74[4];  /* reserved words 71-74 */
142         unsigned short  queue_depth;    /*  */
143         unsigned short  words76_79[4];  /* reserved words 76-79 */
144         unsigned short  major_rev_num;  /*  */
145         unsigned short  minor_rev_num;  /*  */
146         unsigned short  command_set_1;  /* bits 0:Smart 1:Security 2:Removable
147                                                 3:PM */
148         unsigned short  command_set_2;  /* bits 14:Smart Enabled 13:0 zero */
149         unsigned short  cfsse;          /* command set-feature supported
150                                            extensions */
151         unsigned short  cfs_enable_1;   /* command set-feature enabled */
152         unsigned short  cfs_enable_2;   /* command set-feature enabled */
153         unsigned short  csf_default;    /* command set-feature default */
154         unsigned short  dma_ultra;      /*  */
155         unsigned short  word89;         /* reserved (word 89) */
156         unsigned short  word90;         /* reserved (word 90) */
157         unsigned short  CurAPMvalues;   /* current APM values */
158         unsigned short  word92;         /* reserved (word 92) */
159         unsigned short  hw_config;      /* hardware config */
160         unsigned short  words94_105[12];/* reserved words 94-105 */
161         struct ata7_sectinfo ata7_sectinfo; /* ATAPI/ATA7 physical and logical
162                                                sector size */
163         unsigned short  words107_116[10];/* reserved words 107-116 */
164         unsigned int    logical_sectsize;/* ATAPI/ATA7 logical sector size */
165         unsigned short  words119_125[7];/* reserved words 119-125 */
166         unsigned short  last_lun;       /* reserved (word 126) */
167         unsigned short  word127;        /* reserved (word 127) */
168         unsigned short  dlf;            /* device lock function
169                                          * 15:9 reserved
170                                          * 8    security level 1:max 0:high
171                                          * 7:6  reserved
172                                          * 5    enhanced erase
173                                          * 4    expire
174                                          * 3    frozen
175                                          * 2    locked
176                                          * 1    en/disabled
177                                          * 0    capability
178                                          */
179         unsigned short  csfo;           /* current set features options
180                                          * 15:4 reserved
181                                          * 3    auto reassign
182                                          * 2    reverting
183                                          * 1    read-look-ahead
184                                          * 0    write cache
185                                          */
186         unsigned short  words130_155[26];/* reserved vendor words 130-155 */
187         unsigned short  word156;
188         unsigned short  words157_159[3]; /* reserved vendor words 157-159 */
189         unsigned short  words160_255[95];/* reserved words 160-255 */
190 };
191
192 /* from <linux/fs.h> */
193 #define BLKRRPART  _IO(0x12,95) /* re-read partition table */
194 #define BLKGETSIZE _IO(0x12,96) /* return device size */
195 #define BLKFLSBUF  _IO(0x12,97) /* flush buffer cache */
196 #define BLKSSZGET  _IO(0x12,104) /* get block device sector size */
197 #define BLKGETLASTSECT  _IO(0x12,108) /* get last sector of block device */
198 #define BLKSETLASTSECT  _IO(0x12,109) /* set last sector of block device */
199
200 /* return device size in bytes (u64 *arg) */
201 #define BLKGETSIZE64 _IOR(0x12,114,size_t)
202
203 struct blkdev_ioctl_param {
204         unsigned int block;
205         size_t content_length;
206         char * block_contents;
207 };
208
209 /* from <linux/major.h> */
210 #define IDE0_MAJOR              3
211 #define IDE1_MAJOR              22
212 #define IDE2_MAJOR              33
213 #define IDE3_MAJOR              34
214 #define IDE4_MAJOR              56
215 #define IDE5_MAJOR              57
216 #define SCSI_CDROM_MAJOR        11
217 #define SCSI_DISK0_MAJOR        8
218 #define SCSI_DISK1_MAJOR        65
219 #define SCSI_DISK2_MAJOR        66
220 #define SCSI_DISK3_MAJOR        67
221 #define SCSI_DISK4_MAJOR        68
222 #define SCSI_DISK5_MAJOR        69
223 #define SCSI_DISK6_MAJOR        70
224 #define SCSI_DISK7_MAJOR        71
225 #define SCSI_DISK8_MAJOR        128
226 #define SCSI_DISK9_MAJOR        129
227 #define SCSI_DISK10_MAJOR       130
228 #define SCSI_DISK11_MAJOR       131
229 #define SCSI_DISK12_MAJOR       132
230 #define SCSI_DISK13_MAJOR       133
231 #define SCSI_DISK14_MAJOR       134
232 #define SCSI_DISK15_MAJOR       135
233 #define COMPAQ_SMART2_MAJOR     72
234 #define COMPAQ_SMART2_MAJOR1    73
235 #define COMPAQ_SMART2_MAJOR2    74
236 #define COMPAQ_SMART2_MAJOR3    75
237 #define COMPAQ_SMART2_MAJOR4    76
238 #define COMPAQ_SMART2_MAJOR5    77
239 #define COMPAQ_SMART2_MAJOR6    78
240 #define COMPAQ_SMART2_MAJOR7    79
241 #define COMPAQ_SMART_MAJOR      104
242 #define COMPAQ_SMART_MAJOR1     105
243 #define COMPAQ_SMART_MAJOR2     106
244 #define COMPAQ_SMART_MAJOR3     107
245 #define COMPAQ_SMART_MAJOR4     108
246 #define COMPAQ_SMART_MAJOR5     109
247 #define COMPAQ_SMART_MAJOR6     110
248 #define COMPAQ_SMART_MAJOR7     111
249 #define DAC960_MAJOR            48
250 #define ATARAID_MAJOR           114
251 #define I2O_MAJOR1              80
252 #define I2O_MAJOR2              81
253 #define I2O_MAJOR3              82
254 #define I2O_MAJOR4              83
255 #define I2O_MAJOR5              84
256 #define I2O_MAJOR6              85
257 #define I2O_MAJOR7              86
258 #define I2O_MAJOR8              87
259 #define UBD_MAJOR               98
260 #define DASD_MAJOR              94
261 #define VIODASD_MAJOR           112
262 #define AOE_MAJOR               152
263 #define SX8_MAJOR1              160
264 #define SX8_MAJOR2              161
265 #define XVD_MAJOR               202
266 #define SDMMC_MAJOR             179
267 #define LOOP_MAJOR              7
268 #define MD_MAJOR                9
269
270 #define SCSI_BLK_MAJOR(M) (                                             \
271                 (M) == SCSI_DISK0_MAJOR                                 \
272                 || (M) == SCSI_CDROM_MAJOR                              \
273                 || ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) \
274                 || ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
275
276 /* Maximum number of partitions supported by linux. */
277 #define MAX_NUM_PARTS           64
278
279 static char* _device_get_part_path (PedDevice* dev, int num);
280 static int _partition_is_mounted_by_path (const char* path);
281
282 static int
283 _read_fd (int fd, char **buf)
284 {
285         char* p;
286         size_t size = PROC_DEVICES_BUFSIZ;
287         int s, filesize = 0;
288
289         *buf = malloc (size * sizeof (char));
290         if (*buf == 0) {
291                 return -1;
292         }
293
294         do {
295                 p = &(*buf) [filesize];
296                 s = read (fd, p, PROC_DEVICES_BUFSIZ);
297                 /* exit if there is an error or EOF is reached */
298                 if (s <= 0)
299                         break;
300                 filesize += s;
301                 size += s;
302                 char *new_buf = realloc (*buf, size);
303                 if (new_buf == NULL) {
304                         int saved_errno = errno;
305                         free (*buf);
306                         errno = saved_errno;
307                         return -1;
308                 }
309                 *buf = new_buf;
310         } while (1);
311
312         if (filesize == 0 && s < 0) {
313                 free (*buf);
314                 *buf = NULL;
315                 return -1;
316         } else {
317                 char *new_buf = realloc (*buf, filesize + 1);
318                 if (new_buf == NULL) {
319                         int saved_errno = errno;
320                         free (*buf);
321                         errno = saved_errno;
322                         return -1;
323                 }
324                 *buf = new_buf;
325                 (*buf)[filesize] = '\0';
326         }
327
328         return filesize;
329 }
330
331 static int
332 _major_type_in_devices (int major, const char* type)
333 {
334         int fd;
335         char* buf = NULL;
336         char* line;
337         char* end;
338         int bd = 0;
339         char c;
340
341         fd = open ("/proc/devices", O_RDONLY);
342         if (fd < 0)
343                 return 0;
344
345         if (_read_fd(fd, &buf) < 0) {
346                 close(fd);
347                 return 0;
348         }
349
350         line = buf;
351         end = strchr(line, '\n');
352         while (end) {
353                 char *name;
354                 int maj;
355
356                 c = *end;
357                 *end = '\0';
358
359                 if (!bd) {
360                         if (!strncmp(line, "Block devices:", 14))
361                                 bd = 1;
362                         goto next;
363                 }
364
365                 name = strrchr(line, ' ');
366                 if (!name || strcmp(name+1, type))
367                         goto next;
368
369                 maj = strtol(line, &name, 10);
370                 if (maj == major) {
371                         free(buf);
372                         close(fd);
373                         return 1;
374                 }
375
376 next:
377                 *end = c;
378                 line = end+1;
379                 end = strchr(line, '\n');
380         }
381         free(buf);
382         close(fd);
383         return 0;
384 }
385
386 static int
387 _is_ide_major (int major)
388 {
389         switch (major) {
390                 case IDE0_MAJOR:
391                 case IDE1_MAJOR:
392                 case IDE2_MAJOR:
393                 case IDE3_MAJOR:
394                 case IDE4_MAJOR:
395                 case IDE5_MAJOR:
396                         return 1;
397
398                 default:
399                         return 0;
400         }
401 }
402
403 static int
404 _is_cpqarray_major (int major)
405 {
406         return ((COMPAQ_SMART2_MAJOR <= major && major <= COMPAQ_SMART2_MAJOR7)
407              || (COMPAQ_SMART_MAJOR <= major && major <= COMPAQ_SMART_MAJOR7));
408 }
409
410 static int
411 _is_i2o_major (int major)
412 {
413         return (I2O_MAJOR1 <= major && major <= I2O_MAJOR8);
414 }
415
416 static int
417 _is_sx8_major (int major)
418 {
419         return (SX8_MAJOR1 <= major && major <= SX8_MAJOR2);
420 }
421
422 static int
423 _is_virtblk_major (int major)
424 {
425         return _major_type_in_devices (major, "virtblk");
426 }
427
428 #ifdef ENABLE_DEVICE_MAPPER
429 static int
430 _is_dm_major (int major)
431 {
432         return _major_type_in_devices (major, "device-mapper");
433 }
434
435 static int
436 _dm_maptype (PedDevice *dev)
437 {
438         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
439         struct dm_task *dmt;
440         uint64_t start, length;
441         char *target_type = NULL;
442         char *params;
443         int r = -1;
444         const char* dev_dir = getenv ("DM_DEV_DIR");
445
446         if (dev_dir && *dev_dir && !dm_set_dev_dir(dev_dir))
447                 return r;
448
449         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
450                 return r;
451
452         if (!dm_task_set_major_minor(dmt, arch_specific->major,
453                                      arch_specific->minor, 0))
454                 goto bad;
455
456         dm_task_no_open_count(dmt);
457
458         if (!dm_task_run(dmt))
459                 goto bad;
460
461         dm_get_next_target(dmt, NULL, &start, &length, &target_type, &params);
462
463         arch_specific->dmtype = strdup(target_type ? target_type : "NO-TARGET");
464         if (arch_specific->dmtype == NULL)
465                 goto bad;
466         r = 0;
467 bad:
468         dm_task_destroy(dmt);
469         return r;
470 }
471
472
473 static int
474 _probe_dm_devices ()
475 {
476        DIR*            mapper_dir;
477        struct dirent*  dent;
478        char            buf [512];      /* readdir(3) claims d_name[256] */
479        struct stat     st;
480
481        mapper_dir = opendir ("/dev/mapper");
482        if (!mapper_dir)
483                return 0;
484
485        /* Search the /dev/mapper directory for devices w/ the same major
486         * number that was returned from _probe_lvm_major().
487         */
488        while ((dent = readdir (mapper_dir))) {
489                if (strcmp (dent->d_name, ".")  == 0 ||
490                    strcmp (dent->d_name, "..") == 0)
491                        continue;
492
493                snprintf (buf, sizeof (buf), "/dev/mapper/%s", dent->d_name);
494
495                if (stat (buf, &st) != 0)
496                        continue;
497
498                if (_is_dm_major(major(st.st_rdev)))
499                        _ped_device_probe (buf);
500        }
501        closedir (mapper_dir);
502
503        return 1;
504 }
505 #endif
506
507 static int
508 _device_stat (PedDevice* dev, struct stat * dev_stat)
509 {
510         PED_ASSERT (dev != NULL);
511         PED_ASSERT (!dev->external_mode);
512
513         while (1) {
514                 if (!stat (dev->path, dev_stat)) {
515                         return 1;
516                 } else {
517                         if (ped_exception_throw (
518                                 PED_EXCEPTION_ERROR,
519                                 PED_EXCEPTION_RETRY_CANCEL,
520                                 _("Could not stat device %s - %s."),
521                                 dev->path,
522                                 strerror (errno))
523                                         != PED_EXCEPTION_RETRY)
524                                 return 0;
525                 }
526         }
527 }
528
529 static int
530 _device_probe_type (PedDevice* dev)
531 {
532         struct stat             dev_stat;
533         int                     dev_major;
534         int                     dev_minor;
535         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
536
537         if (!_device_stat (dev, &dev_stat))
538                 return 0;
539
540         if (!S_ISBLK(dev_stat.st_mode)) {
541                 dev->type = PED_DEVICE_FILE;
542                 return 1;
543         }
544
545         arch_specific->major = dev_major = major (dev_stat.st_rdev);
546         arch_specific->minor = dev_minor = minor (dev_stat.st_rdev);
547
548         if (SCSI_BLK_MAJOR (dev_major) && (dev_minor % 0x10 == 0)) {
549                 dev->type = PED_DEVICE_SCSI;
550         } else if (_is_ide_major (dev_major) && (dev_minor % 0x40 == 0)) {
551                 dev->type = PED_DEVICE_IDE;
552         } else if (dev_major == DAC960_MAJOR && (dev_minor % 0x8 == 0)) {
553                 dev->type = PED_DEVICE_DAC960;
554         } else if (dev_major == ATARAID_MAJOR && (dev_minor % 0x10 == 0)) {
555                 dev->type = PED_DEVICE_ATARAID;
556         } else if (dev_major == AOE_MAJOR && (dev_minor % 0x10 == 0)) {
557                 dev->type = PED_DEVICE_AOE;
558         } else if (dev_major == DASD_MAJOR && (dev_minor % 0x4 == 0)) {
559                 dev->type = PED_DEVICE_DASD;
560         } else if (dev_major == VIODASD_MAJOR && (dev_minor % 0x8 == 0)) {
561                 dev->type = PED_DEVICE_VIODASD;
562         } else if (_is_sx8_major(dev_major) && (dev_minor % 0x20 == 0)) {
563                 dev->type = PED_DEVICE_SX8;
564         } else if (_is_i2o_major (dev_major) && (dev_minor % 0x10 == 0)) {
565                 dev->type = PED_DEVICE_I2O;
566         } else if (_is_cpqarray_major (dev_major) && (dev_minor % 0x10 == 0)) {
567                 dev->type = PED_DEVICE_CPQARRAY;
568         } else if (dev_major == UBD_MAJOR && (dev_minor % 0x10 == 0)) {
569                 dev->type = PED_DEVICE_UBD;
570 #ifdef ENABLE_DEVICE_MAPPER
571         } else if (_is_dm_major(dev_major)) {
572                 dev->type = PED_DEVICE_DM;
573                 if (_dm_maptype(dev)) {
574                         ped_exception_throw (
575                                 PED_EXCEPTION_BUG,
576                                 PED_EXCEPTION_CANCEL,
577                                 _("Unable to determine the dm type of %s."),
578                                 dev->path);
579                 }
580 #endif
581         } else if (dev_major == XVD_MAJOR && (dev_minor % 0x10 == 0)) {
582                 dev->type = PED_DEVICE_XVD;
583         } else if (dev_major == SDMMC_MAJOR && (dev_minor % 0x08 == 0)) {
584                 dev->type = PED_DEVICE_SDMMC;
585         } else if (_is_virtblk_major(dev_major)) {
586                 dev->type = PED_DEVICE_VIRTBLK;
587         } else if (dev_major == LOOP_MAJOR) {
588                 dev->type = PED_DEVICE_FILE;
589         } else if (dev_major == MD_MAJOR) {
590                 dev->type = PED_DEVICE_MD;
591         } else {
592                 dev->type = PED_DEVICE_UNKNOWN;
593         }
594
595         return 1;
596 }
597
598 static int
599 _get_linux_version ()
600 {
601         static int kver = -1;
602
603         struct utsname uts;
604         int major;
605         int minor;
606         int teeny;
607
608         if (kver != -1)
609                 return kver;
610
611         if (uname (&uts))
612                 return kver = 0;
613         if (sscanf (uts.release, "%u.%u.%u", &major, &minor, &teeny) != 3)
614                 return kver = 0;
615
616         return kver = KERNEL_VERSION (major, minor, teeny);
617 }
618
619 static int
620 _have_kern26 ()
621 {
622         static int have_kern26 = -1;
623         int kver;
624
625         if (have_kern26 != -1)
626                 return have_kern26;
627
628         kver = _get_linux_version();
629         return have_kern26 = kver >= KERNEL_VERSION (2,6,0) ? 1 : 0;
630 }
631
632 #if USE_BLKID
633 static void
634 get_blkid_topology (LinuxSpecific *arch_specific)
635 {
636         arch_specific->probe = blkid_new_probe ();
637         if (!arch_specific->probe)
638                 return;
639
640         if (blkid_probe_set_device(arch_specific->probe,
641                                    arch_specific->fd, 0, 0))
642                 return;
643
644         arch_specific->topology =
645                 blkid_probe_get_topology(arch_specific->probe);
646 }
647 #endif
648
649 static void
650 _device_set_sector_size (PedDevice* dev)
651 {
652         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
653         int sector_size;
654
655         dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
656         dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
657
658         PED_ASSERT (dev->open_count);
659
660         if (_get_linux_version() < KERNEL_VERSION (2,3,0)) {
661                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
662                 return;
663         }
664
665         if (ioctl (arch_specific->fd, BLKSSZGET, &sector_size)) {
666                 ped_exception_throw (
667                         PED_EXCEPTION_WARNING,
668                         PED_EXCEPTION_OK,
669                         _("Could not determine sector size for %s: %s.\n"
670                           "Using the default sector size (%lld)."),
671                         dev->path, strerror (errno), PED_SECTOR_SIZE_DEFAULT);
672         } else {
673                 dev->sector_size = (long long)sector_size;
674                 dev->phys_sector_size = dev->sector_size;
675         }
676
677 #if USE_BLKID
678         get_blkid_topology(arch_specific);
679         if (!arch_specific->topology) {
680                 dev->phys_sector_size = 0;
681         } else {
682                 dev->phys_sector_size =
683                         blkid_topology_get_physical_sector_size(
684                                 arch_specific->topology);
685         }
686         if (dev->phys_sector_size == 0) {
687                 ped_exception_throw (
688                         PED_EXCEPTION_WARNING,
689                         PED_EXCEPTION_OK,
690                         _("Could not determine physical sector size for %s.\n"
691                           "Using the logical sector size (%lld)."),
692                         dev->path, dev->sector_size);
693                 dev->phys_sector_size = dev->sector_size;
694         }
695 #endif
696
697 #if defined __s390__ || defined __s390x__
698         /* Return PED_SECTOR_SIZE_DEFAULT for DASDs. */
699         if (dev->type == PED_DEVICE_DASD) {
700                 arch_specific->real_sector_size = dev->sector_size;
701                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
702         }
703 #endif
704 }
705
706 static int
707 _kernel_has_blkgetsize64(void)
708 {
709         int version = _get_linux_version();
710
711         if (version >= KERNEL_VERSION (2,5,4)) return 1;
712         if (version <  KERNEL_VERSION (2,5,0) &&
713             version >= KERNEL_VERSION (2,4,18)) return 1;
714         return 0;
715 }
716
717 /* TODO: do a binary search if BLKGETSIZE doesn't work?! */
718 static PedSector
719 _device_get_length (PedDevice* dev)
720 {
721         unsigned long           size;
722         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
723         uint64_t bytes=0;
724         const char*             test_str;
725         PedSector               test_size;
726
727
728         PED_ASSERT (dev->open_count > 0);
729         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
730
731         test_str = getenv ("PARTED_TEST_DEVICE_LENGTH");
732         if (test_str
733             && xstrtoll (test_str, NULL, 10, &test_size, NULL) == LONGINT_OK)
734                 return test_size;
735
736         if (_kernel_has_blkgetsize64()) {
737                 if (ioctl(arch_specific->fd, BLKGETSIZE64, &bytes) == 0) {
738                         return bytes / dev->sector_size;
739                 }
740         }
741
742         if (ioctl (arch_specific->fd, BLKGETSIZE, &size)) {
743                 ped_exception_throw (
744                         PED_EXCEPTION_BUG,
745                         PED_EXCEPTION_CANCEL,
746                         _("Unable to determine the size of %s (%s)."),
747                         dev->path,
748                         strerror (errno));
749                 return 0;
750         }
751
752         return size;
753 }
754
755 static int
756 _device_probe_geometry (PedDevice* dev)
757 {
758         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
759         struct stat             dev_stat;
760         struct hd_geometry      geometry;
761
762         if (!_device_stat (dev, &dev_stat))
763                 return 0;
764         PED_ASSERT (S_ISBLK (dev_stat.st_mode));
765
766         _device_set_sector_size (dev);
767
768         dev->length = _device_get_length (dev);
769         if (!dev->length)
770                 return 0;
771
772         /* The GETGEO ioctl is no longer useful (as of linux 2.6.x).  We could
773          * still use it in 2.4.x, but this is contentious.  Perhaps we should
774          * move to EDD. */
775         dev->bios_geom.sectors = 63;
776         dev->bios_geom.heads = 255;
777         dev->bios_geom.cylinders
778                 = dev->length / (63 * 255);
779
780         /* FIXME: what should we put here?  (TODO: discuss on linux-kernel) */
781         if (!ioctl (arch_specific->fd, HDIO_GETGEO, &geometry)
782                         && geometry.sectors && geometry.heads) {
783                 dev->hw_geom.sectors = geometry.sectors;
784                 dev->hw_geom.heads = geometry.heads;
785                 dev->hw_geom.cylinders
786                         = dev->length / (dev->hw_geom.heads
787                                          * dev->hw_geom.sectors);
788         } else {
789                 dev->hw_geom = dev->bios_geom;
790         }
791
792         return 1;
793 }
794
795 static char*
796 strip_name(char* str)
797 {
798         int     i;
799         int     end = 0;
800
801         for (i = 0; str[i] != 0; i++) {
802                 if (!isspace (str[i])
803                     || (isspace (str[i]) && !isspace (str[i+1]) && str[i+1])) {
804                         str [end] = str[i];
805                         end++;
806                 }
807         }
808         str[end] = 0;
809         return strdup (str);
810 }
811
812 static int
813 init_ide (PedDevice* dev)
814 {
815         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
816         struct stat             dev_stat;
817         struct hd_driveid       hdi;
818         PedExceptionOption      ex_status;
819         char                    hdi_buf[41];
820         int                     sector_multiplier = 0;
821
822         if (!_device_stat (dev, &dev_stat))
823                 goto error;
824
825         if (!ped_device_open (dev))
826                 goto error;
827
828         if (ioctl (arch_specific->fd, HDIO_GET_IDENTITY, &hdi)) {
829                 ex_status = ped_exception_throw (
830                                 PED_EXCEPTION_WARNING,
831                                 PED_EXCEPTION_IGNORE_CANCEL,
832                                 _("Could not get identity of device %s - %s"),
833                                 dev->path, strerror (errno));
834                 switch (ex_status) {
835                         case PED_EXCEPTION_CANCEL:
836                                 goto error_close_dev;
837
838                         case PED_EXCEPTION_UNHANDLED:
839                                 ped_exception_catch ();
840                         case PED_EXCEPTION_IGNORE:
841                                 dev->model = strdup(_("Generic IDE"));
842                                 break;
843                         default:
844                                 PED_ASSERT (0);
845                                 break;
846                 }
847         } else {
848                 /* hdi.model is not guaranteed to be NULL terminated */
849                 memcpy (hdi_buf, hdi.model, 40);
850                 hdi_buf[40] = '\0';
851                 dev->model = strip_name (hdi_buf);
852
853                 if (!hdi.ata7_sectinfo.valid1 && hdi.ata7_sectinfo.valid2)
854                         sector_multiplier = hdi.ata7_sectinfo.multiplier;
855                 else
856                         sector_multiplier = 1;
857
858                 if (sector_multiplier != 1) {
859                         ex_status = ped_exception_throw (
860                                 PED_EXCEPTION_WARNING,
861                                 PED_EXCEPTION_IGNORE_CANCEL,
862                                 _("Device %s has multiple (%d) logical sectors "
863                                   "per physical sector.\n"
864                                   "GNU Parted supports this EXPERIMENTALLY for "
865                                   "some special disk label/file system "
866                                   "combinations, e.g. GPT and ext2/3.\n"
867                                   "Please consult the web site for up-to-date "
868                                   "information."),
869                                 dev->path, sector_multiplier);
870
871                         switch (ex_status) {
872                                 case PED_EXCEPTION_CANCEL:
873                                         goto error_close_dev;
874
875                                 case PED_EXCEPTION_UNHANDLED:
876                                         ped_exception_catch ();
877                                 case PED_EXCEPTION_IGNORE:
878                                         break;
879                                 default:
880                                         PED_ASSERT (0);
881                                         break;
882                         }
883                 }
884
885                 /* XXX sector_size has not been set yet! */
886                 /* dev->phys_sector_size = dev->sector_size
887                    * sector_multiplier;*/
888                 dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
889         }
890
891         if (!_device_probe_geometry (dev))
892                 goto error_close_dev;
893
894         ped_device_close (dev);
895         return 1;
896
897 error_close_dev:
898         ped_device_close (dev);
899 error:
900         return 0;
901 }
902
903 /* This function reads the /sys entry named "file" for device "dev". */
904 static char *
905 read_device_sysfs_file (PedDevice *dev, const char *file)
906 {
907         FILE *f;
908         char name_buf[128];
909         char buf[256];
910
911         snprintf (name_buf, 127, "/sys/block/%s/device/%s",
912                   last_component (dev->path), file);
913
914         if ((f = fopen (name_buf, "r")) == NULL)
915                 return NULL;
916
917         if (fgets (buf, 255, f) == NULL)
918                 return NULL;
919
920         fclose (f);
921         return strip_name (buf);
922 }
923
924 /* This function sends a query to a SCSI device for vendor and product
925  * information.  It uses the deprecated SCSI_IOCTL_SEND_COMMAND to
926  * issue this query.
927  */
928 static int
929 scsi_query_product_info (PedDevice* dev, char **vendor, char **product)
930 {
931         /* The following are defined by the SCSI-2 specification. */
932         typedef struct _scsi_inquiry_cmd
933         {
934                 uint8_t op;
935                 uint8_t lun;          /* bits 5-7 denote the LUN */
936                 uint8_t page_code;
937                 uint8_t reserved;
938                 uint8_t alloc_length;
939                 uint8_t control;
940         } __attribute__((packed)) scsi_inquiry_cmd_t;
941
942         typedef struct _scsi_inquiry_data
943         {
944                 uint8_t peripheral_info;
945                 uint8_t device_info;
946                 uint8_t version_info;
947                 uint8_t _field1;
948                 uint8_t additional_length;
949                 uint8_t _reserved1;
950                 uint8_t _reserved2;
951                 uint8_t _field2;
952                 uint8_t vendor_id[8];
953                 uint8_t product_id[16];
954                 uint8_t product_revision[4];
955                 uint8_t vendor_specific[20];
956                 uint8_t _reserved3[40];
957         } __attribute__((packed)) scsi_inquiry_data_t;
958
959         struct scsi_arg
960         {
961                 unsigned int inlen;
962                 unsigned int outlen;
963
964                 union arg_data
965                 {
966                         scsi_inquiry_data_t out;
967                         scsi_inquiry_cmd_t  in;
968                 } data;
969         } arg;
970
971         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
972         char    buf[32];
973
974         *vendor = NULL;
975         *product = NULL;
976
977         memset (&arg, 0x00, sizeof(struct scsi_arg));
978         arg.inlen  = 0;
979         arg.outlen = sizeof(scsi_inquiry_data_t);
980         arg.data.in.op  = INQUIRY;
981         arg.data.in.lun = dev->host << 5;
982         arg.data.in.alloc_length = sizeof(scsi_inquiry_data_t);
983         arg.data.in.page_code = 0;
984         arg.data.in.reserved = 0;
985         arg.data.in.control = 0;
986
987         if (ioctl (arch_specific->fd, SCSI_IOCTL_SEND_COMMAND, &arg) < 0)
988                 return 0;
989
990         memcpy (buf, arg.data.out.vendor_id, 8);
991         buf[8] = '\0';
992         *vendor = strip_name (buf);
993
994         memcpy (buf, arg.data.out.product_id, 16);
995         buf[16] = '\0';
996         *product = strip_name (buf);
997
998         return 1;
999 }
1000
1001 /* This function provides the vendor and product name for a SCSI device.
1002  * It supports both the modern /sys interface and direct queries
1003  * via the deprecated ioctl, SCSI_IOCTL_SEND_COMMAND.
1004  */
1005 static int
1006 scsi_get_product_info (PedDevice* dev, char **vendor, char **product)
1007 {
1008         *vendor = read_device_sysfs_file (dev, "vendor");
1009         *product = read_device_sysfs_file (dev, "model");
1010         if (*vendor && *product)
1011                 return 1;
1012
1013         return scsi_query_product_info (dev, vendor, product);
1014 }
1015
1016 static int
1017 init_scsi (PedDevice* dev)
1018 {
1019         struct scsi_idlun
1020         {
1021                 uint32_t dev_id;
1022                 uint32_t host_unique_id;
1023         } idlun;
1024
1025         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
1026         char* vendor;
1027         char* product;
1028
1029         if (!ped_device_open (dev))
1030                 goto error;
1031
1032         if (ioctl (arch_specific->fd, SCSI_IOCTL_GET_IDLUN, &idlun) < 0) {
1033                 dev->host = 0;
1034                 dev->did = 0;
1035                 if (ped_exception_throw (
1036                         PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
1037                         _("Error initialising SCSI device %s - %s"),
1038                         dev->path, strerror (errno))
1039                                 != PED_EXCEPTION_IGNORE)
1040                         goto error_close_dev;
1041                 if (!_device_probe_geometry (dev))
1042                         goto error_close_dev;
1043                 ped_device_close (dev);
1044                 return 1;
1045         }
1046
1047         dev->host = idlun.host_unique_id;
1048         dev->did  = idlun.dev_id;
1049
1050         dev->model = (char*) ped_malloc (8 + 16 + 2);
1051         if (!dev->model)
1052                 goto error_close_dev;
1053
1054         if (scsi_get_product_info (dev, &vendor, &product)) {
1055                 sprintf (dev->model, "%.8s %.16s", vendor, product);
1056                 free (vendor);
1057                 free (product);
1058         } else {
1059                 strcpy (dev->model, "Generic SCSI");
1060         }
1061
1062         if (!_device_probe_geometry (dev))
1063                 goto error_close_dev;
1064
1065         ped_device_close (dev);
1066         return 1;
1067
1068 error_close_dev:
1069         ped_device_close (dev);
1070 error:
1071         return 0;
1072 }
1073
1074 static int
1075 init_file (PedDevice* dev)
1076 {
1077         struct stat     dev_stat;
1078
1079         if (!_device_stat (dev, &dev_stat))
1080                 goto error;
1081         if (!ped_device_open (dev))
1082                 goto error;
1083
1084         dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
1085         char *p = getenv ("PARTED_SECTOR_SIZE");
1086         if (p) {
1087                 int s = atoi (p);
1088                 if (0 < s && s % 512 == 0)
1089                         dev->sector_size = s;
1090         }
1091         dev->phys_sector_size = dev->sector_size;
1092
1093         if (S_ISBLK(dev_stat.st_mode))
1094                 dev->length = _device_get_length (dev);
1095         else
1096                 dev->length = dev_stat.st_size / dev->sector_size;
1097         if (dev->length <= 0) {
1098                 ped_exception_throw (
1099                         PED_EXCEPTION_ERROR,
1100                         PED_EXCEPTION_CANCEL,
1101                         _("The device %s has zero length, and can't possibly "
1102                           "store a file system or partition table.  Perhaps "
1103                           "you selected the wrong device?"),
1104                         dev->path);
1105                 goto error_close_dev;
1106         }
1107
1108         ped_device_close (dev);
1109
1110         dev->bios_geom.cylinders = dev->length / 4 / 32;
1111         dev->bios_geom.heads = 4;
1112         dev->bios_geom.sectors = 32;
1113         dev->hw_geom = dev->bios_geom;
1114         dev->model = strdup ("");
1115
1116         return 1;
1117
1118 error_close_dev:
1119         ped_device_close (dev);
1120 error:
1121         return 0;
1122 }
1123
1124 #if defined __s390__ || defined __s390x__
1125 static int
1126 init_dasd (PedDevice* dev, const char* model_name)
1127 {
1128         struct stat             dev_stat;
1129         struct hd_geometry      geo;
1130         dasd_information_t dasd_info;
1131
1132         if (!_device_stat (dev, &dev_stat))
1133                 goto error;
1134
1135         if (!ped_device_open (dev))
1136                 goto error;
1137
1138         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
1139
1140         PED_ASSERT (S_ISBLK (dev_stat.st_mode));
1141
1142         _device_set_sector_size (dev);
1143         if (!dev->sector_size)
1144                 goto error_close_dev;
1145
1146         dev->length = _device_get_length (dev);
1147         if (!dev->length)
1148                 goto error_close_dev;
1149
1150         if (!ioctl (arch_specific->fd, HDIO_GETGEO, &geo)) {
1151                 dev->hw_geom.sectors = geo.sectors;
1152                 dev->hw_geom.heads = geo.heads;
1153                 dev->hw_geom.cylinders = dev->length
1154                         / (dev->hw_geom.heads * dev->hw_geom.sectors)
1155                         / (dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
1156                 dev->bios_geom = dev->hw_geom;
1157         } else {
1158                 dev->bios_geom.sectors = 12;
1159                 dev->bios_geom.heads = 15;
1160                 dev->bios_geom.cylinders = dev->length
1161                         / (dev->hw_geom.heads * dev->hw_geom.sectors)
1162                         / (dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
1163                 dev->hw_geom = dev->bios_geom;
1164         }
1165
1166         if (!ioctl(arch_specific->fd, BIODASDINFO, &dasd_info)) {
1167                 arch_specific->devno = dasd_info.devno;
1168         } else {
1169                 arch_specific->devno = arch_specific->major * 256 +
1170                                        arch_specific->minor;
1171         }
1172
1173         dev->model = strdup (model_name);
1174
1175         ped_device_close (dev);
1176         return 1;
1177
1178 error_close_dev:
1179         ped_device_close (dev);
1180 error:
1181         return 0;
1182 }
1183 #endif
1184
1185 static int
1186 init_generic (PedDevice* dev, const char* model_name)
1187 {
1188         struct stat             dev_stat;
1189         PedExceptionOption      ex_status;
1190
1191         if (!_device_stat (dev, &dev_stat))
1192                 goto error;
1193
1194         if (!ped_device_open (dev))
1195                 goto error;
1196
1197         ped_exception_fetch_all ();
1198         if (_device_probe_geometry (dev)) {
1199                 ped_exception_leave_all ();
1200         } else {
1201                 if (!_device_get_length (dev)) {
1202                         ped_exception_catch ();
1203                         ped_exception_leave_all ();
1204                         goto error_close_dev;
1205                 }
1206
1207                 /* hack to allow use of files, for testing */
1208                 ped_exception_catch ();
1209                 ped_exception_leave_all ();
1210
1211                 ex_status = ped_exception_throw (
1212                                 PED_EXCEPTION_WARNING,
1213                                 PED_EXCEPTION_IGNORE_CANCEL,
1214                                 _("Unable to determine geometry of "
1215                                 "file/device %s.  You should not use Parted "
1216                                 "unless you REALLY know what you're doing!"),
1217                                 dev->path);
1218                 switch (ex_status) {
1219                         case PED_EXCEPTION_CANCEL:
1220                                 goto error_close_dev;
1221
1222                         case PED_EXCEPTION_UNHANDLED:
1223                                 ped_exception_catch ();
1224                         case PED_EXCEPTION_IGNORE:
1225                                 break;
1226                         default:
1227                                 PED_ASSERT (0);
1228                                 break;
1229                 }
1230
1231                 /* what should we stick in here? */
1232                 dev->length = dev_stat.st_size / PED_SECTOR_SIZE_DEFAULT;
1233                 dev->bios_geom.cylinders = dev->length / 4 / 32;
1234                 dev->bios_geom.heads = 4;
1235                 dev->bios_geom.sectors = 32;
1236                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
1237                 dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
1238         }
1239
1240         dev->model = strdup (model_name);
1241
1242         ped_device_close (dev);
1243         return 1;
1244
1245 error_close_dev:
1246         ped_device_close (dev);
1247 error:
1248         return 0;
1249 }
1250
1251 static int
1252 sdmmc_get_product_info (PedDevice* dev, char **type, char **name)
1253 {
1254         *type = read_device_sysfs_file (dev, "type");
1255         *name = read_device_sysfs_file (dev, "name");
1256         if (*type && *name)
1257                 return 1;
1258
1259         return 0;
1260 }
1261
1262 static int
1263 init_sdmmc (PedDevice* dev)
1264 {
1265         char id[128];
1266         char *type, *name;
1267
1268         if (sdmmc_get_product_info (dev, &type, &name)) {
1269                 snprintf (id, sizeof(id) - 1, "%s %s", type, name);
1270                 free (type);
1271                 free (name);
1272         } else {
1273                 snprintf (id, sizeof(id) - 1, "%s",
1274                           _("Generic SD/MMC Storage Card"));
1275         }
1276         return init_generic(dev, id);
1277 }
1278
1279 static PedDevice*
1280 linux_new (const char* path)
1281 {
1282         PedDevice*      dev;
1283         LinuxSpecific*  arch_specific;
1284
1285         PED_ASSERT (path != NULL);
1286
1287         dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
1288         if (!dev)
1289                 goto error;
1290
1291         dev->path = strdup (path);
1292         if (!dev->path)
1293                 goto error_free_dev;
1294
1295         dev->arch_specific
1296                 = (LinuxSpecific*) ped_malloc (sizeof (LinuxSpecific));
1297         if (!dev->arch_specific)
1298                 goto error_free_path;
1299         arch_specific = LINUX_SPECIFIC (dev);
1300         arch_specific->dmtype = NULL;
1301 #if USE_BLKID
1302         arch_specific->probe = NULL;
1303         arch_specific->topology = NULL;
1304 #endif
1305
1306         dev->open_count = 0;
1307         dev->read_only = 0;
1308         dev->external_mode = 0;
1309         dev->dirty = 0;
1310         dev->boot_dirty = 0;
1311
1312         if (!_device_probe_type (dev))
1313                 goto error_free_arch_specific;
1314
1315         switch (dev->type) {
1316         case PED_DEVICE_IDE:
1317                 if (!init_ide (dev))
1318                         goto error_free_arch_specific;
1319                 break;
1320
1321         case PED_DEVICE_SCSI:
1322                 if (!init_scsi (dev))
1323                         goto error_free_arch_specific;
1324                 break;
1325
1326         case PED_DEVICE_DAC960:
1327                 if (!init_generic (dev, _("DAC960 RAID controller")))
1328                         goto error_free_arch_specific;
1329                 break;
1330
1331         case PED_DEVICE_SX8:
1332                 if (!init_generic (dev, _("Promise SX8 SATA Device")))
1333                         goto error_free_arch_specific;
1334                 break;
1335
1336         case PED_DEVICE_AOE:
1337                 if (!init_generic (dev, _("ATA over Ethernet Device")))
1338                     goto error_free_arch_specific;
1339                 break;
1340
1341 #if defined __s390__ || defined __s390x__
1342         case PED_DEVICE_DASD:
1343                 if (!init_dasd (dev, _("IBM S390 DASD drive")))
1344                         goto error_free_arch_specific;
1345                 break;
1346 #endif
1347
1348         case PED_DEVICE_VIODASD:
1349                 if (!init_generic (dev, _("IBM iSeries Virtual DASD")))
1350                         goto error_free_arch_specific;
1351                 break;
1352
1353         case PED_DEVICE_CPQARRAY:
1354                 if (!init_generic (dev, _("Compaq Smart Array")))
1355                         goto error_free_arch_specific;
1356                 break;
1357
1358         case PED_DEVICE_ATARAID:
1359                 if (!init_generic (dev, _("ATARAID Controller")))
1360                         goto error_free_arch_specific;
1361                 break;
1362
1363         case PED_DEVICE_I2O:
1364                 if (!init_generic (dev, _("I2O Controller")))
1365                         goto error_free_arch_specific;
1366                 break;
1367
1368         case PED_DEVICE_UBD:
1369                 if (!init_generic (dev, _("User-Mode Linux UBD")))
1370                         goto error_free_arch_specific;
1371                 break;
1372
1373         case PED_DEVICE_FILE:
1374                 if (!init_file (dev))
1375                         goto error_free_arch_specific;
1376                 break;
1377
1378         case PED_DEVICE_DM:
1379                 {
1380                   char* type;
1381                   if (arch_specific->dmtype == NULL
1382                       || asprintf(&type, _("Linux device-mapper (%s)"),
1383                                   arch_specific->dmtype) == -1)
1384                         goto error_free_arch_specific;
1385                   bool ok = init_generic (dev, type);
1386                   free (type);
1387                   if (!ok)
1388                     goto error_free_arch_specific;
1389                   break;
1390                 }
1391
1392         case PED_DEVICE_XVD:
1393                 if (!init_generic (dev, _("Xen Virtual Block Device")))
1394                         goto error_free_arch_specific;
1395                 break;
1396
1397         case PED_DEVICE_UNKNOWN:
1398                 if (!init_generic (dev, _("Unknown")))
1399                         goto error_free_arch_specific;
1400                 break;
1401
1402         case PED_DEVICE_SDMMC:
1403                 if (!init_sdmmc (dev))
1404                         goto error_free_arch_specific;
1405                 break;
1406         case PED_DEVICE_VIRTBLK:
1407                 if (!init_generic(dev, _("Virtio Block Device")))
1408                         goto error_free_arch_specific;
1409                 break;
1410
1411         case PED_DEVICE_MD:
1412                 if (!init_generic(dev, _("Linux Software RAID Array")))
1413                         goto error_free_arch_specific;
1414                 break;
1415
1416         default:
1417                 ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
1418                                 PED_EXCEPTION_CANCEL,
1419                                 _("ped_device_new()  Unsupported device type"));
1420                 goto error_free_arch_specific;
1421         }
1422         return dev;
1423
1424 error_free_arch_specific:
1425         free (dev->arch_specific);
1426 error_free_path:
1427         free (dev->path);
1428 error_free_dev:
1429         free (dev);
1430 error:
1431         return NULL;
1432 }
1433
1434 static void
1435 linux_destroy (PedDevice* dev)
1436 {
1437         LinuxSpecific *arch_specific = LINUX_SPECIFIC(dev);
1438         void *p = arch_specific->dmtype;
1439
1440 #if USE_BLKID
1441         if (arch_specific->probe)
1442                 blkid_free_probe(arch_specific->probe);
1443 #endif
1444         free (p);
1445         free (dev->arch_specific);
1446         free (dev->path);
1447         free (dev->model);
1448         free (dev);
1449 }
1450
1451 static int
1452 linux_is_busy (PedDevice* dev)
1453 {
1454         int     i;
1455         char*   part_name;
1456
1457         if (_partition_is_mounted_by_path (dev->path))
1458                 return 1;
1459
1460         for (i = 0; i < 32; i++) {
1461                 int status;
1462
1463                 part_name = _device_get_part_path (dev, i);
1464                 if (!part_name)
1465                         return 1;
1466                 status = _partition_is_mounted_by_path (part_name);
1467                 free (part_name);
1468
1469                 if (status)
1470                         return 1;
1471         }
1472
1473         return 0;
1474 }
1475
1476 /* we need to flush the master device, and with kernel < 2.6 all the partition
1477  * devices, because there is no coherency between the caches with old kernels.
1478  * We should only flush unmounted partition devices, because:
1479  *  - there is never a need to flush them (we're not doing IO there)
1480  *  - flushing a device that is mounted causes unnecessary IO, and can
1481  * even screw journaling & friends up.  Even cause oopsen!
1482  */
1483 static void
1484 _flush_cache (PedDevice* dev)
1485 {
1486         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1487         int             i;
1488
1489         if (dev->read_only)
1490                 return;
1491         dev->dirty = 0;
1492
1493         ioctl (arch_specific->fd, BLKFLSBUF);
1494
1495         /* With linux-2.6.0 and newer, we're done.  */
1496         if (_have_kern26())
1497                 return;
1498
1499         for (i = 1; i < 16; i++) {
1500                 char*           name;
1501                 int             fd;
1502
1503                 name = _device_get_part_path (dev, i);
1504                 if (!name)
1505                         break;
1506                 if (!_partition_is_mounted_by_path (name)) {
1507                         fd = open (name, WR_MODE, 0);
1508                         if (fd > 0) {
1509                                 ioctl (fd, BLKFLSBUF);
1510 retry:
1511                                 if (fsync (fd) < 0 || close (fd) < 0)
1512                                         if (ped_exception_throw (
1513                                                 PED_EXCEPTION_WARNING,
1514                                                 PED_EXCEPTION_RETRY +
1515                                                         PED_EXCEPTION_IGNORE,
1516                                                 _("Error fsyncing/closing %s: %s"),
1517                                                 name, strerror (errno))
1518                                                         == PED_EXCEPTION_RETRY)
1519                                                 goto retry;
1520                         }
1521                 }
1522                 free (name);
1523         }
1524 }
1525
1526 static int
1527 linux_open (PedDevice* dev)
1528 {
1529         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1530
1531 retry:
1532         arch_specific->fd = open (dev->path, RW_MODE);
1533
1534         if (arch_specific->fd == -1) {
1535                 char*   rw_error_msg = strerror (errno);
1536
1537                 arch_specific->fd = open (dev->path, RD_MODE);
1538
1539                 if (arch_specific->fd == -1) {
1540                         if (ped_exception_throw (
1541                                 PED_EXCEPTION_ERROR,
1542                                 PED_EXCEPTION_RETRY_CANCEL,
1543                                 _("Error opening %s: %s"),
1544                                 dev->path, strerror (errno))
1545                                         != PED_EXCEPTION_RETRY) {
1546                                 return 0;
1547                         } else {
1548                                 goto retry;
1549                         }
1550                 } else {
1551                         ped_exception_throw (
1552                                 PED_EXCEPTION_WARNING,
1553                                 PED_EXCEPTION_OK,
1554                                 _("Unable to open %s read-write (%s).  %s has "
1555                                   "been opened read-only."),
1556                                 dev->path, rw_error_msg, dev->path);
1557                         dev->read_only = 1;
1558                 }
1559         } else {
1560                 dev->read_only = 0;
1561         }
1562
1563         /* With kernels < 2.6 flush cache for cache coherence issues */
1564         if (!_have_kern26())
1565                 _flush_cache (dev);
1566
1567         return 1;
1568 }
1569
1570 static int
1571 linux_refresh_open (PedDevice* dev)
1572 {
1573         return 1;
1574 }
1575
1576 static int
1577 linux_close (PedDevice* dev)
1578 {
1579         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1580
1581         if (dev->dirty)
1582                 _flush_cache (dev);
1583 retry:
1584         if (fsync (arch_specific->fd) < 0 || close (arch_specific->fd) < 0)
1585                 if (ped_exception_throw (
1586                         PED_EXCEPTION_WARNING,
1587                         PED_EXCEPTION_RETRY + PED_EXCEPTION_IGNORE,
1588                         _("Error fsyncing/closing %s: %s"),
1589                         dev->path, strerror (errno))
1590                                 == PED_EXCEPTION_RETRY)
1591                         goto retry;
1592         return 1;
1593 }
1594
1595 static int
1596 linux_refresh_close (PedDevice* dev)
1597 {
1598         if (dev->dirty)
1599                 _flush_cache (dev);
1600         return 1;
1601 }
1602
1603 #if SIZEOF_OFF_T < 8
1604
1605 static _syscall5(int,_llseek,
1606                  unsigned int, fd,
1607                  unsigned long, offset_high,
1608                  unsigned long, offset_low,
1609                  loff_t*, result,
1610                  unsigned int, origin)
1611
1612 loff_t
1613 llseek (unsigned int fd, loff_t offset, unsigned int whence)
1614 {
1615         loff_t result;
1616         int retval;
1617
1618         retval = _llseek(fd,
1619                          ((unsigned long long)offset) >> 32,
1620                          ((unsigned long long)offset) & 0xffffffff,
1621                          &result,
1622                          whence);
1623         return (retval==-1 ? (loff_t) retval : result);
1624 }
1625
1626 #endif /* SIZEOF_OFF_T < 8 */
1627
1628 static int
1629 _device_seek (const PedDevice* dev, PedSector sector)
1630 {
1631         LinuxSpecific*  arch_specific;
1632
1633         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
1634         PED_ASSERT (dev != NULL);
1635         PED_ASSERT (!dev->external_mode);
1636
1637         arch_specific = LINUX_SPECIFIC (dev);
1638
1639 #if SIZEOF_OFF_T < 8
1640         if (sizeof (off_t) < 8) {
1641                 loff_t  pos = (loff_t)(sector * dev->sector_size);
1642                 return llseek (arch_specific->fd, pos, SEEK_SET) == pos;
1643         } else
1644 #endif
1645         {
1646                 off_t   pos = sector * dev->sector_size;
1647                 return lseek (arch_specific->fd, pos, SEEK_SET) == pos;
1648         }
1649 }
1650
1651 static int
1652 _read_lastoddsector (const PedDevice* dev, void* buffer)
1653 {
1654         LinuxSpecific*                  arch_specific;
1655         struct blkdev_ioctl_param       ioctl_param;
1656
1657         PED_ASSERT(dev != NULL);
1658         PED_ASSERT(buffer != NULL);
1659
1660         arch_specific = LINUX_SPECIFIC (dev);
1661
1662 retry:
1663         ioctl_param.block = 0; /* read the last sector */
1664         ioctl_param.content_length = dev->sector_size;
1665         ioctl_param.block_contents = buffer;
1666
1667         if (ioctl(arch_specific->fd, BLKGETLASTSECT, &ioctl_param) == -1) {
1668                 PedExceptionOption      opt;
1669                 opt = ped_exception_throw (
1670                         PED_EXCEPTION_ERROR,
1671                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1672                         _("%s during read on %s"),
1673                         strerror (errno), dev->path);
1674
1675                 if (opt == PED_EXCEPTION_CANCEL)
1676                         return 0;
1677                 if (opt == PED_EXCEPTION_RETRY)
1678                         goto retry;
1679         }
1680
1681         return 1;
1682 }
1683
1684 static int
1685 linux_read (const PedDevice* dev, void* buffer, PedSector start,
1686             PedSector count)
1687 {
1688         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1689         PedExceptionOption      ex_status;
1690         void*                   diobuf = NULL;
1691
1692         PED_ASSERT (dev != NULL);
1693         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
1694
1695         if (_get_linux_version() < KERNEL_VERSION (2,6,0)) {
1696                 /* Kludge.  This is necessary to read/write the last
1697                    block of an odd-sized disk, until Linux 2.5.x kernel fixes.
1698                 */
1699                 if (dev->type != PED_DEVICE_FILE && (dev->length & 1)
1700                     && start + count - 1 == dev->length - 1)
1701                         return ped_device_read (dev, buffer, start, count - 1)
1702                                 && _read_lastoddsector (
1703                                         dev, (char *) buffer + (count-1) * 512);
1704         }
1705         while (1) {
1706                 if (_device_seek (dev, start))
1707                         break;
1708
1709                 ex_status = ped_exception_throw (
1710                         PED_EXCEPTION_ERROR,
1711                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1712                         _("%s during seek for read on %s"),
1713                         strerror (errno), dev->path);
1714
1715                 switch (ex_status) {
1716                         case PED_EXCEPTION_IGNORE:
1717                                 return 1;
1718
1719                         case PED_EXCEPTION_RETRY:
1720                                 break;
1721
1722                         case PED_EXCEPTION_UNHANDLED:
1723                                 ped_exception_catch ();
1724                         case PED_EXCEPTION_CANCEL:
1725                                 return 0;
1726                         default:
1727                                 PED_ASSERT (0);
1728                                 break;
1729                 }
1730         }
1731
1732         size_t read_length = count * dev->sector_size;
1733         if (posix_memalign (&diobuf, dev->sector_size, read_length) != 0)
1734                 return 0;
1735
1736         while (1) {
1737                 ssize_t status = read (arch_specific->fd, diobuf, read_length);
1738                 if (status > 0)
1739                         memcpy(buffer, diobuf, status);
1740                 if (status == (ssize_t) read_length)
1741                         break;
1742                 if (status > 0) {
1743                         read_length -= status;
1744                         buffer = (char *) buffer + status;
1745                         continue;
1746                 }
1747
1748                 ex_status = ped_exception_throw (
1749                         PED_EXCEPTION_ERROR,
1750                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1751                         (status == 0
1752                          ? _("end of file while reading %s")
1753                          : _("%s during read on %s")),
1754                         strerror (errno),
1755                         dev->path);
1756
1757                 switch (ex_status) {
1758                         case PED_EXCEPTION_IGNORE:
1759                                 free(diobuf);
1760                                 return 1;
1761
1762                         case PED_EXCEPTION_RETRY:
1763                                 break;
1764
1765                         case PED_EXCEPTION_UNHANDLED:
1766                                 ped_exception_catch ();
1767                         case PED_EXCEPTION_CANCEL:
1768                                 free(diobuf);
1769                                 return 0;
1770                         default:
1771                                 PED_ASSERT (0);
1772                                 break;
1773                 }
1774         }
1775
1776         free (diobuf);
1777
1778         return 1;
1779 }
1780
1781 static int
1782 _write_lastoddsector (PedDevice* dev, const void* buffer)
1783 {
1784         LinuxSpecific*                  arch_specific;
1785         struct blkdev_ioctl_param       ioctl_param;
1786
1787         PED_ASSERT(dev != NULL);
1788         PED_ASSERT(buffer != NULL);
1789
1790         arch_specific = LINUX_SPECIFIC (dev);
1791
1792 retry:
1793         ioctl_param.block = 0; /* write the last sector */
1794         ioctl_param.content_length = dev->sector_size;
1795         ioctl_param.block_contents = (void*) buffer;
1796
1797         if (ioctl(arch_specific->fd, BLKSETLASTSECT, &ioctl_param) == -1) {
1798                 PedExceptionOption      opt;
1799                 opt = ped_exception_throw (
1800                         PED_EXCEPTION_ERROR,
1801                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1802                         _("%s during write on %s"),
1803                         strerror (errno), dev->path);
1804
1805                 if (opt == PED_EXCEPTION_CANCEL)
1806                         return 0;
1807                 if (opt == PED_EXCEPTION_RETRY)
1808                         goto retry;
1809         }
1810
1811         return 1;
1812 }
1813
1814 static int
1815 linux_write (PedDevice* dev, const void* buffer, PedSector start,
1816              PedSector count)
1817 {
1818         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1819         PedExceptionOption      ex_status;
1820         void*                   diobuf;
1821         void*                   diobuf_start;
1822
1823         PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
1824
1825         if (dev->read_only) {
1826                 if (ped_exception_throw (
1827                         PED_EXCEPTION_ERROR,
1828                         PED_EXCEPTION_IGNORE_CANCEL,
1829                         _("Can't write to %s, because it is opened read-only."),
1830                         dev->path)
1831                                 != PED_EXCEPTION_IGNORE)
1832                         return 0;
1833                 else
1834                         return 1;
1835         }
1836
1837         if (_get_linux_version() < KERNEL_VERSION (2,6,0)) {
1838                 /* Kludge.  This is necessary to read/write the last
1839                    block of an odd-sized disk, until Linux 2.5.x kernel fixes.
1840                 */
1841                 if (dev->type != PED_DEVICE_FILE && (dev->length & 1)
1842                     && start + count - 1 == dev->length - 1)
1843                         return ped_device_write (dev, buffer, start, count - 1)
1844                                 && _write_lastoddsector (
1845                                         dev, ((char*) buffer
1846                                               + (count-1) * dev->sector_size));
1847         }
1848         while (1) {
1849                 if (_device_seek (dev, start))
1850                         break;
1851
1852                 ex_status = ped_exception_throw (
1853                         PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1854                         _("%s during seek for write on %s"),
1855                         strerror (errno), dev->path);
1856
1857                 switch (ex_status) {
1858                         case PED_EXCEPTION_IGNORE:
1859                                 return 1;
1860
1861                         case PED_EXCEPTION_RETRY:
1862                                 break;
1863
1864                         case PED_EXCEPTION_UNHANDLED:
1865                                 ped_exception_catch ();
1866                         case PED_EXCEPTION_CANCEL:
1867                                 return 0;
1868                         default:
1869                                 PED_ASSERT (0);
1870                                 break;
1871                 }
1872         }
1873
1874 #ifdef READ_ONLY
1875         printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
1876                 dev->path, buffer, (int) start, (int) count);
1877 #else
1878         size_t write_length = count * dev->sector_size;
1879         dev->dirty = 1;
1880         if (posix_memalign(&diobuf, dev->sector_size, write_length) != 0)
1881                 return 0;
1882         memcpy(diobuf, buffer, write_length);
1883         diobuf_start = diobuf;
1884         while (1) {
1885                 ssize_t status = write (arch_specific->fd, diobuf, write_length);
1886                 if (status == write_length) break;
1887                 if (status > 0) {
1888                         write_length -= status;
1889                         diobuf = (char *) diobuf + status;
1890                         continue;
1891                 }
1892
1893                 ex_status = ped_exception_throw (
1894                         PED_EXCEPTION_ERROR,
1895                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1896                         _("%s during write on %s"),
1897                         strerror (errno), dev->path);
1898
1899                 switch (ex_status) {
1900                         case PED_EXCEPTION_IGNORE:
1901                                 free(diobuf_start);
1902                                 return 1;
1903
1904                         case PED_EXCEPTION_RETRY:
1905                                 break;
1906
1907                         case PED_EXCEPTION_UNHANDLED:
1908                                 ped_exception_catch ();
1909                         case PED_EXCEPTION_CANCEL:
1910                                 free(diobuf_start);
1911                                 return 0;
1912                         default:
1913                                 PED_ASSERT (0);
1914                                 break;
1915                 }
1916         }
1917         free(diobuf_start);
1918 #endif /* !READ_ONLY */
1919         return 1;
1920 }
1921
1922 /* returns the number of sectors that are ok.
1923  */
1924 static PedSector
1925 linux_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
1926 {
1927         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1928         PedSector       done = 0;
1929         int             status;
1930         void*           diobuf;
1931
1932         PED_ASSERT(dev != NULL);
1933
1934         if (!_device_seek (dev, start))
1935                 return 0;
1936
1937         if (posix_memalign(&diobuf, PED_SECTOR_SIZE_DEFAULT,
1938                            count * PED_SECTOR_SIZE_DEFAULT) != 0)
1939                 return 0;
1940
1941         for (done = 0; done < count; done += status / dev->sector_size) {
1942                 status = read (arch_specific->fd, diobuf,
1943                                (size_t) ((count-done) * dev->sector_size));
1944                 if (status > 0)
1945                         memcpy(buffer, diobuf, status);
1946                 if (status < 0)
1947                         break;
1948         }
1949         free(diobuf);
1950
1951         return done;
1952 }
1953
1954 static int
1955 _do_fsync (PedDevice* dev)
1956 {
1957         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1958         int                     status;
1959         PedExceptionOption      ex_status;
1960
1961         while (1) {
1962                 status = fsync (arch_specific->fd);
1963                 if (status >= 0) break;
1964
1965                 ex_status = ped_exception_throw (
1966                         PED_EXCEPTION_ERROR,
1967                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1968                         _("%s during write on %s"),
1969                         strerror (errno), dev->path);
1970
1971                 switch (ex_status) {
1972                         case PED_EXCEPTION_IGNORE:
1973                                 return 1;
1974
1975                         case PED_EXCEPTION_RETRY:
1976                                 break;
1977
1978                         case PED_EXCEPTION_UNHANDLED:
1979                                 ped_exception_catch ();
1980                         case PED_EXCEPTION_CANCEL:
1981                                 return 0;
1982                         default:
1983                                 PED_ASSERT (0);
1984                                 break;
1985                 }
1986         }
1987         return 1;
1988 }
1989
1990 static int
1991 linux_sync (PedDevice* dev)
1992 {
1993         PED_ASSERT (dev != NULL);
1994         PED_ASSERT (!dev->external_mode);
1995
1996         if (dev->read_only)
1997                 return 1;
1998         if (!_do_fsync (dev))
1999                 return 0;
2000         _flush_cache (dev);
2001         return 1;
2002 }
2003
2004 static int
2005 linux_sync_fast (PedDevice* dev)
2006 {
2007         PED_ASSERT (dev != NULL);
2008         PED_ASSERT (!dev->external_mode);
2009
2010         if (dev->read_only)
2011                 return 1;
2012         if (!_do_fsync (dev))
2013                 return 0;
2014         /* no cache flush... */
2015         return 1;
2016 }
2017
2018 static inline int
2019 _compare_digit_state (char ch, int need_digit)
2020 {
2021         return !!isdigit (ch) == need_digit;
2022 }
2023
2024 /* matches the regexp "[^0-9]+[0-9]+[^0-9]+[0-9]+$".
2025  * Motivation: accept devices looking like /dev/rd/c0d0, but
2026  * not looking like /dev/hda1 and /dev/rd/c0d0p1
2027  */
2028 static int
2029 _match_rd_device (const char* name)
2030 {
2031         const char* pos;
2032         int state;
2033
2034         /* exclude directory names from test */
2035         pos = strrchr(name, '/') ?: name;
2036
2037         /* states:
2038          *      0       non-digits
2039          *      1       digits
2040          *      2       non-digits
2041          *      3       digits
2042          */
2043         for (state = 0; state < 4; state++) {
2044                 int want_digits = (state % 2 == 1);
2045                 do {
2046                         if (!*pos)
2047                                 return 0;
2048                         if (!_compare_digit_state (*pos, want_digits))
2049                                 return 0;
2050                         pos++;
2051                 } while (_compare_digit_state (*pos, want_digits));
2052         }
2053
2054         return *pos == 0;
2055 }
2056
2057 static int
2058 _probe_proc_partitions ()
2059 {
2060         FILE*           proc_part_file;
2061         int             major, minor, size;
2062         char            buf [512];
2063         char            part_name [256];
2064         char            dev_name [256];
2065
2066         proc_part_file = fopen ("/proc/partitions", "r");
2067         if (!proc_part_file)
2068                 return 0;
2069
2070         if (fgets (buf, 256, proc_part_file) == NULL)
2071                 return 0;
2072
2073         if (fgets (buf, 256, proc_part_file) == NULL)
2074                 return 0;
2075
2076         while (fgets (buf, 512, proc_part_file)
2077                && sscanf (buf, "%d %d %d %255s", &major, &minor, &size,
2078                           part_name) == 4) {
2079                 /* Heuristic for telling partitions and devices apart
2080                  * Probably needs to be improved
2081                  */
2082                 if (!_match_rd_device (part_name)
2083                     && isdigit (part_name [strlen (part_name) - 1]))
2084                         continue;
2085
2086                 strcpy (dev_name, "/dev/");
2087                 strcat (dev_name, part_name);
2088                 _ped_device_probe (dev_name);
2089         }
2090
2091         fclose (proc_part_file);
2092         return 1;
2093 }
2094
2095 struct _entry {
2096         const char *name;
2097         size_t len;
2098 };
2099
2100 static int
2101 _skip_entry (const char *name)
2102 {
2103         struct _entry *i;
2104         static struct _entry entries[] = {
2105                 { ".",          sizeof (".") - 1        },
2106                 { "..",         sizeof ("..") - 1       },
2107                 { "dm-",        sizeof ("dm-") - 1      },
2108                 { "loop",       sizeof ("loop") - 1     },
2109                 { "ram",        sizeof ("ram") - 1      },
2110                 { 0, 0 },
2111         };
2112
2113         for (i = entries; i->name != 0; i++) {
2114                 if (strncmp (name, i->name, i->len) == 0)
2115                         return 1;
2116         }
2117
2118         return 0;
2119 }
2120
2121 static int
2122 _probe_sys_block ()
2123 {
2124         DIR *blockdir;
2125         struct dirent *dirent;
2126         char dev_name [256];
2127         char *ptr;
2128
2129         if (!(blockdir = opendir ("/sys/block")))
2130                 return 0;
2131         while ((dirent = readdir (blockdir))) {
2132                 if (_skip_entry (dirent->d_name))
2133                         continue;
2134
2135                 if (strlen (dirent->d_name) > sizeof (dev_name) - 6)
2136                         continue; /* device name too long! */
2137
2138                 strcpy (dev_name, "/dev/");
2139                 strcat (dev_name, dirent->d_name);
2140                 /* in /sys/block, '/'s are replaced with '!' or '.' */
2141                 for (ptr = dev_name; *ptr != '\0'; ptr++) {
2142                         if (*ptr == '!' || *ptr == '.')
2143                                 *ptr = '/';
2144                 }
2145                 _ped_device_probe (dev_name);
2146         }
2147
2148         closedir (blockdir);
2149         return 1;
2150 }
2151
2152 static int
2153 _probe_standard_devices ()
2154 {
2155         _ped_device_probe ("/dev/hda");
2156         _ped_device_probe ("/dev/hdb");
2157         _ped_device_probe ("/dev/hdc");
2158         _ped_device_probe ("/dev/hdd");
2159         _ped_device_probe ("/dev/hde");
2160         _ped_device_probe ("/dev/hdf");
2161         _ped_device_probe ("/dev/hdg");
2162         _ped_device_probe ("/dev/hdh");
2163
2164         _ped_device_probe ("/dev/sda");
2165         _ped_device_probe ("/dev/sdb");
2166         _ped_device_probe ("/dev/sdc");
2167         _ped_device_probe ("/dev/sdd");
2168         _ped_device_probe ("/dev/sde");
2169         _ped_device_probe ("/dev/sdf");
2170
2171         return 1;
2172 }
2173
2174 static void
2175 linux_probe_all ()
2176 {
2177         /* we should probe the standard devs too, even with /proc/partitions,
2178          * because /proc/partitions might return devfs stuff, and we might not
2179          * have devfs available
2180          */
2181         _probe_standard_devices ();
2182
2183 #ifdef ENABLE_DEVICE_MAPPER
2184         /* device-mapper devices aren't listed in /proc/partitions; or, if
2185          * they are, they're listed as dm-X.  So, instead of relying on that,
2186          * we do our own checks.
2187          */
2188         _probe_dm_devices ();
2189 #endif
2190
2191         /* /sys/block is more reliable and consistent; fall back to using
2192          * /proc/partitions if the former is unavailable, however.
2193          */
2194         if (!_probe_sys_block ())
2195                 _probe_proc_partitions ();
2196 }
2197
2198 static char * _GL_ATTRIBUTE_FORMAT ((__printf__, 1, 2))
2199 zasprintf (const char *format, ...)
2200 {
2201   va_list args;
2202   char *resultp;
2203   va_start (args, format);
2204   int r = vasprintf (&resultp, format, args);
2205   va_end (args);
2206   return r < 0 ? NULL : resultp;
2207 }
2208
2209 static char*
2210 _device_get_part_path (PedDevice *dev, int num)
2211 {
2212         size_t path_len = strlen (dev->path);
2213
2214         char *result;
2215         /* Check for devfs-style /disc => /partN transformation
2216            unconditionally; the system might be using udev with devfs rules,
2217            and if not the test is harmless. */
2218         if (5 < path_len && !strcmp (dev->path + path_len - 5, "/disc")) {
2219                 /* replace /disc with /path%d */
2220                 result = zasprintf ("%.*s/part%d",
2221                                     (int) (path_len - 5), dev->path, num);
2222         } else {
2223                 char const *p = (dev->type == PED_DEVICE_DAC960
2224                                  || dev->type == PED_DEVICE_CPQARRAY
2225                                  || dev->type == PED_DEVICE_ATARAID
2226                                  || dev->type == PED_DEVICE_DM
2227                                  || isdigit (dev->path[path_len - 1])
2228                                  ? "p" : "");
2229                 result = zasprintf ("%s%s%d", dev->path, p, num);
2230         }
2231
2232         return result;
2233 }
2234
2235 static char*
2236 linux_partition_get_path (const PedPartition* part)
2237 {
2238         return _device_get_part_path (part->disk->dev, part->num);
2239 }
2240
2241 static dev_t
2242 _partition_get_part_dev (const PedPartition* part)
2243 {
2244         struct stat dev_stat;
2245         int dev_major, dev_minor;
2246
2247         if (stat (part->disk->dev->path, &dev_stat))
2248                 return (dev_t)0;
2249         dev_major = major (dev_stat.st_rdev);
2250         dev_minor = minor (dev_stat.st_rdev);
2251         return (dev_t)makedev (dev_major, dev_minor + part->num);
2252 }
2253
2254 static int
2255 _mount_table_search (const char* file_name, dev_t dev)
2256 {
2257         struct stat part_stat;
2258         char line[512];
2259         char part_name[512];
2260         FILE* file;
2261
2262         file = fopen (file_name, "r");
2263         if (!file)
2264                 return 0;
2265         while (fgets (line, 512, file)) {
2266                 if (sscanf (line, "%s", part_name) == 1
2267                     && stat (part_name, &part_stat) == 0) {
2268                         if (part_stat.st_rdev == dev) {
2269                                 fclose (file);
2270                                 return 1;
2271                         }
2272                 }
2273         }
2274         fclose (file);
2275         return 0;
2276 }
2277
2278 static int
2279 _partition_is_mounted_by_dev (dev_t dev)
2280 {
2281         return  _mount_table_search( "/proc/mounts", dev)
2282                 || _mount_table_search( "/proc/swaps", dev)
2283                 || _mount_table_search( "/etc/mtab", dev);
2284 }
2285
2286 static int
2287 _partition_is_mounted_by_path (const char *path)
2288 {
2289         struct stat part_stat;
2290         if (stat (path, &part_stat) != 0)
2291                 return 0;
2292         if (!S_ISBLK(part_stat.st_mode))
2293                 return 0;
2294         return _partition_is_mounted_by_dev (part_stat.st_rdev);
2295 }
2296
2297 static int
2298 _partition_is_mounted (const PedPartition *part)
2299 {
2300         dev_t dev;
2301         if (!ped_partition_is_active (part))
2302                 return 0;
2303         dev = _partition_get_part_dev (part);
2304         if (!dev)
2305                 return 0;
2306         return _partition_is_mounted_by_dev (dev);
2307 }
2308
2309 static int
2310 _has_partitions (const PedDisk* disk)
2311 {
2312         PED_ASSERT(disk != NULL);
2313
2314         /* Some devices can't be partitioned. */
2315         if (!strcmp (disk->type->name, "loop"))
2316                 return 0;
2317
2318         return 1;
2319 }
2320
2321 static int
2322 linux_partition_is_busy (const PedPartition* part)
2323 {
2324         PedPartition*   walk;
2325
2326         PED_ASSERT (part != NULL);
2327
2328         if (_partition_is_mounted (part))
2329                 return 1;
2330         if (part->type == PED_PARTITION_EXTENDED) {
2331                 for (walk = part->part_list; walk; walk = walk->next) {
2332                         if (linux_partition_is_busy (walk))
2333                                 return 1;
2334                 }
2335         }
2336         return 0;
2337 }
2338
2339 static int
2340 _blkpg_part_command (PedDevice* dev, struct blkpg_partition* part, int op)
2341 {
2342         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
2343         struct blkpg_ioctl_arg  ioctl_arg;
2344
2345         ioctl_arg.op = op;
2346         ioctl_arg.flags = 0;
2347         ioctl_arg.datalen = sizeof (struct blkpg_partition);
2348         ioctl_arg.data = (void*) part;
2349
2350         return ioctl (arch_specific->fd, BLKPG, &ioctl_arg) == 0;
2351 }
2352
2353 static int
2354 _blkpg_add_partition (PedDisk* disk, const PedPartition *part)
2355 {
2356         struct blkpg_partition  linux_part;
2357         const char*             vol_name;
2358         char*                   dev_name;
2359
2360         PED_ASSERT(disk != NULL);
2361         PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
2362
2363         if (!_has_partitions (disk))
2364                 return 0;
2365
2366         if (ped_disk_type_check_feature (disk->type,
2367                                          PED_DISK_TYPE_PARTITION_NAME))
2368                 vol_name = ped_partition_get_name (part);
2369         else
2370                 vol_name = NULL;
2371
2372         dev_name = _device_get_part_path (disk->dev, part->num);
2373         if (!dev_name)
2374                 return 0;
2375
2376         memset (&linux_part, 0, sizeof (linux_part));
2377         linux_part.start = part->geom.start * disk->dev->sector_size;
2378         /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */
2379         if (part->type & PED_PARTITION_EXTENDED)
2380                 linux_part.length = part->geom.length == 1 ? 512 : 1024;
2381         else
2382                 linux_part.length = part->geom.length * disk->dev->sector_size;
2383         linux_part.pno = part->num;
2384         strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
2385         if (vol_name)
2386                 strncpy (linux_part.volname, vol_name, BLKPG_VOLNAMELTH);
2387
2388         free (dev_name);
2389
2390         if (!_blkpg_part_command (disk->dev, &linux_part,
2391                                   BLKPG_ADD_PARTITION)) {
2392                 return ped_exception_throw (
2393                         PED_EXCEPTION_ERROR,
2394                         PED_EXCEPTION_IGNORE_CANCEL,
2395                         _("Error informing the kernel about modifications to "
2396                           "partition %s -- %s.  This means Linux won't know "
2397                           "about any changes you made to %s until you reboot "
2398                           "-- so you shouldn't mount it or use it in any way "
2399                           "before rebooting."),
2400                         linux_part.devname,
2401                         strerror (errno),
2402                         linux_part.devname)
2403                                 == PED_EXCEPTION_IGNORE;
2404         }
2405
2406         return 1;
2407 }
2408
2409 static int
2410 _blkpg_remove_partition (PedDisk* disk, int n)
2411 {
2412         struct blkpg_partition  linux_part;
2413
2414         if (!_has_partitions (disk))
2415                 return 0;
2416
2417         memset (&linux_part, 0, sizeof (linux_part));
2418         linux_part.pno = n;
2419         return _blkpg_part_command (disk->dev, &linux_part,
2420                                     BLKPG_DEL_PARTITION);
2421 }
2422
2423 /*
2424  * The number of partitions that a device can have depends on the kernel.
2425  * If we don't find this value in /sys/block/DEV/range, we will use our own
2426  * value.
2427  */
2428 static unsigned int
2429 _device_get_partition_range(PedDevice* dev)
2430 {
2431         int         range, r;
2432         char        path[128];
2433         FILE*       fp;
2434         bool        ok;
2435
2436         r = snprintf(path, sizeof(path), "/sys/block/%s/range",
2437                      last_component(dev->path));
2438         if (r < 0 || r >= sizeof(path))
2439                 return MAX_NUM_PARTS;
2440
2441         fp = fopen(path, "r");
2442         if (!fp)
2443                 return MAX_NUM_PARTS;
2444
2445         ok = fscanf(fp, "%d", &range) == 1;
2446         fclose(fp);
2447
2448         /* (range <= 0) is none sense.*/
2449         return ok && range > 0 ? range : MAX_NUM_PARTS;
2450 }
2451
2452 /*
2453  * Sync the partition table in two step process:
2454  * 1. Remove all of the partitions from the kernel's tables, but do not attempt
2455  *    removal of any partition for which the corresponding ioctl call fails.
2456  * 2. Add all the partitions that we hold in disk, throwing a warning
2457  *    if we cannot because step 1 failed to remove it and it is not being
2458  *    added back with the same start and length.
2459  *
2460  * To achieve this two step process we must calculate the minimum number of
2461  * maximum possible partitions between what linux supports and what the label
2462  * type supports. EX:
2463  *
2464  * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables)
2465  */
2466 static int
2467 _disk_sync_part_table (PedDisk* disk)
2468 {
2469         PED_ASSERT(disk != NULL);
2470         PED_ASSERT(disk->dev != NULL);
2471         int lpn;
2472
2473         /* lpn = largest partition number. */
2474         if (ped_disk_get_max_supported_partition_count(disk, &lpn))
2475                 lpn = PED_MIN(lpn, _device_get_partition_range(disk->dev));
2476         else
2477                 lpn = _device_get_partition_range(disk->dev);
2478
2479         /* Its not possible to support largest_partnum < 0.
2480          * largest_partnum == 0 would mean does not support partitions.
2481          * */
2482         if (lpn < 0)
2483                 return 0;
2484         int ret = 0;
2485         int *ok = calloc (lpn, sizeof *ok);
2486         if (!ok)
2487                 return 0;
2488         int *errnums = ped_malloc(sizeof(int) * lpn);
2489         if (!errnums)
2490                 goto cleanup;
2491
2492         /* Attempt to remove each and every partition, retrying for
2493            up to max_sleep_seconds upon any failure due to EBUSY. */
2494         unsigned int sleep_microseconds = 10000;
2495         unsigned int max_sleep_seconds = 1;
2496         unsigned int n_sleep = (max_sleep_seconds
2497                                 * 1000000 / sleep_microseconds);
2498         int i;
2499         for (i = 0; i < n_sleep; i++) {
2500             if (i)
2501                 usleep (sleep_microseconds);
2502             bool busy = false;
2503             int j;
2504             for (j = 0; j < lpn; j++) {
2505                 if (!ok[j]) {
2506                     ok[j] = _blkpg_remove_partition (disk, j + 1);
2507                     errnums[j] = errno;
2508                     if (!ok[j] && errnums[j] == EBUSY)
2509                         busy = true;
2510                 }
2511             }
2512             if (!busy)
2513                 break;
2514         }
2515
2516         for (i = 1; i <= lpn; i++) {
2517                 const PedPartition *part = ped_disk_get_partition (disk, i);
2518                 if (part) {
2519                         if (!ok[i - 1] && errnums[i - 1] == EBUSY) {
2520                                 struct hd_geometry geom;
2521                                 unsigned long long length = 0;
2522                                 /* get start and length of existing partition */
2523                                 char *dev_name = _device_get_part_path (disk->dev, i);
2524                                 if (!dev_name)
2525                                         goto cleanup;
2526                                 int fd = open (dev_name, O_RDONLY);
2527                                 if (fd == -1
2528                                     || ioctl (fd, HDIO_GETGEO, &geom)
2529                                     || ioctl (fd, BLKGETSIZE64, &length)) {
2530                                         ped_exception_throw (
2531                                                              PED_EXCEPTION_BUG,
2532                                                              PED_EXCEPTION_CANCEL,
2533                             _("Unable to determine the size and length of %s."),
2534                                                              dev_name);
2535                                         if (fd != -1)
2536                                                 close (fd);
2537                                         free (dev_name);
2538                                         goto cleanup;
2539                                 }
2540                                 free (dev_name);
2541                                 length /= disk->dev->sector_size;
2542                                 close (fd);
2543                                 if (geom.start == part->geom.start
2544                                     && length == part->geom.length)
2545                                         ok[i - 1] = 1;
2546                                 /* If the new partition is unchanged and the
2547                                    existing one was not removed because it was
2548                                    in use, then reset the error flag and do not
2549                                    try to add it since it is already there.  */
2550                                 continue;
2551                         }
2552
2553                         /* add the (possibly modified or new) partition */
2554                         if (!_blkpg_add_partition (disk, part)) {
2555                                 ped_exception_throw (
2556                                         PED_EXCEPTION_ERROR,
2557                                         PED_EXCEPTION_RETRY_CANCEL,
2558                                         _("Failed to add partition %d (%s)"),
2559                                         i, strerror (errno));
2560                                 goto cleanup;
2561                         }
2562                 }
2563         }
2564
2565         char *bad_part_list = NULL;
2566         /* now warn about any errors */
2567         for (i = 1; i <= lpn; i++) {
2568                 if (ok[i - 1] || errnums[i - 1] == ENXIO)
2569                         continue;
2570                 if (bad_part_list == NULL) {
2571                           bad_part_list = malloc (lpn * 5);
2572                           if (!bad_part_list)
2573                                   goto cleanup;
2574                           bad_part_list[0] = 0;
2575                 }
2576                 sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
2577         }
2578         if (bad_part_list == NULL)
2579                 ret = 1;
2580         else {
2581                 bad_part_list[strlen (bad_part_list) - 2] = 0;
2582                 if (ped_exception_throw (
2583                         PED_EXCEPTION_ERROR,
2584                         PED_EXCEPTION_IGNORE_CANCEL,
2585                         _("Partition(s) %s on %s have been written, but we have "
2586                           "been unable to inform the kernel of the change, "
2587                           "probably because it/they are in use.  As a result, "
2588                           "the old partition(s) will remain in use.  You "
2589                           "should reboot now before making further changes."),
2590                         bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
2591                         ret = 1;
2592                 free (bad_part_list);
2593         }
2594  cleanup:
2595         free (errnums);
2596         free (ok);
2597         return ret;
2598 }
2599
2600 #ifdef ENABLE_DEVICE_MAPPER
2601 static int
2602 _dm_remove_map_name(char *name)
2603 {
2604         struct dm_task  *task = NULL;
2605         int             rc;
2606
2607         task = dm_task_create(DM_DEVICE_REMOVE);
2608         if (!task)
2609                 return 1;
2610
2611         dm_task_set_name (task, name);
2612
2613         rc = dm_task_run(task);
2614         dm_task_update_nodes();
2615         dm_task_destroy(task);
2616         if (!rc)
2617                 return 1;
2618
2619         return 0;
2620 }
2621
2622 static int
2623 _dm_is_part (struct dm_info *this, char *name)
2624 {
2625         struct dm_task* task = NULL;
2626         struct dm_info* info = alloca(sizeof *info);
2627         struct dm_deps* deps = NULL;
2628         int             rc = 0;
2629         unsigned int    i;
2630
2631         task = dm_task_create(DM_DEVICE_DEPS);
2632         if (!task)
2633                 return 0;
2634
2635         dm_task_set_name(task, name);
2636         if (!dm_task_run(task))
2637                 goto err;
2638
2639         memset(info, '\0', sizeof *info);
2640         dm_task_get_info(task, info);
2641         if (!info->exists)
2642                 goto err;
2643
2644         deps = dm_task_get_deps(task);
2645         if (!deps)
2646                 goto err;
2647
2648         for (i = 0; i < deps->count; i++) {
2649                 unsigned int ma = major(deps->device[i]),
2650                              mi = minor(deps->device[i]);
2651
2652                 if (ma == this->major && mi == this->minor)
2653                         rc = 1;
2654         }
2655
2656 err:
2657         dm_task_destroy(task);
2658         return rc;
2659 }
2660
2661 static int
2662 _dm_remove_parts (PedDevice* dev)
2663 {
2664         struct dm_task*         task = NULL;
2665         struct dm_info*         info = alloca(sizeof *info);
2666         struct dm_names*        names = NULL;
2667         unsigned int            next = 0;
2668         int                     rc;
2669         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
2670
2671         task = dm_task_create(DM_DEVICE_LIST);
2672         if (!task)
2673                 goto err;
2674
2675         if (!dm_task_set_major_minor (task, arch_specific->major,
2676                                       arch_specific->minor, 0))
2677                 goto err;
2678
2679         if (!dm_task_run(task))
2680                 goto err;
2681
2682         memset(info, '\0', sizeof *info);
2683         dm_task_get_info(task, info);
2684         if (!info->exists)
2685                 goto err;
2686
2687         names = dm_task_get_names(task);
2688         if (!names)
2689                 goto err;
2690
2691         rc = 0;
2692         do {
2693                 names = (void *) ((char *) names + next);
2694
2695                 if (_dm_is_part(info, names->name))
2696                         rc += _dm_remove_map_name(names->name);
2697
2698                 next = names->next;
2699         } while (next);
2700
2701         dm_task_update_nodes();
2702         dm_task_destroy(task);
2703         task = NULL;
2704
2705         if (!rc)
2706                 return 1;
2707 err:
2708         if (task)
2709                 dm_task_destroy(task);
2710         ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE,
2711                 _("parted was unable to re-read the partition "
2712                   "table on %s (%s).  This means Linux won't know "
2713                   "anything about the modifications you made. "),
2714                 dev->path, strerror (errno));
2715         return 0;
2716 }
2717
2718 static int
2719 _dm_add_partition (PedDisk* disk, PedPartition* part)
2720 {
2721         char*           vol_name = NULL;
2722         const char*     dev_name = NULL;
2723         char*           params = NULL;
2724         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (disk->dev);
2725
2726         if (!_has_partitions(disk))
2727                 return 0;
2728
2729         /* Get map name from devicemapper */
2730         struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
2731         if (!task)
2732                 goto err;
2733
2734         if (!dm_task_set_major_minor (task, arch_specific->major,
2735                                       arch_specific->minor, 0))
2736                 goto err;
2737
2738         if (!dm_task_run(task))
2739                 goto err;
2740
2741         dev_name = dm_task_get_name (task);
2742
2743         if (asprintf (&vol_name, "%sp%d", dev_name, part->num) == -1)
2744                 goto err;
2745
2746         /* Caution: dm_task_destroy frees dev_name.  */
2747         dm_task_destroy (task);
2748         task = NULL;
2749
2750         if (asprintf (&params, "%d:%d %lld", arch_specific->major,
2751                       arch_specific->minor, part->geom.start) == -1)
2752                 goto err;
2753
2754         task = dm_task_create (DM_DEVICE_CREATE);
2755         if (!task)
2756                 goto err;
2757
2758         dm_task_set_name (task, vol_name);
2759         dm_task_add_target (task, 0, part->geom.length,
2760                 "linear", params);
2761         if (dm_task_run (task)) {
2762                 //printf("0 %ld linear %s\n", part->geom.length, params);
2763                 dm_task_update_nodes();
2764                 dm_task_destroy(task);
2765                 free(params);
2766                 free(vol_name);
2767                 return 1;
2768         } else {
2769                 _dm_remove_map_name(vol_name);
2770         }
2771 err:
2772         dm_task_update_nodes();
2773         if (task)
2774                 dm_task_destroy (task);
2775         free (params);
2776         free (vol_name);
2777         return 0;
2778 }
2779
2780 static int
2781 _dm_reread_part_table (PedDisk* disk)
2782 {
2783         int largest_partnum = ped_disk_get_last_partition_num (disk);
2784         if (largest_partnum <= 0)
2785           return 1;
2786
2787         int     rc = 1;
2788         int     last = PED_MIN (largest_partnum, 16);
2789         int     i;
2790
2791         sync();
2792         if (!_dm_remove_parts(disk->dev))
2793                 rc = 0;
2794
2795         for (i = 1; i <= last; i++) {
2796                 PedPartition*      part;
2797
2798                 part = ped_disk_get_partition (disk, i);
2799                 if (!part)
2800                         continue;
2801
2802                 if (!_dm_add_partition (disk, part))
2803                         rc = 0;
2804         }
2805         return rc;
2806 }
2807 #endif
2808
2809 static int
2810 _have_blkpg ()
2811 {
2812         static int have_blkpg = -1;
2813         int kver;
2814
2815         if (have_blkpg != -1)
2816                 return have_blkpg;
2817
2818         kver = _get_linux_version();
2819         return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
2820 }
2821
2822 /* Return nonzero upon success, 0 if something fails.  */
2823 static int
2824 linux_disk_commit (PedDisk* disk)
2825 {
2826         if (!_has_partitions (disk))
2827                 return 1;
2828
2829 #ifdef ENABLE_DEVICE_MAPPER
2830         if (disk->dev->type == PED_DEVICE_DM)
2831                 return _dm_reread_part_table (disk);
2832 #endif
2833         if (disk->dev->type != PED_DEVICE_FILE) {
2834
2835                 /* We now require BLKPG support.  If this assertion fails,
2836                    please write to the mailing list describing your system.
2837                    Assuming it's never triggered, ...
2838                    FIXME: remove this assertion in 2012.  */
2839                 assert (_have_blkpg ());
2840
2841                 if (!_disk_sync_part_table (disk))
2842                         return 0;
2843         }
2844
2845         return 1;
2846 }
2847
2848 #if USE_BLKID
2849 static PedAlignment*
2850 linux_get_minimum_alignment(const PedDevice *dev)
2851 {
2852         blkid_topology tp = LINUX_SPECIFIC(dev)->topology;
2853         if (!tp)
2854                 return NULL;
2855
2856         if (blkid_topology_get_minimum_io_size(tp) == 0)
2857                 return ped_alignment_new(
2858                         blkid_topology_get_alignment_offset(tp) /
2859                                 dev->sector_size,
2860                         dev->phys_sector_size / dev->sector_size);
2861
2862         return ped_alignment_new(
2863                 blkid_topology_get_alignment_offset(tp) / dev->sector_size,
2864                 blkid_topology_get_minimum_io_size(tp) / dev->sector_size);
2865 }
2866
2867 static PedAlignment*
2868 linux_get_optimum_alignment(const PedDevice *dev)
2869 {
2870         blkid_topology tp = LINUX_SPECIFIC(dev)->topology;
2871         if (!tp)
2872                 return NULL;
2873
2874         /* When PED_DEFAULT_ALIGNMENT is divisible by the *_io_size or
2875            there are no *_io_size values, use the PED_DEFAULT_ALIGNMENT
2876            If one or the other will not divide evenly, fall through to
2877            previous logic. */
2878         unsigned long optimal_io = blkid_topology_get_optimal_io_size(tp);
2879         unsigned long minimum_io = blkid_topology_get_minimum_io_size(tp);
2880         if (
2881             (!optimal_io && !minimum_io)
2882             || (optimal_io && PED_DEFAULT_ALIGNMENT % optimal_io == 0
2883                 && minimum_io && PED_DEFAULT_ALIGNMENT % minimum_io == 0)
2884             || (!minimum_io && optimal_io
2885                 && PED_DEFAULT_ALIGNMENT % optimal_io == 0)
2886             || (!optimal_io && minimum_io
2887                 && PED_DEFAULT_ALIGNMENT % minimum_io == 0)
2888            ) {
2889             /* DASD needs to use minimum alignment */
2890             if (dev->type == PED_DEVICE_DASD)
2891                 return linux_get_minimum_alignment(dev);
2892
2893             return ped_alignment_new(
2894                     blkid_topology_get_alignment_offset(tp) / dev->sector_size,
2895                     PED_DEFAULT_ALIGNMENT / dev->sector_size);
2896         }
2897
2898         /* If optimal_io_size is 0 and we don't meet the other criteria
2899            for using the device.c default, return the minimum alignment. */
2900         if (blkid_topology_get_optimal_io_size(tp) == 0)
2901                 return linux_get_minimum_alignment(dev);
2902
2903         return ped_alignment_new(
2904                 blkid_topology_get_alignment_offset(tp) / dev->sector_size,
2905                 blkid_topology_get_optimal_io_size(tp) / dev->sector_size);
2906 }
2907 #endif
2908
2909 static PedDeviceArchOps linux_dev_ops = {
2910         _new:           linux_new,
2911         destroy:        linux_destroy,
2912         is_busy:        linux_is_busy,
2913         open:           linux_open,
2914         refresh_open:   linux_refresh_open,
2915         close:          linux_close,
2916         refresh_close:  linux_refresh_close,
2917         read:           linux_read,
2918         write:          linux_write,
2919         check:          linux_check,
2920         sync:           linux_sync,
2921         sync_fast:      linux_sync_fast,
2922         probe_all:      linux_probe_all,
2923 #if USE_BLKID
2924         get_minimum_alignment:  linux_get_minimum_alignment,
2925         get_optimum_alignment:  linux_get_optimum_alignment,
2926 #endif
2927 };
2928
2929 PedDiskArchOps linux_disk_ops =  {
2930         partition_get_path:     linux_partition_get_path,
2931         partition_is_busy:      linux_partition_is_busy,
2932         disk_commit:            linux_disk_commit
2933 };
2934
2935 PedArchitecture ped_linux_arch = {
2936         dev_ops:        &linux_dev_ops,
2937         disk_ops:       &linux_disk_ops
2938 };