OSDN Git Service

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