xref: /netbsd-src/sbin/svhlabel/svhlabel.c (revision 392ef410211998ba683aa3458eeb3f575a4cc64d)
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