xref: /netbsd/sys/arch/atari/stand/ahdilabel/read.c (revision 6550d01e)
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