📄 device.c
字号:
struct hd_geometry hdg; struct stat st; if (fstat (fileno (fp), &st)) return 0; /* If it is a block device and isn't a floppy, check if HDIO_GETGEO succeeds. */ if (S_ISBLK (st.st_mode) && MAJOR (st.st_rdev) != FLOPPY_MAJOR && ioctl (fileno (fp), HDIO_GETGEO, &hdg)) return 0; }# endif /* ! CDROM_GET_CAPABILITY */#endif /* __linux__ */#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)# ifdef CDIOCCLRDEBUG if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0) return 0;# endif /* CDIOCCLRDEBUG */#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ /* Attempt to read the first sector. */ if (fread (buf, 1, 512, fp) != 512) { fclose (fp); return 0; } fclose (fp); return 1;}/* Read mapping information from FP, and write it to MAP. */static intread_device_map (FILE *fp, char **map, const char *map_file){ static void show_error (int no, const char *msg) { fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg); } static void show_warning (int no, const char *msg, ...) { va_list ap; va_start (ap, msg); fprintf (stderr, "%s:%d: warning: ", map_file, no); vfprintf (stderr, msg, ap); va_end (ap); } /* If there is the device map file, use the data in it instead of probing devices. */ char buf[1024]; /* XXX */ int line_number = 0; while (fgets (buf, sizeof (buf), fp)) { char *ptr, *eptr; int drive; int is_floppy = 0; /* Increase the number of lines. */ line_number++; /* If the first character is '#', skip it. */ if (buf[0] == '#') continue; ptr = buf; /* Skip leading spaces. */ while (*ptr && isspace (*ptr)) ptr++; /* Skip empty lines. */ if (! *ptr) continue; if (*ptr != '(') { show_error (line_number, "No open parenthesis found"); return 0; } ptr++; if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd') { show_error (line_number, "Bad drive name"); return 0; } if (*ptr == 'f') is_floppy = 1; ptr += 2; drive = strtoul (ptr, &ptr, 10); if (drive < 0) { show_error (line_number, "Bad device number"); return 0; } else if (drive > 127) { show_warning (line_number, "Ignoring %cd%d due to a BIOS limitation", is_floppy ? 'f' : 'h', drive); continue; } if (! is_floppy) drive += 0x80; if (*ptr != ')') { show_error (line_number, "No close parenthesis found"); return 0; } ptr++; /* Skip spaces. */ while (*ptr && isspace (*ptr)) ptr++; if (! *ptr) { show_error (line_number, "No filename found"); return 0; } /* Terminate the filename. */ eptr = ptr; while (*eptr && ! isspace (*eptr)) eptr++; *eptr = 0; /* Multiple entries for a given drive is not allowed. */ if (map[drive]) { show_error (line_number, "Duplicated entry found"); return 0; } map[drive] = strdup (ptr); assert (map[drive]); } return 1;}/* Initialize the device map MAP. *MAP will be allocated from the heap space. If MAP_FILE is not NULL, then read mappings from the file MAP_FILE if it exists, otherwise, write guessed mappings to the file. FLOPPY_DISKS is the number of floppy disk drives which will be probed. If it is zero, don't probe any floppy at all. If it is one, probe one floppy. If it is two, probe two floppies. And so on. */intinit_device_map (char ***map, const char *map_file, int floppy_disks){ int i; int num_hd = 0; FILE *fp = 0; assert (map); assert (*map == 0); *map = malloc (NUM_DISKS * sizeof (char *)); assert (*map); /* Probe devices for creating the device map. */ /* Initialize DEVICE_MAP. */ for (i = 0; i < NUM_DISKS; i++) (*map)[i] = 0; if (map_file) { /* Open the device map file. */ fp = fopen (map_file, "r"); if (fp) { int ret; ret = read_device_map (fp, *map, map_file); fclose (fp); return ret; } } /* Print something so that the user does not think GRUB has been crashed. */ fprintf (stderr, "Probing devices to guess BIOS drives. " "This may take a long time.\n"); if (map_file) /* Try to open the device map file to write the probed data. */ fp = fopen (map_file, "w"); /* Floppies. */ for (i = 0; i < floppy_disks; i++) { char name[16]; get_floppy_disk_name (name, i); /* In floppies, write the map, whether check_device succeeds or not, because the user just does not insert floppies. */ if (fp) fprintf (fp, "(fd%d)\t%s\n", i, name); if (check_device (name)) { (*map)[i] = strdup (name); assert ((*map)[i]); } } #ifdef __linux__ if (have_devfs ()) { while (1) { char discn[32]; char name[PATH_MAX]; struct stat st; /* Linux creates symlinks "/dev/discs/discN" for convenience. The way to number disks is the same as GRUB's. */ sprintf (discn, "/dev/discs/disc%d", num_hd); if (stat (discn, &st) < 0) break; if (realpath (discn, name)) { strcat (name, "/disc"); (*map)[num_hd + 0x80] = strdup (name); assert ((*map)[num_hd + 0x80]); /* If the device map file is opened, write the map. */ if (fp) fprintf (fp, "(hd%d)\t%s\n", num_hd, name); } num_hd++; } /* OK, close the device map file if opened. */ if (fp) fclose (fp); return 1; }#endif /* __linux__ */ /* IDE disks. */ for (i = 0; i < 8; i++) { char name[16]; get_ide_disk_name (name, i); if (check_device (name)) { (*map)[num_hd + 0x80] = strdup (name); assert ((*map)[num_hd + 0x80]); /* If the device map file is opened, write the map. */ if (fp) fprintf (fp, "(hd%d)\t%s\n", num_hd, name); num_hd++; } } #ifdef __linux__ /* ATARAID disks. */ for (i = 0; i < 8; i++) { char name[20]; get_ataraid_disk_name (name, i); if (check_device (name)) { (*map)[num_hd + 0x80] = strdup (name); assert ((*map)[num_hd + 0x80]); /* If the device map file is opened, write the map. */ if (fp) fprintf (fp, "(hd%d)\t%s\n", num_hd, name); num_hd++; } }#endif /* __linux__ */ /* The rest is SCSI disks. */ for (i = 0; i < 16; i++) { char name[16]; get_scsi_disk_name (name, i); if (check_device (name)) { (*map)[num_hd + 0x80] = strdup (name); assert ((*map)[num_hd + 0x80]); /* If the device map file is opened, write the map. */ if (fp) fprintf (fp, "(hd%d)\t%s\n", num_hd, name); num_hd++; } } #ifdef __linux__ /* This is for DAC960 - we have /dev/rd/c<controller>d<logical drive>p<partition>. DAC960 driver currently supports up to 8 controllers, 32 logical drives, and 7 partitions. */ { int controller, drive; for (controller = 0; controller < 8; controller++) { for (drive = 0; drive < 15; drive++) { char name[24]; get_dac960_disk_name (name, controller, drive); if (check_device (name)) { (*map)[num_hd + 0x80] = strdup (name); assert ((*map)[num_hd + 0x80]); /* If the device map file is opened, write the map. */ if (fp) fprintf (fp, "(hd%d)\t%s\n", num_hd, name); num_hd++; } } } }#endif /* __linux__ */ /* OK, close the device map file if opened. */ if (fp) fclose (fp); return 1;}/* Restore the memory consumed for MAP. */voidrestore_device_map (char **map){ int i; for (i = 0; i < NUM_DISKS; i++) if (map[i]) free (map[i]); free (map);}#ifdef __linux__/* Linux-only functions, because Linux has a bug that the disk cache for a whole disk is not consistent with the one for a partition of the disk. */intis_disk_device (char **map, int drive){ struct stat st; assert (map[drive] != 0); assert (stat (map[drive], &st) == 0); /* For now, disk devices under Linux are all block devices. */ return S_ISBLK (st.st_mode);}intwrite_to_partition (char **map, int drive, int partition, int sector, int size, const char *buf){ char dev[PATH_MAX]; /* XXX */ int fd; if ((partition & 0x00FF00) != 0x00FF00) { /* If the partition is a BSD partition, it is difficult to obtain the representation in Linux. So don't support that. */ errnum = ERR_DEV_VALUES; return 1; } assert (map[drive] != 0); strcpy (dev, map[drive]); if (have_devfs ()) { if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) strcpy (dev + strlen(dev) - 5, "/part"); } sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); /* Open the partition. */ fd = open (dev, O_RDWR); if (fd < 0) { errnum = ERR_NO_PART; return 0; } #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 * (loff_t) SECTOR_SIZE; if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) { errnum = ERR_DEV_VALUES; return 0; } }#else { off_t offset = (off_t) sector * (off_t) SECTOR_SIZE; if (lseek (fd, offset, SEEK_SET) != offset) { errnum = ERR_DEV_VALUES; return 0; } }#endif if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE)) { close (fd); errnum = ERR_WRITE; return 0; } sync (); /* Paranoia. */ close (fd); return 1;}#endif /* __linux__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -