/* $NetBSD: read.c,v 1.4 2009/03/14 21:04:06 dsl Exp $ */ /* * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Julian Coleman, Waldi Ravens and Leo Weppelman. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "privahdi.h" #include #ifdef DEBUG #include #endif #include #include #include #include #include /* * Read AHDI partitions from disk. */ int ahdi_readlabel (struct ahdi_ptable *ptable, char *diskname, int flags) { int fd, rv; struct disklabel *dl; if (!(fd = openraw (diskname, O_RDONLY))) return (-1); if ((dl = read_dl (fd)) == NULL) { close (fd); return (-1); } if (dl->d_secsize != AHDI_BSIZE) { close (fd); return (-2); } if ((rv = check_magic(fd, LABELSECTOR, flags)) < 0) { close (fd); return (rv); } bzero ((void *) ptable, sizeof (struct ahdi_ptable)); if ((rv = read_rsec (fd, ptable, AHDI_BBLOCK, AHDI_BBLOCK, flags)) < 0) { close (fd); return (rv); } if (dl->d_secperunit != ptable->secperunit) { if (flags & AHDI_IGN_SPU) ptable->secperunit = dl->d_secperunit; else { close (fd); return (-6); } } ptable->nsectors = dl->d_nsectors; ptable->ntracks = dl->d_ntracks; ptable->ncylinders = dl->d_ncylinders; ptable->secpercyl = dl->d_secpercyl; assign_letters (ptable); close (fd); return (1); } /* * Read AHDI partitions from root sector/auxillary root sector. */ int read_rsec (int fd, struct ahdi_ptable *ptable, u_int rsec, u_int esec, int flags) { struct ahdi_part *part, *end; struct ahdi_root *root; u_int16_t cksum, newcksum; int rv; if ((root = disk_read (fd, rsec, 1)) == NULL) { return (-1); } if (rsec == AHDI_BBLOCK) { end = &root->ar_parts[AHDI_MAXRPD]; if (root->ar_checksum) { cksum = root->ar_checksum; root->ar_checksum = 0; newcksum = ahdi_cksum (root); if ((cksum != newcksum) && !(flags & AHDI_IGN_CKSUM)) { free (root); return (-4); } } ptable->secperunit=root->ar_hdsize; } else end = &root->ar_parts[AHDI_MAXARPD]; for (part = root->ar_parts; part < end; ++part) { #ifdef DEBUG printf ("Found partitions at sector %u:\n", rsec); printf (" flags : %02x\n", part->ap_flg); printf (" id : %c%c%c\n", part->ap_id[0], part->ap_id[1], part->ap_id[2]); printf (" start : %u\n", part->ap_st); printf (" size : %u\n", part->ap_size); #endif if (!(part->ap_flg & 0x01)) { if ((part->ap_id[0] || part->ap_id[1] || part->ap_id[2]) && (flags & AHDI_IGN_EXISTS)) part->ap_flg &= 0x01; else continue; } if (AHDI_MKPID (part->ap_id[0], part->ap_id[1], part->ap_id[2]) == AHDI_PID_XGM) { u_int offs = part->ap_st + esec; if ((rv = read_rsec (fd, ptable, offs, esec == AHDI_BBLOCK ? offs : esec, flags)) < 0) { free (root); return (rv); } } else { /* Attempt to check for junk values */ if (((part->ap_st + rsec) > ptable->secperunit || (part->ap_st + rsec + part->ap_size -1) > ptable->secperunit)) { if (flags & AHDI_IGN_EXT) { /* Fake previous partition */ ptable->parts[ptable->nparts].id[0] = part->ap_id[0]; ptable->parts[ptable->nparts].id[1] = part->ap_id[1]; ptable->parts[ptable->nparts].id[2] = part->ap_id[2]; } else { free (root); return (-5); } } ptable->parts[ptable->nparts].flag = part->ap_flg; ptable->parts[ptable->nparts].id[0] = part->ap_id[0]; ptable->parts[ptable->nparts].id[1] = part->ap_id[1]; ptable->parts[ptable->nparts].id[2] = part->ap_id[2]; ptable->parts[ptable->nparts].root = rsec; ptable->parts[ptable->nparts].start = part->ap_st + rsec; ptable->parts[ptable->nparts].size = part->ap_size; ptable->nparts++; } } free (root); if (ptable->nparts || FORCE_AHDI) return (1); else return (-3); } /* * Read a sector from the disk. */ void * disk_read (fd, start, count) int fd; u_int start, count; { void *buffer; off_t offset; size_t size; size = count * DEV_BSIZE; offset = start * DEV_BSIZE; if ((buffer = malloc (size)) == NULL) return (NULL); if (lseek (fd, offset, SEEK_SET) != offset) { free (buffer); return (NULL); } if (read (fd, buffer, size) != size) { free (buffer); return (NULL); } return (buffer); } /* * Assign NetBSD drive letters to partitions */ void assign_letters (struct ahdi_ptable *ptable) { int i, have_root, pno; u_int32_t pid; #define ROOT_PART 0 have_root = 0; pno = 0; for (i = 0; i < ptable->nparts; i++) { while (pno == ROOT_PART || pno == SWAP_PART || pno == RAW_PART) pno++; pid = AHDI_MKPID (ptable->parts[i].id[0], ptable->parts[i].id[1], ptable->parts[i].id[2]); if (!have_root && pid == AHDI_PID_NBD) { ptable->parts[i].letter = ROOT_PART; have_root = 1; } else if (pid == AHDI_PID_SWP) ptable->parts[i].letter = SWAP_PART; else { ptable->parts[i].letter = pno; pno++; } } } /* * Read disklabel for disk. */ struct disklabel * read_dl (int fd) { struct disklabel *dl; if ((dl = malloc (sizeof (struct disklabel))) == NULL) { return (NULL); } if (ioctl (fd, DIOCGDINFO, dl) < 0) { free (dl); return (NULL); } return (dl); }