1 /* $NetBSD: read.c,v 1.4 2009/03/14 21:04:06 dsl Exp $ */ 2 3 /* 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julian Coleman, Waldi Ravens and Leo Weppelman. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "privahdi.h" 33 #include <fcntl.h> 34 #ifdef DEBUG 35 #include <stdio.h> 36 #endif 37 #include <stdlib.h> 38 #include <strings.h> 39 #include <unistd.h> 40 #include <sys/dkio.h> 41 #include <sys/ioctl.h> 42 43 /* 44 * Read AHDI partitions from disk. 45 */ 46 int 47 ahdi_readlabel (struct ahdi_ptable *ptable, char *diskname, int flags) 48 { 49 int fd, rv; 50 struct disklabel *dl; 51 52 if (!(fd = openraw (diskname, O_RDONLY))) 53 return (-1); 54 55 if ((dl = read_dl (fd)) == NULL) { 56 close (fd); 57 return (-1); 58 } 59 60 if (dl->d_secsize != AHDI_BSIZE) { 61 close (fd); 62 return (-2); 63 } 64 65 if ((rv = check_magic(fd, LABELSECTOR, flags)) < 0) { 66 close (fd); 67 return (rv); 68 } 69 70 bzero ((void *) ptable, sizeof (struct ahdi_ptable)); 71 72 if ((rv = read_rsec (fd, ptable, AHDI_BBLOCK, AHDI_BBLOCK, flags)) 73 < 0) { 74 close (fd); 75 return (rv); 76 } 77 78 if (dl->d_secperunit != ptable->secperunit) { 79 if (flags & AHDI_IGN_SPU) 80 ptable->secperunit = dl->d_secperunit; 81 else { 82 close (fd); 83 return (-6); 84 } 85 } 86 87 ptable->nsectors = dl->d_nsectors; 88 ptable->ntracks = dl->d_ntracks; 89 ptable->ncylinders = dl->d_ncylinders; 90 ptable->secpercyl = dl->d_secpercyl; 91 92 assign_letters (ptable); 93 94 close (fd); 95 return (1); 96 } 97 98 /* 99 * Read AHDI partitions from root sector/auxillary root sector. 100 */ 101 int 102 read_rsec (int fd, struct ahdi_ptable *ptable, u_int rsec, u_int esec, int flags) 103 { 104 struct ahdi_part *part, *end; 105 struct ahdi_root *root; 106 u_int16_t cksum, newcksum; 107 int rv; 108 109 if ((root = disk_read (fd, rsec, 1)) == NULL) { 110 return (-1); 111 } 112 113 if (rsec == AHDI_BBLOCK) { 114 end = &root->ar_parts[AHDI_MAXRPD]; 115 if (root->ar_checksum) { 116 cksum = root->ar_checksum; 117 root->ar_checksum = 0; 118 newcksum = ahdi_cksum (root); 119 if ((cksum != newcksum) && !(flags & AHDI_IGN_CKSUM)) { 120 free (root); 121 return (-4); 122 } 123 } 124 ptable->secperunit=root->ar_hdsize; 125 } else 126 end = &root->ar_parts[AHDI_MAXARPD]; 127 for (part = root->ar_parts; part < end; ++part) { 128 #ifdef DEBUG 129 printf ("Found partitions at sector %u:\n", rsec); 130 printf (" flags : %02x\n", part->ap_flg); 131 printf (" id : %c%c%c\n", part->ap_id[0], part->ap_id[1], 132 part->ap_id[2]); 133 printf (" start : %u\n", part->ap_st); 134 printf (" size : %u\n", part->ap_size); 135 #endif 136 if (!(part->ap_flg & 0x01)) { 137 if ((part->ap_id[0] || part->ap_id[1] || 138 part->ap_id[2]) && (flags & AHDI_IGN_EXISTS)) 139 part->ap_flg &= 0x01; 140 else 141 continue; 142 } 143 144 if (AHDI_MKPID (part->ap_id[0], part->ap_id[1], 145 part->ap_id[2]) == AHDI_PID_XGM) { 146 u_int offs = part->ap_st + esec; 147 if ((rv = read_rsec (fd, ptable, offs, 148 esec == AHDI_BBLOCK ? offs : esec, flags)) < 0) { 149 free (root); 150 return (rv); 151 } 152 } else { 153 /* Attempt to check for junk values */ 154 if (((part->ap_st + rsec) > ptable->secperunit || 155 (part->ap_st + rsec + part->ap_size -1) > 156 ptable->secperunit)) { 157 if (flags & AHDI_IGN_EXT) { 158 /* Fake previous partition */ 159 ptable->parts[ptable->nparts].id[0] = 160 part->ap_id[0]; 161 ptable->parts[ptable->nparts].id[1] = 162 part->ap_id[1]; 163 ptable->parts[ptable->nparts].id[2] = 164 part->ap_id[2]; 165 } else { 166 free (root); 167 return (-5); 168 } 169 } 170 ptable->parts[ptable->nparts].flag = part->ap_flg; 171 ptable->parts[ptable->nparts].id[0] = part->ap_id[0]; 172 ptable->parts[ptable->nparts].id[1] = part->ap_id[1]; 173 ptable->parts[ptable->nparts].id[2] = part->ap_id[2]; 174 ptable->parts[ptable->nparts].root = rsec; 175 ptable->parts[ptable->nparts].start = 176 part->ap_st + rsec; 177 ptable->parts[ptable->nparts].size = part->ap_size; 178 ptable->nparts++; 179 } 180 } 181 free (root); 182 if (ptable->nparts || FORCE_AHDI) 183 return (1); 184 else 185 return (-3); 186 } 187 188 /* 189 * Read a sector from the disk. 190 */ 191 void * 192 disk_read (fd, start, count) 193 int fd; 194 u_int start, 195 count; 196 { 197 void *buffer; 198 off_t offset; 199 size_t size; 200 201 202 size = count * DEV_BSIZE; 203 offset = start * DEV_BSIZE; 204 205 if ((buffer = malloc (size)) == NULL) 206 return (NULL); 207 208 if (lseek (fd, offset, SEEK_SET) != offset) { 209 free (buffer); 210 return (NULL); 211 } 212 if (read (fd, buffer, size) != size) { 213 free (buffer); 214 return (NULL); 215 } 216 return (buffer); 217 } 218 219 /* 220 * Assign NetBSD drive letters to partitions 221 */ 222 void 223 assign_letters (struct ahdi_ptable *ptable) 224 { 225 int i, have_root, pno; 226 u_int32_t pid; 227 228 #define ROOT_PART 0 229 230 have_root = 0; 231 pno = 0; 232 233 for (i = 0; i < ptable->nparts; i++) { 234 while (pno == ROOT_PART || pno == SWAP_PART || pno == RAW_PART) 235 pno++; 236 pid = AHDI_MKPID (ptable->parts[i].id[0], 237 ptable->parts[i].id[1], ptable->parts[i].id[2]); 238 if (!have_root && pid == AHDI_PID_NBD) { 239 ptable->parts[i].letter = ROOT_PART; 240 have_root = 1; 241 } else if (pid == AHDI_PID_SWP) 242 ptable->parts[i].letter = SWAP_PART; 243 else { 244 ptable->parts[i].letter = pno; 245 pno++; 246 } 247 } 248 } 249 250 /* 251 * Read disklabel for disk. 252 */ 253 struct disklabel * 254 read_dl (int fd) 255 { 256 struct disklabel *dl; 257 258 if ((dl = malloc (sizeof (struct disklabel))) == NULL) { 259 return (NULL); 260 } 261 262 if (ioctl (fd, DIOCGDINFO, dl) < 0) { 263 free (dl); 264 return (NULL); 265 } 266 return (dl); 267 } 268