OSDN Git Service

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