⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 biosdisk.c

📁 最新的grub2源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* biosdisk.c - emulate biosdisk *//* *  GRUB  --  GRand Unified Bootloader *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc. * *  GRUB is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with GRUB; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <grub/machine/biosdisk.h>#include <grub/disk.h>#include <grub/partition.h>#include <grub/pc_partition.h>#include <grub/types.h>#include <grub/err.h>#include <grub/util/misc.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <assert.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <limits.h>#ifdef __linux__# include <sys/ioctl.h>         /* ioctl */# if !defined(__GLIBC__) || \        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))/* Maybe libc doesn't have large file support.  */#  include <linux/unistd.h>     /* _llseek */# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */# ifndef BLKFLSBUF#  define BLKFLSBUF     _IO (0x12,97)   /* flush buffer cache */# endif /* ! BLKFLSBUF */# include <sys/ioctl.h>		/* ioctl */# ifndef HDIO_GETGEO#  define HDIO_GETGEO	0x0301	/* get device geometry *//* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is   defined.  */struct hd_geometry{  unsigned char heads;  unsigned char sectors;  unsigned short cylinders;  unsigned long start;};# endif /* ! HDIO_GETGEO */# ifndef BLKGETSIZE#  define BLKGETSIZE    _IO(0x12,96)    /* return device size */# endif /* ! BLKGETSIZE */# ifndef MAJOR#  ifndef MINORBITS#   define MINORBITS	8#  endif /* ! MINORBITS */#  define MAJOR(dev)	((unsigned) ((dev) >> MINORBITS))# endif /* ! MAJOR */# ifndef FLOPPY_MAJOR#  define FLOPPY_MAJOR	2# endif /* ! FLOPPY_MAJOR */# ifndef LOOP_MAJOR#  define LOOP_MAJOR	7# endif /* ! LOOP_MAJOR */#endif /* __linux__ */static char *map[256];#ifdef __linux__/* Check if we have devfs support.  */static inthave_devfs (void){  static int dev_devfsd_exists = -1;  if (dev_devfsd_exists < 0)    {      struct stat st;      dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;    }  return dev_devfsd_exists;}#endif /* __linux__ */static intget_drive (const char *name){  unsigned long drive;  char *p;    if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd')    goto fail;  drive = strtoul (name + 2, &p, 10);  if (p == name + 2)    goto fail;  if (name[0] == 'h')    drive += 0x80;  if (drive > sizeof (map) / sizeof (map[0]))    goto fail;    return (int) drive; fail:  grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a biosdisk");  return -1;}static intcall_hook (int (*hook) (const char *name), int drive){  char name[10];  sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));  return hook (name);}static intgrub_util_biosdisk_iterate (int (*hook) (const char *name)){  unsigned i;  for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)    if (map[i] && call_hook (hook, i))      return 1;  return 0;}static grub_err_tgrub_util_biosdisk_open (const char *name, grub_disk_t disk){  int drive;  struct stat st;    drive = get_drive (name);  if (drive < 0)    return grub_errno;  if (! map[drive])    return grub_error (GRUB_ERR_BAD_DEVICE,		       "no mapping exists for `%s'", name);    disk->has_partitions = (drive & 0x80);  disk->id = drive;  /* Get the size.  */#ifdef __linux__  {    unsigned long nr;    int fd;    fd = open (map[drive], O_RDONLY);    if (! fd)      return grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", map[drive]);    if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))      {	close (fd);	goto fail;      }        if (ioctl (fd, BLKGETSIZE, &nr))      {	close (fd);	goto fail;      }    close (fd);    disk->total_sectors = nr;        grub_util_info ("the size of %s is %lu", name, disk->total_sectors);        return GRUB_ERR_NONE;  } fail:  /* In GNU/Hurd, stat() will return the right size.  */#elif !defined (__GNU__)# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."#endif  if (stat (map[drive], &st) < 0)    return grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive]);  disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;    grub_util_info ("the size of %s is %lu", name, disk->total_sectors);    return GRUB_ERR_NONE;}#ifdef __linux__static intlinux_find_partition (char *dev, unsigned long sector){  size_t len = strlen (dev);  const char *format;  char *p;  int i;  char *real_dev;  real_dev = xstrdup (dev);    if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)    {      p = real_dev + len - 4;      format = "part%d";    }  else if ((strncmp (real_dev + 5, "hd", 2) == 0	    || strncmp (real_dev + 5, "sd", 2) == 0)	   && real_dev[7] >= 'a' && real_dev[7] <= 'z')    {      p = real_dev + 8;      format = "%d";    }  else if (strncmp (real_dev + 5, "rd/c", 4) == 0)    {      p = strchr (real_dev + 9, 'd');      if (! p)	return 0;      p++;      while (*p && isdigit (*p))	p++;      format = "p%d";    }  else    {      free (real_dev);      return 0;    }  for (i = 1; i < 10000; i++)    {      int fd;      struct hd_geometry hdg;            sprintf (p, format, i);      fd = open (real_dev, O_RDONLY);      if (! fd)	{	  free (real_dev);	  return 0;	}      if (ioctl (fd, HDIO_GETGEO, &hdg))	{	  close (fd);	  free (real_dev);	  return 0;	}      close (fd);            if (hdg.start == sector)	{	  strcpy (dev, real_dev);	  free (real_dev);	  return 1;	}    }  free (real_dev);  return 0;}#endif /* __linux__ */static intopen_device (const grub_disk_t disk, unsigned long sector, int flags){  int fd;#ifdef O_LARGEFILE  flags |= O_LARGEFILE;#endif#ifdef O_SYNC  flags |= O_SYNC;#endif#ifdef O_FSYNC  flags |= O_FSYNC;#endif  #ifdef __linux__  /* Linux has a bug that the disk cache for a whole disk is not consistent     with the one for a partition of the disk.  */  {    int is_partition = 0;    char dev[PATH_MAX];        strcpy (dev, map[disk->id]);    if (disk->partition && strncmp (map[disk->id], "/dev/", 5) == 0)      is_partition = linux_find_partition (dev, disk->partition->start);        /* Open the partition.  */    grub_util_info ("opening the device `%s'", dev);    fd = open (dev, flags);    if (fd < 0)      {	grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev);	return -1;      }    /* Make the buffer cache consistent with the physical disk.  */    ioctl (fd, BLKFLSBUF, 0);        if (is_partition)      sector -= disk->partition->start;  }#else /* ! __linux__ */  fd = open (map[disk->id], flags);  if (fd < 0)    {      grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", map[disk->id]);      return -1;    }#endif /* ! __linux__ */#if defined(__linux__) && (!defined(__GLIBC__) || \        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))  /* Maybe libc doesn't have large file support.  */  {    loff_t offset, result;    static int _llseek (uint filedes, ulong hi, ulong lo,                        loff_t *res, uint wh);    _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,               loff_t *, res, uint, wh);    offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;    if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))      {	grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id]);	close (fd);	return -1;      }  }#else  {    off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;    if (lseek (fd, offset, SEEK_SET) != offset)      {	grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id]);	close (fd);	return -1;      }  }#endif  return fd;}  /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an   error occurs, otherwise return LEN.  */static ssize_tnread (int fd, char *buf, size_t len){  ssize_t size = len;    while (len)    {      ssize_t ret = read (fd, buf, len);            if (ret <= 0)        {          if (errno == EINTR)            continue;          else            return ret;        }            len -= ret;      buf += ret;    }    return size;}/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an   error occurs, otherwise return LEN.  */static ssize_tnwrite (int fd, const char *buf, size_t len){  ssize_t size = len;    while (len)    {      ssize_t ret = write (fd, buf, len);            if (ret <= 0)        {          if (errno == EINTR)            continue;          else            return ret;        }            len -= ret;      buf += ret;    }    return size;}static grub_err_tgrub_util_biosdisk_read (grub_disk_t disk, unsigned long sector,			 unsigned long size, char *buf){  int fd;  fd = open_device (disk, sector, O_RDONLY);  if (fd < 0)    return grub_errno;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -