OSDN Git Service

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