Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2045