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

« back to all changes in this revision

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

Tags: upstream-1.99~20101122
ImportĀ upstreamĀ versionĀ 1.99~20101122

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <config-util.h>
 
20
#include <config.h>
 
21
 
 
22
#include <errno.h>
 
23
#include <error.h>
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <stdint.h>
 
27
#include <string.h>
 
28
#include <sys/time.h>
 
29
#include <sys/types.h>
 
30
#include <sys/stat.h>
 
31
#include <unistd.h>
 
32
#ifdef HAVE_LIMITS_H
 
33
#include <limits.h>
 
34
#endif
 
35
 
 
36
#include <grub/mm.h>
 
37
#include <grub/err.h>
 
38
#include <grub/env.h>
 
39
#include <grub/types.h>
 
40
#include <grub/misc.h>
 
41
#include <grub/i18n.h>
 
42
#include <grub/time.h>
 
43
#include <grub/emu/misc.h>
 
44
 
 
45
#ifdef HAVE_DEVICE_MAPPER
 
46
# include <libdevmapper.h>
 
47
#endif
 
48
 
 
49
#ifdef HAVE_LIBZFS
 
50
# include <grub/util/libzfs.h>
 
51
#endif
 
52
 
 
53
#ifdef HAVE_LIBNVPAIR
 
54
# include <grub/util/libnvpair.h>
 
55
#endif
 
56
 
 
57
#ifdef HAVE_SYS_PARAM_H
 
58
# include <sys/param.h>
 
59
#endif
 
60
 
 
61
#ifdef HAVE_SYS_MOUNT_H
 
62
# include <sys/mount.h>
 
63
#endif
 
64
 
 
65
#ifdef HAVE_SYS_MNTTAB_H
 
66
# include <stdio.h> /* Needed by sys/mnttab.h.  */
 
67
# include <sys/mnttab.h>
 
68
#endif
 
69
 
 
70
#ifdef HAVE_SYS_MKDEV_H
 
71
# include <sys/mkdev.h> /* makedev */
 
72
#endif
 
73
 
 
74
int verbosity;
 
75
 
 
76
void
 
77
grub_util_warn (const char *fmt, ...)
 
78
{
 
79
  va_list ap;
 
80
 
 
81
  fprintf (stderr, _("%s: warn:"), program_name);
 
82
  fprintf (stderr, " ");
 
83
  va_start (ap, fmt);
 
84
  vfprintf (stderr, fmt, ap);
 
85
  va_end (ap);
 
86
  fprintf (stderr, ".\n");
 
87
  fflush (stderr);
 
88
}
 
89
 
 
90
void
 
91
grub_util_info (const char *fmt, ...)
 
92
{
 
93
  if (verbosity > 0)
 
94
    {
 
95
      va_list ap;
 
96
 
 
97
      fprintf (stderr, _("%s: info:"), program_name);
 
98
      fprintf (stderr, " ");
 
99
      va_start (ap, fmt);
 
100
      vfprintf (stderr, fmt, ap);
 
101
      va_end (ap);
 
102
      fprintf (stderr, ".\n");
 
103
      fflush (stderr);
 
104
    }
 
105
}
 
106
 
 
107
void
 
108
grub_util_error (const char *fmt, ...)
 
109
{
 
110
  va_list ap;
 
111
 
 
112
  fprintf (stderr, _("%s: error:"), program_name);
 
113
  fprintf (stderr, " ");
 
114
  va_start (ap, fmt);
 
115
  vfprintf (stderr, fmt, ap);
 
116
  va_end (ap);
 
117
  fprintf (stderr, ".\n");
 
118
  exit (1);
 
119
}
 
120
 
 
121
void *
 
122
xmalloc (grub_size_t size)
 
123
{
 
124
  void *p;
 
125
 
 
126
  p = malloc (size);
 
127
  if (! p)
 
128
    grub_util_error ("out of memory");
 
129
 
 
130
  return p;
 
131
}
 
132
 
 
133
void *
 
134
xrealloc (void *ptr, grub_size_t size)
 
135
{
 
136
  ptr = realloc (ptr, size);
 
137
  if (! ptr)
 
138
    grub_util_error ("out of memory");
 
139
 
 
140
  return ptr;
 
141
}
 
142
 
 
143
char *
 
144
xstrdup (const char *str)
 
145
{
 
146
  size_t len;
 
147
  char *newstr;
 
148
 
 
149
  len = strlen (str);
 
150
  newstr = (char *) xmalloc (len + 1);
 
151
  memcpy (newstr, str, len + 1);
 
152
 
 
153
  return newstr;
 
154
}
 
155
 
 
156
#ifndef HAVE_VASPRINTF
 
157
 
 
158
int
 
159
vasprintf (char **buf, const char *fmt, va_list ap)
 
160
{
 
161
  /* Should be large enough.  */
 
162
  *buf = xmalloc (512);
 
163
 
 
164
  return vsnprintf (*buf, 512, fmt, ap);
 
165
}
 
166
 
 
167
#endif
 
168
 
 
169
#ifndef  HAVE_ASPRINTF
 
170
 
 
171
int
 
172
asprintf (char **buf, const char *fmt, ...)
 
173
{
 
174
  int status;
 
175
  va_list ap;
 
176
 
 
177
  va_start (ap, fmt);
 
178
  status = vasprintf (buf, fmt, ap);
 
179
  va_end (ap);
 
180
 
 
181
  return status;
 
182
}
 
183
 
 
184
#endif
 
185
 
 
186
char *
 
187
xasprintf (const char *fmt, ...)
 
188
 
189
  va_list ap;
 
190
  char *result;
 
191
  
 
192
  va_start (ap, fmt);
 
193
  if (vasprintf (&result, fmt, ap) < 0)
 
194
    { 
 
195
      if (errno == ENOMEM)
 
196
        grub_util_error ("out of memory");
 
197
      return NULL;
 
198
    }
 
199
  
 
200
  return result;
 
201
}
 
202
 
 
203
void
 
204
grub_exit (void)
 
205
{
 
206
  exit (1);
 
207
}
 
208
 
 
209
grub_uint64_t
 
210
grub_get_time_ms (void)
 
211
{
 
212
  struct timeval tv;
 
213
 
 
214
  gettimeofday (&tv, 0);
 
215
 
 
216
  return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
 
217
}
 
218
 
 
219
grub_uint32_t
 
220
grub_get_rtc (void)
 
221
{
 
222
  struct timeval tv;
 
223
 
 
224
  gettimeofday (&tv, 0);
 
225
 
 
226
  return (tv.tv_sec * GRUB_TICKS_PER_SECOND
 
227
          + (((tv.tv_sec % GRUB_TICKS_PER_SECOND) * 1000000 + tv.tv_usec)
 
228
             * GRUB_TICKS_PER_SECOND / 1000000));
 
229
}
 
230
 
 
231
char *
 
232
canonicalize_file_name (const char *path)
 
233
{
 
234
  char *ret;
 
235
#ifdef PATH_MAX
 
236
  ret = xmalloc (PATH_MAX);
 
237
  if (!realpath (path, ret))
 
238
    return NULL;
 
239
#else
 
240
  ret = realpath (path, NULL);
 
241
#endif
 
242
  return ret;
 
243
}
 
244
 
 
245
#ifdef __CYGWIN__
 
246
/* Convert POSIX path to Win32 path,
 
247
   remove drive letter, replace backslashes.  */
 
248
static char *
 
249
get_win32_path (const char *path)
 
250
{
 
251
  char winpath[PATH_MAX];
 
252
  if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath)))
 
253
    grub_util_error ("cygwin_conv_path() failed");
 
254
 
 
255
  int len = strlen (winpath);
 
256
  int offs = (len > 2 && winpath[1] == ':' ? 2 : 0);
 
257
 
 
258
  int i;
 
259
  for (i = offs; i < len; i++)
 
260
    if (winpath[i] == '\\')
 
261
      winpath[i] = '/';
 
262
  return xstrdup (winpath + offs);
 
263
}
 
264
#endif
 
265
 
 
266
#ifdef HAVE_LIBZFS
 
267
static libzfs_handle_t *__libzfs_handle;
 
268
 
 
269
static void
 
270
fini_libzfs (void)
 
271
{
 
272
  libzfs_fini (__libzfs_handle);
 
273
}
 
274
 
 
275
libzfs_handle_t *
 
276
grub_get_libzfs_handle (void)
 
277
{
 
278
  if (! __libzfs_handle)
 
279
    {
 
280
      __libzfs_handle = libzfs_init ();
 
281
 
 
282
      if (__libzfs_handle)
 
283
        atexit (fini_libzfs);
 
284
    }
 
285
 
 
286
  return __libzfs_handle;
 
287
}
 
288
#endif /* HAVE_LIBZFS */
 
289
 
 
290
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 
291
/* ZFS has similar problems to those of btrfs (see above).  */
 
292
void
 
293
grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
 
294
{
 
295
  char *slash;
 
296
 
 
297
  *poolname = *poolfs = NULL;
 
298
 
 
299
#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
 
300
  /* FreeBSD and GNU/kFreeBSD.  */
 
301
  {
 
302
    struct statfs mnt;
 
303
 
 
304
    if (statfs (dir, &mnt) != 0)
 
305
      return;
 
306
 
 
307
    if (strcmp (mnt.f_fstypename, "zfs") != 0)
 
308
      return;
 
309
 
 
310
    *poolname = xstrdup (mnt.f_mntfromname);
 
311
  }
 
312
#elif defined(HAVE_GETEXTMNTENT)
 
313
  /* Solaris.  */
 
314
  {
 
315
    struct stat st;
 
316
    struct extmnttab mnt;
 
317
 
 
318
    if (stat (dir, &st) != 0)
 
319
      return;
 
320
 
 
321
    FILE *mnttab = fopen ("/etc/mnttab", "r");
 
322
    if (! mnttab)
 
323
      return;
 
324
 
 
325
    while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
 
326
      {
 
327
        if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
 
328
            && !strcmp (mnt.mnt_fstype, "zfs"))
 
329
          {
 
330
            *poolname = xstrdup (mnt.mnt_special);
 
331
            break;
 
332
          }
 
333
      }
 
334
 
 
335
    fclose (mnttab);
 
336
  }
 
337
#endif
 
338
 
 
339
  if (! *poolname)
 
340
    return;
 
341
 
 
342
  slash = strchr (*poolname, '/');
 
343
  if (slash)
 
344
    {
 
345
      *slash = '\0';
 
346
      *poolfs = xstrdup (slash + 1);
 
347
    }
 
348
  else
 
349
    *poolfs = xstrdup ("");
 
350
}
 
351
#endif
 
352
 
 
353
/* This function never prints trailing slashes (so that its output
 
354
   can be appended a slash unconditionally).  */
 
355
char *
 
356
grub_make_system_path_relative_to_its_root (const char *path)
 
357
{
 
358
  struct stat st;
 
359
  char *p, *buf, *buf2, *buf3, *ret;
 
360
  uintptr_t offset = 0;
 
361
  dev_t num;
 
362
  size_t len;
 
363
 
 
364
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 
365
  char *poolfs = NULL;
 
366
#endif
 
367
 
 
368
  /* canonicalize.  */
 
369
  p = canonicalize_file_name (path);
 
370
  if (p == NULL)
 
371
    grub_util_error ("failed to get canonical path of %s", path);
 
372
 
 
373
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 
374
  /* For ZFS sub-pool filesystems, could be extended to others (btrfs?).  */
 
375
  {
 
376
    char *dummy;
 
377
    grub_find_zpool_from_dir (p, &dummy, &poolfs);
 
378
  }
 
379
#endif
 
380
 
 
381
  len = strlen (p) + 1;
 
382
  buf = xstrdup (p);
 
383
  free (p);
 
384
 
 
385
  if (stat (buf, &st) < 0)
 
386
    grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
 
387
 
 
388
  buf2 = xstrdup (buf);
 
389
  num = st.st_dev;
 
390
 
 
391
  /* This loop sets offset to the number of chars of the root
 
392
     directory we're inspecting.  */
 
393
  while (1)
 
394
    {
 
395
      p = strrchr (buf, '/');
 
396
      if (p == NULL)
 
397
        /* This should never happen.  */
 
398
        grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)");
 
399
      if (p != buf)
 
400
        *p = 0;
 
401
      else
 
402
        *++p = 0;
 
403
 
 
404
      if (stat (buf, &st) < 0)
 
405
        grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
 
406
 
 
407
      /* buf is another filesystem; we found it.  */
 
408
      if (st.st_dev != num)
 
409
        {
 
410
          /* offset == 0 means path given is the mount point.
 
411
             This works around special-casing of "/" in Un*x.  This function never
 
412
             prints trailing slashes (so that its output can be appended a slash
 
413
             unconditionally).  Each slash in is considered a preceding slash, and
 
414
             therefore the root directory is an empty string.  */
 
415
          if (offset == 0)
 
416
            {
 
417
              free (buf);
 
418
              free (buf2);
 
419
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 
420
              if (poolfs)
 
421
                return xasprintf ("/%s/@", poolfs);
 
422
#endif
 
423
              return xstrdup ("");
 
424
            }
 
425
          else
 
426
            break;
 
427
        }
 
428
 
 
429
      offset = p - buf;
 
430
      /* offset == 1 means root directory.  */
 
431
      if (offset == 1)
 
432
        {
 
433
          /* Include leading slash.  */
 
434
          offset = 0;
 
435
          break;
 
436
        }
 
437
    }
 
438
  free (buf);
 
439
  buf3 = xstrdup (buf2 + offset);
 
440
  free (buf2);
 
441
 
 
442
#ifdef __CYGWIN__
 
443
  if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
 
444
    {
 
445
      /* Reached some mount point not below /cygdrive.
 
446
         GRUB does not know Cygwin's emulated mounts,
 
447
         convert to Win32 path.  */
 
448
      grub_util_info ("Cygwin path = %s\n", buf3);
 
449
      char * temp = get_win32_path (buf3);
 
450
      free (buf3);
 
451
      buf3 = temp;
 
452
    }
 
453
#endif
 
454
 
 
455
  /* Remove trailing slashes, return empty string if root directory.  */
 
456
  len = strlen (buf3);
 
457
  while (len > 0 && buf3[len - 1] == '/')
 
458
    {
 
459
      buf3[len - 1] = '\0';
 
460
      len--;
 
461
    }
 
462
 
 
463
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
 
464
  if (poolfs)
 
465
    {
 
466
      ret = xasprintf ("/%s/@%s", poolfs, buf3);
 
467
      free (buf3);
 
468
    }
 
469
  else
 
470
#endif
 
471
    ret = buf3;
 
472
 
 
473
  return ret;
 
474
}
 
475
 
 
476
#ifdef HAVE_DEVICE_MAPPER
 
477
static void device_mapper_null_log (int level __attribute__ ((unused)),
 
478
                                    const char *file __attribute__ ((unused)),
 
479
                                    int line __attribute__ ((unused)),
 
480
                                    int dm_errno __attribute__ ((unused)),
 
481
                                    const char *f __attribute__ ((unused)),
 
482
                                    ...)
 
483
{
 
484
}
 
485
 
 
486
int
 
487
grub_device_mapper_supported (void)
 
488
{
 
489
  static int supported = -1;
 
490
 
 
491
  if (supported == -1)
 
492
    {
 
493
      struct dm_task *dmt;
 
494
 
 
495
      /* Suppress annoying log messages.  */
 
496
      dm_log_with_errno_init (&device_mapper_null_log);
 
497
 
 
498
      dmt = dm_task_create (DM_DEVICE_VERSION);
 
499
      supported = (dmt != NULL);
 
500
      if (dmt)
 
501
        dm_task_destroy (dmt);
 
502
 
 
503
      /* Restore the original logger.  */
 
504
      dm_log_with_errno_init (NULL);
 
505
    }
 
506
 
 
507
  return supported;
 
508
}
 
509
#endif /* HAVE_DEVICE_MAPPER */