[comp.os.msdos.programmer] Number of drives on system, how do you find out the ...

kooijman@duteca (Richard Kooijman) (10/19/90)

How do you find out what the actual number of drives is on a MS-DOS computer?
I have programmed a utility like NCD. It searches all disks on the computer
to build a database of directories. Later this database can be used to switch
quickly to another directory.
The problem is that I haven't found a descent way to search all drives.
I program in Turbo C and I have used setdisk(drive) which returns the number of
logical drives. On my system (40Mb harddisk with 2 partitions C: & D: and NO
ramdisk) it returns 5, so it includes a drive E:. I know I can set LASTDRIVE=D:
in my CONFIG.SYS, but I don't want to do that.
Later I tried the function biosequip(), but it returns the number of physical 
drives, in my case 3 (A: B: C: or \x00, \x01, \x80 actually).
I have the utility working by just trying to get the current directory of
the drives, and when this fails it stops, starting at drive C: of course.

Who knows a better way, thanks in advance.



Richard.

dwatney@pine.circa.ufl.edu (Marshall Sutherland) (10/20/90)

In article <1085@duteca4.UUCP>, kooijman@duteca (Richard Kooijman) writes...
>How do you find out what the actual number of drives is on a MS-DOS computer?

The best way I have found so far is to use setdisk() and then use getdisk()
to see if it was successful (if you try to go to drive D, but find you are
still on drive C, then there isnt a drive D).

However, this still has problems.  My most common problem with it is
getting the infamous Abort, Retry, Ignore when i had an external floppy
D drive with no disk in it (although, I'm sure there is a way to suppress
that).  Other possible problems (which had never occured to me until
writing this) are how to treat SUBSTed drives.  Since I would start at
C and go until it failed, I assume that if you had SUBSTed drives
which were labeled to follow immediately after your real drives, they
would get counted, while those that arent contiguous would not.  Whether
you want to count these as drives or not depends on your application.

Well, having nearly totally undermined my method, I too, would be
interested in seeing a better method, :)

-----
Marshall Sutherland, Partner/Consultant, Digital Magic Computer Consulting
dwatney@pine.circa.ufl.edu, dwatney@ufpine.bitnet
Sysop, Farthinghale Arms BBS, (904) 378-4861

geoff@bodleian.East.Sun.COM (Geoff Arnold @ Sun BOS - R.H. coast near the top) (10/20/90)

The following little program is derived from the material
in the Ralf Brown "interrupt list". It shows how to
prowl the Logical Drive Table and GetRedirList outputs.
Depending on your system and network, drives may show up
on either or both of these. Sorry about the cryptic
output: the "V" bit in the LDT means that the drive is valid.
Also, you MUST compile with /AL, or all of the pointer will be
screwed up. The code will adjust for DOS 3.x or 4.x correctly.

Enjoy

Geoff

----------------------------------------------------------------------
/*
 * SYS_SCAN.C
 * Compile with "cl /AL sys_scan.c". I use MSC5.0.
 */

#include <dos.h>
#include <io.h>
#include <stdio.h>

/* The following requires that we compile with /Zp for
 * packed structures, or use the pragmas
 */

#pragma pack(1)

struct dpb {
        unsigned                char            d_number;
        unsigned                char            d_unit;
        unsigned                int             d_secsize;
        unsigned                char            d_secpercl;
        unsigned                char            d_allocshf;
        unsigned                int             d_rsvsec;
        unsigned                char            d_fatnum;
        unsigned                int             d_roots;
        unsigned                int             d_data1;
        unsigned                int             d_lastcl;
        unsigned                char            d_fatsize;
        unsigned                int             d_root1;
        void                    far     *       d_blkdev_p;
        unsigned                char            d_mediad;
        unsigned                char            d_mediaf;
        struct dpb      far     *       d_next;
};

struct ldt3 {
        char                                            p_path[67];
        unsigned                int             p_flags;
        struct dpb      far     *       p_dpb_p;
        unsigned                int             p_seek;
        unsigned                int             p_unknown1;
        unsigned                int             p_unknown2;
        unsigned                int             p_substptr;
};


#define NETWORK_DRIVE   0x8000
#define VALID_DRIVE             0x4000
#define JOINED_DRIVE            0x2000
#define SUBST_DRIVE             0x1000

#define DRIVE_UNUSED		0
#define DRIVE_REDIRECTED	1
#define DRIVE_PERMANENT	2
#define DRIVE_INVALID	3

struct ldt4 {
        char                                            p_path[67];
        unsigned                int             p_flags;
        struct dpb      far     *       p_dpb_p;
        unsigned                int             p_seek;
        unsigned                int             p_unknown1;
        unsigned                int             p_unknown2;
        unsigned                int             p_substptr;
        unsigned                char            p_unknown3[7];
};


                

struct dbuf {
        struct dpb      far     *       s_dpb_p;
        void                    far     *       s_oft_p;
        void                    far     *       s_clkdev_p;
        void                    far     *       s_condev_p;
        unsigned                int             s_maxlogsec;
        void                    far     *       s_sbs_p;
        struct ldt3     far     *       s_ldt_p;
        void                    far     *       s_fcb_p;
        int                                             s_fcbs;
        unsigned                char            s_logdrv;
        unsigned                char            s_lastdrv;
};
        
        

static
struct dbuf     far     *       buf_p;

static
struct dpb      far     *       dpb_p;

static
struct ldt3     far     *       ldt_p;

static
int                                             onetime = 1;

static
int                                             lastdrive;

static
unsigned int                    dos_major_version;

/*
 * static prototypes
 */
static  void setup_pointers(void );
static  struct ldt3 far *find_drive(int n);

static
char	get_redir_device[128];

static
char	get_redir_info[128];

static void
display_redir_list()
{
	int	index;
   union           REGS                    inregs;
   union           REGS                    outregs;
   struct  SREGS                   segregs;
	char	far	*dev_p;
	char	far	*info_p;

	printf("\n\nGetRedirectionList output:\n\n");
	index = 0;
	dev_p = &get_redir_device[0];
	info_p = &get_redir_info[0];

	while(1) {
		inregs.h.ah = 0x5f;
		inregs.h.al = 2;
		segregs.ds = FP_SEG(dev_p);
		inregs.x.si = FP_OFF(dev_p);
		segregs.es = FP_SEG(info_p);
		inregs.x.di = FP_OFF(info_p);
		inregs.x.bx = index;
		intdosx(&inregs, &outregs, &segregs);
		if (outregs.x.cflag)
			break;
		if(outregs.h.bh & 1)
			printf("Entry %2d: (invalid)\n", index);
		else
			printf("Entry %2d: Type=%02X Status=%02X User=%04X Device=%s\n   Info=%s\n",
				index, outregs.h.bl, outregs.h.bh, outregs.x.cx,
				get_redir_device, get_redir_info);
		index++;
		}
	printf("GetRedirectionList terminated after %2d entries with Error=%04X\n",
		index, outregs.x.ax);
	if(outregs.x.ax == 1)
		printf(" (Network not installed)\n");
	if(outregs.x.ax == 18)
		printf(" (No more entries)\n");

}




/*
 * -- setup_pointers -- setup_pointers -- setup_pointers --
 *
 * setup_pointers()
 *
 */
static void
setup_pointers()
{
        union           REGS                    inregs;
        union           REGS                    outregs;
        struct  SREGS                   segregs;


        inregs.h.ah = 0x30;     /* get dos version */
        intdos(&inregs, &outregs);
        dos_major_version = outregs.h.al;


        inregs.h.ah = 0x52; /* get address of list of lists */
        intdosx(&inregs, &outregs, &segregs);
        FP_OFF(buf_p)   =       outregs.x.bx;
        FP_SEG(buf_p)   =       segregs.es;

        lastdrive = buf_p->s_lastdrv;
        dpb_p = buf_p->s_dpb_p;
        ldt_p = buf_p->s_ldt_p;

        onetime = 0;
}

/*
 * -- find_drive -- find_drive -- find_drive --
 *
 * find_drive(n)
 *
 */
static struct ldt3 far *
find_drive(n)
int n;
{
        struct ldt4 far *p4;


        if (dos_major_version == 3) 
                return(&ldt_p[n]);

        p4 = (struct ldt4 far *)ldt_p;
        p4 = &p4[n];
        return((struct ldt3 far *)p4);
}



main()
{
	int i;
	struct ldt3 far * lp;

	printf("SYS_SCAN 1.0 - display key device info\n\n");
	printf("Logical Drive Table\n\n");

	setup_pointers();
	printf("Home:%04X:%04X LDT:%04X:%04X DPB:%04X:%04X DosMaj=%d LastDrive=%d\n",
		FP_SEG(buf_p), FP_OFF(buf_p),
		FP_SEG(ldt_p), FP_OFF(ldt_p),
		FP_SEG(dpb_p), FP_OFF(dpb_p),
		dos_major_version,
		lastdrive);
	for(i = 0; i < lastdrive; i++) {
		lp = find_drive(i);
		printf("%04X:%04X %c: Flags=%04X=%c%c%c%c DPB:%04X:%04X Seek=%04X ?1=%04X ?2=%04X Subst=%04X\n",
			FP_SEG(lp), FP_OFF(lp), 'A'+i, lp->p_flags,
			(lp->p_flags & NETWORK_DRIVE ? 'N' : '-'),
			(lp->p_flags & VALID_DRIVE ? 'V' : '-'),
			(lp->p_flags & JOINED_DRIVE ? 'J' : '-'),
			(lp->p_flags & SUBST_DRIVE ? 'S' : '-'),
			FP_SEG(lp->p_dpb_p), FP_OFF(lp->p_dpb_p),
			lp->p_seek, lp->p_unknown1, lp->p_unknown2, lp->p_substptr);
		if(lp->p_flags & VALID_DRIVE)
			printf(".... Path=%s\n", lp->p_path);
	}
	display_redir_list();
}
----------------------------------------------------------------------
-- Geoff Arnold, PC-NFS architect, Sun Microsystems. (geoff@East.Sun.COM)   --
   *** "Now is no time to speculate or hypothecate, but rather a time ***
   *** for action, or at least not a time to rule it out, though not  ***
   *** necessarily a time to rule it in, either." - George Bush       ***

richard@calvin.spp.cornell.edu (Richard Brittain - VOS hacker) (10/20/90)

In article <1085@duteca4.UUCP> kooijman@duteca (Richard Kooijman) writes:
>How do you find out what the actual number of drives is on a MS-DOS computer?
>I have programmed a utility like NCD. It searches all disks on the computer
>to build a database of directories. Later this database can be used to switch
>quickly to another directory.

The setdisk() function returns the number corresponding to the LASTDRIVE=
line in config.sys, which defaults to 5 (A-E) if not given.  If your 
definition of "drive" means any logical/physical/virtual/networked/subst/joined
entity that can legally be addressed as a block device, then I recommend
you test all the drives up to the LASTDRIVE= using the ioctl call for
"test for fixed or removable media".  This gives an error code for 
drives which are bogus, and a valid return for all other (real, networked,
virtual, RAM, subst, etc.).  Best of all though, it makes no disc access
to do this, so it is very fast and never trips the critical error interrupt.
I don't have my references handy, but it should be listed in any of the
standard books - it's even documented!.

-- 
Richard Brittain,                   School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853
ARPA: richard@calvin.spp.cornell.edu	
UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard

ted@arsocomvax.socom.mil (Ted Nolan) (10/22/90)

Here's a little program we use from batch files to see if a drive is
valid; with a little modification, it should do what you want.  It
works with MIX C, and presumably with turbo and msc.  It stats a file on
a disk and sees if you would have gotten "abort,retry,ignore".


				Ted Nolan
				ted@usasoc.soc.mil

---------------------------------------CUT HERE-------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <sys\stat.h>

int dstatus = 0;

main(int argc, char **argv)
{
	int harderror(int error, int ax, int bp, int si);
	char path[15];
	struct stat statbuf;

	if( argc != 2) {
		fprintf(stderr,"Usage %s  d\n",argv[0]);
		fprintf(stderr,"Where d is a drive letter\n");
		exit(1);
	}

	sprintf(path,"%s:\\foo\\bar",argv[1]);

	harderr(harderror);
	(void) stat(path,&statbuf);

	exit(dstatus);
}

int harderror(int error, int ax, int bp, int si)
{
	dstatus = 1;
	hardresume(0);
}