Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/util/fdisk/disk.c

1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Copyright (c) 1997, 2001 Tobias Weingartner
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by Tobias Weingartner.
39 * 4. The name of the author may not be used to endorse or promote products
40 * derived from this software without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54#include <err.h>
55#include <util.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <unistd.h>
59#include <string.h>
60#include <sys/fcntl.h>
61#include <sys/ioctl.h>
62#include <sys/types.h>
63#include <sys/stat.h>
64#include <sys/reboot.h>
65#include <sys/disk.h>
66#include <sys/param.h>
67#include <sys/sysctl.h>
68#ifdef __i386__
69#include <pexpert/i386/boot.h>
70#endif
71#include "disk.h"
72
73int
74DISK_open(disk, mode)
75char *disk;
76int mode;
77{
78int fd;
79struct stat st;
80
81fd = open(disk, mode);
82if (fd == -1)
83err(1, "%s", disk);
84if (fstat(fd, &st) == -1)
85err(1, "%s", disk);
86/* Don't be so picky about needing a character device */
87if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode))
88errx(1, "%s is not a character device or a regular file", disk);
89return (fd);
90}
91
92int
93DISK_openshared(disk, mode, shared)
94char *disk;
95int mode;
96int *shared;
97{
98int fd;
99struct stat st;
100*shared = 0;
101
102fd = open(disk, mode|O_EXLOCK);
103if (fd == -1) {
104 // if we can't have exclusive access, attempt
105 // to gracefully degrade to shared access
106 fd = open(disk, mode|O_SHLOCK);
107 if(fd == -1)
108err(1, "%s", disk);
109
110 *shared = 1;
111}
112
113if (fstat(fd, &st) == -1)
114err(1, "%s", disk);
115/* Don't be so picky about needing a character device */
116if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode))
117errx(1, "%s is not a character device or a regular file", disk);
118return (fd);
119}
120
121int
122DISK_close(fd)
123int fd;
124{
125
126return (close(fd));
127}
128
129/* Given a size in the metrics,
130 * fake up a CHS geometry.
131 */
132void
133DISK_fake_CHS(DISK_metrics *lm)
134{
135 int heads = 4;
136 int spt = 63;
137 int cylinders = (lm->size / heads / spt);
138
139 while (cylinders > 1024 && heads < 256) {
140 heads *= 2;
141 cylinders /= 2;
142 }
143 if (heads == 256) {
144 heads = 255;
145 cylinders = (lm->size / heads / spt);
146 }
147 lm->cylinders = cylinders;
148 lm->heads = heads;
149 lm->sectors = spt;
150}
151
152/* Routine to go after the disklabel for geometry
153 * information. This should work everywhere, but
154 * in the land of PC, things are not always what
155 * they seem.
156 */
157DISK_metrics *
158DISK_getlabelmetrics(name)
159char *name;
160{
161DISK_metrics *lm = NULL;
162long long size;
163uint32_t sector_size;
164int fd;
165struct stat st;
166
167/* Get label metrics */
168if ((fd = DISK_open(name, O_RDONLY)) != -1) {
169lm = malloc(sizeof(DISK_metrics));
170if (!lm) {
171err(1, "DISK_getlabelmetrics: Could not allocate memory");
172return NULL;
173}
174if (fstat(fd, &st) == -1)
175 err(1, "%s", name);
176if (!S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) {
177 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size) == -1) {
178 err(1, "Could not get disk block count");
179 free(lm);
180 return NULL;
181 }
182 if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
183 err(1, "Could not get disk block size");
184 free(lm);
185 return NULL;
186 }
187} else {
188 sector_size = 512;
189 size = st.st_size / sector_size;
190}
191
192lm->sector_size = sector_size;
193lm->size = size;
194DISK_fake_CHS(lm);
195DISK_close(fd);
196}
197
198return (lm);
199}
200
201/*
202 * Don't try to get BIOS disk metrics.
203 */
204DISK_metrics *
205DISK_getbiosmetrics(name)
206char *name;
207{
208return (NULL);
209}
210
211/* This is ugly, and convoluted. All the magic
212 * for disk geo/size happens here. Basically,
213 * the real size is the one we will use in the
214 * rest of the program, the label size is what we
215 * got from the disklabel. If the disklabel fails,
216 * we assume we are working with a normal file,
217 * and should request the user to specify the
218 * geometry he/she wishes to use.
219 */
220int
221DISK_getmetrics(disk, user)
222disk_t *disk;
223DISK_metrics *user;
224{
225
226disk->label = DISK_getlabelmetrics(disk->name);
227disk->bios = DISK_getbiosmetrics(disk->name);
228
229/* If user supplied, use that */
230if (user) {
231disk->real = user;
232return (0);
233}
234
235/* Fixup bios metrics to include cylinders past 1023 boundary */
236if(disk->label && disk->bios){
237int cyls, secs;
238
239cyls = disk->label->size / (disk->bios->heads * disk->bios->sectors);
240secs = cyls * (disk->bios->heads * disk->bios->sectors);
241if ((disk->label->size - secs) < 0)
242errx(1, "BIOS fixup botch (%d sectors)", disk->label->size - secs);
243disk->bios->cylinders = cyls;
244disk->bios->size = secs;
245}
246
247/* If we have a (fixed) BIOS geometry, use that */
248if (disk->bios) {
249disk->real = disk->bios;
250return (0);
251}
252
253/* If we have a label, use that */
254if (disk->label) {
255disk->real = disk->label;
256return (0);
257}
258
259/* Can not get geometry, punt */
260disk->real = NULL;
261return (1);
262}
263
264/* Get the disk's native sector size, updating the metrics' sector_size field.
265 */
266 int
267DISK_get_sector_size(disk, user)
268 disk_t *disk;
269 DISK_metrics *user;
270{
271 int ret = 1;
272 int fd;
273 uint32_t sector_size;
274
275 /* Default to 512 bytes per sector, in case of failure. */
276 user->sector_size = 512;
277
278 fd = DISK_open(disk->name, O_RDONLY);
279 if (fd == -1) {
280err(1, "Could not open %s", disk->name);
281 } else {
282 if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
283 err(1, "Could not get disk block size");
284 } else {
285 user->sector_size = sector_size;
286 ret = 0;
287 }
288 }
289
290 return ret;
291}
292
293int
294DISK_printmetrics(disk)
295disk_t *disk;
296{
297
298printf("Disk: %s\t", disk->name);
299if (disk->real) {
300printf("geometry: %d/%d/%d [%d sectors]\n", disk->real->cylinders,
301 disk->real->heads, disk->real->sectors, disk->real->size);
302if (disk->real->sector_size != 512)
303printf("Sector size: %d bytes\n", disk->real->sector_size);
304} else {
305printf("geometry: <none>\n");
306}
307
308return (0);
309}
310
311

Archive Download this file

Revision: 2679