OSDN Git Service

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