OSDN Git Service

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