/* * 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 <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) { const 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"); } exit(0); } #endif