1 /* $NetBSD: mbrlabel.c,v 1.12 2000/12/27 04:22:11 lukem 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.12 2000/12/27 04:22:11 lukem 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 #define FIRSTPART 0 56 57 int main(int, char **); 58 void usage(void); 59 void getlabel(int); 60 void setlabel(int, int); 61 int getparts(int, int, u_int32_t, u_int32_t, int); 62 int nbsdtype(int); 63 u_int32_t getlong(void *p); 64 65 struct disklabel label; 66 67 void 68 getlabel(int sd) 69 { 70 71 if (ioctl(sd, DIOCGDINFO, &label) < 0) { 72 perror("get label"); 73 exit(1); 74 } 75 /* 76 * Some ports seem to not set the number of partitions 77 * correctly, albeit they seem to set the raw partiton ok! 78 */ 79 if (label.d_npartitions <= RAW_PART) 80 label.d_npartitions = RAW_PART + 1; 81 } 82 83 void 84 setlabel(int sd, int doraw) 85 { 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 } 94 95 static struct typetab { 96 int mbrtype; 97 int nbsdtype; 98 } typetable[] = { 99 { MBR_PTYPE_386BSD, FS_BSDFFS }, 100 { MBR_PTYPE_FAT12, FS_MSDOS }, 101 { MBR_PTYPE_FAT16B, FS_MSDOS }, 102 { MBR_PTYPE_FAT16L, FS_MSDOS }, 103 { MBR_PTYPE_FAT16S, FS_MSDOS }, 104 { MBR_PTYPE_FAT32, FS_MSDOS }, 105 { MBR_PTYPE_FAT32L, FS_MSDOS }, 106 { MBR_PTYPE_LNXEXT2, FS_EX2FS }, 107 { MBR_PTYPE_LNXSWAP, FS_SWAP }, 108 { MBR_PTYPE_NETBSD, FS_BSDFFS }, 109 { MBR_PTYPE_NTFS, FS_NTFS }, 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_int32_t 125 getlong(void *p) 126 { 127 unsigned char *cp = p; 128 129 return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24)); 130 } 131 132 int 133 getparts(int sd, int np, u_int32_t off, u_int32_t extoff, int verbose) 134 { 135 unsigned char buf[DEV_BSIZE]; 136 struct mbr_partition parts[NMBRPART]; 137 struct partition npe; 138 off_t loff; 139 int i, j, unused, changed; 140 141 changed = 0; 142 loff = (off_t)off * DEV_BSIZE; 143 144 if (lseek(sd, loff, SEEK_SET) != loff) { 145 perror("seek label"); 146 exit(1); 147 } 148 if (read(sd, buf, DEV_BSIZE) != DEV_BSIZE) { 149 perror("read label"); 150 exit(1); 151 } 152 if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) 153 return (changed); 154 memcpy(parts, buf + MBR_PARTOFF, sizeof parts); 155 156 /* scan partition table */ 157 for (i = 0; i < NMBRPART; i++) { 158 if (parts[i].mbrp_typ == 0 || 159 /* extended partitions are handled below */ 160 MBR_IS_EXTENDED(parts[i].mbrp_typ)) 161 continue; 162 163 memset((void *)&npe, 0, sizeof(npe)); 164 npe.p_size = getlong(&parts[i].mbrp_size); 165 npe.p_offset = getlong(&parts[i].mbrp_start) + off; 166 npe.p_fstype = nbsdtype(parts[i].mbrp_typ); 167 168 /* find existing entry, or first free slot */ 169 unused = -1; /* flag as no free slot */ 170 if (verbose) 171 printf("Found %s partition at %d, size %d\n", 172 fstypenames[npe.p_fstype], npe.p_offset, 173 npe.p_size); 174 for (j = 0; j < label.d_npartitions; j++) { 175 struct partition *lpe; 176 177 if (j == RAW_PART) 178 continue; 179 lpe = &label.d_partitions[j]; 180 if (lpe->p_size == npe.p_size && 181 lpe->p_offset == npe.p_offset 182 #ifdef notyet 183 && (lpe->p_fstype == npe.p_fstype || 184 lpe->p_fstype == FS_UNUSED) */ 185 #endif 186 ) { 187 if (verbose) 188 printf( 189 " skipping existing %s partition at slot %c.\n", 190 fstypenames[lpe->p_fstype], 191 j + 'a'); 192 unused = -2; /* flag as existing */ 193 break; 194 } 195 if (unused == -1 && lpe->p_size == 0 && 196 lpe->p_fstype == FS_UNUSED) 197 unused = j; 198 } 199 if (unused == -2) 200 continue; /* entry exists, skip... */ 201 if (unused == -1) { 202 if (label.d_npartitions < MAXPARTITIONS) { 203 unused = label.d_npartitions; 204 label.d_npartitions++; 205 } else { 206 printf( 207 " WARNING: no slots free for %s partition.\n", 208 fstypenames[npe.p_fstype]); 209 continue; 210 } 211 } 212 213 if (verbose) 214 printf(" adding %s partition to slot %c.\n", 215 fstypenames[npe.p_fstype], unused + 'a'); 216 switch (npe.p_fstype) { 217 case FS_BSDFFS: 218 npe.p_size = 16384; /* XXX */ 219 npe.p_fsize = 1024; 220 npe.p_frag = 8; 221 npe.p_cpg = 16; 222 break; 223 #ifdef __does_not_happen__ 224 case FS_BSDLFS: 225 npe.p_size = 16384; /* XXX */ 226 npe.p_fsize = 1024; 227 npe.p_frag = 8; 228 npe.p_sgs = XXX; 229 break; 230 #endif 231 } 232 changed++; 233 label.d_partitions[unused] = npe; 234 } 235 236 /* recursively scan extended partitions */ 237 for (i = 0; i < NMBRPART; i++) { 238 u_int32_t poff; 239 240 if (MBR_IS_EXTENDED(parts[i].mbrp_typ)) { 241 poff = getlong(&parts[i].mbrp_start) + extoff; 242 changed += getparts(sd, np, poff, 243 extoff ? extoff : poff, verbose); 244 } 245 } 246 return (changed); 247 } 248 249 void 250 usage(void) 251 { 252 extern char *__progname; 253 254 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n", __progname); 255 exit(1); 256 } 257 258 259 int 260 main(int argc, char **argv) 261 { 262 int sd, ch, changed; 263 char name[MAXPATHLEN]; 264 int force; /* force label update */ 265 int raw; /* update on-disk label as well */ 266 int verbose; /* verbose output */ 267 int write; /* update in-core label if changed */ 268 269 force = 0; 270 raw = 0; 271 verbose = 1; 272 write = 0; 273 while ((ch = getopt(argc, argv, "fqrw")) != -1) { 274 switch (ch) { 275 case 'f': 276 force = 1; 277 break; 278 case 'q': 279 verbose = 0; 280 break; 281 case 'r': 282 raw = 1; 283 break; 284 case 'w': 285 write = 1; 286 break; 287 default: 288 usage(); 289 } 290 } 291 argc -= optind; 292 argv += optind; 293 if (argc != 1) 294 usage(); 295 296 if ((sd = opendisk(argv[0], O_RDWR, name, MAXPATHLEN, 0)) < 0) { 297 perror(argv[0]); 298 exit(1); 299 } 300 getlabel(sd); 301 changed = getparts(sd, FIRSTPART, MBR_BBSECTOR, 0, verbose); 302 303 if (verbose) { 304 putchar('\n'); 305 showpartitions(stdout, &label, 0); 306 putchar('\n'); 307 } 308 if (write) { 309 if (! changed && ! force) 310 printf("No change; not updating disk label.\n"); 311 else { 312 if (verbose) 313 printf("Updating in-core %sdisk label.\n", 314 raw ? "and on-disk " : ""); 315 setlabel(sd, raw); 316 } 317 } else { 318 printf("Not updating disk label.\n"); 319 } 320 close(sd); 321 return (0); 322 } 323