Home | History | Annotate | Line # | Download | only in sgivol
sgivol.c revision 1.20
      1  1.20  christos /*	$NetBSD: sgivol.c,v 1.20 2014/03/26 16:16:06 christos Exp $	*/
      2   1.1     soren 
      3   1.1     soren /*-
      4   1.1     soren  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5   1.1     soren  * All rights reserved.
      6   1.1     soren  *
      7   1.1     soren  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1     soren  * by Michael Hitch and Hubert Feyrer.
      9   1.1     soren  *
     10   1.1     soren  * Redistribution and use in source and binary forms, with or without
     11   1.1     soren  * modification, are permitted provided that the following conditions
     12   1.1     soren  * are met:
     13   1.1     soren  * 1. Redistributions of source code must retain the above copyright
     14   1.1     soren  *    notice, this list of conditions and the following disclaimer.
     15   1.1     soren  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1     soren  *    notice, this list of conditions and the following disclaimer in the
     17   1.1     soren  *    documentation and/or other materials provided with the distribution.
     18   1.1     soren  *
     19   1.1     soren  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1     soren  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1     soren  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1     soren  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1     soren  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1     soren  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1     soren  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1     soren  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1     soren  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1     soren  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1     soren  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1     soren  */
     31   1.1     soren 
     32   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
     33   1.9       jmc #include "nbtool_config.h"
     34   1.9       jmc #endif
     35   1.9       jmc 
     36   1.2   thorpej #include <sys/types.h>
     37   1.2   thorpej #include <sys/ioctl.h>
     38   1.8    sekiya #include <sys/stat.h>
     39   1.9       jmc 
     40   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
     41   1.9       jmc #include "../../../../../sys/sys/bootblock.h"
     42   1.9       jmc /* Ficticious geometry for cross tool usage against a file image */
     43   1.9       jmc #define SGIVOL_NBTOOL_NSECS	32
     44   1.9       jmc #define SGIVOL_NBTOOL_NTRACKS	64
     45   1.9       jmc #else
     46   1.2   thorpej #include <sys/disklabel.h>
     47   1.9       jmc #endif
     48   1.2   thorpej 
     49   1.5     rafal #include <errno.h>
     50   1.1     soren #include <stdio.h>
     51   1.2   thorpej #include <stdlib.h>
     52   1.1     soren #include <unistd.h>
     53   1.1     soren #include <string.h>
     54   1.1     soren #include <fcntl.h>
     55   1.1     soren #include <util.h>
     56  1.12   thorpej #ifndef HAVE_NBTOOL_CONFIG_H
     57   1.7    sekiya #include <sys/endian.h>
     58  1.12   thorpej #endif
     59   1.1     soren 
     60   1.1     soren int	fd;
     61   1.1     soren int	opt_i;			/* Initialize volume header */
     62   1.1     soren int	opt_r;			/* Read a file from volume header */
     63   1.1     soren int	opt_w;			/* Write a file to volume header */
     64   1.1     soren int	opt_d;			/* Delete a file from volume header */
     65  1.17    rumble int	opt_m;			/* Move (rename) a file in the volume header */
     66   1.1     soren int	opt_p;			/* Modify a partition */
     67   1.5     rafal int	opt_q;			/* quiet mode */
     68   1.5     rafal int	opt_f;			/* Don't ask, just do what you're told */
     69   1.1     soren int	partno, partfirst, partblocks, parttype;
     70   1.9       jmc struct sgi_boot_block *volhdr;
     71   1.2   thorpej int32_t	checksum;
     72   1.9       jmc u_int32_t	volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
     73   1.2   thorpej 
     74   1.2   thorpej const char *vfilename = "";
     75   1.2   thorpej const char *ufilename = "";
     76   1.1     soren 
     77   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
     78   1.9       jmc struct stat st;
     79   1.9       jmc #else
     80   1.1     soren struct disklabel lbl;
     81   1.9       jmc #endif
     82   1.1     soren 
     83   1.1     soren unsigned char buf[512];
     84   1.1     soren 
     85   1.2   thorpej const char *sgi_types[] = {
     86   1.1     soren 	"Volume Header",
     87   1.1     soren 	"Repl Trks",
     88   1.1     soren 	"Repl Secs",
     89   1.1     soren 	"Raw",
     90   1.1     soren 	"BSD4.2",
     91   1.1     soren 	"SysV",
     92   1.1     soren 	"Volume",
     93   1.1     soren 	"EFS",
     94   1.1     soren 	"LVol",
     95   1.1     soren 	"RLVol",
     96   1.1     soren 	"XFS",
     97   1.1     soren 	"XSFLog",
     98   1.1     soren 	"XLV",
     99   1.1     soren 	"XVM"
    100   1.1     soren };
    101   1.1     soren 
    102   1.2   thorpej int	main(int, char *[]);
    103   1.2   thorpej 
    104   1.2   thorpej void	display_vol(void);
    105   1.2   thorpej void	init_volhdr(void);
    106   1.2   thorpej void	read_file(void);
    107   1.2   thorpej void	write_file(void);
    108   1.2   thorpej void	delete_file(void);
    109  1.17    rumble void	move_file(void);
    110   1.2   thorpej void	modify_partition(void);
    111   1.2   thorpej void	write_volhdr(void);
    112   1.2   thorpej int	allocate_space(int);
    113   1.2   thorpej void	checksum_vol(void);
    114  1.18    rumble int	names_match(int, const char *);
    115   1.2   thorpej void	usage(void);
    116   1.2   thorpej 
    117   1.2   thorpej int
    118   1.2   thorpej main(int argc, char *argv[])
    119   1.1     soren {
    120  1.17    rumble #define RESET_OPTS()	opt_i = opt_m = opt_r = opt_w = opt_d = opt_p = 0
    121  1.17    rumble 
    122   1.5     rafal 	int ch;
    123  1.17    rumble 	while ((ch = getopt(argc, argv, "qfih:rwdmp?")) != -1) {
    124   1.5     rafal 		switch (ch) {
    125  1.17    rumble 		/* -i, -r, -w, -d, -m and -p override each other */
    126   1.5     rafal 		/* -q implies -f */
    127   1.5     rafal 		case 'q':
    128   1.5     rafal 			++opt_q;
    129   1.5     rafal 			++opt_f;
    130   1.5     rafal 			break;
    131   1.5     rafal 		case 'f':
    132   1.5     rafal 			++opt_f;
    133   1.5     rafal 			break;
    134   1.1     soren 		case 'i':
    135  1.17    rumble 			RESET_OPTS();
    136   1.1     soren 			++opt_i;
    137   1.1     soren 			break;
    138   1.7    sekiya 		case 'h':
    139   1.7    sekiya 			volhdr_size = atoi(optarg);
    140   1.7    sekiya 			break;
    141   1.1     soren 		case 'r':
    142  1.17    rumble 			RESET_OPTS();
    143   1.5     rafal 			++opt_r;
    144   1.5     rafal 			break;
    145   1.1     soren 		case 'w':
    146  1.17    rumble 			RESET_OPTS();
    147   1.5     rafal 			++opt_w;
    148   1.1     soren 			break;
    149   1.1     soren 		case 'd':
    150  1.17    rumble 			RESET_OPTS();
    151   1.1     soren 			++opt_d;
    152  1.17    rumble 			break;
    153  1.17    rumble 		case 'm':
    154  1.17    rumble 			RESET_OPTS();
    155  1.17    rumble 			++opt_m;
    156   1.5     rafal 			break;
    157   1.1     soren 		case 'p':
    158  1.17    rumble 			RESET_OPTS();
    159   1.1     soren 			++opt_p;
    160   1.5     rafal 			partno = atoi(argv[0]);
    161   1.5     rafal 			partfirst = atoi(argv[1]);
    162   1.5     rafal 			partblocks = atoi(argv[2]);
    163   1.5     rafal 			parttype = atoi(argv[3]);
    164   1.1     soren 			break;
    165   1.5     rafal 		case '?':
    166   1.1     soren 		default:
    167   1.1     soren 			usage();
    168   1.1     soren 		}
    169   1.1     soren 	}
    170   1.5     rafal 	argc -= optind;
    171   1.5     rafal 	argv += optind;
    172   1.5     rafal 
    173  1.17    rumble 	if (opt_m || opt_r || opt_w) {
    174   1.5     rafal 		if (argc != 3)
    175   1.5     rafal 			usage();
    176   1.5     rafal 		vfilename = argv[0];
    177   1.5     rafal 		ufilename = argv[1];
    178   1.5     rafal 		argc -= 2;
    179   1.5     rafal 		argv += 2;
    180   1.5     rafal 	}
    181   1.5     rafal 	if (opt_d) {
    182   1.5     rafal 		if (argc != 2)
    183   1.5     rafal 			usage();
    184   1.5     rafal 		vfilename = argv[0];
    185   1.5     rafal 		argc--;
    186   1.5     rafal 		argv++;
    187   1.5     rafal 	}
    188   1.1     soren 
    189   1.5     rafal 	if (opt_p) {
    190   1.5     rafal 		if (argc != 5)
    191   1.5     rafal 			usage();
    192   1.5     rafal 		partno = atoi(argv[0]);
    193   1.5     rafal 		partfirst = atoi(argv[1]);
    194   1.5     rafal 		partblocks = atoi(argv[2]);
    195   1.5     rafal 		parttype = atoi(argv[3]);
    196   1.5     rafal 		argc -= 4;
    197   1.5     rafal 		argv += 4;
    198   1.5     rafal 	}
    199   1.5     rafal 	if (argc != 1)
    200   1.1     soren 		usage();
    201   1.5     rafal 
    202  1.17    rumble 	fd = open(argv[0],
    203  1.17    rumble 	    (opt_i | opt_m | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
    204   1.1     soren 	if (fd < 0) {
    205   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    206   1.9       jmc 		perror("File open");
    207   1.9       jmc 		exit(1);
    208   1.9       jmc #else
    209  1.20  christos 		snprintf(buf, sizeof(buf), "/dev/r%s%c", argv[0],
    210  1.20  christos 		    'a' + getrawpartition());
    211  1.13       mrg 		fd = open((char *)buf, (opt_i | opt_w | opt_d | opt_p)
    212   1.5     rafal 				? O_RDWR : O_RDONLY);
    213   1.1     soren 		if (fd < 0) {
    214   1.5     rafal 			printf("Error opening device %s: %s\n",
    215   1.5     rafal 				argv[0], strerror(errno));
    216   1.1     soren 			exit(1);
    217   1.1     soren 		}
    218   1.9       jmc #endif
    219   1.1     soren 	}
    220   1.2   thorpej 	if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    221   1.1     soren 		perror("read volhdr");
    222   1.1     soren 		exit(1);
    223   1.1     soren 	}
    224   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    225   1.9       jmc 	if (fstat(fd, &st) < 0) {
    226   1.9       jmc 		perror("stat error");
    227   1.9       jmc 		exit(1);
    228   1.9       jmc 	}
    229   1.9       jmc 	if (!S_ISREG(st.st_mode)) {
    230   1.9       jmc 		printf("Must be regular file\n");
    231   1.9       jmc 		exit(1);
    232   1.9       jmc 	}
    233   1.9       jmc 	if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
    234   1.9       jmc 		printf("Size must be multiple of %d\n",
    235   1.9       jmc 		    SGI_BOOT_BLOCK_BLOCKSIZE);
    236   1.9       jmc 		exit(1);
    237   1.9       jmc 	}
    238   1.9       jmc 	if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
    239   1.9       jmc 		printf("Minimum size of %d required\n",
    240   1.9       jmc 		    SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
    241   1.9       jmc 		exit(1);
    242   1.9       jmc 	}
    243   1.9       jmc #else
    244  1.10    sekiya 	if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
    245   1.1     soren 		perror("DIOCGDINFO");
    246   1.1     soren 		exit(1);
    247   1.1     soren 	}
    248   1.9       jmc #endif
    249   1.9       jmc 	volhdr = (struct sgi_boot_block *) buf;
    250   1.1     soren 	if (opt_i) {
    251   1.1     soren 		init_volhdr();
    252   1.1     soren 		exit(0);
    253   1.1     soren 	}
    254   1.9       jmc 	if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
    255   1.5     rafal 		printf("No Volume Header found, magic=%x.  Use -i first.\n",
    256   1.7    sekiya 		       be32toh(volhdr->magic));
    257   1.1     soren 		exit(1);
    258   1.1     soren 	}
    259   1.1     soren 	if (opt_r) {
    260   1.1     soren 		read_file();
    261   1.1     soren 		exit(0);
    262   1.1     soren 	}
    263   1.1     soren 	if (opt_w) {
    264   1.1     soren 		write_file();
    265   1.1     soren 		exit(0);
    266   1.1     soren 	}
    267   1.1     soren 	if (opt_d) {
    268   1.1     soren 		delete_file();
    269   1.1     soren 		exit(0);
    270   1.1     soren 	}
    271  1.17    rumble 	if (opt_m) {
    272  1.17    rumble 		move_file();
    273  1.17    rumble 		exit(0);
    274  1.17    rumble 	}
    275   1.1     soren 	if (opt_p) {
    276   1.1     soren 		modify_partition();
    277   1.1     soren 		exit(0);
    278   1.1     soren 	}
    279   1.5     rafal 
    280   1.5     rafal 	if (!opt_q)
    281   1.5     rafal 		display_vol();
    282   1.1     soren 
    283   1.1     soren 	return 0;
    284   1.1     soren }
    285   1.1     soren 
    286  1.18    rumble /*
    287  1.18    rumble  * Compare the name in `slot' of voldir to `b'. Be careful, as the
    288  1.18    rumble  * name in voldir need not be nul-terminated and `b' may be longer
    289  1.18    rumble  * than the maximum (in which case it will never match).
    290  1.18    rumble  *
    291  1.18    rumble  * Returns non-0 if names are equal.
    292  1.18    rumble  */
    293  1.18    rumble int
    294  1.18    rumble names_match(int slot, const char *b)
    295  1.18    rumble {
    296  1.18    rumble 	int cmp;
    297  1.18    rumble 
    298  1.18    rumble 	if (slot < 0 || slot >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
    299  1.18    rumble 		printf("Internal error: bad slot in %s()\n", __func__);
    300  1.18    rumble 		exit(1);
    301  1.18    rumble 	}
    302  1.18    rumble 
    303  1.18    rumble 	cmp = strncmp(volhdr->voldir[slot].name, b,
    304  1.18    rumble 	    sizeof(volhdr->voldir[slot].name));
    305  1.18    rumble 
    306  1.18    rumble 	return (cmp == 0 && strlen(b) <= sizeof(volhdr->voldir[slot].name));
    307  1.18    rumble }
    308  1.18    rumble 
    309   1.2   thorpej void
    310   1.2   thorpej display_vol(void)
    311   1.1     soren {
    312   1.2   thorpej 	int32_t *l;
    313   1.2   thorpej 	int i;
    314   1.2   thorpej 
    315   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    316   1.9       jmc 	printf("disklabel shows %d sectors\n",
    317   1.9       jmc 	    st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
    318   1.9       jmc #else
    319   1.1     soren 	printf("disklabel shows %d sectors\n", lbl.d_secperunit);
    320   1.9       jmc #endif
    321   1.2   thorpej 	l = (int32_t *)buf;
    322   1.1     soren 	checksum = 0;
    323   1.2   thorpej 	for (i = 0; i < 512 / 4; ++i)
    324   1.7    sekiya 		checksum += be32toh(l[i]);
    325   1.1     soren 	printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
    326   1.7    sekiya 	printf("root part: %d\n", be16toh(volhdr->root));
    327   1.7    sekiya 	printf("swap part: %d\n", be16toh(volhdr->swap));
    328   1.2   thorpej 	printf("bootfile: %s\n", volhdr->bootfile);
    329   1.1     soren 	/* volhdr->devparams[0..47] */
    330   1.1     soren 	printf("\nVolume header files:\n");
    331  1.17    rumble 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i)
    332   1.2   thorpej 		if (volhdr->voldir[i].name[0])
    333   1.9       jmc 			printf("%-8s offset %4d blocks, length %8d bytes "
    334   1.9       jmc 			    "(%d blocks)\n",
    335   1.9       jmc 			    volhdr->voldir[i].name,
    336   1.9       jmc                             be32toh(volhdr->voldir[i].block),
    337   1.9       jmc 			    be32toh(volhdr->voldir[i].bytes),
    338   1.9       jmc                             (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
    339   1.1     soren 	printf("\nSGI partitions:\n");
    340   1.9       jmc 	for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
    341   1.7    sekiya 		if (be32toh(volhdr->partitions[i].blocks)) {
    342   1.2   thorpej 			printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
    343   1.7    sekiya 			  i, i + 'a', be32toh(volhdr->partitions[i].blocks),
    344   1.7    sekiya 			       be32toh(volhdr->partitions[i].first),
    345   1.7    sekiya 			       be32toh(volhdr->partitions[i].type),
    346   1.7    sekiya 			  be32toh(volhdr->partitions[i].type) > 13 ? "???" :
    347   1.7    sekiya 			    sgi_types[be32toh(volhdr->partitions[i].type)]);
    348   1.2   thorpej 		}
    349   1.2   thorpej 	}
    350   1.1     soren }
    351   1.1     soren 
    352   1.2   thorpej void
    353   1.2   thorpej init_volhdr(void)
    354   1.1     soren {
    355   1.1     soren 	memset(buf, 0, sizeof(buf));
    356   1.9       jmc 	volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
    357   1.7    sekiya 	volhdr->root = htobe16(0);
    358   1.7    sekiya 	volhdr->swap = htobe16(1);
    359   1.2   thorpej 	strcpy(volhdr->bootfile, "/netbsd");
    360   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    361   1.9       jmc 	volhdr->dp.dp_skew = 0;
    362   1.9       jmc #else
    363   1.4    simonb 	volhdr->dp.dp_skew = lbl.d_trackskew;
    364   1.9       jmc #endif
    365   1.4    simonb 	volhdr->dp.dp_gap1 = 1; /* XXX */
    366   1.4    simonb 	volhdr->dp.dp_gap2 = 1; /* XXX */
    367   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    368   1.9       jmc 	volhdr->dp.dp_cyls =
    369   1.9       jmc 	    htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
    370   1.9       jmc #else
    371   1.7    sekiya 	volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
    372   1.9       jmc #endif
    373   1.4    simonb 	volhdr->dp.dp_shd0 = 0;
    374   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    375   1.9       jmc 	volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
    376   1.9       jmc 	volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
    377   1.9       jmc 	volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
    378   1.9       jmc 	volhdr->dp.dp_interleave = htobe16(1);
    379   1.9       jmc #else
    380   1.7    sekiya 	volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
    381   1.7    sekiya 	volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
    382   1.7    sekiya 	volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
    383   1.7    sekiya 	volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
    384   1.9       jmc #endif
    385   1.7    sekiya 	volhdr->dp.dp_nretries = htobe32(22);
    386   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    387   1.9       jmc 	volhdr->partitions[10].blocks =
    388   1.9       jmc 	    htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
    389   1.9       jmc #else
    390   1.7    sekiya 	volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
    391   1.9       jmc #endif
    392   1.1     soren 	volhdr->partitions[10].first = 0;
    393   1.7    sekiya 	volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
    394   1.7    sekiya 	volhdr->partitions[8].blocks = htobe32(volhdr_size);
    395   1.1     soren 	volhdr->partitions[8].first = 0;
    396   1.7    sekiya 	volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
    397   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    398   1.9       jmc 	volhdr->partitions[0].blocks =
    399   1.9       jmc 	    htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
    400   1.9       jmc #else
    401   1.7    sekiya 	volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
    402   1.9       jmc #endif
    403   1.7    sekiya 	volhdr->partitions[0].first = htobe32(volhdr_size);
    404   1.7    sekiya 	volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
    405   1.1     soren 	write_volhdr();
    406   1.1     soren }
    407   1.1     soren 
    408   1.2   thorpej void
    409   1.2   thorpej read_file(void)
    410   1.1     soren {
    411   1.1     soren 	FILE *fp;
    412   1.2   thorpej 	int i;
    413   1.1     soren 
    414   1.5     rafal 	if (!opt_q)
    415   1.5     rafal 		printf("Reading file %s\n", vfilename);
    416  1.17    rumble 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
    417   1.3   thorpej 		if (strncmp(vfilename, volhdr->voldir[i].name,
    418   1.7    sekiya 			    strlen(volhdr->voldir[i].name)) == 0)
    419   1.1     soren 			break;
    420   1.1     soren 	}
    421  1.17    rumble 	if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
    422  1.17    rumble 		printf("File '%s' not found\n", vfilename);
    423   1.1     soren 		exit(1);
    424   1.1     soren 	}
    425   1.1     soren 	/* XXX assumes volume header starts at 0? */
    426   1.7    sekiya 	lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
    427   1.1     soren 	fp = fopen(ufilename, "w");
    428   1.1     soren 	if (fp == NULL) {
    429   1.1     soren 		perror("open write");
    430   1.1     soren 		exit(1);
    431   1.1     soren 	}
    432   1.7    sekiya 	i = be32toh(volhdr->voldir[i].bytes);
    433   1.2   thorpej 	while (i > 0) {
    434   1.1     soren 		if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    435   1.1     soren 			perror("read file");
    436   1.1     soren 			exit(1);
    437   1.1     soren 		}
    438   1.2   thorpej 		fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
    439   1.2   thorpej 		i -= i > sizeof(buf) ? sizeof(buf) : i;
    440   1.1     soren 	}
    441   1.1     soren 	fclose(fp);
    442   1.1     soren }
    443   1.1     soren 
    444   1.2   thorpej void
    445   1.2   thorpej write_file(void)
    446   1.1     soren {
    447   1.1     soren 	FILE *fp;
    448   1.2   thorpej 	int slot;
    449   1.2   thorpej 	size_t namelen;
    450   1.2   thorpej 	int block, i;
    451   1.1     soren 	struct stat st;
    452   1.1     soren 	char fbuf[512];
    453   1.1     soren 
    454   1.5     rafal 	if (!opt_q)
    455   1.5     rafal 		printf("Writing file %s\n", ufilename);
    456   1.1     soren 	if (stat(ufilename, &st) < 0) {
    457   1.1     soren 		perror("stat");
    458   1.1     soren 		exit(1);
    459   1.1     soren 	}
    460   1.5     rafal 	if (!opt_q)
    461   1.5     rafal 		printf("File %s has %lld bytes\n", ufilename, st.st_size);
    462   1.2   thorpej 	slot = -1;
    463  1.17    rumble 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
    464   1.2   thorpej 		if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
    465   1.2   thorpej 			slot = i;
    466  1.18    rumble 		if (names_match(i, vfilename)) {
    467   1.2   thorpej 			slot = i;
    468   1.1     soren 			break;
    469   1.1     soren 		}
    470   1.1     soren 	}
    471   1.2   thorpej 	if (slot == -1) {
    472   1.2   thorpej 		printf("No directory space for file %s\n", vfilename);
    473   1.1     soren 		exit(1);
    474   1.1     soren 	}
    475   1.1     soren 	/* -w can overwrite, -a won't overwrite */
    476   1.7    sekiya 	if (be32toh(volhdr->voldir[slot].block) > 0) {
    477   1.5     rafal 		if (!opt_q)
    478   1.5     rafal 			printf("File %s exists, removing old file\n",
    479   1.5     rafal 				vfilename);
    480   1.2   thorpej 		volhdr->voldir[slot].name[0] = 0;
    481   1.2   thorpej 		volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
    482   1.1     soren 	}
    483   1.1     soren 	if (st.st_size == 0) {
    484   1.5     rafal 		printf("bad file size\n");
    485   1.1     soren 		exit(1);
    486   1.1     soren 	}
    487   1.1     soren 	/* XXX assumes volume header starts at 0? */
    488   1.1     soren 	block = allocate_space((int)st.st_size);
    489   1.1     soren 	if (block < 0) {
    490   1.1     soren 		printf("No space for file\n");
    491   1.1     soren 		exit(1);
    492   1.1     soren 	}
    493   1.1     soren 
    494   1.2   thorpej 	/*
    495   1.2   thorpej 	 * Make sure the name in the volume header is max. 8 chars,
    496   1.2   thorpej 	 * NOT including NUL.
    497   1.2   thorpej 	 */
    498   1.2   thorpej 	namelen = strlen(vfilename);
    499   1.2   thorpej 	if (namelen > sizeof(volhdr->voldir[slot].name)) {
    500   1.1     soren 		printf("Warning: '%s' is too long for volume header, ",
    501   1.1     soren 		       vfilename);
    502   1.2   thorpej 		namelen = sizeof(volhdr->voldir[slot].name);
    503  1.17    rumble 		printf("truncating to '%.8s'\n", vfilename);
    504   1.1     soren 	}
    505   1.4    simonb 
    506   1.2   thorpej 	/* Populate it w/ NULs */
    507   1.2   thorpej 	memset(volhdr->voldir[slot].name, 0,
    508   1.2   thorpej 	    sizeof(volhdr->voldir[slot].name));
    509   1.2   thorpej 	/* Then copy the name */
    510   1.2   thorpej 	memcpy(volhdr->voldir[slot].name, vfilename, namelen);
    511   1.2   thorpej 
    512   1.7    sekiya 	volhdr->voldir[slot].block = htobe32(block);
    513   1.7    sekiya 	volhdr->voldir[slot].bytes = htobe32(st.st_size);
    514   1.1     soren 
    515   1.1     soren 	write_volhdr();
    516   1.1     soren 
    517   1.1     soren 	/* write the file itself */
    518   1.2   thorpej 	i = lseek(fd, block * 512, SEEK_SET);
    519   1.2   thorpej 	if (i < 0) {
    520   1.1     soren 		perror("lseek write");
    521   1.1     soren 		exit(1);
    522   1.1     soren 	}
    523   1.2   thorpej 	i = st.st_size;
    524   1.1     soren 	fp = fopen(ufilename, "r");
    525   1.2   thorpej 	while (i > 0) {
    526   1.2   thorpej 		fread(fbuf, 1, i > 512 ? 512 : i, fp);
    527   1.1     soren 		if (write(fd, fbuf, 512) != 512) {
    528   1.1     soren 			perror("write file");
    529   1.1     soren 			exit(1);
    530   1.1     soren 		}
    531   1.2   thorpej 		i -= i > 512 ? 512 : i;
    532   1.1     soren 	}
    533  1.19  christos 	fclose(fp);
    534   1.1     soren }
    535   1.1     soren 
    536   1.2   thorpej void
    537   1.2   thorpej delete_file(void)
    538   1.1     soren {
    539   1.2   thorpej 	int i;
    540   1.2   thorpej 
    541  1.17    rumble 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
    542  1.18    rumble 		if (names_match(i, vfilename)) {
    543   1.1     soren 			break;
    544   1.1     soren 		}
    545   1.1     soren 	}
    546  1.17    rumble 	if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
    547  1.17    rumble 		printf("File '%s' not found\n", vfilename);
    548   1.1     soren 		exit(1);
    549   1.1     soren 	}
    550   1.5     rafal 
    551   1.5     rafal 	/* XXX: we don't compact the file space, so get fragmentation */
    552   1.2   thorpej 	volhdr->voldir[i].name[0] = '\0';
    553   1.2   thorpej 	volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
    554   1.1     soren 	write_volhdr();
    555   1.1     soren }
    556   1.1     soren 
    557   1.2   thorpej void
    558  1.17    rumble move_file(void)
    559  1.17    rumble {
    560  1.17    rumble 	char dstfile[sizeof(volhdr->voldir[0].name) + 1];
    561  1.17    rumble 	size_t namelen;
    562  1.17    rumble 	int i, slot = -1;
    563  1.17    rumble 
    564  1.17    rumble 	/*
    565  1.17    rumble 	 * Make sure the name in the volume header is max. 8 chars,
    566  1.17    rumble 	 * NOT including NUL.
    567  1.17    rumble 	 */
    568  1.17    rumble 	namelen = strlen(ufilename);
    569  1.17    rumble 	if (namelen > sizeof(volhdr->voldir[0].name)) {
    570  1.17    rumble 		printf("Warning: '%s' is too long for volume header, ",
    571  1.17    rumble 		       ufilename);
    572  1.17    rumble 		namelen = sizeof(volhdr->voldir[0].name);
    573  1.17    rumble 		printf("truncating to '%.8s'\n", ufilename);
    574  1.17    rumble 	}
    575  1.17    rumble 	memset(dstfile, 0, sizeof(dstfile));
    576  1.17    rumble 	memcpy(dstfile, ufilename, namelen);
    577  1.17    rumble 
    578  1.17    rumble 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
    579  1.18    rumble 		if (names_match(i, vfilename)) {
    580  1.17    rumble 			if (slot != -1) {
    581  1.17    rumble 				printf("Error: Cannot move '%s' to '%s' - "
    582  1.17    rumble 				    "duplicate source files exist!\n",
    583  1.17    rumble 				    vfilename, dstfile);
    584  1.17    rumble 				exit(1);
    585  1.17    rumble 			}
    586  1.17    rumble 			slot = i;
    587  1.17    rumble 		}
    588  1.18    rumble 		if (names_match(i, dstfile)) {
    589  1.17    rumble 			printf("Error: Cannot move '%s' to '%s' - "
    590  1.17    rumble 			    "destination file already exists!\n",
    591  1.17    rumble 			    vfilename, dstfile);
    592  1.17    rumble 			exit(1);
    593  1.17    rumble 		}
    594  1.17    rumble 	}
    595  1.17    rumble 	if (slot == -1) {
    596  1.17    rumble 		printf("File '%s' not found\n", vfilename);
    597  1.17    rumble 		exit(1);
    598  1.17    rumble 	}
    599  1.17    rumble 
    600  1.17    rumble 	/* `dstfile' is already padded with NULs */
    601  1.17    rumble 	memcpy(volhdr->voldir[slot].name, dstfile,
    602  1.17    rumble 	    sizeof(volhdr->voldir[slot].name));
    603  1.17    rumble 
    604  1.17    rumble 	write_volhdr();
    605  1.17    rumble }
    606  1.17    rumble 
    607  1.17    rumble void
    608   1.2   thorpej modify_partition(void)
    609   1.1     soren {
    610   1.5     rafal 	if (!opt_q)
    611   1.5     rafal 		printf("Modify partition %d start %d length %d\n",
    612   1.5     rafal 			partno, partfirst, partblocks);
    613  1.17    rumble 	if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) {
    614   1.5     rafal 		printf("Invalid partition number: %d\n", partno);
    615   1.1     soren 		exit(1);
    616   1.1     soren 	}
    617   1.7    sekiya 	volhdr->partitions[partno].blocks = htobe32(partblocks);
    618   1.7    sekiya 	volhdr->partitions[partno].first = htobe32(partfirst);
    619   1.7    sekiya 	volhdr->partitions[partno].type = htobe32(parttype);
    620   1.1     soren 	write_volhdr();
    621   1.1     soren }
    622   1.1     soren 
    623   1.2   thorpej void
    624   1.2   thorpej write_volhdr(void)
    625   1.1     soren {
    626   1.2   thorpej 	int i;
    627   1.2   thorpej 
    628   1.1     soren 	checksum_vol();
    629   1.5     rafal 
    630   1.5     rafal 	if (!opt_q)
    631   1.5     rafal 		display_vol();
    632   1.5     rafal 	if (!opt_f) {
    633   1.5     rafal 		printf("\nDo you want to update volume (y/n)? ");
    634   1.5     rafal 		i = getchar();
    635   1.5     rafal 		if (i != 'Y' && i != 'y')
    636   1.5     rafal 			exit(1);
    637   1.5     rafal 	}
    638   1.7    sekiya 	i = lseek(fd, 0, SEEK_SET);
    639   1.2   thorpej 	if (i < 0) {
    640   1.1     soren 		perror("lseek 0");
    641   1.1     soren 		exit(1);
    642   1.1     soren 	}
    643   1.2   thorpej 	i = write(fd, buf, 512);
    644   1.2   thorpej 	if (i < 0)
    645   1.1     soren 		perror("write volhdr");
    646   1.1     soren }
    647   1.1     soren 
    648   1.2   thorpej int
    649   1.2   thorpej allocate_space(int size)
    650   1.1     soren {
    651   1.1     soren 	int n, blocks;
    652   1.1     soren 	int first;
    653   1.1     soren 
    654   1.1     soren 	blocks = (size + 511) / 512;
    655   1.1     soren 	first = 2;
    656   1.1     soren 	n = 0;
    657  1.17    rumble 	while (n < SGI_BOOT_BLOCK_MAXVOLDIRS) {
    658   1.1     soren 		if (volhdr->voldir[n].name[0]) {
    659   1.7    sekiya 			if (first < (be32toh(volhdr->voldir[n].block) +
    660   1.7    sekiya 			  (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
    661   1.7    sekiya 			    (first + blocks) > be32toh(volhdr->voldir[n].block)) {
    662   1.7    sekiya 				first = be32toh(volhdr->voldir[n].block) +
    663   1.7    sekiya 					(be32toh(volhdr->voldir[n].bytes) + 511) / 512;
    664   1.1     soren #if 0
    665   1.7    sekiya 				printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
    666   1.7    sekiya 				printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
    667   1.7    sekiya 				printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
    668   1.7    sekiya 				       first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
    669   1.1     soren #endif
    670   1.1     soren 				n = 0;
    671   1.1     soren 				continue;
    672   1.1     soren 			}
    673   1.1     soren 		}
    674   1.1     soren 		++n;
    675   1.1     soren 	}
    676   1.9       jmc #if HAVE_NBTOOL_CONFIG_H
    677   1.9       jmc 	if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
    678   1.9       jmc #else
    679   1.1     soren 	if (first + blocks > lbl.d_secperunit)
    680   1.9       jmc #endif
    681   1.1     soren 		first = -1;
    682   1.1     soren 	/* XXX assumes volume header is partition 8 */
    683   1.1     soren 	/* XXX assumes volume header starts at 0? */
    684   1.7    sekiya 	if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
    685   1.1     soren 		first = -1;
    686   1.7    sekiya 	return (first);
    687   1.1     soren }
    688   1.1     soren 
    689   1.2   thorpej void
    690   1.2   thorpej checksum_vol(void)
    691   1.1     soren {
    692   1.2   thorpej 	int32_t *l;
    693   1.2   thorpej 	int i;
    694   1.2   thorpej 
    695   1.1     soren 	volhdr->checksum = checksum = 0;
    696   1.2   thorpej 	l = (int32_t *)buf;
    697   1.2   thorpej 	for (i = 0; i < 512 / 4; ++i)
    698   1.7    sekiya 		checksum += be32toh(l[i]);
    699   1.7    sekiya 	volhdr->checksum = htobe32(-checksum);
    700   1.1     soren }
    701   1.1     soren 
    702   1.2   thorpej void
    703   1.2   thorpej usage(void)
    704   1.1     soren {
    705  1.15    rumble 	printf("Usage:	sgivol [-qf] -i [-h vhsize] device\n"
    706  1.15    rumble 	       "	sgivol [-qf] -r vhfilename diskfilename device\n"
    707  1.15    rumble 	       "	sgivol [-qf] -w vhfilename diskfilename device\n"
    708  1.15    rumble 	       "	sgivol [-qf] -d vhfilename device\n"
    709  1.18    rumble 	       "	sgivol [-qf] -m vhfilename vhfilename device\n"
    710  1.15    rumble 	       "	sgivol [-qf] -p partno partfirst partblocks "
    711  1.15    rumble 	       "parttype device\n"
    712   1.1     soren 	       );
    713   1.1     soren 	exit(0);
    714   1.1     soren }
    715