1*392ef410Sapb /* $NetBSD: svhlabel.c,v 1.7 2013/02/07 10:44:45 apb Exp $ */
26912898dSrumble
36912898dSrumble /*
46912898dSrumble * Copyright (C) 2007 Stephen M. Rumble.
56912898dSrumble * Copyright (C) 1998 Wolfgang Solfrank.
66912898dSrumble * Copyright (C) 1998 TooLs GmbH.
76912898dSrumble * All rights reserved.
86912898dSrumble *
96912898dSrumble * Redistribution and use in source and binary forms, with or without
106912898dSrumble * modification, are permitted provided that the following conditions
116912898dSrumble * are met:
126912898dSrumble * 1. Redistributions of source code must retain the above copyright
136912898dSrumble * notice, this list of conditions and the following disclaimer.
146912898dSrumble * 2. Redistributions in binary form must reproduce the above copyright
156912898dSrumble * notice, this list of conditions and the following disclaimer in the
166912898dSrumble * documentation and/or other materials provided with the distribution.
176912898dSrumble * 3. All advertising materials mentioning features or use of this software
186912898dSrumble * must display the following acknowledgement:
196912898dSrumble * This product includes software developed by TooLs GmbH.
206912898dSrumble * 4. The name of TooLs GmbH may not be used to endorse or promote products
216912898dSrumble * derived from this software without specific prior written permission.
226912898dSrumble *
236912898dSrumble * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
246912898dSrumble * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
256912898dSrumble * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
266912898dSrumble * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
276912898dSrumble * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
286912898dSrumble * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
296912898dSrumble * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
306912898dSrumble * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
316912898dSrumble * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
326912898dSrumble * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
336912898dSrumble */
346912898dSrumble
356912898dSrumble #include <sys/cdefs.h>
366912898dSrumble #ifndef lint
37*392ef410Sapb __RCSID("$NetBSD: svhlabel.c,v 1.7 2013/02/07 10:44:45 apb Exp $");
386912898dSrumble #endif /* not lint */
396912898dSrumble
406912898dSrumble #include <stdio.h>
416912898dSrumble #include <err.h>
426912898dSrumble #include <errno.h>
436912898dSrumble #include <fcntl.h>
446912898dSrumble #include <limits.h>
456912898dSrumble #include <stdlib.h>
466912898dSrumble #include <string.h>
476912898dSrumble #include <unistd.h>
486912898dSrumble #include <util.h>
496912898dSrumble
506912898dSrumble #include <sys/param.h>
516912898dSrumble #define FSTYPENAMES
526912898dSrumble #include <sys/disklabel.h>
536912898dSrumble #include <sys/bootblock.h>
546912898dSrumble #include <sys/ioctl.h>
556912898dSrumble
56e222f533Srumble #include <fs/efs/efs.h>
57dd5b82c6Srumble #include <fs/efs/efs_sb.h>
58dd5b82c6Srumble
596912898dSrumble #include "dkcksum.h"
606912898dSrumble #include "extern.h"
616912898dSrumble
628d4273fcSjoerg __dead static void usage(void);
636912898dSrumble static void getlabel(int);
646912898dSrumble static void setlabel(int, int);
656912898dSrumble static int getparts(int, int);
666912898dSrumble static int is_efs(int, uint32_t);
676912898dSrumble static struct sgi_boot_block *convert_sgi_boot_block(unsigned char *);
686912898dSrumble
696912898dSrumble struct disklabel label;
70*392ef410Sapb static int rawpart;
716912898dSrumble
726912898dSrumble static void
getlabel(int sd)736912898dSrumble getlabel(int sd)
746912898dSrumble {
756912898dSrumble
766912898dSrumble if (ioctl(sd, DIOCGDINFO, &label) < 0) {
776912898dSrumble perror("get label");
786912898dSrumble exit(1);
796912898dSrumble }
806912898dSrumble /*
816912898dSrumble * Some ports seem to not set the number of partitions
826912898dSrumble * correctly, albeit they seem to set the raw partition ok!
836912898dSrumble */
84*392ef410Sapb if (label.d_npartitions <= rawpart)
85*392ef410Sapb label.d_npartitions = rawpart + 1;
866912898dSrumble }
876912898dSrumble
886912898dSrumble static void
setlabel(int sd,int doraw)896912898dSrumble setlabel(int sd, int doraw)
906912898dSrumble {
916912898dSrumble int one = 1;
926912898dSrumble
936912898dSrumble label.d_checksum = 0;
946912898dSrumble label.d_checksum = dkcksum(&label);
956912898dSrumble if (ioctl(sd, doraw ? DIOCWDINFO : DIOCSDINFO, &label) < 0) {
966912898dSrumble perror("set label");
976912898dSrumble exit(1);
986912898dSrumble }
996912898dSrumble if (!doraw)
1006912898dSrumble /* If we haven't written to the disk, don't discard on close */
1016912898dSrumble ioctl(sd, DIOCKLABEL, &one);
1026912898dSrumble
1036912898dSrumble }
1046912898dSrumble
1056912898dSrumble static int
getparts(int sd,int verbose)1066912898dSrumble getparts(int sd, int verbose)
1076912898dSrumble {
1086912898dSrumble unsigned char buf[DEV_BSIZE];
1096912898dSrumble struct sgi_boot_block *vh;
1106912898dSrumble struct partition npe;
1116912898dSrumble int i, j, changed;
1126912898dSrumble
1136912898dSrumble changed = 0;
1146912898dSrumble
1156912898dSrumble if (lseek(sd, 0, SEEK_SET) == -1) {
1166912898dSrumble perror("seek vh");
1176912898dSrumble exit(1);
1186912898dSrumble }
1196912898dSrumble if ((i = read(sd, buf, sizeof(buf))) != DEV_BSIZE) {
1206912898dSrumble perror("read vh");
1216912898dSrumble exit(1);
1226912898dSrumble }
1236912898dSrumble vh = convert_sgi_boot_block(buf);
1246912898dSrumble
1256912898dSrumble if (vh->magic != SGI_BOOT_BLOCK_MAGIC)
1266912898dSrumble return (changed);
1276912898dSrumble
1286912898dSrumble if (label.d_secsize != SGI_BOOT_BLOCK_BLOCKSIZE)
1296912898dSrumble changed++;
1306912898dSrumble label.d_secsize = SGI_BOOT_BLOCK_BLOCKSIZE;
1316912898dSrumble
1326912898dSrumble for (i = j = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
1336912898dSrumble if (vh->partitions[i].blocks == 0)
1346912898dSrumble continue;
1356912898dSrumble
1366912898dSrumble if (j == MAXPARTITIONS)
1376912898dSrumble break;
1386912898dSrumble
1396912898dSrumble switch (vh->partitions[i].type) {
1406912898dSrumble case SGI_PTYPE_EFS:
1416912898dSrumble /*
1426912898dSrumble * For some reason, my IRIX CDs list EFS partitions as SYSV!?
1436912898dSrumble */
1446912898dSrumble case SGI_PTYPE_SYSV:
1456912898dSrumble if (is_efs(sd, vh->partitions[i].first)) {
1466912898dSrumble npe.p_fstype = FS_EFS;
1476912898dSrumble npe.p_size = vh->partitions[i].blocks;
1486912898dSrumble npe.p_offset = vh->partitions[i].first;
1496912898dSrumble npe.p_fsize = 0;
1506912898dSrumble npe.p_frag = 0;
1516912898dSrumble npe.p_cpg = 0;
1526912898dSrumble }
1536912898dSrumble break;
1546912898dSrumble
1556912898dSrumble case SGI_PTYPE_VOLUME:
1563a929213Slukem if (label.d_secperunit != (uint32_t)vh->partitions[i].blocks)
1576912898dSrumble changed++;
1586912898dSrumble label.d_secperunit = vh->partitions[i].blocks;
1596912898dSrumble continue;
1606912898dSrumble
1616912898dSrumble default:
1626912898dSrumble continue;
1636912898dSrumble }
1646912898dSrumble
1656912898dSrumble if (j >= label.d_npartitions)
1666912898dSrumble break;
1676912898dSrumble
168*392ef410Sapb if (j == rawpart) {
1696912898dSrumble if (++j >= label.d_npartitions)
1706912898dSrumble break;
1716912898dSrumble }
1726912898dSrumble
1736912898dSrumble if (memcmp(&label.d_partitions[j], &npe, sizeof(npe)) != 0) {
1746912898dSrumble label.d_partitions[j] = npe;
1756912898dSrumble changed++;
1766912898dSrumble }
1776912898dSrumble
1786912898dSrumble j++;
1796912898dSrumble }
1806912898dSrumble
1816912898dSrumble /* XXX - fudge */
1826912898dSrumble if (label.d_nsectors != 1 || label.d_ntracks != 1 ||
1836912898dSrumble label.d_secpercyl != 1 || label.d_ncylinders != label.d_secperunit)
1846912898dSrumble changed++;
1856912898dSrumble label.d_nsectors = 1;
1866912898dSrumble label.d_ntracks = 1;
1876912898dSrumble label.d_secpercyl = 1;
1886912898dSrumble label.d_ncylinders = label.d_secperunit;
1896912898dSrumble
190*392ef410Sapb i = rawpart;
1916912898dSrumble if (label.d_partitions[i].p_fstype != FS_UNUSED ||
1926912898dSrumble label.d_partitions[i].p_offset != 0 ||
1936912898dSrumble label.d_partitions[i].p_size != label.d_secperunit) {
1946912898dSrumble label.d_partitions[i].p_fstype = FS_UNUSED;
1956912898dSrumble label.d_partitions[i].p_offset = 0;
1966912898dSrumble label.d_partitions[i].p_size = label.d_secperunit;
1976912898dSrumble changed++;
1986912898dSrumble }
1996912898dSrumble
2006912898dSrumble return (changed);
2016912898dSrumble }
2026912898dSrumble
2036912898dSrumble static int
is_efs(int sd,uint32_t blkoff)2046912898dSrumble is_efs(int sd, uint32_t blkoff)
2056912898dSrumble {
206e222f533Srumble struct efs_sb sb;
2076912898dSrumble off_t oldoff;
2086912898dSrumble
2096912898dSrumble if ((oldoff = lseek(sd, 0, SEEK_CUR)) == -1) {
2106912898dSrumble perror("is_efs lseek 0");
2116912898dSrumble exit(1);
2126912898dSrumble }
2136912898dSrumble
214e222f533Srumble blkoff *= SGI_BOOT_BLOCK_BLOCKSIZE;
215e222f533Srumble if (lseek(sd, blkoff + (EFS_BB_SB * EFS_BB_SIZE), SEEK_SET) == -1) {
2166912898dSrumble perror("is_efs lseek 1");
2176912898dSrumble exit(1);
2186912898dSrumble }
2196912898dSrumble
220e222f533Srumble if (read(sd, &sb, sizeof(sb)) != sizeof(sb)) {
2216912898dSrumble perror("is_efs read");
2226912898dSrumble exit(1);
2236912898dSrumble }
2246912898dSrumble
2256912898dSrumble if (lseek(sd, oldoff, SEEK_SET) == -1) {
2266912898dSrumble perror("is_efs lseek 2");
2276912898dSrumble exit(1);
2286912898dSrumble }
2296912898dSrumble
230e222f533Srumble BE32TOH(sb.sb_magic);
2316912898dSrumble
232e222f533Srumble return (sb.sb_magic == EFS_SB_MAGIC || sb.sb_magic == EFS_SB_NEWMAGIC);
2336912898dSrumble }
2346912898dSrumble
2356912898dSrumble static struct sgi_boot_block *
convert_sgi_boot_block(unsigned char * buf)2366912898dSrumble convert_sgi_boot_block(unsigned char *buf)
2376912898dSrumble {
2386912898dSrumble struct sgi_boot_block *vh;
2396912898dSrumble int i;
2406912898dSrumble
2416912898dSrumble vh = (struct sgi_boot_block *)buf;
2426912898dSrumble
2436912898dSrumble BE32TOH(vh->magic);
2446912898dSrumble BE16TOH(vh->root);
2456912898dSrumble BE16TOH(vh->swap);
2466912898dSrumble
2476912898dSrumble BE16TOH(vh->dp.dp_cyls);
2486912898dSrumble BE16TOH(vh->dp.dp_shd0);
2496912898dSrumble BE16TOH(vh->dp.dp_trks0);
2506912898dSrumble BE16TOH(vh->dp.dp_secs);
2516912898dSrumble BE16TOH(vh->dp.dp_secbytes);
2526912898dSrumble BE16TOH(vh->dp.dp_interleave);
2536912898dSrumble BE32TOH(vh->dp.dp_flags);
2546912898dSrumble BE32TOH(vh->dp.dp_datarate);
2556912898dSrumble BE32TOH(vh->dp.dp_nretries);
2566912898dSrumble BE32TOH(vh->dp.dp_mspw);
2576912898dSrumble BE16TOH(vh->dp.dp_xgap1);
2586912898dSrumble BE16TOH(vh->dp.dp_xsync);
2596912898dSrumble BE16TOH(vh->dp.dp_xrdly);
2606912898dSrumble BE16TOH(vh->dp.dp_xgap2);
2616912898dSrumble BE16TOH(vh->dp.dp_xrgate);
2626912898dSrumble BE16TOH(vh->dp.dp_xwcont);
2636912898dSrumble
2646912898dSrumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
2656912898dSrumble BE32TOH(vh->voldir[i].block);
2666912898dSrumble BE32TOH(vh->voldir[i].bytes);
2676912898dSrumble }
2686912898dSrumble
2696912898dSrumble for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; i++) {
2706912898dSrumble BE32TOH(vh->partitions[i].blocks);
2716912898dSrumble BE32TOH(vh->partitions[i].first);
2726912898dSrumble BE32TOH(vh->partitions[i].type);
2736912898dSrumble }
2746912898dSrumble
2756912898dSrumble BE32TOH(vh->checksum);
2766912898dSrumble
2776912898dSrumble return (vh);
2786912898dSrumble }
2796912898dSrumble
2806912898dSrumble static void
usage(void)2816912898dSrumble usage(void)
2826912898dSrumble {
2836912898dSrumble fprintf(stderr, "usage: %s [-fqrw] rawdisk\n",
2846912898dSrumble getprogname());
2856912898dSrumble exit(1);
2866912898dSrumble }
2876912898dSrumble
2886912898dSrumble
2896912898dSrumble int
main(int argc,char ** argv)2906912898dSrumble main(int argc, char **argv)
2916912898dSrumble {
2926912898dSrumble int sd, ch, changed;
2936912898dSrumble char name[MAXPATHLEN];
2946912898dSrumble int force; /* force label update */
2956912898dSrumble int raw; /* update on-disk label as well */
2966912898dSrumble int verbose; /* verbose output */
2976912898dSrumble int write_it; /* update in-core label if changed */
2986912898dSrumble
2996912898dSrumble force = 0;
3006912898dSrumble raw = 0;
3016912898dSrumble verbose = 1;
3026912898dSrumble write_it = 0;
3036912898dSrumble while ((ch = getopt(argc, argv, "fqrw")) != -1) {
3046912898dSrumble switch (ch) {
3056912898dSrumble case 'f':
3066912898dSrumble force = 1;
3076912898dSrumble break;
3086912898dSrumble case 'q':
3096912898dSrumble verbose = 0;
3106912898dSrumble break;
3116912898dSrumble case 'r':
3126912898dSrumble raw = 1;
3136912898dSrumble break;
3146912898dSrumble case 'w':
3156912898dSrumble write_it = 1;
3166912898dSrumble break;
3176912898dSrumble default:
3186912898dSrumble usage();
3196912898dSrumble }
3206912898dSrumble }
3216912898dSrumble argc -= optind;
3226912898dSrumble argv += optind;
3236912898dSrumble if (argc != 1)
3246912898dSrumble usage();
3256912898dSrumble
326*392ef410Sapb rawpart = getrawpartition();
327*392ef410Sapb if (rawpart < 0)
328*392ef410Sapb err(EXIT_FAILURE, "getrawpartition");
329*392ef410Sapb
3306912898dSrumble if ((sd = opendisk(argv[0], write_it ? O_RDWR : O_RDONLY, name,
3316912898dSrumble (size_t)MAXPATHLEN, 1)) < 0) {
3326912898dSrumble perror(argv[0]);
3336912898dSrumble exit(1);
3346912898dSrumble }
3356912898dSrumble getlabel(sd);
3366912898dSrumble changed = getparts(sd, verbose);
3376912898dSrumble
3386912898dSrumble if (verbose) {
3396912898dSrumble putchar('\n');
3406912898dSrumble showpartitions(stdout, &label, 0);
3416912898dSrumble putchar('\n');
3426912898dSrumble }
3436912898dSrumble if (write_it) {
3446912898dSrumble if (! changed && ! force)
3456912898dSrumble printf("No change; not updating disk label.\n");
3466912898dSrumble else {
3476912898dSrumble if (verbose)
3486912898dSrumble printf("Updating in-core %sdisk label.\n",
3496912898dSrumble raw ? "and on-disk " : "");
3506912898dSrumble raw = 0; /* XXX */
3516912898dSrumble setlabel(sd, raw);
3526912898dSrumble }
3536912898dSrumble } else {
3546912898dSrumble printf("Not updating disk label.\n");
3556912898dSrumble }
3566912898dSrumble close(sd);
3576912898dSrumble return (0);
3586912898dSrumble }
359