~ubuntu-branches/ubuntu/trusty/grub2/trusty

« back to all changes in this revision

Viewing changes to grub-core/kern/emu/hostdisk.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-01-16 15:18:04 UTC
  • mfrom: (17.6.38 experimental)
  • Revision ID: package-import@ubuntu.com-20140116151804-3foouk7fpqcq3sxx
Tags: 2.02~beta2-2
* Convert patch handling to git-dpm.
* Add bi-endian support to ELF parser (Tomohiro B Berry).
* Adjust restore_mkdevicemap.patch to mark get_kfreebsd_version as static,
  to appease "gcc -Werror=missing-prototypes".
* Cherry-pick from upstream:
  - Change grub-macbless' manual page section to 8.
* Install grub-glue-efi, grub-macbless, grub-render-label, and
  grub-syslinux2cfg.
* grub-shell: Pass -no-pad to xorriso when building floppy images.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
18
 */
19
19
 
 
20
#include <config-util.h>
 
21
 
20
22
#include <grub/disk.h>
21
23
#include <grub/partition.h>
22
24
#include <grub/msdos_partition.h>
37
39
#include <unistd.h>
38
40
#include <sys/types.h>
39
41
#include <sys/stat.h>
40
 
#include <sys/wait.h>
41
42
#include <fcntl.h>
42
43
#include <errno.h>
43
44
#include <limits.h>
45
46
#ifdef __linux__
46
47
# include <sys/ioctl.h>         /* ioctl */
47
48
# include <sys/mount.h>
48
 
# if !defined(__GLIBC__) || \
49
 
        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
50
 
/* Maybe libc doesn't have large file support.  */
51
 
#  include <linux/unistd.h>     /* _llseek */
52
 
# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
53
49
# ifndef BLKFLSBUF
54
50
#  define BLKFLSBUF     _IO (0x12,97)   /* flush buffer cache */
55
51
# endif /* ! BLKFLSBUF */
56
 
# include <sys/ioctl.h>         /* ioctl */
57
 
# ifndef HDIO_GETGEO
58
 
#  define HDIO_GETGEO   0x0301  /* get device geometry */
59
 
/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
60
 
   defined.  */
61
 
struct hd_geometry
62
 
{
63
 
  unsigned char heads;
64
 
  unsigned char sectors;
65
 
  unsigned short cylinders;
66
 
  unsigned long start;
67
 
};
68
 
# endif /* ! HDIO_GETGEO */
69
 
# ifndef BLKGETSIZE64
70
 
#  define BLKGETSIZE64  _IOR(0x12,114,size_t)    /* return device size */
71
 
# endif /* ! BLKGETSIZE64 */
72
52
#endif /* __linux__ */
73
53
 
74
 
#ifdef __CYGWIN__
75
 
# include <sys/ioctl.h>
76
 
# include <cygwin/fs.h> /* BLKGETSIZE64 */
77
 
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
78
 
#endif
79
 
 
80
 
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
81
 
# include <sys/disk.h> /* DIOCGMEDIASIZE */
82
 
# include <sys/param.h>
83
 
# include <sys/sysctl.h>
84
 
# include <sys/mount.h>
85
 
#include <libgeom.h>
86
 
#endif
87
 
 
88
 
#if defined (__sun__)
89
 
# include <sys/dkio.h>
90
 
#endif
91
 
 
92
 
#if defined(__APPLE__)
93
 
# include <sys/disk.h>
94
 
#endif
95
 
 
96
 
#ifdef HAVE_DEVICE_MAPPER
97
 
# include <libdevmapper.h>
98
 
#endif
99
 
 
100
 
#if defined(__NetBSD__)
101
 
# define HAVE_DIOCGDINFO
102
 
# include <sys/ioctl.h>
103
 
# include <sys/disklabel.h>    /* struct disklabel */
104
 
# include <sys/disk.h>    /* struct dkwedge_info */
105
 
#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
106
 
# undef HAVE_DIOCGDINFO
107
 
#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
108
 
 
109
 
#if defined(__NetBSD__)
110
 
# ifdef HAVE_GETRAWPARTITION
111
 
#  include <util.h>    /* getrawpartition */
112
 
# endif /* HAVE_GETRAWPARTITION */
113
 
# include <sys/fdio.h>
114
 
# ifndef RAW_FLOPPY_MAJOR
115
 
#  define RAW_FLOPPY_MAJOR      9
116
 
# endif /* ! RAW_FLOPPY_MAJOR */
117
 
#endif /* defined(__NetBSD__) */
118
 
 
119
54
static struct
120
55
{
121
56
  char *drive;
123
58
  int device_map;
124
59
} map[256];
125
60
 
126
 
struct grub_util_biosdisk_data
127
 
{
128
 
  char *dev;
129
 
  int access_mode;
130
 
  int fd;
131
 
  int is_disk;
132
 
  int device_map;
133
 
};
134
 
 
135
 
#ifdef __linux__
136
 
/* Check if we have devfs support.  */
137
 
static int
138
 
have_devfs (void)
139
 
{
140
 
  static int dev_devfsd_exists = -1;
141
 
 
142
 
  if (dev_devfsd_exists < 0)
143
 
    {
144
 
      struct stat st;
145
 
 
146
 
      dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
147
 
    }
148
 
 
149
 
  return dev_devfsd_exists;
150
 
}
151
 
#endif /* __linux__ */
152
 
 
153
 
#if defined(__NetBSD__)
154
 
/* Adjust device driver parameters.  This function should be called just
155
 
   after successfully opening the device.  For now, it simply prevents the
156
 
   floppy driver from retrying operations on failure, as otherwise the
157
 
   driver takes a while to abort when there is no floppy in the drive.  */
158
 
static void
159
 
configure_device_driver (int fd)
160
 
{
161
 
  struct stat st;
162
 
 
163
 
  if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
164
 
    return;
165
 
  if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
166
 
    {
167
 
      int floppy_opts;
168
 
 
169
 
      if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1)
170
 
        return;
171
 
      floppy_opts |= FDOPT_NORETRY;
172
 
      if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1)
173
 
        return;
174
 
    }
175
 
}
176
 
#endif /* defined(__NetBSD__) */
177
 
 
178
61
static int
179
62
unescape_cmp (const char *a, const char *b_escaped)
180
63
{
224
107
}
225
108
 
226
109
static int
227
 
grub_util_biosdisk_iterate (int (*hook) (const char *name),
 
110
grub_util_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
228
111
                            grub_disk_pull_t pull)
229
112
{
230
113
  unsigned i;
233
116
    return 0;
234
117
 
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))
237
120
      return 1;
238
121
 
239
122
  return 0;
240
123
}
241
124
 
242
 
#if !defined(__MINGW32__)
243
 
grub_uint64_t
244
 
grub_util_get_fd_size (int fd, const char *name, unsigned *log_secsize)
245
 
{
246
 
#if !defined (__GNU__)
247
 
# if defined(__NetBSD__)
248
 
  struct disklabel label;
249
 
# elif defined (__sun__)
250
 
  struct dk_minfo minfo;
251
 
# else
252
 
  unsigned long long nr;
253
 
# endif
254
 
#endif
255
 
  unsigned sector_size, log_sector_size;
256
 
  struct stat st;
257
 
 
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));
261
 
 
262
 
#if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
263
 
  defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \
264
 
  || defined (__sun__)
265
 
 
266
 
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
267
 
  if (! S_ISCHR (st.st_mode))
268
 
# else
269
 
  if (! S_ISBLK (st.st_mode))
270
 
# endif
271
 
    goto fail;
272
 
 
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))
282
 
# else
283
 
    if (ioctl (fd, BLKGETSIZE64, &nr))
284
 
# endif
285
 
      goto fail;
286
 
 
287
 
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
288
 
    if (ioctl (fd, DIOCGSECTORSIZE, &sector_size))
289
 
      goto fail;
290
 
# elif defined(__APPLE__)
291
 
    if (ioctl (fd, DKIOCGETBLOCKSIZE, &sector_size))
292
 
      goto fail;
293
 
# elif defined(__sun__)
294
 
    sector_size = minfo.dki_lbsize;
295
 
# elif defined(__NetBSD__)
296
 
    sector_size = label.d_secsize;
297
 
# else
298
 
    if (ioctl (fd, BLKSSZGET, &sector_size))
299
 
      goto fail;
300
 
# endif
301
 
    if (sector_size & (sector_size - 1) || !sector_size)
302
 
      goto fail;
303
 
    for (log_sector_size = 0;
304
 
         (1 << log_sector_size) < sector_size;
305
 
         log_sector_size++);
306
 
 
307
 
    if (log_secsize)
308
 
      *log_secsize = log_sector_size;
309
 
 
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;
316
 
# else
317
 
    if (nr & ((1 << log_sector_size) - 1))
318
 
      grub_util_error ("%s", _("unaligned device size"));
319
 
 
320
 
    return nr;
321
 
# endif
322
 
 
323
 
 fail:
324
 
 
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."
328
 
#endif
329
 
 
330
 
  sector_size = 512;
331
 
  log_sector_size = 9;
332
 
 
333
 
  if (log_secsize)
334
 
   *log_secsize = 9;
335
 
 
336
 
  return st.st_size;
337
 
}
338
 
#endif
339
 
 
340
125
static grub_err_t
341
126
grub_util_biosdisk_open (const char *name, grub_disk_t disk)
342
127
{
343
128
  int drive;
344
 
  struct stat st;
345
 
  struct grub_util_biosdisk_data *data;
 
129
  struct grub_util_hostdisk_data *data;
346
130
 
347
131
  drive = find_grub_drive (name);
 
132
  grub_util_info ("drive = %d", drive);
348
133
  if (drive < 0)
349
134
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
350
135
                       "no mapping exists for `%s'", name);
351
136
 
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;
356
 
  data->fd = -1;
 
141
  data->fd = GRUB_UTIL_FD_INVALID;
357
142
  data->is_disk = 0;
358
143
  data->device_map = map[drive].device_map;
359
144
 
360
145
  /* Get the size.  */
361
 
#if defined(__MINGW32__)
362
 
  {
363
 
    grub_uint64_t size;
364
 
 
365
 
    size = grub_util_get_disk_size (map[drive].device);
366
 
 
367
 
    if (size % 512)
368
 
      grub_util_error (_("unaligned device size"));
369
 
 
370
 
    disk->total_sectors = size >> 9;
371
 
 
372
 
    grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
373
 
 
374
 
    return GRUB_ERR_NONE;
375
 
  }
376
 
#else
377
 
  {
378
 
    int fd;
379
 
 
380
 
    fd = open (map[drive].device, O_RDONLY);
381
 
    if (fd == -1)
 
146
  {
 
147
    grub_util_fd_t fd;
 
148
 
 
149
    fd = grub_util_fd_open (map[drive].device, GRUB_UTIL_FD_O_RDONLY);
 
150
 
 
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 ());
384
154
 
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;
388
159
 
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
 
161
    {
 
162
      struct stat st;
 
163
# if GRUB_DISK_DEVS_ARE_CHAR
 
164
      if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
391
165
# else
392
 
    if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
 
166
      if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
393
167
# endif
394
 
      data->is_disk = 1;
395
 
 
396
 
    close (fd);
397
 
 
398
 
    grub_util_info ("the size of %s is %" PRIuGRUB_UINT64_T,
399
 
                    name, disk->total_sectors);
 
168
        data->is_disk = 1;
 
169
    }
 
170
#endif
 
171
 
 
172
    grub_util_fd_close (fd);
 
173
 
 
174
    grub_util_info ("the size of %s is %" GRUB_HOST_PRIuLONG_LONG,
 
175
                    name, (unsigned long long) disk->total_sectors);
400
176
 
401
177
    return GRUB_ERR_NONE;
402
178
  }
403
 
#endif
404
 
}
405
 
 
406
 
int
407
 
grub_util_device_is_mapped (const char *dev)
408
 
{
409
 
#ifdef HAVE_DEVICE_MAPPER
410
 
  struct stat st;
411
 
 
412
 
  if (!grub_device_mapper_supported ())
413
 
    return 0;
414
 
 
415
 
  if (stat (dev, &st) < 0)
416
 
    return 0;
417
 
 
418
 
  return dm_is_dm_major (major (st.st_rdev));
419
 
#else
420
 
  return 0;
421
 
#endif /* HAVE_DEVICE_MAPPER */
422
 
}
423
 
 
424
 
#ifdef HAVE_DEVICE_MAPPER
425
 
int
426
 
grub_util_get_dm_node_linear_info (const char *dev,
427
 
                                   int *maj, int *min,
428
 
                                   grub_disk_addr_t *st)
429
 
{
430
 
  struct dm_task *dmt;
431
 
  void *next = NULL;
432
 
  uint64_t length, start;
433
 
  char *target, *params;
434
 
  char *ptr;
435
 
  int major, minor;
436
 
  int first = 1;
437
 
  grub_disk_addr_t partstart = 0;
438
 
 
439
 
  while (1)
440
 
    {
441
 
      dmt = dm_task_create(DM_DEVICE_TABLE);
442
 
      if (!dmt)
443
 
        break;
444
 
      
445
 
      if (! (first ? dm_task_set_name (dmt, dev)
446
 
             : dm_task_set_major_minor (dmt, major, minor, 0)))
447
 
        {
448
 
          dm_task_destroy (dmt);
449
 
          break;
450
 
        }
451
 
      dm_task_no_open_count(dmt);
452
 
      if (!dm_task_run(dmt))
453
 
        {
454
 
          dm_task_destroy (dmt);
455
 
          break;
456
 
        }
457
 
      next = dm_get_next_target(dmt, next, &start, &length,
458
 
                                &target, &params);
459
 
      if (grub_strcmp (target, "linear") != 0)
460
 
        {
461
 
          dm_task_destroy (dmt);
462
 
          break;
463
 
        }
464
 
      major = grub_strtoul (params, &ptr, 10);
465
 
      if (grub_errno)
466
 
        {
467
 
          dm_task_destroy (dmt);
468
 
          grub_errno = GRUB_ERR_NONE;
469
 
          return 0;
470
 
        }
471
 
      if (*ptr != ':')
472
 
        {
473
 
          dm_task_destroy (dmt);
474
 
          return 0;
475
 
        }
476
 
      ptr++;
477
 
      minor = grub_strtoul (ptr, &ptr, 10);
478
 
      if (grub_errno)
479
 
        {
480
 
          grub_errno = GRUB_ERR_NONE;
481
 
          dm_task_destroy (dmt);
482
 
          return 0;
483
 
        }
484
 
 
485
 
      if (*ptr != ' ')
486
 
        {
487
 
          dm_task_destroy (dmt);
488
 
          return 0;
489
 
        }
490
 
      ptr++;
491
 
      partstart += grub_strtoull (ptr, &ptr, 10);
492
 
      if (grub_errno)
493
 
        {
494
 
          grub_errno = GRUB_ERR_NONE;
495
 
          dm_task_destroy (dmt);
496
 
          return 0;
497
 
        }
498
 
 
499
 
      dm_task_destroy (dmt);
500
 
      first = 0;
501
 
    }
502
 
  if (first)
503
 
    return 0;
504
 
  if (maj)
505
 
    *maj = major;
506
 
  if (min)
507
 
    *min = minor;
508
 
  if (st)
509
 
    *st = partstart;
510
 
  return 1;
511
 
}
512
 
#endif
513
 
 
514
 
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
515
 
 
516
 
/* FIXME: geom actually gives us the whole container hierarchy.
517
 
   It can be used more efficiently than this.  */
518
 
void
519
 
grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
520
 
{
521
 
  struct gmesh mesh;
522
 
  struct gclass *class;
523
 
  int error;
524
 
  struct ggeom *geom;
525
 
 
526
 
  grub_util_info ("following geom '%s'", name);
527
 
 
528
 
  error = geom_gettree (&mesh);
529
 
  if (error != 0)
530
 
    /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
531
 
       Usually left untranslated.
532
 
     */
533
 
    grub_util_error ("%s", _("couldn't open geom"));
534
 
 
535
 
  LIST_FOREACH (class, &mesh.lg_class, lg_class)
536
 
    if (strcasecmp (class->lg_name, "part") == 0)
537
 
      break;
538
 
  if (!class)
539
 
    /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
540
 
       Usually left untranslated. "part" is the identifier of one of its
541
 
       classes.  */
542
 
    grub_util_error ("%s", _("couldn't find geom `part' class"));
543
 
 
544
 
  LIST_FOREACH (geom, &class->lg_geom, lg_geom)
545
 
    { 
546
 
      struct gprovider *provider;
547
 
      LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
548
 
        if (strcmp (provider->lg_name, name) == 0)
549
 
          {
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);
554
 
 
555
 
            grub_util_follow_gpart_up (name_tmp, &off, name_out);
556
 
            free (name_tmp);
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);
560
 
            if (off_out)
561
 
              *off_out = off;
562
 
            return;
563
 
          }
564
 
    }
565
 
  grub_util_info ("geom '%s' has no parent", name);
566
 
  if (name_out)
567
 
    *name_out = xstrdup (name);
568
 
  if (off_out)
569
 
    *off_out = 0;
570
 
}
571
 
 
572
 
grub_disk_addr_t
573
 
grub_hostdisk_find_partition_start (const char *dev)
574
 
{
575
 
  grub_disk_addr_t out;
576
 
  if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
577
 
    return 0;
578
 
  grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
579
 
 
580
 
  return out;
581
 
}
582
 
 
583
 
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
584
 
#ifdef __linux__
585
 
static char *
586
 
sysfs_partition_path (const char *dev, const char *entry)
587
 
{
588
 
  const char *argv[7];
589
 
  int pipe_fd[2];
590
 
  pid_t pid;
591
 
  FILE *udevadm;
592
 
  char *buf = NULL;
593
 
  size_t len = 0;
594
 
  char *path = NULL;
595
 
 
596
 
  argv[0] = "udevadm";
597
 
  argv[1] = "info";
598
 
  argv[2] = "--query";
599
 
  argv[3] = "path";
600
 
  argv[4] = "--name";
601
 
  argv[5] = dev;
602
 
  argv[6] = NULL;
603
 
 
604
 
  if (pipe (pipe_fd) < 0)
605
 
    {
606
 
      grub_util_warn (_("Unable to create pipe: %s"), strerror (errno));
607
 
      return NULL;
608
 
    }
609
 
  pid = fork ();
610
 
  if (pid < 0)
611
 
    grub_util_error (_("Unable to fork: %s"), strerror (errno));
612
 
  else if (pid == 0)
613
 
    {
614
 
      /* Child.  */
615
 
      /* Ensure child is not localised.  */
616
 
      setenv ("LC_ALL", "C", 1);
617
 
 
618
 
      close (pipe_fd[0]);
619
 
      dup2 (pipe_fd[1], STDOUT_FILENO);
620
 
      close (pipe_fd[1]);
621
 
 
622
 
      execvp ((char *) argv[0], (char **) argv);
623
 
      exit (127);
624
 
    }
625
 
  else
626
 
    {
627
 
      /* Parent.  Read udevadm's output.  */
628
 
      close (pipe_fd[1]);
629
 
 
630
 
      udevadm = fdopen (pipe_fd[0], "r");
631
 
      if (!udevadm)
632
 
        {
633
 
          grub_util_warn (_("Unable to open stream from %s: %s"),
634
 
                          "udevadm", strerror (errno));
635
 
          close (pipe_fd[0]);
636
 
          goto out;
637
 
        }
638
 
 
639
 
      if (getline (&buf, &len, udevadm) > 0)
640
 
        {
641
 
          char *newline;
642
 
 
643
 
          newline = strchr (buf, '\n');
644
 
          if (newline)
645
 
            *newline = '\0';
646
 
          path = xasprintf ("/sys%s/%s", buf, entry);
647
 
        }
648
 
 
649
 
out:
650
 
      if (udevadm)
651
 
        fclose (udevadm);
652
 
      waitpid (pid, NULL, 0);
653
 
      free (buf);
654
 
 
655
 
      return path;
656
 
    }
657
 
}
658
 
 
659
 
static int
660
 
sysfs_partition_start (const char *dev, grub_disk_addr_t *start)
661
 
{
662
 
  char *path;
663
 
  FILE *fp;
664
 
  unsigned long long val;
665
 
  int ret = 0;
666
 
 
667
 
  path = sysfs_partition_path (dev, "start");
668
 
  if (!path)
669
 
    return 0;
670
 
 
671
 
  fp = fopen (path, "r");
672
 
  if (!fp)
673
 
    goto out;
674
 
 
675
 
  if (fscanf (fp, "%llu", &val) == 1)
676
 
    {
677
 
      *start = (grub_disk_addr_t) val;
678
 
      ret = 1;
679
 
    }
680
 
 
681
 
out:
682
 
  free (path);
683
 
  if (fp)
684
 
    fclose (fp);
685
 
 
686
 
  return ret;
687
 
}
688
 
#endif /* __linux__ */
689
 
 
690
 
grub_disk_addr_t
691
 
grub_hostdisk_find_partition_start (const char *dev)
692
 
{
693
 
  int fd;
694
 
#ifdef __linux__
695
 
  grub_disk_addr_t start = 0;
696
 
#endif /* __linux__ */
697
 
#ifdef __sun__
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;
706
 
  int p_index;
707
 
# endif /* !defined(HAVE_DIOCGDINFO) */
708
 
 
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 */
715
 
 
716
 
# ifdef __linux__
717
 
  if (sysfs_partition_start (dev, &start))
718
 
    return start;
719
 
# endif /* __linux__ */
720
 
 
721
 
  fd = open (dev, O_RDONLY);
722
 
  if (fd == -1)
723
 
    {
724
 
      grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
725
 
                  dev, strerror (errno));
726
 
      return 0;
727
 
    }
728
 
 
729
 
#if defined(__sun__)
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)
738
 
    {
739
 
      close (fd);
740
 
      return (grub_disk_addr_t) dkw.dkw_offset;
741
 
    }
742
 
#  endif /* defined(__NetBSD__) */
743
 
  if (ioctl (fd, DIOCGDINFO, &label) == -1)
744
 
# endif /* !defined(HAVE_DIOCGDINFO) */
745
 
    {
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) */
752
 
      close (fd);
753
 
      return 0;
754
 
    }
755
 
 
756
 
  close (fd);
757
 
 
758
 
#ifdef __sun__
759
 
  return pinfo.p_start;
760
 
# elif !defined(HAVE_DIOCGDINFO)
761
 
  return hdg.start;
762
 
# else /* defined(HAVE_DIOCGDINFO) */
763
 
  if (dev[0])
764
 
    p_index = dev[strlen(dev) - 1] - 'a';
765
 
  else
766
 
    p_index = -1;
767
 
  
768
 
  if (p_index >= label.d_npartitions || p_index < 0)
769
 
    {
770
 
      grub_error (GRUB_ERR_BAD_DEVICE,
771
 
                  "no disk label entry for `%s'", dev);
772
 
      return 0;
773
 
    }
774
 
  return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
775
 
# endif /* !defined(HAVE_DIOCGDINFO) */
776
 
}
777
 
#endif /* __linux__ || __CYGWIN__ || HAVE_DIOCGDINFO */
778
 
 
779
 
#ifdef __linux__
780
 
/* Cache of partition start sectors for each disk.  */
781
 
struct linux_partition_cache
782
 
{
783
 
  struct linux_partition_cache *next;
784
 
  struct linux_partition_cache **prev;
785
 
  char *dev;
786
 
  unsigned long start;
787
 
  int partno;
788
 
};
789
 
 
790
 
struct linux_partition_cache *linux_partition_cache_list;
791
 
 
792
 
static int
793
 
linux_find_partition (char *dev, grub_disk_addr_t sector)
794
 
{
795
 
  size_t len = strlen (dev);
796
 
  const char *format;
797
 
  char *p;
798
 
  int i;
799
 
  char real_dev[PATH_MAX];
800
 
  struct linux_partition_cache *cache;
801
 
  int missing = 0;
802
 
 
803
 
  strcpy(real_dev, dev);
804
 
 
805
 
  if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
806
 
    {
807
 
      p = real_dev + len - 4;
808
 
      format = "part%d";
809
 
    }
810
 
  else if (strncmp (real_dev, "/dev/disk/by-id/",
811
 
                    sizeof ("/dev/disk/by-id/") - 1) == 0)
812
 
    {
813
 
      p = real_dev + len;
814
 
      format = "-part%d";
815
 
    }
816
 
  else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
817
 
    {
818
 
      p = real_dev + len;
819
 
      format = "p%d";
820
 
    }
821
 
  else
822
 
    {
823
 
      p = real_dev + len;
824
 
      format = "%d";
825
 
    }
826
 
 
827
 
  for (cache = linux_partition_cache_list; cache; cache = cache->next)
828
 
    {
829
 
      if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
830
 
        {
831
 
          sprintf (p, format, cache->partno);
832
 
          strcpy (dev, real_dev);
833
 
          return 1;
834
 
        }
835
 
    }
836
 
 
837
 
  for (i = 1; i < 10000; i++)
838
 
    {
839
 
      int fd;
840
 
      grub_disk_addr_t start;
841
 
 
842
 
      sprintf (p, format, i);
843
 
 
844
 
      fd = open (real_dev, O_RDONLY);
845
 
      if (fd == -1)
846
 
        {
847
 
          if (missing++ < 10)
848
 
            continue;
849
 
          else
850
 
            return 0;
851
 
        }
852
 
      missing = 0;
853
 
      close (fd);
854
 
 
855
 
      start = grub_hostdisk_find_partition_start (real_dev);
856
 
      /* We don't care about errors here.  */
857
 
      grub_errno = GRUB_ERR_NONE;
858
 
 
859
 
      if (start == sector)
860
 
        {
861
 
          struct linux_partition_cache *new_cache_item;
862
 
 
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));
869
 
 
870
 
          strcpy (dev, real_dev);
871
 
          return 1;
872
 
        }
873
 
    }
874
 
 
875
 
  return 0;
876
 
}
877
 
#endif /* __linux__ */
878
 
 
879
 
#if defined(__linux__) && (!defined(__GLIBC__) || \
880
 
        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
881
 
  /* Maybe libc doesn't have large file support.  */
882
 
grub_err_t
883
 
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
884
 
{
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);
890
 
 
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;
896
 
}
897
 
#else
898
 
grub_err_t
899
 
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
900
 
{
901
 
  off_t offset = (off_t) off;
902
 
 
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));
906
 
  return 0;
907
 
}
908
 
#endif
909
 
 
910
 
static void
911
 
flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
912
 
{
913
 
#ifdef __linux__
914
 
  int fd;
915
 
  struct stat st;
916
 
 
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);
920
 
  if (fd >= 0)
921
 
    close (fd);
922
 
#endif
923
179
}
924
180
 
925
181
const char *
926
182
grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
927
183
{
928
184
  unsigned int i;
 
185
  char *canon;
 
186
 
 
187
  canon = canonicalize_file_name (os_disk);
 
188
  if (!canon)
 
189
    canon = xstrdup (os_disk);
929
190
 
930
191
  for (i = 0; i < ARRAY_SIZE (map); i++)
931
192
    if (! map[i].device)
932
193
      break;
933
 
    else if (strcmp (map[i].device, os_disk) == 0)
934
 
      return map[i].drive;
 
194
    else if (strcmp (map[i].device, canon) == 0)
 
195
      {
 
196
        free (canon);
 
197
        return map[i].drive;
 
198
      }
935
199
 
936
200
  if (!add)
937
 
    return NULL;
 
201
    {
 
202
      free (canon);
 
203
      return NULL;
 
204
    }
938
205
 
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"));
942
209
 
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;
948
215
 
949
 
  flush_initial_buffer (os_disk);
 
216
  grub_hostdisk_flush_initial_buffer (os_disk);
950
217
 
951
218
  return map[i].drive;
952
219
}
953
220
 
954
 
static int
955
 
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
956
 
             grub_disk_addr_t *max)
 
221
#ifndef __linux__
 
222
grub_util_fd_t
 
223
grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
 
224
                          grub_disk_addr_t *max)
957
225
{
958
 
  int fd;
959
 
  struct grub_util_biosdisk_data *data = disk->data;
 
226
  grub_util_fd_t fd;
 
227
  struct grub_util_hostdisk_data *data = disk->data;
960
228
 
961
229
  *max = ~0ULL;
962
230
 
963
 
#ifdef O_LARGEFILE
964
 
  flags |= O_LARGEFILE;
965
 
#endif
966
 
#ifdef O_SYNC
967
 
  flags |= O_SYNC;
968
 
#endif
969
 
#ifdef O_FSYNC
970
 
  flags |= O_FSYNC;
971
 
#endif
972
 
#ifdef O_BINARY
973
 
  flags |= O_BINARY;
974
 
#endif
975
 
 
976
 
#ifdef __linux__
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.  */
979
 
  {
980
 
    int is_partition = 0;
981
 
    char dev[PATH_MAX];
982
 
    grub_disk_addr_t part_start = 0;
983
 
 
984
 
    part_start = grub_partition_get_start (disk->partition);
985
 
 
986
 
    strcpy (dev, map[disk->id].device);
987
 
    if (disk->partition
988
 
        && strncmp (map[disk->id].device, "/dev/", 5) == 0)
989
 
      {
990
 
        if (sector >= part_start)
991
 
          is_partition = linux_find_partition (dev, part_start);
992
 
        else
993
 
          *max = part_start - sector;
994
 
      }
995
 
 
996
 
  reopen:
997
 
 
998
 
    if (data->dev && strcmp (data->dev, dev) == 0 &&
999
 
        data->access_mode == (flags & O_ACCMODE))
1000
 
      {
1001
 
        grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
1002
 
        fd = data->fd;
1003
 
      }
1004
 
    else
1005
 
      {
1006
 
        free (data->dev);
1007
 
        data->dev = 0;
1008
 
        if (data->fd != -1)
1009
 
          {
1010
 
            if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
1011
 
              {
1012
 
                fsync (data->fd);
1013
 
#ifdef __linux__
1014
 
                if (data->is_disk)
1015
 
                  ioctl (data->fd, BLKFLSBUF, 0);
1016
 
#endif
1017
 
              }
1018
 
 
1019
 
            close (data->fd);
1020
 
            data->fd = -1;
1021
 
          }
1022
 
 
1023
 
        /* Open the partition.  */
1024
 
        grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
1025
 
        fd = open (dev, flags);
1026
 
        if (fd < 0)
1027
 
          {
1028
 
            grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
1029
 
                        dev, strerror (errno));
1030
 
            return -1;
1031
 
          }
1032
 
 
1033
 
        data->dev = xstrdup (dev);
1034
 
        data->access_mode = (flags & O_ACCMODE);
1035
 
        data->fd = fd;
1036
 
 
1037
 
#ifdef __linux__
1038
 
        if (data->is_disk)
1039
 
          ioctl (data->fd, BLKFLSBUF, 0);
1040
 
#endif
1041
 
      }
1042
 
 
1043
 
    if (is_partition)
1044
 
      {
1045
 
        *max = grub_util_get_fd_size (fd, dev, 0);
1046
 
        *max >>= disk->log_sector_size;
1047
 
        if (sector - part_start >= *max)
1048
 
          {
1049
 
            *max = disk->partition->len - (sector - part_start);
1050
 
            if (*max == 0)
1051
 
              *max = ~0ULL;
1052
 
            is_partition = 0;
1053
 
            strcpy (dev, map[disk->id].device);
1054
 
            goto reopen;
1055
 
          }
1056
 
        sector -= part_start;
1057
 
        *max -= sector;
1058
 
      }
1059
 
  }
1060
 
#else /* ! __linux__ */
1061
 
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
1062
 
  int sysctl_flags, sysctl_oldflags;
1063
 
  size_t sysctl_size = sizeof (sysctl_flags);
1064
 
 
1065
 
  if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0))
1066
 
    {
1067
 
      grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags");
1068
 
      return -1;
1069
 
    }
1070
 
  sysctl_flags = sysctl_oldflags | 0x10;
1071
 
  if (! (sysctl_oldflags & 0x10)
1072
 
      && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size))
1073
 
    {
1074
 
      grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags");
1075
 
      return -1;
1076
 
    }
1077
 
#endif
 
231
  flags |= GRUB_UTIL_FD_O_SYNC;
1078
232
 
1079
233
  if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 &&
1080
234
      data->access_mode == (flags & O_ACCMODE))
1086
240
    {
1087
241
      free (data->dev);
1088
242
      data->dev = 0;
1089
 
      if (data->fd != -1)
 
243
      if (GRUB_UTIL_FD_IS_VALID(data->fd))
1090
244
        {
1091
245
            if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
1092
 
              {
1093
 
                fsync (data->fd);
1094
 
#ifdef __linux__
1095
 
                if (data->is_disk)
1096
 
                  ioctl (data->fd, BLKFLSBUF, 0);
1097
 
#endif
1098
 
              }
1099
 
            close (data->fd);
1100
 
            data->fd = -1;
 
246
              grub_util_fd_sync (data->fd);
 
247
            grub_util_fd_close (data->fd);
 
248
            data->fd = GRUB_UTIL_FD_INVALID;
1101
249
        }
1102
250
 
1103
 
      fd = open (map[disk->id].device, flags);
1104
 
      if (fd >= 0)
 
251
      fd = grub_util_fd_open (map[disk->id].device, flags);
 
252
      if (GRUB_UTIL_FD_IS_VALID(fd))
1105
253
        {
1106
254
          data->dev = xstrdup (map[disk->id].device);
1107
255
          data->access_mode = (flags & O_ACCMODE);
1109
257
        }
1110
258
    }
1111
259
 
1112
 
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1113
 
  if (! (sysctl_oldflags & 0x10)
1114
 
      && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size))
1115
 
    {
1116
 
      grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
1117
 
      return -1;
1118
 
    }
1119
 
#endif
1120
 
 
1121
 
#if defined(__APPLE__)
1122
 
  /* If we can't have exclusive access, try shared access */
1123
 
  if (fd < 0)
1124
 
    fd = open(map[disk->id].device, flags | O_SHLOCK);
1125
 
#endif
1126
 
 
1127
 
  if (fd < 0)
 
260
  if (!GRUB_UTIL_FD_IS_VALID(data->fd))
1128
261
    {
1129
262
      grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
1130
 
                  map[disk->id].device, strerror (errno));
1131
 
      return -1;
 
263
                  map[disk->id].device, grub_util_fd_strerror ());
 
264
      return GRUB_UTIL_FD_INVALID;
1132
265
    }
1133
 
#endif /* ! __linux__ */
1134
 
 
1135
 
#if defined(__NetBSD__)
1136
 
  configure_device_driver (fd);
1137
 
#endif /* defined(__NetBSD__) */
1138
 
 
1139
 
  if (grub_util_fd_seek (fd, map[disk->id].device,
1140
 
                         sector << disk->log_sector_size))
 
266
 
 
267
  if (grub_util_fd_seek (fd, sector << disk->log_sector_size))
1141
268
    {
1142
 
      close (fd);
1143
 
      return -1;
 
269
      grub_util_fd_close (fd);
 
270
      grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
 
271
                  map[disk->id].device, grub_util_fd_strerror ());
 
272
 
 
273
      return GRUB_UTIL_FD_INVALID;
1144
274
    }
1145
275
 
1146
276
  return fd;
1147
277
}
1148
 
 
1149
 
/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
1150
 
   error occurs, otherwise return LEN.  */
1151
 
ssize_t
1152
 
grub_util_fd_read (int fd, char *buf, size_t len)
1153
 
{
1154
 
  ssize_t size = len;
1155
 
 
1156
 
  while (len)
1157
 
    {
1158
 
      ssize_t ret = read (fd, buf, len);
1159
 
 
1160
 
      if (ret <= 0)
1161
 
        {
1162
 
          if (errno == EINTR)
1163
 
            continue;
1164
 
          else
1165
 
            return ret;
1166
 
        }
1167
 
 
1168
 
      len -= ret;
1169
 
      buf += ret;
1170
 
    }
1171
 
 
1172
 
  return size;
1173
 
}
1174
 
 
1175
 
/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
1176
 
   error occurs, otherwise return LEN.  */
1177
 
ssize_t
1178
 
grub_util_fd_write (int fd, const char *buf, size_t len)
1179
 
{
1180
 
  ssize_t size = len;
1181
 
 
1182
 
  while (len)
1183
 
    {
1184
 
      ssize_t ret = write (fd, buf, len);
1185
 
 
1186
 
      if (ret <= 0)
1187
 
        {
1188
 
          if (errno == EINTR)
1189
 
            continue;
1190
 
          else
1191
 
            return ret;
1192
 
        }
1193
 
 
1194
 
      len -= ret;
1195
 
      buf += ret;
1196
 
    }
1197
 
 
1198
 
  return size;
1199
 
}
 
278
#endif
 
279
 
1200
280
 
1201
281
static grub_err_t
1202
282
grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
1204
284
{
1205
285
  while (size)
1206
286
    {
1207
 
      int fd;
 
287
      grub_util_fd_t fd;
1208
288
      grub_disk_addr_t max = ~0ULL;
1209
 
      fd = open_device (disk, sector, O_RDONLY, &max);
1210
 
      if (fd < 0)
 
289
      fd = grub_util_fd_open_device (disk, sector, GRUB_UTIL_FD_O_RDONLY, &max);
 
290
      if (!GRUB_UTIL_FD_IS_VALID (fd))
1211
291
        return grub_errno;
1212
292
 
1213
293
#ifdef __linux__
1225
305
      if (grub_util_fd_read (fd, buf, max << disk->log_sector_size)
1226
306
          != (ssize_t) (max << disk->log_sector_size))
1227
307
        return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
1228
 
                           map[disk->id].device, strerror (errno));
 
308
                           map[disk->id].device, grub_util_fd_strerror ());
1229
309
      size -= max;
1230
310
      buf += (max << disk->log_sector_size);
1231
311
      sector += max;
1239
319
{
1240
320
  while (size)
1241
321
    {
1242
 
      int fd;
 
322
      grub_util_fd_t fd;
1243
323
      grub_disk_addr_t max = ~0ULL;
1244
 
      fd = open_device (disk, sector, O_WRONLY, &max);
1245
 
      if (fd < 0)
 
324
      fd = grub_util_fd_open_device (disk, sector, GRUB_UTIL_FD_O_WRONLY, &max);
 
325
      if (!GRUB_UTIL_FD_IS_VALID (fd))
1246
326
        return grub_errno;
1247
327
 
1248
328
#ifdef __linux__
1260
340
      if (grub_util_fd_write (fd, buf, max << disk->log_sector_size)
1261
341
          != (ssize_t) (max << disk->log_sector_size))
1262
342
        return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write to `%s': %s"),
1263
 
                           map[disk->id].device, strerror (errno));
 
343
                           map[disk->id].device, grub_util_fd_strerror ());
1264
344
      size -= max;
1265
345
      buf += (max << disk->log_sector_size);
1266
346
    }
1270
350
grub_err_t
1271
351
grub_util_biosdisk_flush (struct grub_disk *disk)
1272
352
{
1273
 
  struct grub_util_biosdisk_data *data = disk->data;
 
353
  struct grub_util_hostdisk_data *data = disk->data;
1274
354
 
1275
355
  if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID)
1276
356
    return GRUB_ERR_NONE;
1277
 
  if (data->fd == -1)
 
357
  if (!GRUB_UTIL_FD_IS_VALID (data->fd))
1278
358
    {
1279
359
      grub_disk_addr_t max;
1280
 
      data->fd = open_device (disk, 0, O_RDONLY, &max);
1281
 
      if (data->fd < 0)
 
360
      data->fd = grub_util_fd_open_device (disk, 0, GRUB_UTIL_FD_O_RDONLY, &max);
 
361
      if (!GRUB_UTIL_FD_IS_VALID (data->fd))
1282
362
        return grub_errno;
1283
363
    }
1284
 
  fsync (data->fd);
 
364
  grub_util_fd_sync (data->fd);
1285
365
#ifdef __linux__
1286
366
  if (data->is_disk)
1287
367
    ioctl (data->fd, BLKFLSBUF, 0);
1292
372
static void
1293
373
grub_util_biosdisk_close (struct grub_disk *disk)
1294
374
{
1295
 
  struct grub_util_biosdisk_data *data = disk->data;
 
375
  struct grub_util_hostdisk_data *data = disk->data;
1296
376
 
1297
377
  free (data->dev);
1298
 
  if (data->fd != -1)
 
378
  if (GRUB_UTIL_FD_IS_VALID (data->fd))
1299
379
    {
1300
380
      if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
1301
381
        grub_util_biosdisk_flush (disk);
1302
 
      close (data->fd);
 
382
      grub_util_fd_close (data->fd);
1303
383
    }
1304
384
  free (data);
1305
385
}
1316
396
    .next = 0
1317
397
  };
1318
398
 
 
399
static int
 
400
grub_util_check_file_presence (const char *p)
 
401
{
 
402
#if !GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
 
403
  grub_util_fd_t h;
 
404
  h = grub_util_fd_open (p, GRUB_UTIL_FD_O_RDONLY);
 
405
  if (!GRUB_UTIL_FD_IS_VALID(h))
 
406
    return 0;
 
407
  grub_util_fd_close (h);
 
408
  return 1;
 
409
#else
 
410
  struct stat st;
 
411
 
 
412
  if (stat (p, &st) == -1)
 
413
    return 0;
 
414
  return 1;
 
415
#endif
 
416
}
 
417
 
1319
418
static void
1320
419
read_device_map (const char *dev_map)
1321
420
{
1322
421
  FILE *fp;
1323
422
  char buf[1024];       /* XXX */
1324
423
  int lineno = 0;
1325
 
  struct stat st;
1326
 
 
1327
 
  auto void show_error (const char *msg)
1328
 
    __attribute__ ((noreturn));
1329
 
  void __attribute__ ((noreturn)) show_error (const char *msg)
1330
 
    {
1331
 
      grub_util_error ("%s:%d: %s", dev_map, lineno, msg);
1332
 
    }
1333
424
 
1334
425
  if (dev_map[0] == '\0')
1335
426
    {
1337
428
      return;
1338
429
    }
1339
430
 
1340
 
  fp = fopen (dev_map, "r");
 
431
  fp = grub_util_fopen (dev_map, "r");
1341
432
  if (! fp)
1342
433
    {
1343
434
      grub_util_info (_("cannot open `%s': %s"), dev_map, strerror (errno));
1365
456
        {
1366
457
          char *tmp;
1367
458
          tmp = xasprintf (_("missing `%c' symbol"), '(');
1368
 
          show_error (tmp);
 
459
          grub_util_error ("%s:%d: %s", dev_map, lineno, tmp);
1369
460
        }
1370
461
 
1371
462
      p++;
1372
463
      /* Find a free slot.  */
1373
464
      drive = find_free_slot ();
1374
465
      if (drive < 0)
1375
 
        show_error (_("device count exceeds limit"));
 
466
        grub_util_error ("%s:%d: %s", dev_map, lineno, _("device count exceeds limit"));
1376
467
 
1377
468
      e = p;
1378
469
      p = strchr (p, ')');
1380
471
        {
1381
472
          char *tmp;
1382
473
          tmp = xasprintf (_("missing `%c' symbol"), ')');
1383
 
          show_error (tmp);
 
474
          grub_util_error ("%s:%d: %s", dev_map, lineno, tmp);
1384
475
        }
1385
476
 
1386
477
      map[drive].drive = 0;
1425
516
        p++;
1426
517
 
1427
518
      if (*p == '\0')
1428
 
        show_error (_("filename expected"));
 
519
        grub_util_error ("%s:%d: %s", dev_map, lineno, _("filename expected"));
1429
520
 
1430
521
      /* NUL-terminate the filename.  */
1431
522
      e = p;
1433
524
        e++;
1434
525
      *e = '\0';
1435
526
 
1436
 
#ifdef __MINGW32__
1437
 
      (void) st;
1438
 
      if (grub_util_get_disk_size (p) == -1LL)
1439
 
#else
1440
 
      if (stat (p, &st) == -1)
1441
 
#endif
 
527
      if (!grub_util_check_file_presence (p))
1442
528
        {
1443
529
          free (map[drive].drive);
1444
530
          map[drive].drive = NULL;
1458
544
            }
1459
545
        }
1460
546
 
1461
 
#ifdef __linux__
1462
547
      /* On Linux, the devfs uses symbolic links horribly, and that
1463
548
         confuses the interface very much, so use realpath to expand
1464
 
         symbolic links.  Leave /dev/mapper/ alone, though.  */
1465
 
      if (strncmp (p, "/dev/mapper/", 12) != 0)
1466
 
        {
1467
 
          map[drive].device = xmalloc (PATH_MAX);
1468
 
          if (! realpath (p, map[drive].device))
1469
 
            grub_util_error (_("failed to get canonical path of %s"), p);
1470
 
        }
1471
 
      else
1472
 
#endif
1473
 
      map[drive].device = xstrdup (p);
 
549
         symbolic links.  */
 
550
      map[drive].device = canonicalize_file_name (p);
 
551
      if (! map[drive].device)
 
552
        map[drive].device = xstrdup (p);
 
553
      
1474
554
      if (!map[drive].drive)
1475
555
        {
1476
556
          char c;
1492
572
          *drive_p = c;
1493
573
        }
1494
574
 
1495
 
      flush_initial_buffer (map[drive].device);
 
575
      grub_util_info ("adding `%s' -> `%s' from device.map", map[drive].drive,
 
576
                      map[drive].device);
 
577
 
 
578
      grub_hostdisk_flush_initial_buffer (map[drive].device);
1496
579
    }
1497
580
 
1498
581
  fclose (fp);
1538
621
 
1539
622
  return map[disk->id].device;
1540
623
}
 
624
 
 
625
 
 
626
static char *
 
627
grub_util_path_concat_real (size_t n, int ext, va_list ap)
 
628
{
 
629
  size_t totlen = 0;
 
630
  char **l = xmalloc ((n + ext) * sizeof (l[0]));
 
631
  char *r, *p, *pi;
 
632
  size_t i;
 
633
  int first = 1;
 
634
 
 
635
  for (i = 0; i < n + ext; i++)
 
636
    {
 
637
      l[i] = va_arg (ap, char *);
 
638
      if (l[i])
 
639
        totlen += strlen (l[i]) + 1;
 
640
    }
 
641
 
 
642
  r = xmalloc (totlen + 10);
 
643
 
 
644
  p = r;
 
645
  for (i = 0; i < n; i++)
 
646
    {
 
647
      pi = l[i];
 
648
      if (!pi)
 
649
        continue;
 
650
      while (*pi == '/')
 
651
        pi++;
 
652
      if ((p != r || (pi != l[i] && first)) && (p == r || *(p - 1) != '/'))
 
653
        *p++ = '/';
 
654
      first = 0;
 
655
      p = grub_stpcpy (p, pi);
 
656
      while (p != r && p != r + 1 && *(p - 1) == '/')
 
657
        p--;
 
658
    }
 
659
 
 
660
  if (ext && l[i])
 
661
    p = grub_stpcpy (p, l[i]);
 
662
 
 
663
  *p = '\0';
 
664
 
 
665
  free (l);
 
666
 
 
667
  return r;
 
668
}
 
669
 
 
670
char *
 
671
grub_util_path_concat (size_t n, ...)
 
672
{
 
673
  va_list ap;
 
674
  char *r;
 
675
 
 
676
  va_start (ap, n);
 
677
 
 
678
  r = grub_util_path_concat_real (n, 0, ap);
 
679
 
 
680
  va_end (ap);
 
681
 
 
682
  return r;
 
683
}
 
684
 
 
685
char *
 
686
grub_util_path_concat_ext (size_t n, ...)
 
687
{
 
688
  va_list ap;
 
689
  char *r;
 
690
 
 
691
  va_start (ap, n);
 
692
 
 
693
  r = grub_util_path_concat_real (n, 1, ap);
 
694
 
 
695
  va_end (ap);
 
696
 
 
697
  return r;
 
698
}