OSDN Git Service

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