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