OSDN Git Service

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