mbrlabel.c revision 1.19 1 /* $NetBSD: mbrlabel.c,v 1.19 2002/02/07 02:14:02 ross Exp $ */
2
3 /*
4 * Copyright (C) 1998 Wolfgang Solfrank.
5 * Copyright (C) 1998 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: mbrlabel.c,v 1.19 2002/02/07 02:14:02 ross Exp $");
37 #endif /* not lint */
38
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <util.h>
45
46 #include <sys/param.h>
47 #define FSTYPENAMES
48 #include <sys/disklabel.h>
49 #include <sys/disklabel_mbr.h>
50 #include <sys/ioctl.h>
51
52 #include "dkcksum.h"
53 #include "extern.h"
54
55 int main(int, char **);
56 void usage(void);
57 void getlabel(int);
58 void setlabel(int, int);
59 int getparts(int, u_int32_t, u_int32_t, int);
60 int nbsdtype(int);
61 u_int16_t getshort(void *);
62 u_int32_t getlong(void *);
63
64 struct disklabel label;
65
66 void
67 getlabel(int sd)
68 {
69
70 if (ioctl(sd, DIOCGDINFO, &label) < 0) {
71 perror("get label");
72 exit(1);
73 }
74 /*
75 * Some ports seem to not set the number of partitions
76 * correctly, albeit they seem to set the raw partition ok!
77 */
78 if (label.d_npartitions <= getrawpartition())
79 label.d_npartitions = getrawpartition() + 1;
80 }
81
82 void
83 setlabel(int sd, int doraw)
84 {
85
86 label.d_checksum = 0;
87 label.d_checksum = dkcksum(&label);
88 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
89 perror("set label");
90 exit(1);
91 }
92 }
93
94 static struct typetab {
95 int mbrtype;
96 int nbsdtype;
97 } typetable[] = {
98 { MBR_PTYPE_386BSD, FS_BSDFFS },
99 { MBR_PTYPE_FAT12, FS_MSDOS },
100 { MBR_PTYPE_FAT16B, FS_MSDOS },
101 { MBR_PTYPE_FAT16L, FS_MSDOS },
102 { MBR_PTYPE_FAT16S, FS_MSDOS },
103 { MBR_PTYPE_FAT32, FS_MSDOS },
104 { MBR_PTYPE_FAT32L, FS_MSDOS },
105 { MBR_PTYPE_LNXEXT2, FS_EX2FS },
106 { MBR_PTYPE_LNXSWAP, FS_SWAP },
107 { MBR_PTYPE_NETBSD, FS_BSDFFS },
108 { MBR_PTYPE_NTFS, FS_NTFS },
109 { 0, 0 }
110 };
111
112 int
113 nbsdtype(int type)
114 {
115 struct typetab *tt;
116
117 for (tt = typetable; tt->mbrtype; tt++)
118 if (tt->mbrtype == type)
119 return (tt->nbsdtype);
120 return (FS_OTHER);
121 }
122
123 u_int16_t
124 getshort(void *p)
125 {
126 unsigned char *cp = p;
127
128 return (cp[0] | (cp[1] << 8));
129 }
130
131 u_int32_t
132 getlong(void *p)
133 {
134 unsigned char *cp = p;
135
136 return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
137 }
138
139 int
140 getparts(int sd, u_int32_t off, u_int32_t extoff, int verbose)
141 {
142 unsigned char buf[DEV_BSIZE];
143 struct mbr_partition parts[NMBRPART];
144 struct partition npe;
145 off_t loff;
146 int i, j, unused, changed;
147
148 changed = 0;
149 loff = (off_t)off * DEV_BSIZE;
150
151 if (lseek(sd, loff, SEEK_SET) != loff) {
152 perror("seek label");
153 exit(1);
154 }
155 if (read(sd, buf, sizeof buf) != DEV_BSIZE) {
156 perror("read label");
157 exit(1);
158 }
159 if (getshort(buf + MBR_MAGICOFF) != MBR_MAGIC)
160 return (changed);
161 memcpy(parts, buf + MBR_PARTOFF, sizeof parts);
162
163 /* scan partition table */
164 for (i = 0; i < NMBRPART; i++) {
165 if (parts[i].mbrp_typ == 0 ||
166 /* extended partitions are handled below */
167 MBR_IS_EXTENDED(parts[i].mbrp_typ))
168 continue;
169
170 memset((void *)&npe, 0, sizeof(npe));
171 npe.p_size = getlong(&parts[i].mbrp_size);
172 npe.p_offset = getlong(&parts[i].mbrp_start) + off;
173 npe.p_fstype = nbsdtype(parts[i].mbrp_typ);
174
175 /* find existing entry, or first free slot */
176 unused = -1; /* flag as no free slot */
177 if (verbose)
178 printf(
179 "Found %s partition; size %u (%u MB), offset %u\n",
180 fstypenames[npe.p_fstype],
181 npe.p_size, npe.p_size / 2048, npe.p_offset);
182 for (j = 0; j < label.d_npartitions; j++) {
183 struct partition *lpe;
184
185 if (j == RAW_PART)
186 continue;
187 lpe = &label.d_partitions[j];
188 if (lpe->p_size == npe.p_size &&
189 lpe->p_offset == npe.p_offset
190 #ifdef notyet
191 && (lpe->p_fstype == npe.p_fstype ||
192 lpe->p_fstype == FS_UNUSED) */
193 #endif
194 ) {
195 if (verbose)
196 printf(
197 " skipping existing %s partition at slot %c.\n",
198 fstypenames[lpe->p_fstype],
199 j + 'a');
200 unused = -2; /* flag as existing */
201 break;
202 }
203 if (unused == -1 && lpe->p_size == 0 &&
204 lpe->p_fstype == FS_UNUSED)
205 unused = j;
206 }
207 if (unused == -2)
208 continue; /* entry exists, skip... */
209 if (unused == -1) {
210 if (label.d_npartitions < MAXPARTITIONS) {
211 unused = label.d_npartitions;
212 label.d_npartitions++;
213 } else {
214 printf(
215 " WARNING: no slots free for %s partition.\n",
216 fstypenames[npe.p_fstype]);
217 continue;
218 }
219 }
220
221 if (verbose)
222 printf(" adding %s partition to slot %c.\n",
223 fstypenames[npe.p_fstype], unused + 'a');
224 switch (npe.p_fstype) {
225 case FS_BSDFFS:
226 npe.p_size = 16384; /* XXX */
227 npe.p_fsize = 1024;
228 npe.p_frag = 8;
229 npe.p_cpg = 16;
230 break;
231 #ifdef __does_not_happen__
232 case FS_BSDLFS:
233 npe.p_size = 16384; /* XXX */
234 npe.p_fsize = 1024;
235 npe.p_frag = 8;
236 npe.p_sgs = XXX;
237 break;
238 #endif
239 }
240 changed++;
241 label.d_partitions[unused] = npe;
242 }
243
244 /* recursively scan extended partitions */
245 for (i = 0; i < NMBRPART; i++) {
246 u_int32_t poff;
247
248 if (MBR_IS_EXTENDED(parts[i].mbrp_typ)) {
249 poff = getlong(&parts[i].mbrp_start) + extoff;
250 changed += getparts(sd, poff,
251 extoff ? extoff : poff, verbose);
252 }
253 }
254 return (changed);
255 }
256
257 void
258 usage(void)
259 {
260 fprintf(stderr, "Usage: %s [-fqrw] rawdisk\n", getprogname());
261 exit(1);
262 }
263
264
265 int
266 main(int argc, char **argv)
267 {
268 int sd, ch, changed;
269 char name[MAXPATHLEN];
270 int force; /* force label update */
271 int raw; /* update on-disk label as well */
272 int verbose; /* verbose output */
273 int write_it; /* update in-core label if changed */
274
275 force = 0;
276 raw = 0;
277 verbose = 1;
278 write_it = 0;
279 while ((ch = getopt(argc, argv, "fqrw")) != -1) {
280 switch (ch) {
281 case 'f':
282 force = 1;
283 break;
284 case 'q':
285 verbose = 0;
286 break;
287 case 'r':
288 raw = 1;
289 break;
290 case 'w':
291 write_it = 1;
292 break;
293 default:
294 usage();
295 }
296 }
297 argc -= optind;
298 argv += optind;
299 if (argc != 1)
300 usage();
301
302 if ((sd = opendisk(argv[0], O_RDWR, name, (size_t)MAXPATHLEN, 0)) < 0) {
303 perror(argv[0]);
304 exit(1);
305 }
306 getlabel(sd);
307 changed = getparts(sd, MBR_BBSECTOR, 0, verbose);
308
309 if (verbose) {
310 putchar('\n');
311 showpartitions(stdout, &label, 0);
312 putchar('\n');
313 }
314 if (write_it) {
315 if (! changed && ! force)
316 printf("No change; not updating disk label.\n");
317 else {
318 if (verbose)
319 printf("Updating in-core %sdisk label.\n",
320 raw ? "and on-disk " : "");
321 setlabel(sd, raw);
322 }
323 } else {
324 printf("Not updating disk label.\n");
325 }
326 close(sd);
327 return (0);
328 }
329