OSDN Git Service

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