Subject: Reworked sys/arch/sgimips/stand/sgivol/sgivol.c
To: None <port-sgimips@netbsd.org>
From: sgimips NetBSD list <sgimips@mrynet.com>
List: port-sgimips
Date: 02/09/2002 10:26:40
Could someone please review and consider my modified sgivol.c
for checkin into the source tree?
The changes are basically as follows...
CURRENT:
mod80 (605)# /ousr/mdec/sgivol
Usage: sgivol [-i] device
sgivol [-r vhfilename diskfilename] device
sgivol [-w vhfilename diskfilename] device
sgivol [-d vhfilename] device
MODIFIED:
mod80 (606)# /usr/mdec/sgivol
Usage: sgivol device
sgivol (to view volume header)
or sgivol -i [-qf] device
sgivol (to initialize volumeheader)
or sgivol -r [-q] vhfilename diskfilename device
sgivol (to read a disk file from the volume header)
or sgivol -w [-qf] vhfilename diskfilename device
sgivol (to write a disk file to the volume header)
or sgivol -d [-qf] vhfilename device
sgivol (to delete a volume header file)
or sgivol -p [-q] partition first blocks type device
sgivol (to modify a volume header partition entry)
I have modified sgivol to accept the -q and -f flags.
The -f flag (force) bypasses any confirmation prompting.
This is necessary for release-generation and install-time
procedures.
The -q flag (quiet) mutes normal processing output. This
cleans up the install-time screen.
Thanks for the consideration.
-scott
--------------------------
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Michael Hitch and Hubert Feyrer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <util.h>
/*
* Some IRIX man pages refer to the size being a multiple of whole cylinders.
* Later ones only refer to the size being "typically" 2MB. IRIX fx(1)
* uses a default drive geometry if one can't be determined, suggesting
* that "whole cylinder" multiples are not required.
*/
#define SGI_SIZE_VOLHDR 3135 /* XXX This is really arbitrary */
int fd;
int n;
int opt_i = 0; /* Initialize volume header */
int opt_r = 0; /* Read a file from volume header */
int opt_w = 0; /* Write a file to volume header */
int opt_d = 0; /* Delete a file from volume header */
int opt_p = 0; /* Modify a partition */
int opt_f = 0; /* Force actions */
int opt_q = 0; /* quiet mode */
char *vfilename = "";
char *ufilename = "";
int partno, partfirst, partblocks, parttype;
struct sgilabel *volhdr;
int32_t checksum;
struct disklabel lbl;
unsigned char buf[512];
char *sgi_types[] = {
"Volume Header",
"Repl Trks",
"Repl Secs",
"Raw",
"BSD4.2",
"SysV",
"Volume",
"EFS",
"LVol",
"RLVol",
"XFS",
"XSFLog",
"XLV",
"XVM"
};
void display_vol(void);
void init_volhdr(void);
void read_file(void);
void write_file(void);
void delete_file(void);
void modify_partition(void);
void write_volhdr(void);
int allocate_space(int);
void checksum_vol(void);
void usage(void);
int
main(int argc, char **argv)
{
int ch;
while ((ch = getopt(argc, argv, "irwpdqf")) != -1)
switch (ch) {
/* -i, -r, -w, -d and -p override each other */
/* -q implies -f */
case 'q':
++opt_q;
++opt_f;
break;
case 'f':
++opt_f;
break;
case 'i':
++opt_i;
opt_r = opt_w = opt_d = opt_p = 0;
break;
case 'r':
++opt_r;
opt_i = opt_w = opt_d = opt_p = 0;
break;
case 'w':
++opt_w;
opt_i = opt_r = opt_d = opt_p = 0;
break;
case 'd':
++opt_d;
opt_i = opt_r = opt_w = opt_p = 0;
break;
case 'p':
++opt_p;
opt_i = opt_r = opt_w = opt_d = 0;
partno = atoi(argv[0]);
partfirst = atoi(argv[1]);
partblocks = atoi(argv[2]);
parttype = atoi(argv[3]);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (opt_r || opt_w) {
if (argc != 3)
usage();
vfilename = argv[0];
ufilename = argv[1];
argc -= 2;
argv += 2;
}
if (opt_d) {
if (argc != 2)
usage();
vfilename = argv[0];
argc--;
argv++;
}
if (opt_p) {
if (argc != 5)
usage();
partno = atoi(argv[0]);
partfirst = atoi(argv[1]);
partblocks = atoi(argv[2]);
parttype = atoi(argv[3]);
argc -= 4;
argv += 4;
}
if (argc != 1)
usage();
fd = open(argv[0], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
if (fd < 0) {
sprintf(buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
fd = open(buf, (opt_i | opt_w | opt_d | opt_p)
? O_RDWR : O_RDONLY);
if (fd < 0) {
printf("Error opening device %s: %s\n",
argv[0], strerror(errno));
exit(1);
}
}
n = read(fd, buf, sizeof(buf));
if (n != sizeof(buf)) {
perror("read volhdr");
exit(1);
}
n = ioctl(fd, DIOCGDINFO, &lbl);
if (n < 0) {
perror("DIOCGDINFO");
exit(1);
}
volhdr = (struct sgilabel *)buf;
if (opt_i) {
init_volhdr();
exit(0);
}
if (volhdr->magic != SGILABEL_MAGIC) {
printf("No Volume Header found, magic=%x. Use -i first.\n",
volhdr->magic);
exit(1);
}
if (opt_r) {
read_file();
exit(0);
}
if (opt_w) {
write_file();
exit(0);
}
if (opt_d) {
delete_file();
exit(0);
}
if (opt_p) {
modify_partition();
exit(0);
}
display_vol();
exit(0);
}
void
display_vol(void)
{
int32_t *l;
l = (int32_t *)buf;
checksum = 0;
for (n = 0; n < 512 / 4; ++n)
checksum += l[n];
printf("disklabel shows %d sectors\n", lbl.d_secperunit);
printf("checksum: %08x%s\n", checksum, checksum == 0
? "" : " *ERROR*");
printf("root part: %d\n", volhdr->root);
printf("swap part: %d\n", volhdr->swap);
printf("bootfile: %s\n", volhdr->bootfile);
/* volhdr->devparams[0..47] */
printf("\nVolume header files:\n");
for (n = 0; n < 15; ++n)
if (volhdr->voldir[n].name[0])
printf("%-8s offset %4d blocks, length %8d bytes (%d blocks)\n",
volhdr->voldir[n].name, volhdr->voldir[n].block,
volhdr->voldir[n].bytes, (volhdr->voldir[n].bytes + 511 ) / 512);
printf("\nSGI partitions:\n");
for (n = 0; n < MAXPARTITIONS; ++n)
if (volhdr->partitions[n].blocks)
printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
n, n + 'a',
volhdr->partitions[n].blocks,
volhdr->partitions[n].first,
volhdr->partitions[n].type,
volhdr->partitions[n].type > 13 ? "???" :
sgi_types[volhdr->partitions[n].type]);
}
void
init_volhdr(void)
{
memset(buf, 0, sizeof(buf));
volhdr->magic = SGILABEL_MAGIC;
volhdr->root = 0;
volhdr->swap = 1;
strcpy(volhdr->bootfile, "netbsd");
volhdr->partitions[10].blocks = lbl.d_secperunit;
volhdr->partitions[10].first = 0;
volhdr->partitions[10].type = SGI_PTYPE_VOLUME;
volhdr->partitions[8].blocks = SGI_SIZE_VOLHDR;
volhdr->partitions[8].first = 0;
volhdr->partitions[8].type = SGI_PTYPE_VOLHDR;
volhdr->partitions[0].blocks = lbl.d_secperunit - SGI_SIZE_VOLHDR;
volhdr->partitions[0].first = SGI_SIZE_VOLHDR;
volhdr->partitions[0].type = SGI_PTYPE_EFS;
write_volhdr();
}
void
read_file(void)
{
FILE *fp;
if (!opt_q)
printf("Reading file %s\n", vfilename);
for (n = 0; n < 15; ++n) {
if (strcmp(vfilename, volhdr->voldir[n].name) == NULL)
break;
}
if (n >= 15) {
printf("file %s not found\n", vfilename);
exit(1);
}
lseek(fd, volhdr->voldir[n].block * 512, SEEK_SET);
fp = fopen(ufilename, "w");
if (fp == NULL) {
perror("open write");
exit(1);
}
n = volhdr->voldir[n].bytes;
while (n > 0) {
if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
perror("read file");
exit(1);
}
fwrite(buf, 1, n > sizeof(buf) ? sizeof(buf) : n, fp);
n -= n > sizeof(buf) ? sizeof(buf) : n;
}
fclose(fp);
}
void
write_file(void)
{
FILE *fp;
int fno;
int block;
struct stat st;
char fbuf[512];
if (!opt_q)
printf("Writing file %s\n", ufilename);
if (stat(ufilename, &st) < 0) {
perror("stat");
exit(1);
}
if (!opt_q)
printf("File %s has %lld bytes\n", ufilename, st.st_size);
fno = -1;
for (n = 0; n < 15; ++n) {
if (volhdr->voldir[n].name[0] == '\0' && fno < 0)
fno = n;
if (strcmp(vfilename, volhdr->voldir[n].name) == 0) {
fno = n;
break;
}
}
if (fno == -1) {
printf("No directory space for file %s\n", vfilename);
exit(1);
}
/* -w can overwrite, -a won't overwrite */
if (volhdr->voldir[fno].block > 0) {
if (!opt_q)
printf("File %s exists, removing old file\n",
vfilename);
volhdr->voldir[fno].name[0] = 0;
volhdr->voldir[fno].block = volhdr->voldir[fno].bytes = 0;
}
if (st.st_size == 0) {
printf("bad file size\n");
exit(1);
}
block = allocate_space((int)st.st_size);
if (block < 0) {
printf("No space for file\n");
exit(1);
}
/* Warn if the filename exceeds 8 chars -- Terminating NULL */
/* not required for 8-character filenames */
if (strlen(vfilename) > sizeof(volhdr->voldir[fno].name) - 1
&& !opt_q) {
printf("Warning: '%s' will be truncated to 8 characters.\n",
vfilename);
}
strncpy(volhdr->voldir[fno].name, vfilename, 8);
volhdr->voldir[fno].block = block;
volhdr->voldir[fno].bytes = st.st_size;
write_volhdr();
/* write the file itself */
n = lseek(fd, block * 512, SEEK_SET);
if (n < 0) {
perror("lseek write");
exit(1);
}
n = st.st_size;
fp = fopen(ufilename, "r");
while (n > 0) {
fread(fbuf, 1, n > 512 ? 512 : n, fp);
if (write(fd, fbuf, 512) != 512) {
perror("write file");
exit(1);
}
n -= n > 512 ? 512 : n;
}
}
void
delete_file(void)
{
for (n = 0; n < 15; ++n) {
if (strcmp(vfilename, volhdr->voldir[n].name) == NULL) {
break;
}
}
if (n >= 15) {
if (!opt_q)
printf("File %s not found\n", vfilename);
exit(1);
}
volhdr->voldir[n].name[0] = '\0';
volhdr->voldir[n].block = volhdr->voldir[n].bytes = 0;
write_volhdr();
}
void
modify_partition(void)
{
if (!opt_p)
printf("Modify partition %d start %d length %d\n",
partno, partfirst, partblocks);
if (partno < 0 || partno > 15) {
printf("Invalid partition number: %d\n", partno);
exit(1);
}
volhdr->partitions[partno].blocks = partblocks;
volhdr->partitions[partno].first = partfirst;
volhdr->partitions[partno].type = parttype;
write_volhdr();
}
void
write_volhdr(void)
{
checksum_vol();
if (!opt_q)
display_vol();
if (!opt_f) {
printf("\nDo you want to update volume (y/n)? ");
n = getchar();
if (n != 'Y' && n != 'y')
exit(1);
}
n = lseek(fd, 0 , SEEK_SET);
if (n < 0) {
perror("lseek 0");
exit(1);
}
n = write(fd, buf, 512);
if (n < 0)
perror("write volhdr");
}
/*
* HF: There's still a bug in there which allows things like:
*
* Volume header files:
* sgiboot offset 2 blocks, length 260730 bytes (510 blocks)
* sash offset 2 blocks, length 283648 bytes (554 blocks)
* ^^^
*/
int
allocate_space(int size)
{
int n2, blocks;
int first;
blocks = (size + 511) / 512;
first = 2;
n2 = 0;
while (n2 < 15) {
if (volhdr->voldir[n2].name[0]) {
if (first < (volhdr->voldir[n2].block +
(volhdr->voldir[n2].bytes + 511) / 512) &&
(first + blocks) >= volhdr->voldir[n2].block) {
first = volhdr->voldir[n2].block +
(volhdr->voldir[n2].bytes + 511) / 512;
#ifdef DEBUG
printf("allocate: n=%d first=%d blocks=%d size=%d\n", n2, first, blocks, size);
printf("%s %d %d\n", volhdr->voldir[n2].name, volhdr->voldir[n2].block,
volhdr->voldir[n2].bytes);
printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n2].block,
first + blocks - 1,
volhdr->voldir[n2].block +
(volhdr->voldir[n2].bytes + 511)/512);
#endif
n2 = 0;
continue;
}
}
++n2;
}
if (first + blocks > lbl.d_secperunit)
first = -1;
return(first);
}
void
checksum_vol(void)
{
int32_t *l;
volhdr->checksum = checksum = 0;
l = (int32_t *)buf;
for (n = 0; n < 512 / 4; ++n)
checksum += l[n];
volhdr->checksum = -checksum;
}
void
usage(void)
{
int i;
static const struct {
const char *name;
const char *expn;
} usages[] = {
{ "device",
"(to view volume header)" },
{ "-i [-qf] device",
"(to initialize volumeheader)" },
{ "-r [-q] vhfilename diskfilename device",
"(to read a disk file from the volume header)" },
{ "-w [-qf] vhfilename diskfilename device",
"(to write a disk file to the volume header)" },
{ "-d [-qf] vhfilename device",
"(to delete a volume header file)" },
{ "-p [-q] partition first blocks type device",
"(to modify a volume header partition entry)" },
{ NULL,
NULL }
};
if (!opt_q)
for (i = 0; usages[i].name; i++) {
(void) fputs(i ? "or " : "Usage: ", stderr);
(void) fprintf(stderr, "%s %s", getprogname(), usages[i].name);
(void) fputs("\n\t", stderr);
(void) fprintf(stderr, "%s %s", getprogname(), usages[i].expn);
(void) fputs("\n", stderr);
}
exit(1);
}