xref: /netbsd-src/sbin/mbrlabel/mbrlabel.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: mbrlabel.c,v 1.22 2003/06/07 10:03:39 dsl 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.22 2003/06/07 10:03:39 dsl 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 	int one = 1;
86 
87 	label.d_checksum = 0;
88 	label.d_checksum = dkcksum(&label);
89 	if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
90 		perror("set label");
91 		exit(1);
92 	}
93 	if (!doraw)
94 		/* If we haven't written to the disk, don't discard on close */
95 		ioctl(sd, DIOCKLABEL, &one);
96 
97 }
98 
99 static struct typetab {
100 	int mbrtype;
101 	int nbsdtype;
102 } typetable[] = {
103 	{ MBR_PTYPE_386BSD,	FS_BSDFFS },
104 	{ MBR_PTYPE_FAT12,	FS_MSDOS },
105 	{ MBR_PTYPE_FAT16B,	FS_MSDOS },
106 	{ MBR_PTYPE_FAT16L,	FS_MSDOS },
107 	{ MBR_PTYPE_FAT16S,	FS_MSDOS },
108 	{ MBR_PTYPE_FAT32,	FS_MSDOS },
109 	{ MBR_PTYPE_FAT32L,	FS_MSDOS },
110 	{ MBR_PTYPE_LNXEXT2,	FS_EX2FS },
111 	{ MBR_PTYPE_LNXSWAP,	FS_SWAP },
112 	{ MBR_PTYPE_NETBSD,	FS_BSDFFS },
113 	{ MBR_PTYPE_NTFS,	FS_NTFS },
114 	{ MBR_PTYPE_APPLEUFS,	FS_APPLEUFS },
115 	{ 0, 0 }
116 };
117 
118 int
119 nbsdtype(int type)
120 {
121 	struct typetab *tt;
122 
123 	for (tt = typetable; tt->mbrtype; tt++)
124 		if (tt->mbrtype == type)
125 			return (tt->nbsdtype);
126 	return (FS_OTHER);
127 }
128 
129 u_int16_t
130 getshort(void *p)
131 {
132 	unsigned char *cp = p;
133 
134 	return (cp[0] | (cp[1] << 8));
135 }
136 
137 u_int32_t
138 getlong(void *p)
139 {
140 	unsigned char *cp = p;
141 
142 	return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
143 }
144 
145 int
146 getparts(int sd, u_int32_t off, u_int32_t extoff, int verbose)
147 {
148 	unsigned char		buf[DEV_BSIZE];
149 	struct mbr_partition	parts[NMBRPART];
150 	struct partition	npe;
151 	off_t			loff;
152 	int			i, j, unused, changed;
153 
154 	changed = 0;
155 	loff = (off_t)off * DEV_BSIZE;
156 
157 	if (lseek(sd, loff, SEEK_SET) != loff) {
158 		perror("seek label");
159 		exit(1);
160 	}
161 	if (read(sd, buf, sizeof buf) != DEV_BSIZE) {
162 		perror("read label");
163 		exit(1);
164 	}
165 	if (getshort(buf + MBR_MAGICOFF) != MBR_MAGIC)
166 		return (changed);
167 	memcpy(parts, buf + MBR_PARTOFF, sizeof parts);
168 
169 				/* scan partition table */
170 	for (i = 0; i < NMBRPART; i++) {
171 		if (parts[i].mbrp_typ == 0 ||
172 				/* extended partitions are handled below */
173 		    MBR_IS_EXTENDED(parts[i].mbrp_typ))
174 			continue;
175 
176 		memset((void *)&npe, 0, sizeof(npe));
177 		npe.p_size = getlong(&parts[i].mbrp_size);
178 		npe.p_offset = getlong(&parts[i].mbrp_start) + off;
179 		npe.p_fstype = nbsdtype(parts[i].mbrp_typ);
180 
181 				/* find existing entry, or first free slot */
182 		unused = -1;	/* flag as no free slot */
183 		if (verbose)
184 			printf(
185 			    "Found %s partition; size %u (%u MB), offset %u\n",
186 			    fstypenames[npe.p_fstype],
187 			    npe.p_size, npe.p_size / 2048, npe.p_offset);
188 		for (j = 0; j < label.d_npartitions; j++) {
189 			struct partition *lpe;
190 
191 			if (j == RAW_PART)
192 				continue;
193 			lpe = &label.d_partitions[j];
194 			if (lpe->p_size == npe.p_size &&
195 			    lpe->p_offset == npe.p_offset
196 #ifdef notyet
197 			    && (lpe->p_fstype == npe.p_fstype ||
198 			     lpe->p_fstype == FS_UNUSED) */
199 #endif
200 			     ) {
201 				if (verbose)
202 					printf(
203 			    "  skipping existing %s partition at slot %c.\n",
204 					    fstypenames[lpe->p_fstype],
205 					    j + 'a');
206 				unused = -2;	/* flag as existing */
207 				break;
208 			}
209 			if (unused == -1 && lpe->p_size == 0 &&
210 			    lpe->p_fstype == FS_UNUSED)
211 				unused = j;
212 		}
213 		if (unused == -2)
214 			continue;	/* entry exists, skip... */
215 		if (unused == -1) {
216 			if (label.d_npartitions < MAXPARTITIONS) {
217 				unused = label.d_npartitions;
218 				label.d_npartitions++;
219 			} else {
220 				printf(
221 				"  WARNING: no slots free for %s partition.\n",
222 				    fstypenames[npe.p_fstype]);
223 				continue;
224 			}
225 		}
226 
227 		if (verbose)
228 			printf("  adding %s partition to slot %c.\n",
229 			    fstypenames[npe.p_fstype], unused + 'a');
230 		switch (npe.p_fstype) {
231 		case FS_BSDFFS:
232 		case FS_APPLEUFS:
233 			npe.p_size = 16384;	/* XXX */
234 			npe.p_fsize = 1024;
235 			npe.p_frag = 8;
236 			npe.p_cpg = 16;
237 			break;
238 #ifdef	__does_not_happen__
239 		case FS_BSDLFS:
240 			npe.p_size = 16384;	/* XXX */
241 			npe.p_fsize = 1024;
242 			npe.p_frag = 8;
243 			npe.p_sgs = XXX;
244 			break;
245 #endif
246 		}
247 		changed++;
248 		label.d_partitions[unused] = npe;
249 	}
250 
251 				/* recursively scan extended partitions */
252 	for (i = 0; i < NMBRPART; i++) {
253 		u_int32_t poff;
254 
255 		if (MBR_IS_EXTENDED(parts[i].mbrp_typ)) {
256 			poff = getlong(&parts[i].mbrp_start) + extoff;
257 			changed += getparts(sd, poff,
258 			    extoff ? extoff : poff, verbose);
259 		}
260 	}
261 	return (changed);
262 }
263 
264 void
265 usage(void)
266 {
267 	fprintf(stderr, "Usage: %s [-fqrw] rawdisk\n", getprogname());
268 	exit(1);
269 }
270 
271 
272 int
273 main(int argc, char **argv)
274 {
275 	int	sd, ch, changed;
276 	char	name[MAXPATHLEN];
277 	int	force;			/* force label update */
278 	int	raw;			/* update on-disk label as well */
279 	int	verbose;		/* verbose output */
280 	int	write_it;		/* update in-core label if changed */
281 
282 	force = 0;
283 	raw = 0;
284 	verbose = 1;
285 	write_it = 0;
286 	while ((ch = getopt(argc, argv, "fqrw")) != -1) {
287 		switch (ch) {
288 		case 'f':
289 			force = 1;
290 			break;
291 		case 'q':
292 			verbose = 0;
293 			break;
294 		case 'r':
295 			raw = 1;
296 			break;
297 		case 'w':
298 			write_it = 1;
299 			break;
300 		default:
301 			usage();
302 		}
303 	}
304 	argc -= optind;
305 	argv += optind;
306 	if (argc != 1)
307 		usage();
308 
309 	if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
310 	    (size_t)MAXPATHLEN, 0)) < 0) {
311 		perror(argv[0]);
312 		exit(1);
313 	}
314 	getlabel(sd);
315 	changed = getparts(sd, MBR_BBSECTOR, 0, verbose);
316 
317 	if (verbose) {
318 		putchar('\n');
319 		showpartitions(stdout, &label, 0);
320 		putchar('\n');
321 	}
322 	if (write_it) {
323 		if (! changed && ! force)
324 			printf("No change; not updating disk label.\n");
325 		else {
326 			if (verbose)
327 				printf("Updating in-core %sdisk label.\n",
328 				    raw ? "and on-disk " : "");
329 			setlabel(sd, raw);
330 		}
331 	} else {
332 		printf("Not updating disk label.\n");
333 	}
334 	close(sd);
335 	return (0);
336 }
337