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