xref: /netbsd/sbin/mbrlabel/mbrlabel.c (revision bf9ec67e)
1 /*	$NetBSD: mbrlabel.c,v 1.20 2002/05/21 01:39:56 yamt 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.20 2002/05/21 01:39:56 yamt 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], write_it ? O_RDWR : O_RDONLY, name,
303 	    (size_t)MAXPATHLEN, 0)) < 0) {
304 		perror(argv[0]);
305 		exit(1);
306 	}
307 	getlabel(sd);
308 	changed = getparts(sd, MBR_BBSECTOR, 0, verbose);
309 
310 	if (verbose) {
311 		putchar('\n');
312 		showpartitions(stdout, &label, 0);
313 		putchar('\n');
314 	}
315 	if (write_it) {
316 		if (! changed && ! force)
317 			printf("No change; not updating disk label.\n");
318 		else {
319 			if (verbose)
320 				printf("Updating in-core %sdisk label.\n",
321 				    raw ? "and on-disk " : "");
322 			setlabel(sd, raw);
323 		}
324 	} else {
325 		printf("Not updating disk label.\n");
326 	}
327 	close(sd);
328 	return (0);
329 }
330