1/* $NetBSD: svhlabel.c,v 1.5 2009/04/06 12:33:11 lukem 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.5 2009/04/06 12:33:11 lukem 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); 63static void getlabel(int); 64static void setlabel(int, int); 65static int getparts(int, int); 66static int is_efs(int, uint32_t); 67static struct sgi_boot_block *convert_sgi_boot_block(unsigned char *); 68 69struct disklabel label; 70 71static void 72getlabel(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 87static void 88setlabel(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 104static int 105getparts(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 202static int 203is_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 234static struct sgi_boot_block * 235convert_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 279static void 280usage(void) 281{ 282 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n", 283 getprogname()); 284 exit(1); 285} 286 287 288int 289main(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 " : ""); 345raw = 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