make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub / lib / device.c
blobd0663b396d1b3c9528bf8f7d8c7148cde14273bd
1 /* device.c - Some helper functions for OS devices and BIOS drives */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* Try to use glibc's transparant LFS support. */
22 #define _LARGEFILE_SOURCE 1
23 /* lseek becomes synonymous with lseek64. */
24 #define _FILE_OFFSET_BITS 64
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <stdarg.h>
39 #ifdef __linux__
40 # if !defined(__GLIBC__) || \
41 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
42 /* Maybe libc doesn't have large file support. */
43 # include <linux/unistd.h> /* _llseek */
44 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
45 # include <sys/ioctl.h> /* ioctl */
46 # ifndef HDIO_GETGEO
47 # define HDIO_GETGEO 0x0301 /* get device geometry */
48 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
49 defined. */
50 struct hd_geometry
52 unsigned char heads;
53 unsigned char sectors;
54 unsigned short cylinders;
55 unsigned long start;
57 # endif /* ! HDIO_GETGEO */
58 # ifndef FLOPPY_MAJOR
59 # define FLOPPY_MAJOR 2 /* the major number for floppy */
60 # endif /* ! FLOPPY_MAJOR */
61 # ifndef MAJOR
62 # define MAJOR(dev) \
63 ({ \
64 unsigned long long __dev = (dev); \
65 (unsigned) ((__dev >> 8) & 0xfff) \
66 | ((unsigned int) (__dev >> 32) & ~0xfff); \
68 # endif /* ! MAJOR */
69 # ifndef CDROM_GET_CAPABILITY
70 # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
71 # endif /* ! CDROM_GET_CAPABILITY */
72 # ifndef BLKGETSIZE
73 # define BLKGETSIZE _IO(0x12,96) /* return device size */
74 # endif /* ! BLKGETSIZE */
75 #endif /* __linux__ */
77 /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
78 kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
79 #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
80 # define __FreeBSD_kernel__
81 #endif
82 #ifdef __FreeBSD_kernel__
83 /* Obtain version of kFreeBSD headers */
84 # include <osreldate.h>
85 # ifndef __FreeBSD_kernel_version
86 # define __FreeBSD_kernel_version __FreeBSD_version
87 # endif
89 /* Runtime detection of kernel */
90 # include <sys/utsname.h>
91 int
92 get_kfreebsd_version ()
94 struct utsname uts;
95 int major; int minor, v[2];
97 uname (&uts);
98 sscanf (uts.release, "%d.%d", &major, &minor);
100 if (major >= 9)
101 major = 9;
102 if (major >= 5)
104 v[0] = minor/10; v[1] = minor%10;
106 else
108 v[0] = minor%10; v[1] = minor/10;
110 return major*100000+v[0]*10000+v[1]*1000;
112 #endif /* __FreeBSD_kernel__ */
114 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
115 # include <sys/ioctl.h> /* ioctl */
116 # include <sys/disklabel.h>
117 # include <sys/cdio.h> /* CDIOCCLRDEBUG */
118 # if defined(__FreeBSD_kernel__)
119 # include <sys/param.h>
120 # if __FreeBSD_kernel_version >= 500040
121 # include <sys/disk.h>
122 # endif
123 # endif /* __FreeBSD_kernel__ */
124 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
126 #ifdef HAVE_OPENDISK
127 # include <util.h>
128 #endif /* HAVE_OPENDISK */
130 #define WITHOUT_LIBC_STUBS 1
131 #include <shared.h>
132 #include <device.h>
134 /* Get the geometry of a drive DRIVE. */
135 void
136 get_drive_geometry (struct geometry *geom, char **map, int drive)
138 int fd;
140 if (geom->flags == -1)
142 fd = open (map[drive], O_RDONLY);
143 assert (fd >= 0);
145 else
146 fd = geom->flags;
148 /* XXX This is the default size. */
149 geom->sector_size = SECTOR_SIZE;
151 #if defined(__linux__)
152 /* Linux */
154 struct hd_geometry hdg;
155 unsigned long nr;
157 if (ioctl (fd, HDIO_GETGEO, &hdg))
158 goto fail;
160 if (ioctl (fd, BLKGETSIZE, &nr))
161 goto fail;
163 /* Got the geometry, so save it. */
164 geom->cylinders = hdg.cylinders;
165 geom->heads = hdg.heads;
166 geom->sectors = hdg.sectors;
167 geom->total_sectors = nr;
169 goto success;
172 #elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
173 # if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040
174 /* kFreeBSD version 5 or later */
175 if (get_kfreebsd_version () >= 500040)
177 unsigned int sector_size;
178 off_t media_size;
179 unsigned int tmp;
181 if(ioctl (fd, DIOCGSECTORSIZE, &sector_size) != 0)
182 sector_size = 512;
184 if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0)
185 goto fail;
187 geom->total_sectors = media_size / sector_size;
189 if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0)
190 geom->sectors = tmp;
191 else
192 geom->sectors = 63;
193 if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0)
194 geom->heads = tmp;
195 else if (geom->total_sectors <= 63 * 1 * 1024)
196 geom->heads = 1;
197 else if (geom->total_sectors <= 63 * 16 * 1024)
198 geom->heads = 16;
199 else
200 geom->heads = 255;
202 geom->cylinders = (geom->total_sectors
203 / geom->heads
204 / geom->sectors);
206 goto success;
208 else
209 #endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */
211 /* kFreeBSD < 5, NetBSD or OpenBSD */
213 struct disklabel hdg;
214 if (ioctl (fd, DIOCGDINFO, &hdg))
215 goto fail;
217 geom->cylinders = hdg.d_ncylinders;
218 geom->heads = hdg.d_ntracks;
219 geom->sectors = hdg.d_nsectors;
220 geom->total_sectors = hdg.d_secperunit;
222 goto success;
225 #else
226 /* Notably, defined(__GNU__) */
227 # warning "Automatic detection of geometries will be performed only \
228 partially. This is not fatal."
229 #endif
231 fail:
233 struct stat st;
235 /* FIXME: It would be nice to somehow compute fake C/H/S settings,
236 given a proper st_blocks size. */
237 if (drive & 0x80)
239 geom->cylinders = DEFAULT_HD_CYLINDERS;
240 geom->heads = DEFAULT_HD_HEADS;
241 geom->sectors = DEFAULT_HD_SECTORS;
243 else
245 geom->cylinders = DEFAULT_FD_CYLINDERS;
246 geom->heads = DEFAULT_FD_HEADS;
247 geom->sectors = DEFAULT_FD_SECTORS;
250 /* Set the total sectors properly, if we can. */
251 if (! fstat (fd, &st) && st.st_size)
252 geom->total_sectors = st.st_size >> SECTOR_BITS;
253 else
254 geom->total_sectors = geom->cylinders * geom->heads * geom->sectors;
257 success:
258 if (geom->flags == -1)
259 close (fd);
262 #ifdef __linux__
263 /* Check if we have devfs support. */
264 static int
265 have_devfs (void)
267 static int dev_devfsd_exists = -1;
269 if (dev_devfsd_exists < 0)
271 struct stat st;
273 dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
276 return dev_devfsd_exists;
278 #endif /* __linux__ */
280 /* These three functions are quite different among OSes. */
281 static void
282 get_floppy_disk_name (char *name, int unit)
284 #if defined(__linux__)
285 /* GNU/Linux */
286 if (have_devfs ())
287 sprintf (name, "/dev/floppy/%d", unit);
288 else
289 sprintf (name, "/dev/fd%d", unit);
290 #elif defined(__GNU__)
291 /* GNU/Hurd */
292 sprintf (name, "/dev/fd%d", unit);
293 #elif defined(__FreeBSD_kernel__)
294 /* kFreeBSD */
295 if (get_kfreebsd_version () >= 400000)
296 sprintf (name, "/dev/fd%d", unit);
297 else
298 sprintf (name, "/dev/rfd%d", unit);
299 #elif defined(__NetBSD__)
300 /* NetBSD */
301 /* opendisk() doesn't work for floppies. */
302 sprintf (name, "/dev/rfd%da", unit);
303 #elif defined(__OpenBSD__)
304 /* OpenBSD */
305 sprintf (name, "/dev/rfd%dc", unit);
306 #elif defined(__QNXNTO__)
307 /* QNX RTP */
308 sprintf (name, "/dev/fd%d", unit);
309 #else
310 # warning "BIOS floppy drives cannot be guessed in your operating system."
311 /* Set NAME to a bogus string. */
312 *name = 0;
313 #endif
316 static void
317 get_ide_disk_name (char *name, int unit)
319 #if defined(__linux__)
320 /* GNU/Linux */
321 sprintf (name, "/dev/hd%c", unit + 'a');
322 #elif defined(__GNU__)
323 /* GNU/Hurd */
324 sprintf (name, "/dev/hd%d", unit);
325 #elif defined(__FreeBSD_kernel__)
326 /* kFreeBSD */
327 if (get_kfreebsd_version () >= 400000)
328 sprintf (name, "/dev/ad%d", unit);
329 else
330 sprintf (name, "/dev/rwd%d", unit);
331 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
332 /* NetBSD */
333 char shortname[16];
334 int fd;
336 sprintf (shortname, "wd%d", unit);
337 fd = opendisk (shortname, O_RDONLY, name,
338 16, /* length of NAME */
339 0 /* char device */
341 close (fd);
342 #elif defined(__OpenBSD__)
343 /* OpenBSD */
344 sprintf (name, "/dev/rwd%dc", unit);
345 #elif defined(__QNXNTO__)
346 /* QNX RTP */
347 /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
348 contain SCSI disks. */
349 sprintf (name, "/dev/hd%d", unit);
350 #else
351 # warning "BIOS IDE drives cannot be guessed in your operating system."
352 /* Set NAME to a bogus string. */
353 *name = 0;
354 #endif
357 static void
358 get_scsi_disk_name (char *name, int unit)
360 #if defined(__linux__)
361 /* GNU/Linux */
362 sprintf (name, "/dev/sd%c", unit + 'a');
363 #elif defined(__GNU__)
364 /* GNU/Hurd */
365 sprintf (name, "/dev/sd%d", unit);
366 #elif defined(__FreeBSD_kernel__)
367 /* kFreeBSD */
368 if (get_kfreebsd_version () >= 400000)
369 sprintf (name, "/dev/da%d", unit);
370 else
371 sprintf (name, "/dev/rda%d", unit);
372 #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
373 /* NetBSD */
374 char shortname[16];
375 int fd;
377 sprintf (shortname, "sd%d", unit);
378 fd = opendisk (shortname, O_RDONLY, name,
379 16, /* length of NAME */
380 0 /* char device */
382 close (fd);
383 #elif defined(__OpenBSD__)
384 /* OpenBSD */
385 sprintf (name, "/dev/rsd%dc", unit);
386 #elif defined(__QNXNTO__)
387 /* QNX RTP */
388 /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
389 disable the detection of SCSI disks here. */
390 *name = 0;
391 #else
392 # warning "BIOS SCSI drives cannot be guessed in your operating system."
393 /* Set NAME to a bogus string. */
394 *name = 0;
395 #endif
398 #ifdef __linux__
399 static void
400 get_dac960_disk_name (char *name, int controller, int drive)
402 sprintf (name, "/dev/rd/c%dd%d", controller, drive);
405 static void
406 get_ataraid_disk_name (char *name, int unit)
408 sprintf (name, "/dev/ataraid/d%c", unit + '0');
410 #endif
412 /* Check if DEVICE can be read. If an error occurs, return zero,
413 otherwise return non-zero. */
415 check_device (const char *device)
417 char buf[512];
418 FILE *fp;
420 /* If DEVICE is empty, just return 1. */
421 if (*device == 0)
422 return 1;
424 fp = fopen (device, "r");
425 if (! fp)
427 switch (errno)
429 #ifdef ENOMEDIUM
430 case ENOMEDIUM:
431 # if 0
432 /* At the moment, this finds only CDROMs, which can't be
433 read anyway, so leave it out. Code should be
434 reactivated if `removable disks' and CDROMs are
435 supported. */
436 /* Accept it, it may be inserted. */
437 return 1;
438 # endif
439 break;
440 #endif /* ENOMEDIUM */
441 default:
442 /* Break case and leave. */
443 break;
445 /* Error opening the device. */
446 return 0;
449 /* Make sure CD-ROMs don't get assigned a BIOS disk number
450 before SCSI disks! */
451 #ifdef __linux__
452 # ifdef CDROM_GET_CAPABILITY
453 if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
454 return 0;
455 # else /* ! CDROM_GET_CAPABILITY */
456 /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
458 struct hd_geometry hdg;
459 struct stat st;
461 if (fstat (fileno (fp), &st))
462 return 0;
464 /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
465 succeeds. */
466 if (S_ISBLK (st.st_mode)
467 && MAJOR (st.st_rdev) != FLOPPY_MAJOR
468 && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
469 return 0;
471 # endif /* ! CDROM_GET_CAPABILITY */
472 #endif /* __linux__ */
474 #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
475 # ifdef CDIOCCLRDEBUG
476 if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
477 return 0;
478 # endif /* CDIOCCLRDEBUG */
479 #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
481 /* Attempt to read the first sector. */
482 if (fread (buf, 1, 512, fp) != 512)
484 fclose (fp);
485 return 0;
488 fclose (fp);
489 return 1;
492 /* Read mapping information from FP, and write it to MAP. */
493 static int
494 read_device_map (FILE *fp, char **map, const char *map_file)
496 auto void show_error (int no, const char *msg);
497 auto void show_warning (int no, const char *msg, ...);
499 auto void show_error (int no, const char *msg)
501 fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
504 auto void show_warning (int no, const char *msg, ...)
506 va_list ap;
508 va_start (ap, msg);
509 fprintf (stderr, "%s:%d: warning: ", map_file, no);
510 vfprintf (stderr, msg, ap);
511 va_end (ap);
514 /* If there is the device map file, use the data in it instead of
515 probing devices. */
516 char buf[1024]; /* XXX */
517 int line_number = 0;
519 while (fgets (buf, sizeof (buf), fp))
521 char *ptr, *eptr;
522 int drive;
523 int is_floppy = 0;
525 /* Increase the number of lines. */
526 line_number++;
528 /* If the first character is '#', skip it. */
529 if (buf[0] == '#')
530 continue;
532 ptr = buf;
533 /* Skip leading spaces. */
534 while (*ptr && isspace (*ptr))
535 ptr++;
537 /* Skip empty lines. */
538 if (! *ptr)
539 continue;
541 if (*ptr != '(')
543 show_error (line_number, "No open parenthesis found");
544 return 0;
547 ptr++;
548 if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
550 show_error (line_number, "Bad drive name");
551 return 0;
554 if (*ptr == 'f')
555 is_floppy = 1;
557 ptr += 2;
558 drive = strtoul (ptr, &ptr, 10);
559 if (drive < 0)
561 show_error (line_number, "Bad device number");
562 return 0;
564 else if (drive > 127)
566 show_warning (line_number,
567 "Ignoring %cd%d due to a BIOS limitation",
568 is_floppy ? 'f' : 'h', drive);
569 continue;
572 if (! is_floppy)
573 drive += 0x80;
575 if (*ptr != ')')
577 show_error (line_number, "No close parenthesis found");
578 return 0;
581 ptr++;
582 /* Skip spaces. */
583 while (*ptr && isspace (*ptr))
584 ptr++;
586 if (! *ptr)
588 show_error (line_number, "No filename found");
589 return 0;
592 /* Terminate the filename. */
593 eptr = ptr;
594 while (*eptr && ! isspace (*eptr))
595 eptr++;
596 *eptr = 0;
598 /* Multiple entries for a given drive is not allowed. */
599 if (map[drive])
601 show_error (line_number, "Duplicated entry found");
602 return 0;
605 map[drive] = strdup (ptr);
606 assert (map[drive]);
609 return 1;
612 /* Initialize the device map MAP. *MAP will be allocated from the heap
613 space. If MAP_FILE is not NULL, then read mappings from the file
614 MAP_FILE if it exists, otherwise, write guessed mappings to the file.
615 FLOPPY_DISKS is the number of floppy disk drives which will be probed.
616 If it is zero, don't probe any floppy at all. If it is one, probe one
617 floppy. If it is two, probe two floppies. And so on. */
619 init_device_map (char ***map, const char *map_file, int floppy_disks)
621 int i;
622 int num_hd = 0;
623 FILE *fp = 0;
625 assert (map);
626 assert (*map == 0);
627 *map = malloc (NUM_DISKS * sizeof (char *));
628 assert (*map);
630 /* Probe devices for creating the device map. */
632 /* Initialize DEVICE_MAP. */
633 for (i = 0; i < NUM_DISKS; i++)
634 (*map)[i] = 0;
636 if (map_file)
638 /* Open the device map file. */
639 fp = fopen (map_file, "r");
640 if (fp)
642 int ret;
644 ret = read_device_map (fp, *map, map_file);
645 fclose (fp);
646 return ret;
650 /* Print something so that the user does not think GRUB has been
651 crashed. */
652 fprintf (stderr,
653 "Probing devices to guess BIOS drives. "
654 "This may take a long time.\n");
656 if (map_file)
657 /* Try to open the device map file to write the probed data. */
658 fp = fopen (map_file, "w");
660 /* Floppies. */
661 for (i = 0; i < floppy_disks; i++)
663 char name[16];
665 get_floppy_disk_name (name, i);
666 /* In floppies, write the map, whether check_device succeeds
667 or not, because the user just does not insert floppies. */
668 if (fp)
669 fprintf (fp, "(fd%d)\t%s\n", i, name);
671 if (check_device (name))
673 (*map)[i] = strdup (name);
674 assert ((*map)[i]);
678 #ifdef __linux__
679 if (have_devfs ())
681 while (1)
683 char discn[32];
684 char name[PATH_MAX];
685 struct stat st;
687 /* Linux creates symlinks "/dev/discs/discN" for convenience.
688 The way to number disks is the same as GRUB's. */
689 sprintf (discn, "/dev/discs/disc%d", num_hd);
690 if (stat (discn, &st) < 0)
691 break;
693 if (realpath (discn, name))
695 strcat (name, "/disc");
696 (*map)[num_hd + 0x80] = strdup (name);
697 assert ((*map)[num_hd + 0x80]);
699 /* If the device map file is opened, write the map. */
700 if (fp)
701 fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
704 num_hd++;
707 /* OK, close the device map file if opened. */
708 if (fp)
709 fclose (fp);
711 return 1;
713 #endif /* __linux__ */
715 /* IDE disks. */
716 for (i = 0; i < 8; i++)
718 char name[16];
720 get_ide_disk_name (name, i);
721 if (check_device (name))
723 (*map)[num_hd + 0x80] = strdup (name);
724 assert ((*map)[num_hd + 0x80]);
726 /* If the device map file is opened, write the map. */
727 if (fp)
728 fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
730 num_hd++;
734 #ifdef __linux__
735 /* ATARAID disks. */
736 for (i = 0; i < 8; i++)
738 char name[20];
740 get_ataraid_disk_name (name, i);
741 if (check_device (name))
743 (*map)[num_hd + 0x80] = strdup (name);
744 assert ((*map)[num_hd + 0x80]);
746 /* If the device map file is opened, write the map. */
747 if (fp)
748 fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
750 num_hd++;
753 #endif /* __linux__ */
755 /* The rest is SCSI disks. */
756 for (i = 0; i < 16; i++)
758 char name[16];
760 get_scsi_disk_name (name, i);
761 if (check_device (name))
763 (*map)[num_hd + 0x80] = strdup (name);
764 assert ((*map)[num_hd + 0x80]);
766 /* If the device map file is opened, write the map. */
767 if (fp)
768 fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
770 num_hd++;
774 #ifdef __linux__
775 /* This is for DAC960 - we have
776 /dev/rd/c<controller>d<logical drive>p<partition>.
778 DAC960 driver currently supports up to 8 controllers, 32 logical
779 drives, and 7 partitions. */
781 int controller, drive;
783 for (controller = 0; controller < 8; controller++)
785 for (drive = 0; drive < 15; drive++)
787 char name[24];
789 get_dac960_disk_name (name, controller, drive);
790 if (check_device (name))
792 (*map)[num_hd + 0x80] = strdup (name);
793 assert ((*map)[num_hd + 0x80]);
795 /* If the device map file is opened, write the map. */
796 if (fp)
797 fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
799 num_hd++;
804 #endif /* __linux__ */
806 /* OK, close the device map file if opened. */
807 if (fp)
808 fclose (fp);
810 return 1;
813 /* Restore the memory consumed for MAP. */
814 void
815 restore_device_map (char **map)
817 int i;
819 for (i = 0; i < NUM_DISKS; i++)
820 if (map[i])
821 free (map[i]);
823 free (map);
826 #ifdef __linux__
827 /* Linux-only functions, because Linux has a bug that the disk cache for
828 a whole disk is not consistent with the one for a partition of the
829 disk. */
831 is_disk_device (char **map, int drive)
833 struct stat st;
835 assert (map[drive] != 0);
836 assert (stat (map[drive], &st) == 0);
837 /* For now, disk devices under Linux are all block devices. */
838 return S_ISBLK (st.st_mode);
842 write_to_partition (char **map, int drive, int partition,
843 int sector, int size, const char *buf)
845 char dev[PATH_MAX]; /* XXX */
846 int fd;
848 if ((partition & 0x00FF00) != 0x00FF00)
850 /* If the partition is a BSD partition, it is difficult to
851 obtain the representation in Linux. So don't support that. */
852 errnum = ERR_DEV_VALUES;
853 return 1;
856 assert (map[drive] != 0);
858 strcpy (dev, map[drive]);
859 if (have_devfs ())
861 if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
862 strcpy (dev + strlen(dev) - 5, "/part");
864 sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
866 /* Open the partition. */
867 fd = open (dev, O_RDWR);
868 if (fd < 0)
870 errnum = ERR_NO_PART;
871 return 0;
874 #if defined(__linux__) && (!defined(__GLIBC__) || \
875 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
876 /* Maybe libc doesn't have large file support. */
878 loff_t offset, result;
879 static int _llseek (uint filedes, ulong hi, ulong lo,
880 loff_t *res, uint wh);
881 _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
882 loff_t *, res, uint, wh);
884 offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
885 if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
887 errnum = ERR_DEV_VALUES;
888 return 0;
891 #else
893 off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
895 if (lseek (fd, offset, SEEK_SET) != offset)
897 errnum = ERR_DEV_VALUES;
898 return 0;
901 #endif
903 if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
905 close (fd);
906 errnum = ERR_WRITE;
907 return 0;
910 sync (); /* Paranoia. */
911 close (fd);
913 return 1;
915 #endif /* __linux__ */