1 /* $NetBSD: svhlabel.c,v 1.6 2011/08/27 18:55:58 joerg Exp $ */ 2 3 /* 4 * Copyright (C) 2007 Stephen M. Rumble. 5 * Copyright (C) 1998 Wolfgang Solfrank. 6 * Copyright (C) 1998 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 __RCSID("$NetBSD: svhlabel.c,v 1.6 2011/08/27 18:55:58 joerg Exp $"); 38 #endif /* not lint */ 39 40 #include <stdio.h> 41 #include <err.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <limits.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <util.h> 49 50 #include <sys/param.h> 51 #define FSTYPENAMES 52 #include <sys/disklabel.h> 53 #include <sys/bootblock.h> 54 #include <sys/ioctl.h> 55 56 #include <fs/efs/efs.h> 57 #include <fs/efs/efs_sb.h> 58 59 #include "dkcksum.h" 60 #include "extern.h" 61 62 __dead static void usage(void); 63 static void getlabel(int); 64 static void setlabel(int, int); 65 static int getparts(int, int); 66 static int is_efs(int, uint32_t); 67 static struct sgi_boot_block *convert_sgi_boot_block(unsigned char *); 68 69 struct disklabel label; 70 71 static void 72 getlabel(int sd) 73 { 74 75 if (ioctl(sd, DIOCGDINFO, &label) < 0) { 76 perror("get label"); 77 exit(1); 78 } 79 /* 80 * Some ports seem to not set the number of partitions 81 * correctly, albeit they seem to set the raw partition ok! 82 */ 83 if (label.d_npartitions <= getrawpartition()) 84 label.d_npartitions = getrawpartition() + 1; 85 } 86 87 static void 88 setlabel(int sd, int doraw) 89 { 90 int one = 1; 91 92 label.d_checksum = 0; 93 label.d_checksum = dkcksum(&label); 94 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) { 95 perror("set label"); 96 exit(1); 97 } 98 if (!doraw) 99 /* If we haven't written to the disk, don't discard on close */ 100 ioctl(sd, DIOCKLABEL, &one); 101 102 } 103 104 static int 105 getparts(int sd, int verbose) 106 { 107 unsigned char buf[DEV_BSIZE]; 108 struct sgi_boot_block *vh; 109 struct partition npe; 110 int i, j, changed; 111 112 changed = 0; 113 114 if (lseek(sd, 0, SEEK_SET) == -1) { 115 perror("seek vh"); 116 exit(1); 117 } 118 if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) { 119 perror("read vh"); 120 exit(1); 121 } 122 vh = convert_sgi_boot_block(buf); 123 124 if (vh->magic != SGI_BOOT_BLOCK_MAGIC) 125 return (changed); 126 127 if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE) 128 changed++; 129 label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE; 130 131 for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) { 132 if (vh->partitions[i].blocks == 0) 133 continue; 134 135 if (j == MAXPARTITIONS) 136 break; 137 138 switch (vh->partitions[i].type) { 139 case SGI_PTYPE_EFS: 140 /* 141 * For some reason, my IRIX CDs list EFS partitions as SYSV!? 142 */ 143 case SGI_PTYPE_SYSV: 144 if (is_efs(sd, vh->partitions[i].first)) { 145 npe.p_fstype = FS_EFS; 146 npe.p_size = vh->partitions[i].blocks; 147 npe.p_offset = vh->partitions[i].first; 148 npe.p_fsize = 0; 149 npe.p_frag = 0; 150 npe.p_cpg = 0; 151 } 152 break; 153 154 case SGI_PTYPE_VOLUME: 155 if (label.d_secperunit != (uint32_t)vh->partitions[i].blocks) 156 changed++; 157 label.d_secperunit = vh->partitions[i].blocks; 158 continue; 159 160 default: 161 continue; 162 } 163 164 if (j >= label.d_npartitions) 165 break; 166 167 if (j == getrawpartition()) { 168 if (++j >= label.d_npartitions) 169 break; 170 } 171 172 if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) { 173 label.d_partitions[j] = npe; 174 changed++; 175 } 176 177 j++; 178 } 179 180 /* XXX - fudge */ 181 if (label.d_nsectors != 1 || label.d_ntracks != 1 || 182 label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit) 183 changed++; 184 label.d_nsectors = 1; 185 label.d_ntracks = 1; 186 label.d_secpercyl = 1; 187 label.d_ncylinders = label.d_secperunit; 188 189 i = getrawpartition(); 190 if (label.d_partitions[i].p_fstype != FS_UNUSED || 191 label.d_partitions[i].p_offset != 0 || 192 label.d_partitions[i].p_size != label.d_secperunit) { 193 label.d_partitions[i].p_fstype = FS_UNUSED; 194 label.d_partitions[i].p_offset = 0; 195 label.d_partitions[i].p_size = label.d_secperunit; 196 changed++; 197 } 198 199 return (changed); 200 } 201 202 static int 203 is_efs(int sd, uint32_t blkoff) 204 { 205 struct efs_sb sb; 206 off_t oldoff; 207 208 if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) { 209 perror("is_efs lseek 0"); 210 exit(1); 211 } 212 213 blkoff *= SGI_BOOT_BLOCK_BLOCKSIZE; 214 if (lseek(sd, blkoff + (EFS_BB_SB * EFS_BB_SIZE), SEEK_SET) == -1) { 215 perror("is_efs lseek 1"); 216 exit(1); 217 } 218 219 if (read(sd, &sb, sizeof(sb)) != sizeof(sb)) { 220 perror("is_efs read"); 221 exit(1); 222 } 223 224 if (lseek(sd, oldoff, SEEK_SET) == -1) { 225 perror("is_efs lseek 2"); 226 exit(1); 227 } 228 229 BE32TOH(sb.sb_magic); 230 231 return (sb.sb_magic == EFS_SB_MAGIC || sb.sb_magic == EFS_SB_NEWMAGIC); 232 } 233 234 static struct sgi_boot_block * 235 convert_sgi_boot_block(unsigned char *buf) 236 { 237 struct sgi_boot_block *vh; 238 int i; 239 240 vh = (struct sgi_boot_block *)buf; 241 242 BE32TOH(vh->magic); 243 BE16TOH(vh->root); 244 BE16TOH(vh->swap); 245 246 BE16TOH(vh->dp.dp_cyls); 247 BE16TOH(vh->dp.dp_shd0); 248 BE16TOH(vh->dp.dp_trks0); 249 BE16TOH(vh->dp.dp_secs); 250 BE16TOH(vh->dp.dp_secbytes); 251 BE16TOH(vh->dp.dp_interleave); 252 BE32TOH(vh->dp.dp_flags); 253 BE32TOH(vh->dp.dp_datarate); 254 BE32TOH(vh->dp.dp_nretries); 255 BE32TOH(vh->dp.dp_mspw); 256 BE16TOH(vh->dp.dp_xgap1); 257 BE16TOH(vh->dp.dp_xsync); 258 BE16TOH(vh->dp.dp_xrdly); 259 BE16TOH(vh->dp.dp_xgap2); 260 BE16TOH(vh->dp.dp_xrgate); 261 BE16TOH(vh->dp.dp_xwcont); 262 263 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) { 264 BE32TOH(vh->voldir[i].block); 265 BE32TOH(vh->voldir[i].bytes); 266 } 267 268 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) { 269 BE32TOH(vh->partitions[i].blocks); 270 BE32TOH(vh->partitions[i].first); 271 BE32TOH(vh->partitions[i].type); 272 } 273 274 BE32TOH(vh->checksum); 275 276 return (vh); 277 } 278 279 static void 280 usage(void) 281 { 282 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n", 283 getprogname()); 284 exit(1); 285 } 286 287 288 int 289 main(int argc, char **argv) 290 { 291 int sd, ch, changed; 292 char name[MAXPATHLEN]; 293 int force; /* force label update */ 294 int raw; /* update on-disk label as well */ 295 int verbose; /* verbose output */ 296 int write_it; /* update in-core label if changed */ 297 298 force = 0; 299 raw = 0; 300 verbose = 1; 301 write_it = 0; 302 while ((ch = getopt(argc, argv, "fqrw")) != -1) { 303 switch (ch) { 304 case 'f': 305 force = 1; 306 break; 307 case 'q': 308 verbose = 0; 309 break; 310 case 'r': 311 raw = 1; 312 break; 313 case 'w': 314 write_it = 1; 315 break; 316 default: 317 usage(); 318 } 319 } 320 argc -= optind; 321 argv += optind; 322 if (argc != 1) 323 usage(); 324 325 if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name, 326 (size_t)MAXPATHLEN, 1)) < 0) { 327 perror(argv[0]); 328 exit(1); 329 } 330 getlabel(sd); 331 changed = getparts(sd, verbose); 332 333 if (verbose) { 334 putchar('\n'); 335 showpartitions(stdout, &label, 0); 336 putchar('\n'); 337 } 338 if (write_it) { 339 if (! changed && ! force) 340 printf("No change; not updating disk label.\n"); 341 else { 342 if (verbose) 343 printf("Updating in-core %sdisk label.\n", 344 raw ? "and on-disk " : ""); 345 raw = 0; /* XXX */ 346 setlabel(sd, raw); 347 } 348 } else { 349 printf("Not updating disk label.\n"); 350 } 351 close(sd); 352 return (0); 353 } 354