Chameleon

Chameleon Svn Source Tree

Root/branches/Chimera/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));
170
171if (fstat(fd, &st) == -1)
172 err(1, "%s", name);
173if (!S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) {
174 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size) == -1) {
175 err(1, "Could not get disk block count");
176 free(lm);
177 return NULL;
178 }
179 if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
180 err(1, "Could not get disk block size");
181 free(lm);
182 return NULL;
183 }
184} else {
185 sector_size = 512;
186 size = st.st_size / sector_size;
187}
188
189lm->sector_size = sector_size;
190lm->size = size;
191DISK_fake_CHS(lm);
192DISK_close(fd);
193}
194
195return (lm);
196}
197
198/*
199 * Don't try to get BIOS disk metrics.
200 */
201DISK_metrics *
202DISK_getbiosmetrics(name)
203char *name;
204{
205return (NULL);
206}
207
208/* This is ugly, and convoluted. All the magic
209 * for disk geo/size happens here. Basically,
210 * the real size is the one we will use in the
211 * rest of the program, the label size is what we
212 * got from the disklabel. If the disklabel fails,
213 * we assume we are working with a normal file,
214 * and should request the user to specify the
215 * geometry he/she wishes to use.
216 */
217int
218DISK_getmetrics(disk, user)
219disk_t *disk;
220DISK_metrics *user;
221{
222
223disk->label = DISK_getlabelmetrics(disk->name);
224disk->bios = DISK_getbiosmetrics(disk->name);
225
226/* If user supplied, use that */
227if (user) {
228disk->real = user;
229return (0);
230}
231
232/* Fixup bios metrics to include cylinders past 1023 boundary */
233if(disk->label && disk->bios){
234int cyls, secs;
235
236cyls = disk->label->size / (disk->bios->heads * disk->bios->sectors);
237secs = cyls * (disk->bios->heads * disk->bios->sectors);
238if ((disk->label->size - secs) < 0)
239errx(1, "BIOS fixup botch (%d sectors)", disk->label->size - secs);
240disk->bios->cylinders = cyls;
241disk->bios->size = secs;
242}
243
244/* If we have a (fixed) BIOS geometry, use that */
245if (disk->bios) {
246disk->real = disk->bios;
247return (0);
248}
249
250/* If we have a label, use that */
251if (disk->label) {
252disk->real = disk->label;
253return (0);
254}
255
256/* Can not get geometry, punt */
257disk->real = NULL;
258return (1);
259}
260
261/* Get the disk's native sector size, updating the metrics' sector_size field.
262 */
263 int
264DISK_get_sector_size(disk, user)
265 disk_t *disk;
266 DISK_metrics *user;
267{
268 int ret;
269 int fd;
270 uint32_t sector_size;
271
272 /* Default to 512 bytes per sector, in case of failure. */
273 user->sector_size = 512;
274 ret = 1;
275
276 fd = DISK_open(disk->name, O_RDONLY);
277 if (fd == -1) {
278err(1, "Could not open %s", disk->name);
279 } else {
280 if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
281 err(1, "Could not get disk block size");
282 } else {
283 user->sector_size = sector_size;
284 ret = 0;
285 }
286 }
287
288 return ret;
289}
290
291int
292DISK_printmetrics(disk)
293disk_t *disk;
294{
295
296printf("Disk: %s\t", disk->name);
297if (disk->real) {
298printf("geometry: %d/%d/%d [%d sectors]\n", disk->real->cylinders,
299 disk->real->heads, disk->real->sectors, disk->real->size);
300if (disk->real->sector_size != 512)
301printf("Sector size: %d bytes\n", disk->real->sector_size);
302} else {
303printf("geometry: <none>\n");
304}
305
306return (0);
307}
308
309

Archive Download this file

Revision: 2225