OSDN Git Service

Don't try to avoid "free (x)" when x is NULL.
[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 #define XVD_MAJOR               202
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
394 static int
395 _probe_dm_devices ()
396 {
397        DIR*            mapper_dir;
398        struct dirent*  dent;
399        char            buf [512];      /* readdir(3) claims d_name[256] */
400        struct stat     st;
401
402        mapper_dir = opendir ("/dev/mapper");
403        if (!mapper_dir)
404                return 0;
405
406        /* Search the /dev/mapper directory for devices w/ the same major
407         * number that was returned from _probe_lvm_major().
408         */
409        while ((dent = readdir (mapper_dir))) {
410                if (strcmp (dent->d_name, ".")  == 0 ||
411                    strcmp (dent->d_name, "..") == 0)
412                        continue;
413
414                snprintf (buf, sizeof (buf), "/dev/mapper/%s", dent->d_name);
415
416                if (stat (buf, &st) != 0)
417                        continue;
418
419                if (_is_dm_major(major(st.st_rdev)))
420                        _ped_device_probe (buf);
421        }
422        closedir (mapper_dir);
423
424        return 1;
425 }
426 #endif
427
428 static int
429 _device_stat (PedDevice* dev, struct stat * dev_stat)
430 {
431         PED_ASSERT (dev != NULL, return 0);
432         PED_ASSERT (!dev->external_mode, return 0);
433
434         while (1) {
435                 if (!stat (dev->path, dev_stat)) {
436                         return 1;
437                 } else {
438                         if (ped_exception_throw (
439                                 PED_EXCEPTION_ERROR,
440                                 PED_EXCEPTION_RETRY_CANCEL,
441                                 _("Could not stat device %s - %s."),
442                                 dev->path,
443                                 strerror (errno))
444                                         != PED_EXCEPTION_RETRY)
445                                 return 0;
446                 }
447         }
448 }
449
450 static int
451 _device_probe_type (PedDevice* dev)
452 {
453         struct stat             dev_stat;
454         int                     dev_major;
455         int                     dev_minor;
456
457         if (!_device_stat (dev, &dev_stat))
458                 return 0;
459
460         if (!S_ISBLK(dev_stat.st_mode)) {
461                 dev->type = PED_DEVICE_FILE;
462                 return 1;
463         }
464
465         dev_major = major (dev_stat.st_rdev);
466         dev_minor = minor (dev_stat.st_rdev);
467
468         if (SCSI_BLK_MAJOR (dev_major) && (dev_minor % 0x10 == 0)) {
469                 dev->type = PED_DEVICE_SCSI;
470         } else if (_is_ide_major (dev_major) && (dev_minor % 0x40 == 0)) {
471                 dev->type = PED_DEVICE_IDE;
472         } else if (dev_major == DAC960_MAJOR && (dev_minor % 0x8 == 0)) {
473                 dev->type = PED_DEVICE_DAC960;
474         } else if (dev_major == ATARAID_MAJOR && (dev_minor % 0x10 == 0)) {
475                 dev->type = PED_DEVICE_ATARAID;
476         } else if (dev_major == DASD_MAJOR && (dev_minor % 0x4 == 0)) {
477                 dev->type = PED_DEVICE_DASD;
478         } else if (dev_major == VIODASD_MAJOR && (dev_minor % 0x8 == 0)) {
479                 dev->type = PED_DEVICE_VIODASD;
480         } else if (_is_sx8_major(dev_major) && (dev_minor % 0x20 == 0)) {
481                 dev->type = PED_DEVICE_SX8;
482         } else if (_is_i2o_major (dev_major) && (dev_minor % 0x10 == 0)) {
483                 dev->type = PED_DEVICE_I2O;
484         } else if (_is_cpqarray_major (dev_major) && (dev_minor % 0x10 == 0)) {
485                 dev->type = PED_DEVICE_CPQARRAY;
486         } else if (dev_major == UBD_MAJOR && (dev_minor % 0x10 == 0)) {
487                 dev->type = PED_DEVICE_UBD;
488 #ifdef ENABLE_DEVICE_MAPPER
489         } else if (_is_dm_major(dev_major)) {
490                 dev->type = PED_DEVICE_DM;
491 #endif
492         } else if (dev_major == XVD_MAJOR && (dev_minor % 0x10 == 0)) {
493                 dev->type = PED_DEVICE_XVD;
494         } else {
495                 dev->type = PED_DEVICE_UNKNOWN;
496         }
497
498         return 1;
499 }
500
501 static int
502 _get_linux_version ()
503 {
504         static int kver = -1;
505
506         struct utsname uts;
507         int major;
508         int minor;
509         int teeny;
510
511         if (kver != -1)
512                 return kver;
513
514         if (uname (&uts))
515                 return kver = 0;
516         if (sscanf (uts.release, "%u.%u.%u", &major, &minor, &teeny) != 3)
517                 return kver = 0;
518
519         return kver = KERNEL_VERSION (major, minor, teeny);
520 }
521
522 static int
523 _have_devfs ()
524 {
525         static int have_devfs = -1;
526         struct stat sb;
527
528         if (have_devfs != -1)
529                 return have_devfs;
530
531         /* the presence of /dev/.devfsd implies that DevFS is active */
532         if (stat("/dev/.devfsd", &sb) < 0)
533                 return have_devfs = 0;
534
535         return have_devfs = S_ISCHR(sb.st_mode) ? 1 : 0;
536 }
537
538 static void 
539 _device_set_sector_size (PedDevice* dev)
540 {
541         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
542         int sector_size;
543         
544         dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
545         dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
546
547         PED_ASSERT (dev->open_count, return);
548
549         if (_get_linux_version() < KERNEL_VERSION (2,3,0)) {
550                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
551                 return;
552         }
553         
554         if (ioctl (arch_specific->fd, BLKSSZGET, &sector_size)) {
555                 ped_exception_throw (
556                         PED_EXCEPTION_WARNING,
557                         PED_EXCEPTION_OK,
558                         _("Could not determine sector size for %s: %s.\n"
559                           "Using the default sector size (%lld)."),
560                         dev->path, strerror (errno), PED_SECTOR_SIZE_DEFAULT);
561         } else {
562                 dev->sector_size = (long long)sector_size;
563         }
564
565         /* Return PED_SECTOR_SIZE_DEFAULT for DASDs. */
566         if (dev->type == PED_DEVICE_DASD) {
567                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
568         }
569
570         if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
571                 ped_exception_throw (
572                         PED_EXCEPTION_WARNING,
573                         PED_EXCEPTION_OK,
574                         _("Device %s has a logical sector size of %lld.  Not "
575                           "all parts of GNU Parted support this at the moment, "
576                           "and the working code is HIGHLY EXPERIMENTAL.\n"),
577                         dev->path, dev->sector_size);
578         }
579 }
580
581 static int
582 _kernel_has_blkgetsize64(void)
583 {
584         int version = _get_linux_version();
585
586         if (version >= KERNEL_VERSION (2,5,4)) return 1;
587         if (version <  KERNEL_VERSION (2,5,0) &&
588             version >= KERNEL_VERSION (2,4,18)) return 1;
589         return 0;
590 }
591
592 /* TODO: do a binary search if BLKGETSIZE doesn't work?! */
593 static PedSector
594 _device_get_length (PedDevice* dev)
595 {
596         unsigned long           size;
597         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
598         uint64_t bytes=0;
599
600
601         PED_ASSERT (dev->open_count > 0, return 0);
602         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
603
604         if (_kernel_has_blkgetsize64()) {
605                 if (ioctl(arch_specific->fd, BLKGETSIZE64, &bytes) == 0) {
606                         return bytes / dev->sector_size;
607                 }
608         }
609
610         if (ioctl (arch_specific->fd, BLKGETSIZE, &size)) {
611                 ped_exception_throw (
612                         PED_EXCEPTION_BUG,
613                         PED_EXCEPTION_CANCEL,
614                         _("Unable to determine the size of %s (%s)."),
615                         dev->path,
616                         strerror (errno));
617                 return 0;
618         }
619
620         return size;
621 }
622
623 static int
624 _device_probe_geometry (PedDevice* dev)
625 {
626         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
627         struct stat             dev_stat;
628         struct hd_geometry      geometry;
629
630         if (!_device_stat (dev, &dev_stat))
631                 return 0;
632         PED_ASSERT (S_ISBLK (dev_stat.st_mode), return 0);
633
634         _device_set_sector_size (dev);
635         
636         dev->length = _device_get_length (dev);
637         if (!dev->length)
638                 return 0;
639
640         /* The GETGEO ioctl is no longer useful (as of linux 2.6.x).  We could
641          * still use it in 2.4.x, but this is contentious.  Perhaps we should
642          * move to EDD. */
643         dev->bios_geom.sectors = 63;
644         dev->bios_geom.heads = 255;
645         dev->bios_geom.cylinders
646                 = dev->length / (63 * 255);
647
648         /* FIXME: what should we put here?  (TODO: discuss on linux-kernel) */
649         if (!ioctl (arch_specific->fd, HDIO_GETGEO, &geometry)
650                         && geometry.sectors && geometry.heads) {
651                 dev->hw_geom.sectors = geometry.sectors;
652                 dev->hw_geom.heads = geometry.heads;
653                 dev->hw_geom.cylinders
654                         = dev->length / (dev->hw_geom.heads
655                                          * dev->hw_geom.sectors);
656         } else {
657                 dev->hw_geom = dev->bios_geom;
658         }
659
660         return 1;
661 }
662
663 static char*
664 strip_name(char* str)
665 {
666         int     i;
667         int     end = 0;
668
669         for (i = 0; str[i] != 0; i++) {
670                 if (!isspace (str[i])
671                     || (isspace (str[i]) && !isspace (str[i+1]) && str[i+1])) {
672                         str [end] = str[i];
673                         end++;
674                 }
675         }
676         str[end] = 0;
677         return strdup (str);
678 }
679
680 static int
681 init_ide (PedDevice* dev)
682 {
683         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
684         struct stat             dev_stat;
685         int                     dev_major;
686         struct hd_driveid       hdi;
687         PedExceptionOption      ex_status;
688         char                    hdi_buf[41];
689         int                     sector_multiplier = 0;
690         
691         if (!_device_stat (dev, &dev_stat))
692                 goto error;
693
694         dev_major = major (dev_stat.st_rdev);
695
696         if (!ped_device_open (dev))
697                 goto error;
698
699         if (ioctl (arch_specific->fd, HDIO_GET_IDENTITY, &hdi)) {
700                 ex_status = ped_exception_throw (
701                                 PED_EXCEPTION_WARNING,
702                                 PED_EXCEPTION_IGNORE_CANCEL,
703                                 _("Could not get identity of device %s - %s"),
704                                 dev->path, strerror (errno));
705                 switch (ex_status) {
706                         case PED_EXCEPTION_CANCEL:
707                                 goto error_close_dev;
708
709                         case PED_EXCEPTION_UNHANDLED:
710                                 ped_exception_catch ();
711                         case PED_EXCEPTION_IGNORE:
712                                 dev->model = strdup(_("Generic IDE"));
713                                 break;
714                         default:
715                                 PED_ASSERT (0, (void) 0);
716                                 break;
717                 }
718         } else {
719                 /* hdi.model is not guaranteed to be NULL terminated */
720                 memcpy (hdi_buf, hdi.model, 40);
721                 hdi_buf[40] = '\0';
722                 dev->model = strip_name (hdi_buf);
723                 
724                 if (!hdi.ata7_sectinfo.valid1 && hdi.ata7_sectinfo.valid2)
725                         sector_multiplier = hdi.ata7_sectinfo.multiplier;
726                 else
727                         sector_multiplier = 1;
728                         
729                 if (sector_multiplier != 1) {
730                         ex_status = ped_exception_throw (
731                                 PED_EXCEPTION_WARNING,
732                                 PED_EXCEPTION_IGNORE_CANCEL,
733                                 _("Device %s has multiple (%d) logical sectors "
734                                   "per physical sector.\n"
735                                   "GNU Parted supports this EXPERIMENTALLY for "
736                                   "some special disk label/file system "
737                                   "combinations, e.g. GPT and ext2/3.\n"
738                                   "Please consult the web site for up-to-date "
739                                   "information."),
740                                 dev->path, sector_multiplier);
741                         
742                         switch (ex_status) {
743                                 case PED_EXCEPTION_CANCEL:
744                                         goto error_close_dev;
745
746                                 case PED_EXCEPTION_UNHANDLED:
747                                         ped_exception_catch ();
748                                 case PED_EXCEPTION_IGNORE:
749                                         break;
750                                 default:
751                                         PED_ASSERT (0, (void) 0);
752                                         break;
753                         }
754                 }
755                 
756                 /* XXX sector_size has not been set yet! */
757                 /* dev->phys_sector_size = dev->sector_size
758                    * sector_multiplier;*/
759                 dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
760         }
761
762         if (!_device_probe_geometry (dev))
763                 goto error_close_dev;
764
765         ped_device_close (dev);
766         return 1;
767
768 error_close_dev:
769         ped_device_close (dev);
770 error:
771         return 0;
772 }
773
774 /* This function reads the /sys entry named "file" for device "dev". */
775 static char *
776 read_device_sysfs_file (PedDevice *dev, const char *file)
777 {
778         FILE *f;
779         char name_buf[128];
780         char buf[256];
781
782         snprintf (name_buf, 127, "/sys/block/%s/device/%s",
783                   basename (dev->path), file);
784
785         if ((f = fopen (name_buf, "r")) == NULL)
786                 return NULL;
787
788         if (fgets (buf, 255, f) == NULL)
789                 return NULL;
790
791         fclose (f);
792         return strip_name (buf);
793 }
794
795 /* This function sends a query to a SCSI device for vendor and product
796  * information.  It uses the deprecated SCSI_IOCTL_SEND_COMMAND to
797  * issue this query.
798  */
799 static int
800 scsi_query_product_info (PedDevice* dev, char **vendor, char **product)
801 {
802         /* The following are defined by the SCSI-2 specification. */
803         typedef struct _scsi_inquiry_cmd
804         {
805                 uint8_t op;
806                 uint8_t lun;          /* bits 5-7 denote the LUN */
807                 uint8_t page_code;
808                 uint8_t reserved;
809                 uint8_t alloc_length;
810                 uint8_t control;
811         } __attribute__((packed)) scsi_inquiry_cmd_t;
812
813         typedef struct _scsi_inquiry_data
814         {
815                 uint8_t peripheral_info;
816                 uint8_t device_info;
817                 uint8_t version_info;
818                 uint8_t _field1;
819                 uint8_t additional_length;
820                 uint8_t _reserved1;
821                 uint8_t _reserved2;
822                 uint8_t _field2;
823                 uint8_t vendor_id[8];
824                 uint8_t product_id[16];
825                 uint8_t product_revision[4];
826                 uint8_t vendor_specific[20];
827                 uint8_t _reserved3[40];
828         } __attribute__((packed)) scsi_inquiry_data_t;
829
830         struct scsi_arg
831         {
832                 unsigned int inlen;
833                 unsigned int outlen;
834
835                 union arg_data
836                 {
837                         scsi_inquiry_data_t out;
838                         scsi_inquiry_cmd_t  in;
839                 } data;
840         } arg;
841
842         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
843         char    buf[32];
844
845         *vendor = NULL;
846         *product = NULL;
847
848         memset (&arg, 0x00, sizeof(struct scsi_arg));
849         arg.inlen  = 0;
850         arg.outlen = sizeof(scsi_inquiry_data_t);
851         arg.data.in.op  = INQUIRY;
852         arg.data.in.lun = dev->host << 5;
853         arg.data.in.alloc_length = sizeof(scsi_inquiry_data_t);
854         arg.data.in.page_code = 0;
855         arg.data.in.reserved = 0;
856         arg.data.in.control = 0;
857
858         if (ioctl (arch_specific->fd, SCSI_IOCTL_SEND_COMMAND, &arg) < 0)
859                 return 0;
860
861         memcpy (buf, arg.data.out.vendor_id, 8);
862         buf[8] = '\0';
863         *vendor = strip_name (buf);
864
865         memcpy (buf, arg.data.out.product_id, 16);
866         buf[16] = '\0';
867         *product = strip_name (buf);
868
869         return 1;
870 }
871
872 /* This function provides the vendor and product name for a SCSI device.
873  * It supports both the modern /sys interface and direct queries
874  * via the deprecated ioctl, SCSI_IOCTL_SEND_COMMAND.
875  */
876 static int
877 scsi_get_product_info (PedDevice* dev, char **vendor, char **product)
878 {
879         *vendor = read_device_sysfs_file (dev, "vendor");
880         *product = read_device_sysfs_file (dev, "model");
881         if (*vendor && *product)
882                 return 1;
883
884         return scsi_query_product_info (dev, vendor, product);
885 }
886
887 static int
888 init_scsi (PedDevice* dev)
889 {
890         struct scsi_idlun
891         {
892                 uint32_t dev_id;
893                 uint32_t host_unique_id;
894         } idlun;
895
896         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
897         char* vendor;
898         char* product;
899
900         if (!ped_device_open (dev))
901                 goto error;
902
903         if (ioctl (arch_specific->fd, SCSI_IOCTL_GET_IDLUN, &idlun) < 0) {
904                 dev->host = 0;
905                 dev->did = 0;
906                 if (ped_exception_throw (
907                         PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
908                         _("Error initialising SCSI device %s - %s"),
909                         dev->path, strerror (errno))
910                                 != PED_EXCEPTION_IGNORE)
911                         goto error_close_dev;
912                 if (!_device_probe_geometry (dev))
913                         goto error_close_dev;
914                 ped_device_close (dev);
915                 return 1;
916         }
917
918         dev->host = idlun.host_unique_id;
919         dev->did  = idlun.dev_id;
920
921         dev->model = (char*) ped_malloc (8 + 16 + 2);
922         if (!dev->model)
923                 goto error_close_dev;
924
925         if (scsi_get_product_info (dev, &vendor, &product)) {
926                 sprintf (dev->model, "%.8s %.16s", vendor, product);
927                 ped_free (vendor);
928                 ped_free (product);
929         } else {
930                 strcpy (dev->model, "Generic SCSI");
931         }
932
933         if (!_device_probe_geometry (dev))
934                 goto error_close_dev;
935
936         ped_device_close (dev);
937         return 1;
938
939 error_close_dev:
940         ped_device_close (dev);
941 error:
942         return 0;
943 }
944
945 static int
946 init_file (PedDevice* dev)
947 {
948         struct stat     dev_stat;
949  
950         if (!_device_stat (dev, &dev_stat))
951                 goto error;
952         if (!ped_device_open (dev))
953                 goto error;
954
955         if (S_ISBLK(dev_stat.st_mode))
956                 dev->length = _device_get_length (dev);
957         else
958                 dev->length = dev_stat.st_size / 512;
959         if (dev->length <= 0) {
960                 ped_exception_throw (
961                         PED_EXCEPTION_ERROR,
962                         PED_EXCEPTION_CANCEL,
963                         _("The device %s has zero length, and can't possibly "
964                           "store a file system or partition table.  Perhaps "
965                           "you selected the wrong device?"),
966                         dev->path);
967                 goto error_close_dev;
968         }
969
970         ped_device_close (dev);
971
972         dev->bios_geom.cylinders = dev->length / 4 / 32;
973         dev->bios_geom.heads = 4;
974         dev->bios_geom.sectors = 32;
975         dev->hw_geom = dev->bios_geom;
976         dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
977         dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
978         dev->model = strdup ("");
979         
980         return 1;
981         
982 error_close_dev:
983         ped_device_close (dev);
984 error:
985         return 0;
986 }
987
988 static int
989 init_dasd (PedDevice* dev, char* model_name)
990 {
991         struct stat             dev_stat;
992         struct hd_geometry      geo;
993         char *errstr = 0;
994
995         if (!_device_stat (dev, &dev_stat))
996                 goto error;
997
998         if (!ped_device_open (dev))
999                 goto error;
1000
1001         LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev);
1002
1003         PED_ASSERT (S_ISBLK (dev_stat.st_mode), return 0);
1004
1005         _device_set_sector_size (dev);
1006         if (!dev->sector_size)
1007                 goto error_close_dev;
1008
1009         dev->length = _device_get_length (dev);
1010         if (!dev->length)
1011                 goto error_close_dev;
1012
1013         if (!ioctl (arch_specific->fd, HDIO_GETGEO, &geo)) {
1014                 dev->hw_geom.sectors = geo.sectors;
1015                 dev->hw_geom.heads = geo.heads;
1016                 dev->hw_geom.cylinders = dev->length
1017                         / (dev->hw_geom.heads * dev->hw_geom.sectors)
1018                         / (dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
1019                 dev->bios_geom = dev->hw_geom;
1020         } else {
1021                 dev->bios_geom.sectors = 12;
1022                 dev->bios_geom.heads = 15;
1023                 dev->bios_geom.cylinders = dev->length
1024                         / (dev->hw_geom.heads * dev->hw_geom.sectors)
1025                         / (dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
1026                 dev->hw_geom = dev->bios_geom;
1027         }
1028
1029         dev->model = strdup (model_name);
1030
1031         ped_device_close (dev);
1032         return 1;
1033
1034         ped_exception_throw ( PED_EXCEPTION_ERROR,
1035                               PED_EXCEPTION_IGNORE_CANCEL,
1036                               errstr );
1037
1038 error_close_dev:
1039         ped_device_close (dev);
1040 error:
1041         return 0;
1042 }
1043
1044 static int
1045 init_generic (PedDevice* dev, char* model_name)
1046 {
1047         struct stat             dev_stat;
1048         PedExceptionOption      ex_status;
1049
1050         if (!_device_stat (dev, &dev_stat))
1051                 goto error;
1052
1053         if (!ped_device_open (dev))
1054                 goto error;
1055
1056         ped_exception_fetch_all ();
1057         if (_device_probe_geometry (dev)) {
1058                 ped_exception_leave_all ();
1059         } else {
1060                 /* hack to allow use of files, for testing */
1061                 ped_exception_catch ();
1062                 ped_exception_leave_all ();
1063
1064                 ex_status = ped_exception_throw (
1065                                 PED_EXCEPTION_WARNING,
1066                                 PED_EXCEPTION_IGNORE_CANCEL,
1067                                 _("Unable to determine geometry of "
1068                                 "file/device %s.  You should not use Parted "
1069                                 "unless you REALLY know what you're doing!"),
1070                                 dev->path);
1071                 switch (ex_status) {
1072                         case PED_EXCEPTION_CANCEL:
1073                                 goto error_close_dev;
1074
1075                         case PED_EXCEPTION_UNHANDLED:
1076                                 ped_exception_catch ();
1077                         case PED_EXCEPTION_IGNORE:
1078                                 break;
1079                         default:
1080                                 PED_ASSERT (0, (void) 0);
1081                                 break;
1082                 }
1083
1084                 /* what should we stick in here? */
1085                 dev->length = dev_stat.st_size / PED_SECTOR_SIZE_DEFAULT;
1086                 dev->bios_geom.cylinders = dev->length / 4 / 32;
1087                 dev->bios_geom.heads = 4;
1088                 dev->bios_geom.sectors = 32;
1089                 dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
1090                 dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
1091         }
1092
1093         dev->model = strdup (model_name);
1094
1095         ped_device_close (dev);
1096         return 1;
1097
1098 error_close_dev:
1099         ped_device_close (dev);
1100 error:
1101         return 0;
1102 }
1103
1104 static PedDevice*
1105 linux_new (const char* path)
1106 {
1107         PedDevice*      dev;
1108
1109         PED_ASSERT (path != NULL, return NULL);
1110
1111         dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
1112         if (!dev)
1113                 goto error;
1114
1115         dev->path = strdup (path);
1116         if (!dev->path)
1117                 goto error_free_dev;
1118
1119         dev->arch_specific
1120                 = (LinuxSpecific*) ped_malloc (sizeof (LinuxSpecific));
1121         if (!dev->arch_specific)
1122                 goto error_free_path;
1123
1124         dev->open_count = 0;
1125         dev->read_only = 0;
1126         dev->external_mode = 0;
1127         dev->dirty = 0;
1128         dev->boot_dirty = 0;
1129
1130         if (!_device_probe_type (dev))
1131                 goto error_free_arch_specific;
1132
1133         switch (dev->type) {
1134         case PED_DEVICE_IDE:
1135                 if (!init_ide (dev))
1136                         goto error_free_arch_specific;
1137                 break;
1138
1139         case PED_DEVICE_SCSI:
1140                 if (!init_scsi (dev))
1141                         goto error_free_arch_specific;
1142                 break;
1143
1144         case PED_DEVICE_DAC960:
1145                 if (!init_generic (dev, _("DAC960 RAID controller")))
1146                         goto error_free_arch_specific;
1147                 break;
1148
1149         case PED_DEVICE_SX8:
1150                 if (!init_generic (dev, _("Promise SX8 SATA Device")))
1151                         goto error_free_arch_specific;
1152                 break;
1153
1154         case PED_DEVICE_DASD:
1155                 if (!init_dasd (dev, _("IBM S390 DASD drive")))
1156                         goto error_free_arch_specific;
1157                 break;
1158
1159         case PED_DEVICE_VIODASD:
1160                 if (!init_generic (dev, _("IBM iSeries Virtual DASD")))
1161                         goto error_free_arch_specific;
1162                 break;
1163
1164         case PED_DEVICE_CPQARRAY:
1165                 if (!init_generic (dev, _("Compaq Smart Array")))
1166                         goto error_free_arch_specific;
1167                 break;
1168
1169         case PED_DEVICE_ATARAID:
1170                 if (!init_generic (dev, _("ATARAID Controller")))
1171                         goto error_free_arch_specific;
1172                 break;
1173
1174         case PED_DEVICE_I2O:
1175                 if (!init_generic (dev, _("I2O Controller")))
1176                         goto error_free_arch_specific;
1177                 break;
1178
1179         case PED_DEVICE_UBD:
1180                 if (!init_generic (dev, _("User-Mode Linux UBD")))
1181                         goto error_free_arch_specific;
1182                 break;
1183
1184         case PED_DEVICE_FILE:
1185                 if (!init_file (dev))
1186                         goto error_free_arch_specific;
1187                 break;
1188
1189 #ifdef ENABLE_DEVICE_MAPPER
1190         case PED_DEVICE_DM:
1191                 if (!init_generic (dev, _("Linux device-mapper")))
1192                         goto error_free_arch_specific;
1193                 break;
1194 #endif
1195
1196         case PED_DEVICE_XVD:
1197                 if (!init_generic (dev, _("Xen Virtual Block Device")))
1198                         goto error_free_arch_specific;
1199                 break;
1200
1201         case PED_DEVICE_UNKNOWN:
1202                 if (!init_generic (dev, _("Unknown")))
1203                         goto error_free_arch_specific;
1204                 break;
1205
1206         default:
1207                 ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
1208                                 PED_EXCEPTION_CANCEL,
1209                                 _("ped_device_new()  Unsupported device type"));
1210                 goto error_free_arch_specific;
1211         }
1212         return dev;
1213
1214 error_free_arch_specific:
1215         ped_free (dev->arch_specific);
1216 error_free_path:
1217         ped_free (dev->path);
1218 error_free_dev:
1219         ped_free (dev);
1220 error:
1221         return NULL;
1222 }
1223
1224 static void
1225 linux_destroy (PedDevice* dev)
1226 {
1227         ped_free (dev->arch_specific);
1228         ped_free (dev->path);
1229         ped_free (dev->model);
1230         ped_free (dev);
1231 }
1232
1233 static int
1234 linux_is_busy (PedDevice* dev)
1235 {
1236         int     i;
1237         char*   part_name;
1238
1239         if (_partition_is_mounted_by_path (dev->path))
1240                 return 1;
1241
1242         for (i = 0; i < 32; i++) {
1243                 int status;
1244
1245                 part_name = _device_get_part_path (dev, i);
1246                 if (!part_name)
1247                         return 1;
1248                 status = _partition_is_mounted_by_path (part_name);
1249                 ped_free (part_name);
1250
1251                 if (status)
1252                         return 1;
1253         }
1254
1255         return 0;
1256 }
1257
1258 /* we need to flush the master device, and all the partition devices,
1259  * because there is no coherency between the caches.
1260  * We should only flush unmounted partition devices, because:
1261  *  - there is never a need to flush them (we're not doing IO there)
1262  *  - flushing a device that is mounted causes unnecessary IO, and can
1263  * even screw journaling & friends up.  Even cause oopsen!
1264  */
1265 static void
1266 _flush_cache (PedDevice* dev)
1267 {
1268         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1269         int             i;
1270
1271         if (dev->read_only)
1272                 return;
1273         dev->dirty = 0;
1274
1275         ioctl (arch_specific->fd, BLKFLSBUF);
1276
1277         for (i = 1; i < 16; i++) {
1278                 char*           name;
1279                 int             fd;
1280
1281                 name = _device_get_part_path (dev, i);
1282                 if (!name)
1283                         break;
1284                 if (!_partition_is_mounted_by_path (name)) {
1285                         fd = open (name, WR_MODE, 0);
1286                         if (fd > 0) {
1287                                 ioctl (fd, BLKFLSBUF);
1288                                 close (fd);
1289                         }
1290                 }
1291                 ped_free (name);
1292         }
1293 }
1294
1295 static int
1296 linux_open (PedDevice* dev)
1297 {
1298         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1299
1300 retry:
1301         arch_specific->fd = open (dev->path, RW_MODE);
1302
1303         if (arch_specific->fd == -1) {
1304                 char*   rw_error_msg = strerror (errno);
1305
1306                 arch_specific->fd = open (dev->path, RD_MODE);
1307
1308                 if (arch_specific->fd == -1) {
1309                         if (ped_exception_throw (
1310                                 PED_EXCEPTION_ERROR,
1311                                 PED_EXCEPTION_RETRY_CANCEL,
1312                                 _("Error opening %s: %s"),
1313                                 dev->path, strerror (errno))
1314                                         != PED_EXCEPTION_RETRY) {
1315                                 return 0;
1316                         } else {
1317                                 goto retry;
1318                         }
1319                 } else {
1320                         ped_exception_throw (
1321                                 PED_EXCEPTION_WARNING,
1322                                 PED_EXCEPTION_OK,
1323                                 _("Unable to open %s read-write (%s).  %s has "
1324                                   "been opened read-only."),
1325                                 dev->path, rw_error_msg, dev->path);
1326                         dev->read_only = 1;
1327                 }
1328         } else {
1329                 dev->read_only = 0;
1330         }
1331
1332         _flush_cache (dev);
1333
1334         return 1;
1335 }
1336
1337 static int
1338 linux_refresh_open (PedDevice* dev)
1339 {
1340         return 1;
1341 }
1342
1343 static int
1344 linux_close (PedDevice* dev)
1345 {
1346         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1347
1348         if (dev->dirty)
1349                 _flush_cache (dev);
1350         close (arch_specific->fd);
1351         return 1;
1352 }
1353
1354 static int
1355 linux_refresh_close (PedDevice* dev)
1356 {
1357         if (dev->dirty)
1358                 _flush_cache (dev);
1359         return 1;
1360 }
1361
1362 #if SIZEOF_OFF_T < 8
1363
1364 static _syscall5(int,_llseek,
1365                  unsigned int, fd,
1366                  unsigned long, offset_high,
1367                  unsigned long, offset_low,
1368                  loff_t*, result,
1369                  unsigned int, origin)
1370
1371 loff_t
1372 llseek (unsigned int fd, loff_t offset, unsigned int whence)
1373 {
1374         loff_t result;
1375         int retval;
1376
1377         retval = _llseek(fd,
1378                          ((unsigned long long)offset) >> 32,
1379                          ((unsigned long long)offset) & 0xffffffff,
1380                          &result,
1381                          whence);
1382         return (retval==-1 ? (loff_t) retval : result);
1383 }
1384
1385 #endif /* SIZEOF_OFF_T < 8 */
1386
1387 static int
1388 _device_seek (const PedDevice* dev, PedSector sector)
1389 {
1390         LinuxSpecific*  arch_specific;
1391         
1392         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
1393         PED_ASSERT (dev != NULL, return 0);
1394         PED_ASSERT (!dev->external_mode, return 0);
1395         
1396         arch_specific = LINUX_SPECIFIC (dev);
1397
1398 #if SIZEOF_OFF_T < 8
1399         if (sizeof (off_t) < 8) {
1400                 loff_t  pos = (loff_t)(sector * dev->sector_size);
1401                 return llseek (arch_specific->fd, pos, SEEK_SET) == pos;
1402         } else
1403 #endif
1404         {
1405                 off_t   pos = sector * dev->sector_size;
1406                 return lseek (arch_specific->fd, pos, SEEK_SET) == pos;
1407         }
1408 }
1409
1410 static int
1411 _read_lastoddsector (const PedDevice* dev, void* buffer)
1412 {
1413         LinuxSpecific*                  arch_specific;
1414         struct blkdev_ioctl_param       ioctl_param;
1415
1416         PED_ASSERT(dev != NULL, return 0);
1417         PED_ASSERT(buffer != NULL, return 0);
1418         
1419         arch_specific = LINUX_SPECIFIC (dev);
1420
1421 retry:
1422         ioctl_param.block = 0; /* read the last sector */
1423         ioctl_param.content_length = dev->sector_size;
1424         ioctl_param.block_contents = buffer;
1425         
1426         if (ioctl(arch_specific->fd, BLKGETLASTSECT, &ioctl_param) == -1) {
1427                 PedExceptionOption      opt;
1428                 opt = ped_exception_throw (
1429                         PED_EXCEPTION_ERROR,
1430                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1431                         _("%s during read on %s"),
1432                         strerror (errno), dev->path);
1433
1434                 if (opt == PED_EXCEPTION_CANCEL)
1435                         return 0;
1436                 if (opt == PED_EXCEPTION_RETRY)
1437                         goto retry;
1438         }
1439
1440         return 1;
1441 }
1442
1443 static int
1444 linux_read (const PedDevice* dev, void* buffer, PedSector start,
1445             PedSector count)
1446 {
1447         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1448         PedExceptionOption      ex_status;
1449         void*                   diobuf = NULL;
1450
1451         PED_ASSERT (dev != NULL, return 0);
1452         PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
1453
1454         if (_get_linux_version() < KERNEL_VERSION (2,6,0)) {
1455                 /* Kludge.  This is necessary to read/write the last
1456                    block of an odd-sized disk, until Linux 2.5.x kernel fixes.
1457                 */
1458                 if (dev->type != PED_DEVICE_FILE && (dev->length & 1)
1459                     && start + count - 1 == dev->length - 1)
1460                         return ped_device_read (dev, buffer, start, count - 1)
1461                                 && _read_lastoddsector (
1462                                         dev, (char *) buffer + (count-1) * 512);
1463         }
1464         while (1) {
1465                 if (_device_seek (dev, start))
1466                         break;
1467
1468                 ex_status = ped_exception_throw (
1469                         PED_EXCEPTION_ERROR,
1470                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1471                         _("%s during seek for read on %s"),
1472                         strerror (errno), dev->path);
1473
1474                 switch (ex_status) {
1475                         case PED_EXCEPTION_IGNORE:
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                                 return 0;
1485                         default:
1486                                 PED_ASSERT (0, (void) 0);
1487                                 break;
1488                 }
1489         }
1490
1491         size_t read_length = count * dev->sector_size;
1492         if (posix_memalign (&diobuf, dev->sector_size, read_length) != 0)
1493                 return 0;
1494
1495         while (1) {
1496                 ssize_t status = read (arch_specific->fd, diobuf, read_length);
1497                 if (status > 0)
1498                         memcpy(buffer, diobuf, status);
1499                 if (status == (ssize_t) read_length)
1500                         break;
1501                 if (status > 0) {
1502                         read_length -= status;
1503                         buffer = (char *) buffer + status;
1504                         continue;
1505                 }
1506
1507                 ex_status = ped_exception_throw (
1508                         PED_EXCEPTION_ERROR,
1509                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1510                         _("%s during read on %s"),
1511                         strerror (errno),
1512                         dev->path);
1513
1514                 switch (ex_status) {
1515                         case PED_EXCEPTION_IGNORE:
1516                                 free(diobuf);
1517                                 return 1;
1518
1519                         case PED_EXCEPTION_RETRY:
1520                                 break;
1521
1522                         case PED_EXCEPTION_UNHANDLED:
1523                                 ped_exception_catch ();
1524                         case PED_EXCEPTION_CANCEL:
1525                                 free(diobuf);
1526                                 return 0;
1527                         default:
1528                                 PED_ASSERT (0, (void) 0);
1529                                 break;
1530                 }
1531         }
1532
1533         free (diobuf);
1534
1535         return 1;
1536 }
1537
1538 static int
1539 _write_lastoddsector (PedDevice* dev, const void* buffer)
1540 {
1541         LinuxSpecific*                  arch_specific;
1542         struct blkdev_ioctl_param       ioctl_param;
1543
1544         PED_ASSERT(dev != NULL, return 0);
1545         PED_ASSERT(buffer != NULL, return 0);
1546         
1547         arch_specific = LINUX_SPECIFIC (dev);
1548
1549 retry:
1550         ioctl_param.block = 0; /* write the last sector */
1551         ioctl_param.content_length = dev->sector_size;
1552         ioctl_param.block_contents = (void*) buffer;
1553         
1554         if (ioctl(arch_specific->fd, BLKSETLASTSECT, &ioctl_param) == -1) {
1555                 PedExceptionOption      opt;
1556                 opt = ped_exception_throw (
1557                         PED_EXCEPTION_ERROR,
1558                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1559                         _("%s during write on %s"),
1560                         strerror (errno), dev->path);
1561
1562                 if (opt == PED_EXCEPTION_CANCEL)
1563                         return 0;
1564                 if (opt == PED_EXCEPTION_RETRY)
1565                         goto retry;
1566         }
1567
1568         return 1;
1569 }
1570
1571 static int
1572 linux_write (PedDevice* dev, const void* buffer, PedSector start,
1573              PedSector count)
1574 {
1575         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1576         PedExceptionOption      ex_status;
1577         void*                   diobuf;
1578         void*                   diobuf_start;
1579
1580         PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
1581
1582         if (dev->read_only) {
1583                 if (ped_exception_throw (
1584                         PED_EXCEPTION_ERROR,
1585                         PED_EXCEPTION_IGNORE_CANCEL,
1586                         _("Can't write to %s, because it is opened read-only."),
1587                         dev->path)
1588                                 != PED_EXCEPTION_IGNORE)
1589                         return 0;
1590                 else
1591                         return 1;
1592         }
1593
1594         if (_get_linux_version() < KERNEL_VERSION (2,6,0)) {
1595                 /* Kludge.  This is necessary to read/write the last
1596                    block of an odd-sized disk, until Linux 2.5.x kernel fixes.
1597                 */
1598                 if (dev->type != PED_DEVICE_FILE && (dev->length & 1)
1599                     && start + count - 1 == dev->length - 1)
1600                         return ped_device_write (dev, buffer, start, count - 1)
1601                                 && _write_lastoddsector (
1602                                         dev, (char*) buffer + (count-1) * 512);
1603         }
1604         while (1) {
1605                 if (_device_seek (dev, start))
1606                         break;
1607
1608                 ex_status = ped_exception_throw (
1609                         PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1610                         _("%s during seek for write on %s"),
1611                         strerror (errno), dev->path);
1612
1613                 switch (ex_status) {
1614                         case PED_EXCEPTION_IGNORE:
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                                 return 0;
1624                         default:
1625                                 PED_ASSERT (0, (void) 0);
1626                                 break;
1627                 }
1628         }
1629
1630 #ifdef READ_ONLY
1631         printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
1632                 dev->path, buffer, (int) start, (int) count);
1633 #else
1634         size_t write_length = count * dev->sector_size;
1635         dev->dirty = 1;
1636         if (posix_memalign(&diobuf, dev->sector_size, write_length) != 0)
1637                 return 0;
1638         memcpy(diobuf, buffer, write_length);
1639         diobuf_start = diobuf;
1640         while (1) {
1641                 ssize_t status = write (arch_specific->fd, diobuf, write_length);
1642                 if (status == write_length) break;
1643                 if (status > 0) {
1644                         write_length -= status;
1645                         diobuf = (char *) diobuf + status;
1646                         continue;
1647                 }
1648
1649                 ex_status = ped_exception_throw (
1650                         PED_EXCEPTION_ERROR,
1651                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1652                         _("%s during write on %s"),
1653                         strerror (errno), dev->path);
1654
1655                 switch (ex_status) {
1656                         case PED_EXCEPTION_IGNORE:
1657                                 free(diobuf_start);
1658                                 return 1;
1659
1660                         case PED_EXCEPTION_RETRY:
1661                                 break;
1662
1663                         case PED_EXCEPTION_UNHANDLED:
1664                                 ped_exception_catch ();
1665                         case PED_EXCEPTION_CANCEL:
1666                                 free(diobuf_start);
1667                                 return 0;
1668                         default:
1669                                 PED_ASSERT (0, (void) 0);
1670                                 break;
1671                 }
1672         }
1673         free(diobuf_start);
1674 #endif /* !READ_ONLY */
1675         return 1;
1676 }
1677
1678 /* returns the number of sectors that are ok.
1679  */
1680 static PedSector
1681 linux_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
1682 {
1683         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
1684         PedSector       done = 0;
1685         int             status;
1686         void*           diobuf;
1687
1688         PED_ASSERT(dev != NULL, return 0);
1689         
1690         if (!_device_seek (dev, start))
1691                 return 0;
1692
1693         if (posix_memalign(&diobuf, PED_SECTOR_SIZE_DEFAULT,
1694                            count * PED_SECTOR_SIZE_DEFAULT) != 0)
1695                 return 0;
1696
1697         for (done = 0; done < count; done += status / dev->sector_size) {
1698                 status = read (arch_specific->fd, diobuf,
1699                                (size_t) ((count-done) * dev->sector_size));
1700                 if (status > 0)
1701                         memcpy(buffer, diobuf, status);
1702                 if (status < 0)
1703                         break;
1704         }
1705         free(diobuf);
1706
1707         return done;
1708 }
1709
1710 static int
1711 _do_fsync (PedDevice* dev)
1712 {
1713         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
1714         int                     status;
1715         PedExceptionOption      ex_status;
1716
1717         while (1) {
1718                 status = fsync (arch_specific->fd);
1719                 if (status >= 0) break;
1720
1721                 ex_status = ped_exception_throw (
1722                         PED_EXCEPTION_ERROR,
1723                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
1724                         _("%s during write on %s"),
1725                         strerror (errno), dev->path);
1726
1727                 switch (ex_status) {
1728                         case PED_EXCEPTION_IGNORE:
1729                                 return 1;
1730
1731                         case PED_EXCEPTION_RETRY:
1732                                 break;
1733
1734                         case PED_EXCEPTION_UNHANDLED:
1735                                 ped_exception_catch ();
1736                         case PED_EXCEPTION_CANCEL:
1737                                 return 0;
1738                         default:
1739                                 PED_ASSERT (0, (void) 0);
1740                                 break;
1741                 }
1742         } 
1743         return 1;
1744 }
1745
1746 static int
1747 linux_sync (PedDevice* dev)
1748 {
1749         PED_ASSERT (dev != NULL, return 0);
1750         PED_ASSERT (!dev->external_mode, return 0);
1751
1752         if (dev->read_only)
1753                 return 1;
1754         if (!_do_fsync (dev))
1755                 return 0;
1756         _flush_cache (dev);
1757         return 1;
1758 }
1759
1760 static int
1761 linux_sync_fast (PedDevice* dev)
1762 {
1763         PED_ASSERT (dev != NULL, return 0);
1764         PED_ASSERT (!dev->external_mode, return 0);
1765
1766         if (dev->read_only)
1767                 return 1;
1768         if (!_do_fsync (dev))
1769                 return 0;
1770         /* no cache flush... */
1771         return 1;
1772 }
1773
1774 static inline int
1775 _compare_digit_state (char ch, int need_digit)
1776 {
1777         return !!isdigit (ch) == need_digit;
1778 }
1779
1780 /* matches the regexp "[^0-9]+[0-9]+[^0-9]+[0-9]+$".
1781  * Motivation: accept devices looking like /dev/rd/c0d0, but
1782  * not looking like /dev/hda1 and /dev/rd/c0d0p1
1783  */
1784 static int
1785 _match_rd_device (const char* name)
1786 {
1787         const char* pos;
1788         int state;
1789
1790         /* exclude directory names from test */
1791         pos = strrchr(name, '/') ?: name;
1792
1793         /* states:
1794          *      0       non-digits
1795          *      1       digits
1796          *      2       non-digits
1797          *      3       digits
1798          */
1799         for (state = 0; state < 4; state++) {
1800                 int want_digits = (state % 2 == 1);
1801                 do {
1802                         if (!*pos)
1803                                 return 0;
1804                         if (!_compare_digit_state (*pos, want_digits))
1805                                 return 0;
1806                         pos++;
1807                 } while (_compare_digit_state (*pos, want_digits));
1808         }
1809
1810         return *pos == 0;
1811 }
1812
1813 static int
1814 _probe_proc_partitions ()
1815 {
1816         FILE*           proc_part_file;
1817         int             major, minor, size;
1818         char            buf [512];
1819         char            part_name [256];
1820         char            dev_name [256];
1821
1822         proc_part_file = fopen ("/proc/partitions", "r");
1823         if (!proc_part_file)
1824                 return 0;
1825
1826         if (fgets (buf, 256, proc_part_file) == NULL)
1827                 return 0;
1828
1829         if (fgets (buf, 256, proc_part_file) == NULL)
1830                 return 0;
1831
1832         while (fgets (buf, 512, proc_part_file)
1833                && sscanf (buf, "%d %d %d %255s", &major, &minor, &size,
1834                           part_name) == 4) {
1835                 /* Heuristic for telling partitions and devices apart
1836                  * Probably needs to be improved
1837                  */
1838                 if (!_match_rd_device (part_name)
1839                     && isdigit (part_name [strlen (part_name) - 1]))
1840                         continue;
1841
1842                 strcpy (dev_name, "/dev/");
1843                 strcat (dev_name, part_name);
1844                 _ped_device_probe (dev_name);
1845         }
1846
1847         fclose (proc_part_file);
1848         return 1;
1849 }
1850
1851 struct _entry {
1852         const char *name;
1853         size_t len;
1854 };
1855
1856 static int
1857 _skip_entry (const char *name)
1858 {
1859         struct _entry *i;
1860         static struct _entry entries[] = {
1861                 { ".",          sizeof (".") - 1        },
1862                 { "..",         sizeof ("..") - 1       },
1863                 { "dm-",        sizeof ("dm-") - 1      },
1864                 { "loop",       sizeof ("loop") - 1     },
1865                 { "ram",        sizeof ("ram") - 1      },
1866                 { 0, 0 },
1867         };
1868
1869         for (i = entries; i->name != 0; i++) {
1870                 if (strncmp (name, i->name, i->len) == 0)
1871                         return 1;
1872         }
1873
1874         return 0;
1875 }
1876
1877 static int
1878 _probe_sys_block ()
1879 {
1880         DIR *blockdir;
1881         struct dirent *dirent;
1882         char dev_name [256];
1883         char *ptr;
1884
1885         if (!(blockdir = opendir ("/sys/block")))
1886                 return 0;
1887         while ((dirent = readdir (blockdir))) {
1888                 if (_skip_entry (dirent->d_name))
1889                         continue;
1890
1891                 if (strlen (dirent->d_name) > sizeof (dev_name) - 6)
1892                         continue; /* device name too long! */
1893
1894                 strcpy (dev_name, "/dev/");
1895                 strcat (dev_name, dirent->d_name);
1896                 /* in /sys/block, '/'s are replaced with '!' or '.' */
1897                 for (ptr = dev_name; *ptr != '\0'; ptr++) {
1898                         if (*ptr == '!' || *ptr == '.')
1899                                 *ptr = '/';
1900                 }
1901                 _ped_device_probe (dev_name);
1902         }
1903         
1904         closedir (blockdir);
1905         return 1;
1906 }
1907
1908 static int
1909 _probe_standard_devices ()
1910 {
1911         _ped_device_probe ("/dev/hda");
1912         _ped_device_probe ("/dev/hdb");
1913         _ped_device_probe ("/dev/hdc");
1914         _ped_device_probe ("/dev/hdd");
1915         _ped_device_probe ("/dev/hde");
1916         _ped_device_probe ("/dev/hdf");
1917         _ped_device_probe ("/dev/hdg");
1918         _ped_device_probe ("/dev/hdh");
1919
1920         _ped_device_probe ("/dev/sda");
1921         _ped_device_probe ("/dev/sdb");
1922         _ped_device_probe ("/dev/sdc");
1923         _ped_device_probe ("/dev/sdd");
1924         _ped_device_probe ("/dev/sde");
1925         _ped_device_probe ("/dev/sdf");
1926
1927         return 1;
1928 }
1929
1930 static void
1931 linux_probe_all ()
1932 {
1933         /* we should probe the standard devs too, even with /proc/partitions,
1934          * because /proc/partitions might return devfs stuff, and we might not
1935          * have devfs available
1936          */
1937         _probe_standard_devices ();
1938
1939 #ifdef ENABLE_DEVICE_MAPPER
1940         /* device-mapper devices aren't listed in /proc/partitions; or, if
1941          * they are, they're listed as dm-X.  So, instead of relying on that,
1942          * we do our own checks.
1943          */
1944         _probe_dm_devices ();
1945 #endif
1946
1947         /* /sys/block is more reliable and consistent; fall back to using
1948          * /proc/partitions if the former is unavailable, however.
1949          */
1950         if (!_probe_sys_block ())
1951                 _probe_proc_partitions ();
1952 }
1953
1954 static char*
1955 _device_get_part_path (PedDevice* dev, int num)
1956 {
1957         int             path_len = strlen (dev->path);
1958         int             result_len = path_len + 16;
1959         char*           result;
1960
1961         result = (char*) ped_malloc (result_len);
1962         if (!result)
1963                 return NULL;
1964
1965         /* Check for devfs-style /disc => /partN transformation
1966            unconditionally; the system might be using udev with devfs rules,
1967            and if not the test is harmless. */
1968         if (!strcmp (dev->path + path_len - 5, "/disc")) {
1969                 /* replace /disc with /path%d */
1970                 strcpy (result, dev->path);
1971                 snprintf (result + path_len - 5, 16, "/part%d", num);
1972         } else if (dev->type == PED_DEVICE_DAC960
1973                         || dev->type == PED_DEVICE_CPQARRAY
1974                         || dev->type == PED_DEVICE_ATARAID
1975 #ifdef ENABLE_DEVICE_MAPPER
1976                         || dev->type == PED_DEVICE_DM
1977 #endif
1978                         || isdigit (dev->path[path_len - 1]))
1979                 snprintf (result, result_len, "%sp%d", dev->path, num);
1980         else
1981                 snprintf (result, result_len, "%s%d", dev->path, num);
1982
1983         return result;
1984 }
1985
1986 static char*
1987 linux_partition_get_path (const PedPartition* part)
1988 {
1989         return _device_get_part_path (part->disk->dev, part->num);
1990 }
1991
1992 static dev_t
1993 _partition_get_part_dev (const PedPartition* part)
1994 {
1995         struct stat dev_stat;
1996         int dev_major, dev_minor;
1997
1998         if (!_device_stat (part->disk->dev, &dev_stat))
1999                 return (dev_t)0;
2000         dev_major = major (dev_stat.st_rdev);
2001         dev_minor = minor (dev_stat.st_rdev);
2002         return (dev_t)makedev (dev_major, dev_minor + part->num);
2003 }
2004
2005 static int
2006 _mount_table_search (const char* file_name, dev_t dev)
2007 {
2008         struct stat part_stat;
2009         char line[512];
2010         char part_name[512];
2011         FILE* file;
2012         int junk;
2013
2014         file = fopen (file_name, "r");
2015         if (!file)
2016                 return 0;
2017         while (fgets (line, 512, file)) {
2018                 junk = sscanf (line, "%s", part_name);
2019                 if (stat (part_name, &part_stat) == 0) {
2020                         if (part_stat.st_rdev == dev) {
2021                                 fclose (file);
2022                                 return 1;
2023                         }
2024                 }
2025         }
2026         fclose (file);
2027         return 0;
2028 }
2029
2030 static int
2031 _partition_is_mounted_by_dev (dev_t dev)
2032 {
2033         return  _mount_table_search( "/proc/mounts", dev)
2034                 || _mount_table_search( "/proc/swaps", dev)
2035                 || _mount_table_search( "/etc/mtab", dev);
2036 }
2037
2038 static int
2039 _partition_is_mounted_by_path (const char *path)
2040 {
2041         struct stat part_stat;
2042         if (stat (path, &part_stat) != 0)
2043                 return 0;
2044         if (!S_ISBLK(part_stat.st_mode))
2045                 return 0;
2046         return _partition_is_mounted_by_dev (part_stat.st_rdev);
2047 }
2048
2049 static int
2050 _partition_is_mounted (const PedPartition *part)
2051 {
2052         dev_t dev;
2053         if (!ped_partition_is_active (part))
2054                 return 0;
2055         dev = _partition_get_part_dev (part);
2056         return _partition_is_mounted_by_dev (dev);
2057 }
2058
2059 static int
2060 linux_partition_is_busy (const PedPartition* part)
2061 {
2062         PedPartition*   walk;
2063
2064         PED_ASSERT (part != NULL, return 0);
2065
2066         if (_partition_is_mounted (part))
2067                 return 1;
2068         if (part->type == PED_PARTITION_EXTENDED) {
2069                 for (walk = part->part_list; walk; walk = walk->next) {
2070                         if (linux_partition_is_busy (walk))
2071                                 return 1;
2072                 }
2073         }
2074         return 0;
2075 }
2076
2077 static int
2078 _blkpg_part_command (PedDevice* dev, struct blkpg_partition* part, int op)
2079 {
2080         LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
2081         struct blkpg_ioctl_arg  ioctl_arg;
2082
2083         ioctl_arg.op = op;
2084         ioctl_arg.flags = 0;
2085         ioctl_arg.datalen = sizeof (struct blkpg_partition);
2086         ioctl_arg.data = (void*) part;
2087
2088         return ioctl (arch_specific->fd, BLKPG, &ioctl_arg) == 0;
2089 }
2090
2091 static int
2092 _blkpg_add_partition (PedDisk* disk, PedPartition* part)
2093 {
2094         struct blkpg_partition  linux_part;
2095         const char*             vol_name;
2096         char*                   dev_name;
2097
2098         PED_ASSERT(disk != NULL, return 0);
2099         PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
2100                    return 0);
2101
2102         if (ped_disk_type_check_feature (disk->type,
2103                                          PED_DISK_TYPE_PARTITION_NAME))
2104                 vol_name = ped_partition_get_name (part);
2105         else
2106                 vol_name = NULL;
2107
2108         dev_name = _device_get_part_path (disk->dev, part->num);
2109         if (!dev_name)
2110                 return 0;
2111
2112         memset (&linux_part, 0, sizeof (linux_part));
2113         linux_part.start = part->geom.start * disk->dev->sector_size;
2114         /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */
2115         if (part->type & PED_PARTITION_EXTENDED)
2116                 linux_part.length = part->geom.length == 1 ? 512 : 1024;
2117         else
2118                 linux_part.length = part->geom.length * disk->dev->sector_size;
2119         linux_part.pno = part->num;
2120         strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
2121         if (vol_name)
2122                 strncpy (linux_part.volname, vol_name, BLKPG_VOLNAMELTH);
2123
2124         ped_free (dev_name);
2125
2126         if (!_blkpg_part_command (disk->dev, &linux_part,
2127                                   BLKPG_ADD_PARTITION)) {
2128                 return ped_exception_throw (
2129                         PED_EXCEPTION_ERROR,
2130                         PED_EXCEPTION_IGNORE_CANCEL,
2131                         _("Error informing the kernel about modifications to "
2132                           "partition %s -- %s.  This means Linux won't know "
2133                           "about any changes you made to %s until you reboot "
2134                           "-- so you shouldn't mount it or use it in any way "
2135                           "before rebooting."),
2136                         linux_part.devname,
2137                         strerror (errno),
2138                         linux_part.devname)
2139                                 == PED_EXCEPTION_IGNORE;
2140         }
2141
2142         return 1;
2143 }
2144
2145 static int
2146 _blkpg_remove_partition (PedDisk* disk, int n)
2147 {
2148         struct blkpg_partition  linux_part;
2149
2150         memset (&linux_part, 0, sizeof (linux_part));
2151         linux_part.pno = n;
2152         return _blkpg_part_command (disk->dev, &linux_part,
2153                                     BLKPG_DEL_PARTITION);
2154 }
2155
2156 static int
2157 _disk_sync_part_table (PedDisk* disk)
2158 {
2159         int     i;
2160         int     last = PED_MAX (ped_disk_get_last_partition_num (disk), 16);
2161         int*    rets = ped_malloc(sizeof(int) * last);
2162         int*    errnums = ped_malloc(sizeof(int) * last);
2163         int     ret = 1;
2164
2165         for (i = 1; i <= last; i++) {
2166                 rets[i - 1] = _blkpg_remove_partition (disk, i);
2167                 errnums[i - 1] = errno;
2168         }
2169
2170         for (i = 1; i <= last; i++) {
2171                 PedPartition*           part;
2172
2173                 part = ped_disk_get_partition (disk, i);
2174                 if (part) {
2175                         /* busy... so we won't (can't!) disturb ;)  Prolly
2176                          * doesn't matter anyway, because users shouldn't be
2177                          * changing mounted partitions anyway...
2178                          */
2179                         if (!rets[i - 1] && errnums[i - 1] == EBUSY)
2180                                         continue;
2181
2182                         /* add the (possibly modified or new) partition */
2183                         if (!_blkpg_add_partition (disk, part))
2184                                 ret = 0;
2185                 }
2186         }
2187
2188         return ret;
2189 }
2190
2191 #ifdef ENABLE_DEVICE_MAPPER
2192 static int
2193 _dm_remove_map_name(char *name)
2194 {
2195         struct dm_task  *task = NULL;
2196         int             rc;
2197
2198         task = dm_task_create(DM_DEVICE_REMOVE);
2199         if (!task)
2200                 return 1;
2201
2202         dm_task_set_name (task, name);
2203
2204         rc = dm_task_run(task);
2205         dm_task_update_nodes();
2206         dm_task_destroy(task);
2207         if (rc < 0)
2208                 return 1;
2209
2210         return 0;
2211 }
2212
2213 static int 
2214 _dm_is_part (struct dm_info *this, char *name)
2215 {
2216         struct dm_task* task = NULL;
2217         struct dm_info* info = alloca(sizeof *info);
2218         struct dm_deps* deps = NULL;
2219         int             rc = 0;
2220         unsigned int    i;
2221
2222         task = dm_task_create(DM_DEVICE_DEPS);
2223         if (!task)
2224                 return 0;
2225         
2226         dm_task_set_name(task, name);
2227         rc = dm_task_run(task);
2228         if (rc < 0) {
2229                 rc = 0;
2230                 goto err;
2231         }
2232         rc = 0;
2233
2234         memset(info, '\0', sizeof *info);
2235         dm_task_get_info(task, info);
2236         if (!info->exists)
2237                 goto err;
2238
2239         deps = dm_task_get_deps(task);
2240         if (!deps)
2241                 goto err;
2242
2243         rc = 0;
2244         for (i = 0; i < deps->count; i++) {
2245                 unsigned int ma = major(deps->device[i]),
2246                              mi = minor(deps->device[i]);
2247
2248                 if (ma == this->major && mi == this->minor)
2249                         rc = 1;
2250         }
2251
2252 err:
2253         dm_task_destroy(task);
2254         return rc;
2255 }
2256
2257 static int
2258 _dm_remove_parts (PedDevice* dev)
2259 {
2260         struct stat             dev_stat;
2261         struct dm_task*         task = NULL;
2262         struct dm_info*         info = alloca(sizeof *info);
2263         struct dm_names*        names = NULL;
2264         unsigned int            next = 0;
2265         int                     rc;
2266
2267         if (!_device_stat (dev, &dev_stat))
2268                 goto err;
2269
2270         task = dm_task_create(DM_DEVICE_LIST);
2271         if (!task)
2272                 goto err;
2273
2274         dm_task_set_major (task, major (dev_stat.st_rdev));
2275         dm_task_set_minor (task, minor (dev_stat.st_rdev));
2276
2277         rc = dm_task_run(task);
2278         if (rc < 0)
2279                 goto err;
2280
2281         memset(info, '\0', sizeof *info);
2282         dm_task_get_info(task, info);
2283         if (!info->exists)
2284                 goto err;
2285
2286         names = dm_task_get_names(task);
2287         if (!names)
2288                 goto err;
2289
2290         rc = 0;
2291         do {
2292                 names = (void *)names + next;
2293
2294                 if (_dm_is_part(info, names->name))
2295                         rc += _dm_remove_map_name(names->name);
2296
2297                 next = names->next;
2298         } while (next);
2299
2300         dm_task_update_nodes();
2301         dm_task_destroy(task);
2302         task = NULL;
2303
2304         if (!rc)
2305                 return 1;
2306 err:
2307         if (task)
2308                 dm_task_destroy(task);
2309         ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE,
2310                 _("parted was unable to re-read the partition "
2311                   "table on %s (%s).  This means Linux won't know "
2312                   "anything about the modifications you made. "),
2313                 dev->path, strerror (errno));
2314         return 0;
2315 }
2316
2317 static int
2318 _dm_add_partition (PedDisk* disk, PedPartition* part)
2319 {
2320         struct stat     dev_stat;
2321         struct dm_task* task = NULL;
2322         int             rc;
2323         char*           vol_name = NULL;
2324         char*           dev_name = NULL;
2325         char*           params = NULL;
2326
2327         dev_name = _device_get_part_path (disk->dev, part->num);
2328         if (!dev_name)
2329                 return 0;
2330
2331         vol_name = strrchr (dev_name, '/');
2332         if (vol_name && *vol_name && *(++vol_name))
2333                 vol_name = strdup (vol_name);
2334         else
2335                 vol_name = strdup (dev_name);
2336         if (!vol_name)
2337                 return 0;
2338
2339         if (!_device_stat (disk->dev, &dev_stat))
2340                 goto err;
2341
2342         if (asprintf (&params, "%d:%d %lld", major (dev_stat.st_rdev),
2343                       minor (dev_stat.st_rdev), part->geom.start) == -1)
2344                 goto err;
2345
2346         if (!params)
2347                 goto err;
2348
2349         task = dm_task_create (DM_DEVICE_CREATE);
2350         if (!task)
2351                 goto err;
2352
2353         dm_task_set_name (task, vol_name);
2354         dm_task_add_target (task, 0, part->geom.length,
2355                 "linear", params);
2356         rc = dm_task_run(task);
2357         if (rc >= 0) {
2358                 //printf("0 %ld linear %s\n", part->geom.length, params);
2359                 dm_task_update_nodes();
2360                 dm_task_destroy(task);
2361                 free(params);
2362                 free(vol_name);
2363                 return 1;
2364         } else {
2365                 _dm_remove_map_name(vol_name);
2366         }
2367 err:
2368         dm_task_update_nodes();
2369         if (task)
2370                 dm_task_destroy (task);
2371         if (params)
2372                 free (params);
2373         free (vol_name);
2374         return 0;
2375 }
2376
2377 static int
2378 _dm_reread_part_table (PedDisk* disk)
2379 {
2380         int     rc = 1;
2381         int     last = PED_MAX (ped_disk_get_last_partition_num (disk), 16);
2382         int     i;
2383
2384         sync();
2385         if (!_dm_remove_parts(disk->dev))
2386                 rc = 0;
2387
2388         for (i = 1; i <= last; i++) {
2389                 PedPartition*      part;
2390
2391                 part = ped_disk_get_partition (disk, i);
2392                 if (!part)
2393                         continue;
2394
2395                 if (!_dm_add_partition (disk, part))
2396                         rc = 0;
2397         }
2398         return rc;
2399 }
2400 #endif
2401
2402 static int
2403 _kernel_reread_part_table (PedDevice* dev)
2404 {
2405         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
2406         int             retry_count = 5;
2407
2408         sync();
2409         while (ioctl (arch_specific->fd, BLKRRPART)) {
2410                 retry_count--;
2411                 sync();
2412                 if (!retry_count) {
2413                         ped_exception_throw (
2414                                 PED_EXCEPTION_WARNING,
2415                                 PED_EXCEPTION_IGNORE,
2416                         _("The kernel was unable to re-read the partition "
2417                           "table on %s (%s).  This means Linux won't know "
2418                           "anything about the modifications you made "
2419                           "until you reboot.  You should reboot your computer "
2420                           "before doing anything with %s."),
2421                                 dev->path, strerror (errno), dev->path);
2422                         return 0;
2423                 }
2424         }
2425
2426         return 1;
2427 }
2428
2429 static int
2430 _have_blkpg ()
2431 {
2432         static int have_blkpg = -1;
2433         int kver;
2434
2435         if (have_blkpg != -1)
2436                 return have_blkpg;
2437
2438         kver = _get_linux_version();
2439         return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
2440 }
2441
2442 static int
2443 linux_disk_commit (PedDisk* disk)
2444 {
2445 #ifdef ENABLE_DEVICE_MAPPER
2446         if (disk->dev->type == PED_DEVICE_DM)
2447                 return _dm_reread_part_table (disk);
2448 #endif
2449         if (disk->dev->type != PED_DEVICE_FILE) {
2450                 /* The ioctl() command BLKPG_ADD_PARTITION does not notify
2451                  * the devfs system; consequently, /proc/partitions will not
2452                  * be up to date, and the proper links in /dev are not
2453                  * created.  Therefore, if using DevFS, we must get the kernel
2454                  * to re-read and grok the partition table.
2455                  */
2456                 /* Work around kernel dasd problem so we really do BLKRRPART */
2457                 if (disk->dev->type != PED_DEVICE_DASD &&
2458                     _have_blkpg () && !_have_devfs ()) {
2459                         if (_disk_sync_part_table (disk))
2460                                 return 1;
2461                 }
2462
2463                 return _kernel_reread_part_table (disk->dev);
2464         }
2465
2466         return 1;
2467 }
2468
2469 static PedDeviceArchOps linux_dev_ops = {
2470         _new:           linux_new,
2471         destroy:        linux_destroy,
2472         is_busy:        linux_is_busy,
2473         open:           linux_open,
2474         refresh_open:   linux_refresh_open,
2475         close:          linux_close,
2476         refresh_close:  linux_refresh_close,
2477         read:           linux_read,
2478         write:          linux_write,
2479         check:          linux_check,
2480         sync:           linux_sync,
2481         sync_fast:      linux_sync_fast,
2482         probe_all:      linux_probe_all
2483 };
2484
2485 PedDiskArchOps linux_disk_ops =  {
2486         partition_get_path:     linux_partition_get_path,
2487         partition_is_busy:      linux_partition_is_busy,
2488         disk_commit:            linux_disk_commit
2489 };
2490
2491 PedArchitecture ped_linux_arch = {
2492         dev_ops:        &linux_dev_ops,
2493         disk_ops:       &linux_disk_ops
2494 };