/************************************************************************** * * * Copyright (C) 1988, Silicon Graphics, Inc. * * * * These coded instructions, statements, and computer programs contain * * unpublished proprietary information of Silicon Graphics, Inc., and * * are protected by Federal copyright law. They may not be disclosed * * to third parties or copied or duplicated in any form, in whole or * * in part, without the prior written consent of Silicon Graphics, Inc. * * * **************************************************************************/ #ident "$Revision: 1.13 $" /* Subroutines doing various pathname conversions for the logical * volume utilities. * These are inevitably dependent on the SGI device naming conventions! * * Therefore: * SEVERE UGLINESS WARNING!! SEVERE UGLINESS WARNING! * Lovers of portable code leave the room now!! * * We make the assumption that while new controller names (such as * 'ips', 'xyl', 'dks') may appear, the #d#s# format following will * NOT change, likewise that the /dev/dsk and /dev/rdsk locations of * block and character files for disk devices will not change. * * General convention note: apart from functions returning a pointer, * all others return 0 for OK and -1 for error. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lvutils.h" extern int errno; extern char *progname; extern int verbose; /* Workhorse function for decomposing pathnames into controller # etc. */ static struct pathanalysis * decompose_path(p) char *p; { static struct pathanalysis pa; int i; if (!strncmp(p, BLOCKPATHPREF, BLOCKPATHLEN)) p += BLOCKPATHLEN; else if (!strncmp(p, RAWPATHPREF, RAWPATHLEN)) p += RAWPATHLEN; else return (NULL); bzero (&pa, sizeof(pa)); /* p is now positioned at the start of the controller name. * We shall assume that controller names will never contain * numeric characters, & will always be < MAXCTLRNAMELEN * chars long... */ i = 0; while ((i < MAXCTLRNAMELEN) && !isdigit(*p)) { pa.ctlrname[i++] = *p++; } if (i == MAXCTLRNAMELEN) return (NULL); /* Now controller number. We assume this will not be more than * 3 digits. */ i = 0; while ((i <= 3) && isdigit(*p)) { pa.ctlr *= 10; pa.ctlr += (*p++ - '0'); i++; } if (i == 4) return (NULL); /* Now drive number. We assume this will not be more than * 3 digits. */ if (*p++ != 'd') return (NULL); i = 0; while ((i <= 3) && isdigit(*p)) { pa.drive *= 10; pa.drive += (*p++ - '0'); i++; } if (i == 4) return (NULL); /* Now there can be either a partition or a lun number. */ if (*p == 'l') { /* Now lun number. We assume this will not be more than * 2 digits. */ p++; i = 0; while ((i <= 2) && isdigit(*p)) { pa.lun *= 10; pa.lun += (*p++ - '0'); i++; } /* the lun number MUST be non 0. * otherwise there would be two names for devices with a lun * of 0: * dks#d#l0s# and * dks#d#s# * * Irix only allows the second form */ if ((i == 3) || (pa.lun == 0) ) return (NULL); } else { pa.lun = 0; } /* Now partition. This will not be more than 2 digits, and may * not exceed 15. */ if (*p++ != 's') return (NULL); i = 0; while ((i <= 2) && isdigit(*p)) { pa.partition *= 10; pa.partition += (*p++ - '0'); i++; } if (i == 3) return (NULL); if (pa.partition > 15) return (NULL); return (&pa); } /* checkformat(): tests if the given string is a plausible block device * pathname in /dev/dsk */ checkformat(p) register char *p; { int part; if (strncmp(p, BLOCKPATHPREF, BLOCKPATHLEN)) return (-1); if (decompose_path(p) == NULL) return (-1); return (0); } /* pathtopart: returns the partition implied by the given name. */ pathtopart(p) register char *p; { struct pathanalysis *pa; if ((pa = decompose_path(p)) == NULL) return (-1); return (pa->partition); } /* Pathtovhpath: takes a pathname of a block device & deduces the pathname * of the relevent volume header. Returns a pointer to this in static * storage. Note that we use the raw dev for the volume header: so that * if writing, it's synchronous & we get reliable notification of errors. */ char * pathtovhpath(p) register char *p; { static char vhnbuf[MAXDEVPATHLEN]; struct pathanalysis *pa; if ((pa = decompose_path(p)) == NULL) return (NULL); bzero(vhnbuf, MAXDEVPATHLEN); if (pa->lun) { sprintf(vhnbuf,"/dev/rdsk/%s%dd%dl%dvh", pa->ctlrname, pa->ctlr, pa->drive, pa->lun); } else { sprintf(vhnbuf,"/dev/rdsk/%s%dd%dvh", pa->ctlrname, pa->ctlr, pa->drive); } return (vhnbuf); } /* pathtolabname: constructs the name of the logical volume label file * for the partition implied by the given pathname. Returns a pointer * to this in static storage. */ char * pathtolabname(p) register char *p; { static char labnbuf[MAXDEVPATHLEN]; bzero(labnbuf, MAXDEVPATHLEN); sprintf(labnbuf,"lvlab%d", pathtopart(p)); return (labnbuf); } /* devtopath(): given a dev, return the pathname for it. The dev is expected * to be a block disk device. * * This has even more horribly arbitrary & nonportable assumptions about * external major numbers & SGI device naming conventions built into it! * * If confirm is set, having guessed the pathname, we stat it to confirm * the guess... */ char * devtopath(dev, confirm) register dev_t dev; int confirm; { struct stat buf; static char pathbuf[MAXDEVPATHLEN]; int maj; bzero(pathbuf, MAXDEVPATHLEN); maj = major(dev); switch (maj) { case DKSC_MAJOR: if ( SCSI_LUNOF(dev) ) { sprintf(pathbuf,"/dev/dsk/dks%dd%dl%ds%d", SCSI_CTLROF(dev), SCSI_UNITOF(dev), SCSI_LUNOF(dev), PARTOF(dev)); } else { sprintf(pathbuf,"/dev/dsk/dks%dd%ds%d", SCSI_CTLROF(dev), SCSI_UNITOF(dev), PARTOF(dev)); } break; case USRAID_MAJOR: /* same structure as DKSC, diff prefix */ sprintf(pathbuf,"/dev/dsk/rad%dd%ds%d", SCSI_CTLROF(dev), SCSI_UNITOF(dev), PARTOF(dev)); break; case OLDDKSC_MAJOR : sprintf(pathbuf,"/dev/dsk/dks0d%ds%d", OSCSI_UNITOF(dev), PARTOF(dev)); break; case OLDDKSC1_MAJOR : sprintf(pathbuf,"/dev/dsk/dks1d%ds%d", OSCSI_UNITOF(dev), PARTOF(dev)); break; case OLDDKSC2_MAJOR : sprintf(pathbuf,"/dev/dsk/dks2d%ds%d", OSCSI_UNITOF(dev), PARTOF(dev)); break; case OLDDKSC3_MAJOR : sprintf(pathbuf,"/dev/dsk/dks3d%ds%d", OSCSI_UNITOF(dev), PARTOF(dev)); break; case JAG0_MAJOR : case JAG1_MAJOR : case JAG2_MAJOR : case JAG3_MAJOR : case JAG4_MAJOR : case JAG5_MAJOR : case JAG6_MAJOR : case JAG7_MAJOR : sprintf(pathbuf,"/dev/dsk/jag%dd%ds%d", JAG_CTLROF(dev), JAG_UNITOF(dev), PARTOF(dev)); break; default : sprintf(pathbuf,"Unknown device: maj %d min %d", major(dev), (unsigned) dev & L_MAXMIN); return (pathbuf); }; if (confirm) { if ((stat(pathbuf, &buf) < 0) || (buf.st_rdev != dev)) { bzero(pathbuf, MAXDEVPATHLEN); sprintf(pathbuf,"Unknown device: maj %d min %d", major(dev), (unsigned) dev & L_MAXMIN); } } return (pathbuf); } /* printpath(): given a dev, prints the deduced pathname. * The error flag controls whether print is on stdout or stderr. * The confirm flag controls whether the textual guess should be confirmed * by actually 'stat'ing the generated guess. */ printpath(dev, error, confirm) register dev_t dev; int error, confirm; { char *path; path = devtopath(dev, confirm); if (!error) printf("%s", path); else fprintf(stderr,"%s", path); }