OSDN Git Service

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