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); 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; 70static int rawpart; 71 72static void 73getlabel(int sd) 74{ 75 76 if (ioctl(sd, DIOCGDINFO, &label) < 0) { 77 perror("get label"); 78 exit(1); 79 } 80 /* 81 * Some ports seem to not set the number of partitions 82 * correctly, albeit they seem to set the raw partition ok! 83 */ 84 if (label.d_npartitions <= rawpart) 85 label.d_npartitions = rawpart + 1; 86} 87 88static void 89setlabel(int sd, int doraw) 90{ 91 int one = 1; 92 93 label.d_checksum = 0; 94 label.d_checksum = dkcksum(&label); 95 if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) { 96 perror("set label"); 97 exit(1); 98 } 99 if (!doraw) 100 /* If we haven't written to the disk, don't discard on close */ 101 ioctl(sd, DIOCKLABEL, &one); 102 103} 104 105static int 106getparts(int sd, int verbose) 107{ 108 unsigned char buf[DEV_BSIZE]; 109 struct sgi_boot_block *vh; 110 struct partition npe; 111 int i, j, changed; 112 113 changed = 0; 114 115 if (lseek(sd, 0, SEEK_SET) == -1) { 116 perror("seek vh"); 117 exit(1); 118 } 119 if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) { 120 perror("read vh"); 121 exit(1); 122 } 123 vh = convert_sgi_boot_block(buf); 124 125 if (vh->magic != SGI_BOOT_BLOCK_MAGIC) 126 return (changed); 127 128 if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE) 129 changed++; 130 label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE; 131 132 for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) { 133 if (vh->partitions[i].blocks == 0) 134 continue; 135 136 if (j == MAXPARTITIONS) 137 break; 138 139 switch (vh->partitions[i].type) { 140 case SGI_PTYPE_EFS: 141 /* 142 * For some reason, my IRIX CDs list EFS partitions as SYSV!? 143 */ 144 case SGI_PTYPE_SYSV: 145 if (is_efs(sd, vh->partitions[i].first)) { 146 npe.p_fstype = FS_EFS; 147 npe.p_size = vh->partitions[i].blocks; 148 npe.p_offset = vh->partitions[i].first; 149 npe.p_fsize = 0; 150 npe.p_frag = 0; 151 npe.p_cpg = 0; 152 } 153 break; 154 155 case SGI_PTYPE_VOLUME: 156 if (label.d_secperunit != (uint32_t)vh->partitions[i].blocks) 157 changed++; 158 label.d_secperunit = vh->partitions[i].blocks; 159 continue; 160 161 default: 162 continue; 163 } 164 165 if (j >= label.d_npartitions) 166 break; 167 168 if (j == rawpart) { 169 if (++j >= label.d_npartitions) 170 break; 171 } 172 173 if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) { 174 label.d_partitions[j] = npe; 175 changed++; 176 } 177 178 j++; 179 } 180 181 /* XXX - fudge */ 182 if (label.d_nsectors != 1 || label.d_ntracks != 1 || 183 label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit) 184 changed++; 185 label.d_nsectors = 1; 186 label.d_ntracks = 1; 187 label.d_secpercyl = 1; 188 label.d_ncylinders = label.d_secperunit; 189 190 i = rawpart; 191 if (label.d_partitions[i].p_fstype != FS_UNUSED || 192 label.d_partitions[i].p_offset != 0 || 193 label.d_partitions[i].p_size != label.d_secperunit) { 194 label.d_partitions[i].p_fstype = FS_UNUSED; 195 label.d_partitions[i].p_offset = 0; 196 label.d_partitions[i].p_size = label.d_secperunit; 197 changed++; 198 } 199 200 return (changed); 201} 202 203static int 204is_efs(int sd, uint32_t blkoff) 205{ 206 struct efs_sb sb; 207 off_t oldoff; 208 209 if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) { 210 perror("is_efs lseek 0"); 211 exit(1); 212 } 213 214 blkoff *= SGI_BOOT_BLOCK_BLOCKSIZE; 215 if (lseek(sd, blkoff + (EFS_BB_SB * EFS_BB_SIZE), SEEK_SET) == -1) { 216 perror("is_efs lseek 1"); 217 exit(1); 218 } 219 220 if (read(sd, &sb, sizeof(sb)) != sizeof(sb)) { 221 perror("is_efs read"); 222 exit(1); 223 } 224 225 if (lseek(sd, oldoff, SEEK_SET) == -1) { 226 perror("is_efs lseek 2"); 227 exit(1); 228 } 229 230 BE32TOH(sb.sb_magic); 231 232 return (sb.sb_magic == EFS_SB_MAGIC || sb.sb_magic == EFS_SB_NEWMAGIC); 233} 234 235static struct sgi_boot_block * 236convert_sgi_boot_block(unsigned char *buf) 237{ 238 struct sgi_boot_block *vh; 239 int i; 240 241 vh = (struct sgi_boot_block *)buf; 242 243 BE32TOH(vh->magic); 244 BE16TOH(vh->root); 245 BE16TOH(vh->swap); 246 247 BE16TOH(vh->dp.dp_cyls); 248 BE16TOH(vh->dp.dp_shd0); 249 BE16TOH(vh->dp.dp_trks0); 250 BE16TOH(vh->dp.dp_secs); 251 BE16TOH(vh->dp.dp_secbytes); 252 BE16TOH(vh->dp.dp_interleave); 253 BE32TOH(vh->dp.dp_flags); 254 BE32TOH(vh->dp.dp_datarate); 255 BE32TOH(vh->dp.dp_nretries); 256 BE32TOH(vh->dp.dp_mspw); 257 BE16TOH(vh->dp.dp_xgap1); 258 BE16TOH(vh->dp.dp_xsync); 259 BE16TOH(vh->dp.dp_xrdly); 260 BE16TOH(vh->dp.dp_xgap2); 261 BE16TOH(vh->dp.dp_xrgate); 262 BE16TOH(vh->dp.dp_xwcont); 263 264 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) { 265 BE32TOH(vh->voldir[i].block); 266 BE32TOH(vh->voldir[i].bytes); 267 } 268 269 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) { 270 BE32TOH(vh->partitions[i].blocks); 271 BE32TOH(vh->partitions[i].first); 272 BE32TOH(vh->partitions[i].type); 273 } 274 275 BE32TOH(vh->checksum); 276 277 return (vh); 278} 279 280static void 281usage(void) 282{ 283 fprintf(stderr, "usage: %s [-fqrw] rawdisk\n", 284 getprogname()); 285 exit(1); 286} 287 288 289int 290main(int argc, char **argv) 291{ 292 int sd, ch, changed; 293 char name[MAXPATHLEN]; 294 int force; /* force label update */ 295 int raw; /* update on-disk label as well */ 296 int verbose; /* verbose output */ 297 int write_it; /* update in-core label if changed */ 298 299 force = 0; 300 raw = 0; 301 verbose = 1; 302 write_it = 0; 303 while ((ch = getopt(argc, argv, "fqrw")) != -1) { 304 switch (ch) { 305 case 'f': 306 force = 1; 307 break; 308 case 'q': 309 verbose = 0; 310 break; 311 case 'r': 312 raw = 1; 313 break; 314 case 'w': 315 write_it = 1; 316 break; 317 default: 318 usage(); 319 } 320 } 321 argc -= optind; 322 argv += optind; 323 if (argc != 1) 324 usage(); 325 326 rawpart = getrawpartition(); 327 if (rawpart < 0) 328 err(EXIT_FAILURE, "getrawpartition"); 329 330 if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name, 331 (size_t)MAXPATHLEN, 1)) < 0) { 332 perror(argv[0]); 333 exit(1); 334 } 335 getlabel(sd); 336 changed = getparts(sd, verbose); 337 338 if (verbose) { 339 putchar('\n'); 340 showpartitions(stdout, &label, 0); 341 putchar('\n'); 342 } 343 if (write_it) { 344 if (! changed && ! force) 345 printf("No change; not updating disk label.\n"); 346 else { 347 if (verbose) 348 printf("Updating in-core %sdisk label.\n", 349 raw ? "and on-disk " : ""); 350raw = 0; /* XXX */ 351 setlabel(sd, raw); 352 } 353 } else { 354 printf("Not updating disk label.\n"); 355 } 356 close(sd); 357 return (0); 358} 359