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
ahdi_readlabel(struct ahdi_ptable * ptable,char * diskname,int flags)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
read_rsec(int fd,struct ahdi_ptable * ptable,u_int rsec,u_int esec,int flags)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 *
disk_read(fd,start,count)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
assign_letters(struct ahdi_ptable * ptable)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 *
read_dl(int fd)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