text: /*
   * base_device.c
   *
   * Return the "base device" given a particular device; this is used to
   * assure that we only fsck one partition on a particular drive at any
   * one time.  Otherwise, the disk heads will be seeking all over the
   * place.  If the base device can not be determined, return NULL.
   *
   * The base_device() function returns an allocated string which must
   * be freed.
   *
   * Written by Theodore Ts'o, <tytso@mit.edu>
   *
   * Copyright (C) 2000 Theodore Ts'o.
   *
   * %Begin-Header%
   * This file may be redistributed under the terms of the GNU Public
   * License.
   * %End-Header%
   */
  #include "config.h"
  #include <stdio.h>
  #if HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  #if HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #include <ctype.h>
  #include <string.h>
  
  #include "fsck.h"
  
  /*
   * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
   * pathames.
   */
  static const char *devfs_hier[] = {
  	"host", "bus", "target", "lun", 0
  };
  
  char *base_device(const char *device)
  {
  	char *str, *cp;
  	const char **hier, *disk;
  	int len;
  
  	str = malloc(strlen(device)+1);
  	if (!str)
  		return NULL;
  	strcpy(str, device);
  	cp = str;
  
  	/* Skip over /dev/; if it's not present, give up. */
  	if (strncmp(cp, "/dev/", 5) != 0)
  		goto errout;
  	cp += 5;
  
  	/* Skip over /dev/dsk/... */
  	if (strncmp(cp, "dsk/", 4) == 0)
  		cp += 4;
  
  	/*
  	 * For md devices, we treat them all as if they were all
  	 * on one disk, since we don't know how to parallelize them.
  	 */
  	if (cp[0] == 'm' && cp[1] == 'd') {
  		*(cp+2) = 0;
  		return str;
  	}
  
  	/* Handle DAC 960 devices */
  	if (strncmp(cp, "rd/", 3) == 0) {
  		cp += 3;
  		if (cp[0] != 'c' || cp[2] != 'd' ||
  		    !isdigit(cp[1]) || !isdigit(cp[3]))
  			goto errout;
  		*(cp+4) = 0;
  		return str;
  	}
  
  	/* Now let's handle /dev/hd* and /dev/sd* devices.... */
  	if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
  		cp += 2;
  		/* If there's a single number after /dev/hd, skip it */
  		if (isdigit(*cp))
  			cp++;
  		/* What follows must be an alpha char, or give up */
  		if (!isalpha(*cp))
  			goto errout;
  		*(cp + 1) = 0;
  		return str;
  	}
  
  	/* Now let's handle devfs (ugh) names */
  	len = 0;
  	if (strncmp(cp, "ide/", 4) == 0)
  		len = 4;
  	if (strncmp(cp, "scsi/", 5) == 0)
  		len = 5;
  	if (len) {
  		cp += len;
  		/*
  		 * Now we proceed down the expected devfs hierarchy.
  		 * i.e., .../host1/bus2/target3/lun4/...
  		 * If we don't find the expected token, followed by
  		 * some number of digits at each level, abort.
  		 */
  		for (hier = devfs_hier; *hier; hier++) {
  			len = strlen(*hier);
  			if (strncmp(cp, *hier, len) != 0)
  				goto errout;
  			cp += len;
  			while (*cp != '/' && *cp != 0) {
  				if (!isdigit(*cp))
  					goto errout;
  				cp++;
  			}
  			cp++;
  		}
  		*(cp - 1) = 0;
  		return str;
  	}
  
  	/* Now handle devfs /dev/disc or /dev/disk names */
  	disk = 0;
  	if (strncmp(cp, "discs/", 6) == 0)
  		disk = "disc";
  	else if (strncmp(cp, "disks/", 6) == 0)
  		disk = "disk";
  	if (disk) {
  		cp += 6;
  		if (strncmp(cp, disk, 4) != 0)
  			goto errout;
  		cp += 4;
  		while (*cp != '/' && *cp != 0) {
  			if (!isdigit(*cp))
  				goto errout;
  			cp++;
  		}
  		*cp = 0;
  		return str;
  	}
  
  errout:
  	free(str);
  	return NULL;
  }
  
  #ifdef DEBUG
  int main(int argc, char** argv)
  {
  	char *base;
  	char  buf[256], *cp;
  
  	while (1) {
  		if (fgets(buf, sizeof(buf), stdin) == NULL)
  			break;
  		cp = strchr(buf, '\n');
  		if (cp)
  			*cp = 0;
  		cp = strchr(buf, '\t');
  		if (cp)
  			*cp = 0;
  		base = base_device(buf);
  		printf("%s\t%s\n", buf, base ? base : "NONE");
  		free(base);
  	}
  	exit(0);
  }
  #endif
  