OSDN Git Service

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