Home | History | Annotate | Download | only in misc
      1 /*
      2  * base_device.c
      3  *
      4  * Return the "base device" given a particular device; this is used to
      5  * assure that we only fsck one partition on a particular drive at any
      6  * one time.  Otherwise, the disk heads will be seeking all over the
      7  * place.  If the base device can not be determined, return NULL.
      8  *
      9  * The base_device() function returns an allocated string which must
     10  * be freed.
     11  *
     12  * Written by Theodore Ts'o, <tytso (at) mit.edu>
     13  *
     14  * Copyright (C) 2000 Theodore Ts'o.
     15  *
     16  * %Begin-Header%
     17  * This file may be redistributed under the terms of the GNU Public
     18  * License.
     19  * %End-Header%
     20  */
     21 #include "config.h"
     22 #include <stdio.h>
     23 #if HAVE_UNISTD_H
     24 #include <unistd.h>
     25 #endif
     26 #if HAVE_STDLIB_H
     27 #include <stdlib.h>
     28 #endif
     29 #include <ctype.h>
     30 #include <string.h>
     31 
     32 #include "fsck.h"
     33 
     34 /*
     35  * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
     36  * pathames.
     37  */
     38 static const char *devfs_hier[] = {
     39 	"host", "bus", "target", "lun", 0
     40 };
     41 
     42 char *base_device(const char *device)
     43 {
     44 	char *str, *cp;
     45 	const char **hier, *disk;
     46 	int len;
     47 
     48 	str = malloc(strlen(device)+1);
     49 	if (!str)
     50 		return NULL;
     51 	strcpy(str, device);
     52 	cp = str;
     53 
     54 	/* Skip over /dev/; if it's not present, give up. */
     55 	if (strncmp(cp, "/dev/", 5) != 0)
     56 		goto errout;
     57 	cp += 5;
     58 
     59 	/* Skip over /dev/dsk/... */
     60 	if (strncmp(cp, "dsk/", 4) == 0)
     61 		cp += 4;
     62 
     63 	/*
     64 	 * For md devices, we treat them all as if they were all
     65 	 * on one disk, since we don't know how to parallelize them.
     66 	 */
     67 	if (cp[0] == 'm' && cp[1] == 'd') {
     68 		*(cp+2) = 0;
     69 		return str;
     70 	}
     71 
     72 	/* Handle DAC 960 devices */
     73 	if (strncmp(cp, "rd/", 3) == 0) {
     74 		cp += 3;
     75 		if (cp[0] != 'c' || cp[2] != 'd' ||
     76 		    !isdigit(cp[1]) || !isdigit(cp[3]))
     77 			goto errout;
     78 		*(cp+4) = 0;
     79 		return str;
     80 	}
     81 
     82 	/* Now let's handle /dev/hd* and /dev/sd* devices.... */
     83 	if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
     84 		cp += 2;
     85 		/* If there's a single number after /dev/hd, skip it */
     86 		if (isdigit(*cp))
     87 			cp++;
     88 		/* What follows must be an alpha char, or give up */
     89 		if (!isalpha(*cp))
     90 			goto errout;
     91 		*(cp + 1) = 0;
     92 		return str;
     93 	}
     94 
     95 	/* Now let's handle devfs (ugh) names */
     96 	len = 0;
     97 	if (strncmp(cp, "ide/", 4) == 0)
     98 		len = 4;
     99 	if (strncmp(cp, "scsi/", 5) == 0)
    100 		len = 5;
    101 	if (len) {
    102 		cp += len;
    103 		/*
    104 		 * Now we proceed down the expected devfs hierarchy.
    105 		 * i.e., .../host1/bus2/target3/lun4/...
    106 		 * If we don't find the expected token, followed by
    107 		 * some number of digits at each level, abort.
    108 		 */
    109 		for (hier = devfs_hier; *hier; hier++) {
    110 			len = strlen(*hier);
    111 			if (strncmp(cp, *hier, len) != 0)
    112 				goto errout;
    113 			cp += len;
    114 			while (*cp != '/' && *cp != 0) {
    115 				if (!isdigit(*cp))
    116 					goto errout;
    117 				cp++;
    118 			}
    119 			cp++;
    120 		}
    121 		*(cp - 1) = 0;
    122 		return str;
    123 	}
    124 
    125 	/* Now handle devfs /dev/disc or /dev/disk names */
    126 	disk = 0;
    127 	if (strncmp(cp, "discs/", 6) == 0)
    128 		disk = "disc";
    129 	else if (strncmp(cp, "disks/", 6) == 0)
    130 		disk = "disk";
    131 	if (disk) {
    132 		cp += 6;
    133 		if (strncmp(cp, disk, 4) != 0)
    134 			goto errout;
    135 		cp += 4;
    136 		while (*cp != '/' && *cp != 0) {
    137 			if (!isdigit(*cp))
    138 				goto errout;
    139 			cp++;
    140 		}
    141 		*cp = 0;
    142 		return str;
    143 	}
    144 
    145 errout:
    146 	free(str);
    147 	return NULL;
    148 }
    149 
    150 #ifdef DEBUG
    151 int main(int argc, char** argv)
    152 {
    153 	const char *base;
    154 	char  buf[256], *cp;
    155 
    156 	while (1) {
    157 		if (fgets(buf, sizeof(buf), stdin) == NULL)
    158 			break;
    159 		cp = strchr(buf, '\n');
    160 		if (cp)
    161 			*cp = 0;
    162 		cp = strchr(buf, '\t');
    163 		if (cp)
    164 			*cp = 0;
    165 		base = base_device(buf);
    166 		printf("%s\t%s\n", buf, base ? base : "NONE");
    167 	}
    168 	exit(0);
    169 }
    170 #endif
    171