[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Autodetection of CD-ROM devices



Chris Lawrence <cnlawren@olemiss.edu> writes:

> I'll take a look around and see where else we can benefit from looking
> in /proc.  I'm pretty sure we can use /proc/partitions to bypass a lot
> of logic, especially if we're commited to using a 2.2 kernel in potato.

Yeah... see utilities/fdisk/ -- Also, check out the included patch
from Mark van Walraven.

-- 
.....Adam Di Carlo....adam@onShore.com.....<URL:http://www.onShore.com/>

--- Begin Message ---
Hi,

Hope this is the right way to do this ... submitted for your approval:

This patch adds /dev/ida/* and /dev/rd/* devices to fdisk_reread(),
and modifies the way device name patterns are encoded and expanded,
allowing a more reasonable representation for the ida and rd devices.

I have harness-tested the new code, but am unable to fully test it
in situ.  I don't *think* there will be any problems ... would someone
please try it out on suitably-equipped systems?

I intend to improve the CD-ROM detection and will soon submit another
patch for that.

Regards,

Mark.
--- fdisk.c-1.29	Wed Dec  8 23:02:14 1999
+++ fdisk.c	Wed Dec  8 23:29:19 1999
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -876,73 +877,126 @@
     }
 }
 
-static struct trylist {
-    char *dev_pattern;
-    char start, end;
-} trylist[] = {
-    { "/dev/hd", 'a', 'h' },
-    { "/dev/sd", 'a', 'h' },
-#if #cpu (i386)
-    { "/dev/ed", 'a', 'd' },
-#endif
-#if #cpu (m68k)
-    { "/dev/ad", 'a', 'h' },
-#endif
-/* 
- * #ifdef DEBUG
- *     { "/dev/loop", '0', '7' },
- * #endif
- */
-};
 
 static int timed_out;
 
-static void alarmed(int signo)
+static void alarmed(int signo) { timed_out = 1; }
+
+
+/* is_disk: return true is device is a disk drive */
+static int is_disk(char *device, int fd)
 {
-    timed_out = 1;
+    struct cdrom_volctrl cdvol;
+
+    /** TODO *****************************************************************/
+    /* Erik thinks the CD-ROM test is inadequate.  I'm inclined to agree.    */
+    /* We could instead consult /proc/ide and /proc/scsi, which will allow   */
+    /* us to eliminate IDE CD-ROMs (and CD-Rs) and non-random-access SCSI    */
+    /* devices.  See debian-boot list for discussion.                        */
+    /* I'm not sure how to check for such devices on dac960 or smart2.       */
+    /* ***********************************************************************/
+
+    /* supposedly anything failing CDROMVOLREAD for the right reasons is ok */
+    return ioctl(fd, CDROMVOLREAD, &cdvol) && (errno == EINVAL ||
+					       errno == EPERM  ||
+					       errno == EIO    ||
+					       errno == EBADRQC);
 }
 
-void
-fdisk_reread(void)
+
+/* try_device: check specific device by name, add to disk/part lists if ok */
+static void try_device(char *device)
 {
-    struct trylist *p;
-    struct cdrom_volctrl cdvol;
-    int i, fd;
-    char letter, device[12], *q;
-    unsigned size;
-    
-    fdisk_init();
-    
-    for( p = trylist, i = 0; i < SIZE(trylist); ++p, ++i ) {
-	strcpy( device, p->dev_pattern );
-	q = device+strlen(device);
-	q[1] = 0;
-	for( letter = p->start; letter <= p->end; ++letter ) {
-	    *q = letter;
-	    signal( SIGALRM, alarmed );
-	    timed_out = 0;
-	    alarm( 30 );
-	    if ((fd = open( device, O_RDONLY )) >= 0 && !timed_out) {
-		alarm( 0 );
-		if (ioctl(fd, CDROMVOLREAD, &cdvol )!= 0) {
-      /* if returns EINVAL or EPERM or EIO, this is not a CD-ROM drive */
-      		    if ((errno==EINVAL)||(errno==EPERM)||(errno==EIO)) {
-			if (ioctl(fd, BLKGETSIZE, &size))
-			    size = 0; /* don't complain, size not really 
-					 used yet */
-			size >>= 1; /* convert from 512-byte sectors to kB */
-			fdisk_add_disk( device, size );
-
-			parse_partition( device, fd );
-		    }
-		}
-		close( fd );
-	    }
-	    else {
-		/* else: don't complain, ignore open errors */
-		alarm( 0 );
+    int fd;
+
+    signal(SIGALRM, alarmed);
+    timed_out = 0;
+    alarm(30);
+    fd = open(device, O_RDONLY);
+    alarm(0);
+
+    if (fd >= 0) {
+        if (is_disk(device, fd)) {
+	    unsigned int size;
+	    if (ioctl(fd, BLKGETSIZE, &size))
+		size = 0;   /* don't complain, size not really used yet */
+	    size >>= 1;     /* convert from 512-byte sectors to kB */
+	    fdisk_add_disk(device, size);
+	    parse_partition(device, fd);
+	}
+	close(fd);
+    }
+}
+
+
+/* walk - recursively walk pattern string, calling fn for every expansion */
+static void walk(char *pattern, char *expansion, char *p, void (*fn)(char *))
+{
+    while (*pattern) {
+	if (*pattern == '{') {
+	    /* inside {..} can be either a character range or a number range */
+	    pattern++;
+	    if (isdigit(*pattern)) {
+		/* a digit may only be a (decimal) number range */
+		unsigned int min, max, pos, i;
+		char term;
+		int rc = sscanf(pattern, "%u-%u%c%n", &min, &max, &term, &pos);
+		assert(rc >= 3 && term == '}' && min <= max);
+		/* walk remainder of pattern for all possible values in range */
+		for (i = min; i <= max; i++) 
+		    walk(pattern + pos, expansion, p + sprintf(p, "%u", i), fn);
+	    } else {
+		/* a non-digit must be a character range */
+		char min, max, term;
+		int rc = sscanf(pattern, "%c-%c%c", &min, &max, &term);
+		assert(rc == 3 && term == '}' && min <= max);
+		/* walk remainder of pattern for all possible chars in range */
+		for (*p = min; *p <= max; (*p)++) 
+		    walk(pattern + 4, expansion, p + 1, fn);
 	    }
+	    return;
 	}
+	*p++ = *pattern++;
+    }
+    /* reached end of pattern, so terminate expansion string and call fn() */
+    *p++ = '\0';
+    (*fn)(expansion);
+}
+
+
+/* fdisk_reread: scan for disk devices and build up disk and partition lists */
+void fdisk_reread(void)
+{
+    static char *patterns[] = {
+	"/dev/sd{a-h}",
+	"/dev/hd{a-h}",
+	"/dev/ida/c{0-7}d{0-15}",
+	"/dev/rd/c{0-7}d{0-31}",
+#if #cpu (i386)
+	"/dev/ed{a-d}",
+#elif #cpu (m68k)
+	"/dev/ad{a-h}",
+#endif
+/* 
+ * #ifdef DEBUG
+ *	"/dev/loop{0-7}",
+ * #endif
+ */
+	NULL
+    };
+    char **p;
+
+    fdisk_init();
+
+    for (p = patterns; *p; p++) {
+	char expansion[30]; /* storage for pattern expansions */
+
+	/* a pattern never expands to anything large than itself, so we can */
+	/* use the pattern length to make sure buffer is always big enough  */
+	assert(strlen(*p) < sizeof expansion);
+
+	/* call try_device(expansion) for each expansion of current pattern */
+	walk(*p, expansion, expansion, try_device);
     }
 
     mounted_reread();

--- End Message ---

Reply to: