1
0
Files
irix-657m-src/eoe/cmd/fx/script.c
2022-09-29 17:59:04 +03:00

333 lines
8.9 KiB
C

/* this option implements the -s (script) option of fx, added primarily
* for the autoinst feature, but documented and usable for other purposes.
* At this time, it only implements partitioning. When -s is given, all
* other command line arguments are ignored!
*/
/* Blank lines and lines starting with # are ignored. Continuation lines
* are not currently supported, but could be added (ending in \).
* script format is:
* device size type
* with trailing junk (name field from inst mrconfig file) ignored.
* see doline() for how fields are parsed. sizes/starting block, etc.
* are always in terms of 512 byte blocks.
* Field seperators can be space or tab, or a combination.
* No spaces are allowed. Device names are as they show up in
* /dev/rdsk/ (without leading /dev/rdsk). Each line is treated
* independently, and if they are conflicting, the later line always
* wins. Partition, ID, and controller are derived by parsing the
* device name. Unnecessary opens (ID and controller the same as
* previous device) are prevented by remembering the previous device.
*/
#include "fx.h" /* only for types in prototypes.h */
#include "prototypes.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
extern char fulldrivename[];
static char sline[256];
static int vhok; /* did we read the vh OK? */
static int prot_ctlr, prot_id, prot_part, prot_lun, protected;
static int64_t prot_firstblk, prot_blocks; /* keep as blocks, not
partition data, for easier detection of overlap */
/* actually do the partitioning */
dopart(int part, int fstype, int std, int64_t startblk, int64_t psize, int
chkprot)
{
if(!vhok && !std) {
fprintf(stderr, "Warning: %s: no valid disk info, initializing as generic disk\n",
fulldrivename);
create_all_func();
show_pts(&vh);
}
if(std) {
/* zero all the other partitions also. normal fx code does,
* but we don't go through quite the same path, so do it
* explictly */
int fpart;
for(fpart=0; fpart<NPARTAB; fpart++)
if(fpart != PTNUM_VOLUME && fpart != PTNUM_VOLHDR)
PT(&vh)[fpart].pt_nblks = 0;
if(std == 1)
pt_sroot_func();
else
pt_optdrive_func();
}
else {
if(psize == -1LL)
psize = PT(&vh)[PTNUM_VOLUME].pt_nblks - startblk;
if((psize+startblk) > PT(&vh)[PTNUM_VOLUME].pt_nblks) {
fprintf(stderr, "Error: start + size too large to fit on disk\n");
return 1;
}
if(chkprot) {
struct partition_table p = PT(&vh)[prot_part];
struct partition_table pint;
p.pt_nblks = prot_blocks;
p.pt_firstlbn = prot_firstblk;
pint.pt_nblks = psize;
pint.pt_firstlbn = startblk;
if(intersect(&p, &pint)) {
fprintf(stderr, "Error: Overlaps protected partition, ignored\n\t");
return 1;
}
}
PT(&vh)[part].pt_firstlbn = startblk;
PT(&vh)[part].pt_nblks = psize;
if(fstype != -1)
PT(&vh)[part].pt_type = fstype;
}
(void)update_vh();
return 0;
}
doline(char *spec)
{
char *dev, *sdev, *size, *type, *tmp, *sz;
int bad=0, dostd=0, thisprot=0, chkover=0, doallochk=0, fstyp, r;
unsigned ctlr, id, part, lun=0;
int64_t startblk, psize=0;
if(!(dev=strtok(spec, " \t\n")) || !*dev)
bad = 1;
else if(*dev == '#')
return 0; /* allow whitespace # comments */
else if(!(size=strtok(NULL, " \t\n")) || !*size)
bad = 1;
else if(!(type=strtok(NULL, " /\t\n")) || !*type) /* / because
* xfs/blocksize, and we don't want the /blocksize part */
bad = 1;
/* don't care about trailing stuff */
if(bad)
return bad;
if(!strcmp("protect", type))
thisprot = 1;
if(!strcmp("existing", size)) {
if(!thisprot)
return 0; /* fx nop, except for type == protect */
else
psize = -1LL;
}
else if(strcmp("standard", size)) {
/* check for valid sizes here, including "remainder".
* If not valid size:
* (start#|followspart#):("remainder"|"all"|sizeinblocks#)
* fail. /blocksize is ignored in fx. */
sz = strtok(size, ":");
if(!sz || !*sz)
return 1;
if(!strncmp("all", sz, 3)) {
psize = -1LL; /* whole disk, follows part 8 */
startblk = -PTNUM_VOLHDR;
}
else if(strncmp("followspart", sz, 11)) {
startblk = (int64_t)strtoull(sz, &tmp, 10);
/* 0 valid for vh, and for deleting parts! */
if(sz == tmp)
return 1;
}
else /* have to defer check, in case not already opened */
doallochk = 1;
if(psize != -1LL) { /* if not the "all" case above */
char *psz = strtok(NULL, "");
if(!psz || !*psz)
return 1;
else if(strncmp("remainder", psz, 9)) {
psize = (int64_t)strtoull(psz, &tmp, 10);
if(psz == tmp)
return 1; /* 0 valid to allow them to delete partitions,
but must be explict, not empty */
}
else /* remainder */
psize = -1LL;
}
}
if(thisprot)
;
else if(!(r=strcmp("root", type)) || !strcmp("option", type)) {
if(strcmp("standard", size))
return 1; /* root and option require standard */
fstyp = PTYPE_XFS;
dostd = r ? 2 : 1;
startblk = 0; /* not used */
}
else if(!strcmp("xfs", type))
fstyp = PTYPE_XFS;
else if(!strcmp("efs", type))
fstyp = PTYPE_EFS;
else if(!strcmp("raw", type))
fstyp = PTYPE_RAW;
else if(!strcmp("swap", type))
fstyp = PTYPE_RAW;
else if(!strcmp("preserve", type))
fstyp = -1;
else
return 1;
if(strncmp("dks", dev, 3))
bad = 1;
ctlr = strtoul(&dev[3], &tmp, 10);
if(ctlr == 0 && tmp == &dev[3])
return 1;
if(*tmp != 'd')
return 1;
sdev = dev;
dev = tmp+1;
id = strtoul(dev, &tmp, 10);
if(id == 0 && tmp == dev)
return 1;
if(*tmp == 'l') { /* LUN */
dev = tmp+1;
lun = strtoul(dev, &tmp, 10);
if(lun == 0 && tmp == dev)
return 1;
}
else
lun = 0;
if(*tmp != 's')
return 1;
dev = tmp+1;
part = strtoul(dev, &tmp, 10);
if((part==0 && tmp==dev) || part==PTNUM_VOLUME)
return 1; /* has to be a number, and not vol, volhdr OK */
if(ctlrno != ctlr || scsilun != lun || id != driveno) {
ctlrno = ctlr;
scsilun = lun;
driveno = id;
/* show what we wound up with */
if(ctlrno != (uint)-1) /* show the last disk we did */
show_pts(&vh);
gclose(); /* close previous */
strncpy(fulldrivename, sdev, 80); /* from fx.c */
if(gopen(id, PTNUM_VOLUME) < 0) {
ctlrno = (uint)-1; /* for open for next line */
return 0; /* error message already issued */
}
/* read these in here, for partition overlap checking, etc. */
if(readdvh(&vh) && readinvh(&vh)) {
memset(&vh, 0, sizeof(vh)); /* make sure no leftovers */
vhok = 0; /* don't complain here, we complain in dopart(),
if not initializing as standard */
}
else
vhok = 1;
}
if(doallochk) {
unsigned lpart = strtoul(&sz[11], &tmp, 10);
if(tmp == &sz[11] || lpart >= NPARTAB)
return 1; /* not numeric, or invalid partition # */
if(PT(&vh)[lpart].pt_nblks <= 0) {
fprintf(stderr, "Error: can't follow partition %u, not allocated\n\t",
lpart);
return 1;
}
startblk = PT(&vh)[lpart].pt_firstlbn + PT(&vh)[lpart].pt_nblks;
}
if(thisprot) { /* only after successful open */
if(psize == 0LL) {
/* turn off protect, if size is explictly 0 */
protected = 0;
prot_blocks = 0;
return 0;
}
if(!vhok) {
fprintf(stderr, "Error: can't protect, no volume header\n\t");
return 1;
}
prot_part = part;
protected = 1;
prot_ctlr = ctlr;
prot_id = id;
prot_lun = lun;
if(psize == -1LL) {
/* "existing" or "all" */
prot_blocks = PT(&vh)[part].pt_nblks;
prot_firstblk = PT(&vh)[part].pt_firstlbn;
}
else { /* explict */
prot_blocks = psize;
prot_firstblk = startblk + PT(&vh)[part].pt_firstlbn;
}
return 0;
/* nothing else to do for this line */
}
if(protected && prot_ctlr == ctlr && prot_id == id &&
prot_lun == lun) {
/* need to be sure we won't trash the protected partition */
if(prot_part == part) {
if(startblk > prot_firstblk ||
(startblk+psize) < (prot_firstblk+prot_blocks)) {
fprintf(stderr,
"Error: would change protected partition, ignored\n\t");
return 1;
}
}
else if(dostd) {
fprintf(stderr, "Error: can't use \"standard\"; disk has protected partition\n\t");
return 1;
}
else
chkover = 1;
}
return dopart(part, fstyp, dostd, startblk, psize, chkover);
}
void
fxscript(char *scriptname)
{
char line[256];
FILE *sc;
int errs = 0;
if((sc=fopen(scriptname, "r")) == NULL) {
fprintf(stderr, "Error: couldn't open script file %s: %s\n",
scriptname, strerror(errno));
exit(1);
}
driver = SCSI_NAME; /* only work with dks devices */
drivernum = SCSI_NUMBER;
driveno = 0; /* only have one drive open at a time */
ctlrno = (uint)-1; /* to force gopen() on first device */
line[sizeof(line)-1] = '\n';
while(fgets(line, sizeof(line), sc)) {
if(line[sizeof(line)-1] != '\n') {
fprintf(stderr, "Error: line too long, skipped:\n\t%s\n", line);
while(fgetc(sc) != '\n' && !(feof(sc)||ferror(sc)))
;
line[sizeof(line)-1] = '\n';
continue;
}
if(*line == '\n' || *line == '#') {
continue;
}
strcpy(sline, line); /* for error messages, "line" is trashed */
if(doline(line)) {
fprintf(stderr, "Error: script line:\n\t%s\n", sline);
errs++;
}
}
if(ctlrno != (uint)-1) /* show the last disk we did */
show_pts(&vh);
exit(errs);
}