OSDN Git Service

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