OSDN Git Service

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