OSDN Git Service

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