235
118
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
236
if (map[i].drive && hook (map[i].drive))
119
if (map[i].drive && hook (map[i].drive, hook_data))
242
#if !defined(__MINGW32__)
244
grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
246
#if !defined (__GNU__)
247
# if defined(__NetBSD__)
248
struct disklabel label;
249
# elif defined (__sun__)
250
struct dk_minfo minfo;
252
unsigned long long nr;
255
unsigned sector_size, log_sector_size;
258
if (fstat (fd, &st) < 0)
259
/* TRANSLATORS: "stat" comes from the name of POSIX function. */
260
grub_util_error (_("cannot stat `%s': %s"), name, strerror (errno));
262
#if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
263
defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \
266
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
267
if (! S_ISCHR (st.st_mode))
269
if (! S_ISBLK (st.st_mode))
273
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
274
if (ioctl (fd, DIOCGMEDIASIZE, &nr))
275
# elif defined(__APPLE__)
276
if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
277
# elif defined(__NetBSD__)
278
configure_device_driver (fd);
279
if (ioctl (fd, DIOCGDINFO, &label) == -1)
280
# elif defined (__sun__)
281
if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
283
if (ioctl (fd, BLKGETSIZE64, &nr))
287
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
288
if (ioctl (fd, DIOCGSECTORSIZE, §or_size))
290
# elif defined(__APPLE__)
291
if (ioctl (fd, DKIOCGETBLOCKSIZE, §or_size))
293
# elif defined(__sun__)
294
sector_size = minfo.dki_lbsize;
295
# elif defined(__NetBSD__)
296
sector_size = label.d_secsize;
298
if (ioctl (fd, BLKSSZGET, §or_size))
301
if (sector_size & (sector_size - 1) || !sector_size)
303
for (log_sector_size = 0;
304
(1 << log_sector_size) < sector_size;
308
*log_secsize = log_sector_size;
310
# if defined (__APPLE__)
311
return nr << log_sector_size;
312
# elif defined(__NetBSD__)
313
return (grub_uint64_t) label.d_secperunit << log_sector_size;
314
# elif defined (__sun__)
315
return minfo.dki_capacity << log_sector_size;
317
if (nr & ((1 << log_sector_size) - 1))
318
grub_util_error ("%s", _("unaligned device size"));
325
/* In GNU/Hurd, stat() will return the right size. */
326
#elif !defined (__GNU__)
327
# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
340
125
static grub_err_t
341
126
grub_util_biosdisk_open (const char *name, grub_disk_t disk)
345
struct grub_util_biosdisk_data *data;
129
struct grub_util_hostdisk_data *data;
347
131
drive = find_grub_drive (name);
132
grub_util_info ("drive = %d", drive);
349
134
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
350
135
"no mapping exists for `%s'", name);
352
137
disk->id = drive;
353
disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data));
138
disk->data = data = xmalloc (sizeof (struct grub_util_hostdisk_data));
354
139
data->dev = NULL;
355
140
data->access_mode = 0;
141
data->fd = GRUB_UTIL_FD_INVALID;
357
142
data->is_disk = 0;
358
143
data->device_map = map[drive].device_map;
360
145
/* Get the size. */
361
#if defined(__MINGW32__)
365
size = grub_util_get_disk_size (map[drive].device);
368
grub_util_error (_("unaligned device size"));
370
disk->total_sectors = size >> 9;
372
grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
374
return GRUB_ERR_NONE;
380
fd = open (map[drive].device, O_RDONLY);
149
fd = grub_util_fd_open (map[drive].device, GRUB_UTIL_FD_O_RDONLY);
151
if (!GRUB_UTIL_FD_IS_VALID(fd))
382
152
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("cannot open `%s': %s"),
383
map[drive].device, strerror (errno));
153
map[drive].device, grub_util_fd_strerror ());
385
155
disk->total_sectors = grub_util_get_fd_size (fd, map[drive].device,
386
156
&disk->log_sector_size);
387
157
disk->total_sectors >>= disk->log_sector_size;
158
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
389
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
390
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
160
#if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
163
# if GRUB_DISK_DEVS_ARE_CHAR
164
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
392
if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
166
if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
398
grub_util_info ("the size of %s is %" PRIuGRUB_UINT64_T,
399
name, disk->total_sectors);
172
grub_util_fd_close (fd);
174
grub_util_info ("the size of %s is %" GRUB_HOST_PRIuLONG_LONG,
175
name, (unsigned long long) disk->total_sectors);
401
177
return GRUB_ERR_NONE;
407
grub_util_device_is_mapped (const char *dev)
409
#ifdef HAVE_DEVICE_MAPPER
412
if (!grub_device_mapper_supported ())
415
if (stat (dev, &st) < 0)
418
return dm_is_dm_major (major (st.st_rdev));
421
#endif /* HAVE_DEVICE_MAPPER */
424
#ifdef HAVE_DEVICE_MAPPER
426
grub_util_get_dm_node_linear_info (const char *dev,
428
grub_disk_addr_t *st)
432
uint64_t length, start;
433
char *target, *params;
437
grub_disk_addr_t partstart = 0;
441
dmt = dm_task_create(DM_DEVICE_TABLE);
445
if (! (first ? dm_task_set_name (dmt, dev)
446
: dm_task_set_major_minor (dmt, major, minor, 0)))
448
dm_task_destroy (dmt);
451
dm_task_no_open_count(dmt);
452
if (!dm_task_run(dmt))
454
dm_task_destroy (dmt);
457
next = dm_get_next_target(dmt, next, &start, &length,
459
if (grub_strcmp (target, "linear") != 0)
461
dm_task_destroy (dmt);
464
major = grub_strtoul (params, &ptr, 10);
467
dm_task_destroy (dmt);
468
grub_errno = GRUB_ERR_NONE;
473
dm_task_destroy (dmt);
477
minor = grub_strtoul (ptr, &ptr, 10);
480
grub_errno = GRUB_ERR_NONE;
481
dm_task_destroy (dmt);
487
dm_task_destroy (dmt);
491
partstart += grub_strtoull (ptr, &ptr, 10);
494
grub_errno = GRUB_ERR_NONE;
495
dm_task_destroy (dmt);
499
dm_task_destroy (dmt);
514
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
516
/* FIXME: geom actually gives us the whole container hierarchy.
517
It can be used more efficiently than this. */
519
grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
522
struct gclass *class;
526
grub_util_info ("following geom '%s'", name);
528
error = geom_gettree (&mesh);
530
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
531
Usually left untranslated.
533
grub_util_error ("%s", _("couldn't open geom"));
535
LIST_FOREACH (class, &mesh.lg_class, lg_class)
536
if (strcasecmp (class->lg_name, "part") == 0)
539
/* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
540
Usually left untranslated. "part" is the identifier of one of its
542
grub_util_error ("%s", _("couldn't find geom `part' class"));
544
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
546
struct gprovider *provider;
547
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
548
if (strcmp (provider->lg_name, name) == 0)
550
char *name_tmp = xstrdup (geom->lg_name);
551
grub_disk_addr_t off = 0;
552
struct gconfig *config;
553
grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
555
grub_util_follow_gpart_up (name_tmp, &off, name_out);
557
LIST_FOREACH (config, &provider->lg_config, lg_config)
558
if (strcasecmp (config->lg_name, "start") == 0)
559
off += strtoull (config->lg_val, 0, 10);
565
grub_util_info ("geom '%s' has no parent", name);
567
*name_out = xstrdup (name);
573
grub_hostdisk_find_partition_start (const char *dev)
575
grub_disk_addr_t out;
576
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
578
grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
583
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
586
sysfs_partition_path (const char *dev, const char *entry)
604
if (pipe (pipe_fd) < 0)
606
grub_util_warn (_("Unable to create pipe: %s"), strerror (errno));
611
grub_util_error (_("Unable to fork: %s"), strerror (errno));
615
/* Ensure child is not localised. */
616
setenv ("LC_ALL", "C", 1);
619
dup2 (pipe_fd[1], STDOUT_FILENO);
622
execvp ((char *) argv[0], (char **) argv);
627
/* Parent. Read udevadm's output. */
630
udevadm = fdopen (pipe_fd[0], "r");
633
grub_util_warn (_("Unable to open stream from %s: %s"),
634
"udevadm", strerror (errno));
639
if (getline (&buf, &len, udevadm) > 0)
643
newline = strchr (buf, '\n');
646
path = xasprintf ("/sys%s/%s", buf, entry);
652
waitpid (pid, NULL, 0);
660
sysfs_partition_start (const char *dev, grub_disk_addr_t *start)
664
unsigned long long val;
667
path = sysfs_partition_path (dev, "start");
671
fp = fopen (path, "r");
675
if (fscanf (fp, "%llu", &val) == 1)
677
*start = (grub_disk_addr_t) val;
688
#endif /* __linux__ */
691
grub_hostdisk_find_partition_start (const char *dev)
695
grub_disk_addr_t start = 0;
696
#endif /* __linux__ */
698
struct extpart_info pinfo;
699
# elif !defined(HAVE_DIOCGDINFO)
700
struct hd_geometry hdg;
701
# else /* defined(HAVE_DIOCGDINFO) */
702
# if defined(__NetBSD__)
703
struct dkwedge_info dkw;
704
# endif /* defined(__NetBSD__) */
705
struct disklabel label;
707
# endif /* !defined(HAVE_DIOCGDINFO) */
709
# ifdef HAVE_DEVICE_MAPPER
710
grub_disk_addr_t partition_start;
711
if (grub_util_device_is_mapped (dev)
712
&& grub_util_get_dm_node_linear_info (dev, 0, 0, &partition_start))
713
return partition_start;
714
# endif /* HAVE_DEVICE_MAPPER */
717
if (sysfs_partition_start (dev, &start))
719
# endif /* __linux__ */
721
fd = open (dev, O_RDONLY);
724
grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
725
dev, strerror (errno));
730
if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
731
# elif !defined(HAVE_DIOCGDINFO)
732
if (ioctl (fd, HDIO_GETGEO, &hdg))
733
# else /* defined(HAVE_DIOCGDINFO) */
734
# if defined(__NetBSD__)
735
configure_device_driver (fd);
736
/* First handle the case of disk wedges. */
737
if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == 0)
740
return (grub_disk_addr_t) dkw.dkw_offset;
742
# endif /* defined(__NetBSD__) */
743
if (ioctl (fd, DIOCGDINFO, &label) == -1)
744
# endif /* !defined(HAVE_DIOCGDINFO) */
746
grub_error (GRUB_ERR_BAD_DEVICE,
747
# if !defined(HAVE_DIOCGDINFO)
748
"cannot get disk geometry of `%s'", dev);
749
# else /* defined(HAVE_DIOCGDINFO) */
750
"cannot get disk label of `%s'", dev);
751
# endif /* !defined(HAVE_DIOCGDINFO) */
759
return pinfo.p_start;
760
# elif !defined(HAVE_DIOCGDINFO)
762
# else /* defined(HAVE_DIOCGDINFO) */
764
p_index = dev[strlen(dev) - 1] - 'a';
768
if (p_index >= label.d_npartitions || p_index < 0)
770
grub_error (GRUB_ERR_BAD_DEVICE,
771
"no disk label entry for `%s'", dev);
774
return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
775
# endif /* !defined(HAVE_DIOCGDINFO) */
777
#endif /* __linux__ || __CYGWIN__ || HAVE_DIOCGDINFO */
780
/* Cache of partition start sectors for each disk. */
781
struct linux_partition_cache
783
struct linux_partition_cache *next;
784
struct linux_partition_cache **prev;
790
struct linux_partition_cache *linux_partition_cache_list;
793
linux_find_partition (char *dev, grub_disk_addr_t sector)
795
size_t len = strlen (dev);
799
char real_dev[PATH_MAX];
800
struct linux_partition_cache *cache;
803
strcpy(real_dev, dev);
805
if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
807
p = real_dev + len - 4;
810
else if (strncmp (real_dev, "/dev/disk/by-id/",
811
sizeof ("/dev/disk/by-id/") - 1) == 0)
816
else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
827
for (cache = linux_partition_cache_list; cache; cache = cache->next)
829
if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
831
sprintf (p, format, cache->partno);
832
strcpy (dev, real_dev);
837
for (i = 1; i < 10000; i++)
840
grub_disk_addr_t start;
842
sprintf (p, format, i);
844
fd = open (real_dev, O_RDONLY);
855
start = grub_hostdisk_find_partition_start (real_dev);
856
/* We don't care about errors here. */
857
grub_errno = GRUB_ERR_NONE;
861
struct linux_partition_cache *new_cache_item;
863
new_cache_item = xmalloc (sizeof *new_cache_item);
864
new_cache_item->dev = xstrdup (dev);
865
new_cache_item->start = start;
866
new_cache_item->partno = i;
867
grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
868
GRUB_AS_LIST (new_cache_item));
870
strcpy (dev, real_dev);
877
#endif /* __linux__ */
879
#if defined(__linux__) && (!defined(__GLIBC__) || \
880
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
881
/* Maybe libc doesn't have large file support. */
883
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
885
loff_t offset, result;
886
static int _llseek (uint filedes, ulong hi, ulong lo,
887
loff_t *res, uint wh);
888
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
889
loff_t *, res, uint, wh);
891
offset = (loff_t) off;
892
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
893
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
894
name, strerror (errno));
895
return GRUB_ERR_NONE;
899
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
901
off_t offset = (off_t) off;
903
if (lseek (fd, offset, SEEK_SET) != offset)
904
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
905
name, strerror (errno));
911
flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
917
fd = open (os_dev, O_RDONLY);
918
if (fd >= 0 && fstat (fd, &st) >= 0 && S_ISBLK (st.st_mode))
919
ioctl (fd, BLKFLSBUF, 0);
926
182
grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
187
canon = canonicalize_file_name (os_disk);
189
canon = xstrdup (os_disk);
930
191
for (i = 0; i < ARRAY_SIZE (map); i++)
931
192
if (! map[i].device)
933
else if (strcmp (map[i].device, os_disk) == 0)
194
else if (strcmp (map[i].device, canon) == 0)
939
206
if (i == ARRAY_SIZE (map))
940
207
/* TRANSLATORS: it refers to the lack of free slots. */
941
208
grub_util_error ("%s", _("device count exceeds limit"));
943
map[i].device = xstrdup (os_disk);
210
map[i].device = canon;
944
211
map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
945
212
strcpy (map[i].drive, "hostdisk/");
946
213
strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
947
214
map[i].device_map = 0;
949
flush_initial_buffer (os_disk);
216
grub_hostdisk_flush_initial_buffer (os_disk);
951
218
return map[i].drive;
955
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
956
grub_disk_addr_t *max)
223
grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
224
grub_disk_addr_t *max)
959
struct grub_util_biosdisk_data *data = disk->data;
227
struct grub_util_hostdisk_data *data = disk->data;
964
flags |= O_LARGEFILE;
977
/* Linux has a bug that the disk cache for a whole disk is not consistent
978
with the one for a partition of the disk. */
980
int is_partition = 0;
982
grub_disk_addr_t part_start = 0;
984
part_start = grub_partition_get_start (disk->partition);
986
strcpy (dev, map[disk->id].device);
988
&& strncmp (map[disk->id].device, "/dev/", 5) == 0)
990
if (sector >= part_start)
991
is_partition = linux_find_partition (dev, part_start);
993
*max = part_start - sector;
998
if (data->dev && strcmp (data->dev, dev) == 0 &&
999
data->access_mode == (flags & O_ACCMODE))
1001
grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
1010
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
1015
ioctl (data->fd, BLKFLSBUF, 0);
1023
/* Open the partition. */
1024
grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
1025
fd = open (dev, flags);
1028
grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
1029
dev, strerror (errno));
1033
data->dev = xstrdup (dev);
1034
data->access_mode = (flags & O_ACCMODE);
1039
ioctl (data->fd, BLKFLSBUF, 0);
1045
*max = grub_util_get_fd_size (fd, dev, 0);
1046
*max >>= disk->log_sector_size;
1047
if (sector - part_start >= *max)
1049
*max = disk->partition->len - (sector - part_start);
1053
strcpy (dev, map[disk->id].device);
1056
sector -= part_start;
1060
#else /* ! __linux__ */
1061
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1062
int sysctl_flags, sysctl_oldflags;
1063
size_t sysctl_size = sizeof (sysctl_flags);
1065
if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0))
1067
grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags");
1070
sysctl_flags = sysctl_oldflags | 0x10;
1071
if (! (sysctl_oldflags & 0x10)
1072
&& sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size))
1074
grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags");
231
flags |= GRUB_UTIL_FD_O_SYNC;
1079
233
if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 &&
1080
234
data->access_mode == (flags & O_ACCMODE))