home *** CD-ROM | disk | FTP | other *** search
- /*
- MEM.C -- walks DOS MCB chain(s): detailed version
- Andrew Schulman and Jim Kyle, July 1990
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <dos.h>
-
- typedef enum { FALSE, TRUE } BOOL;
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- typedef unsigned long ULONG;
- typedef void far *FP;
-
- #ifndef MK_FP
- #define MK_FP(seg,ofs) ((FP)(((ULONG)(seg) << 16) | (ofs)))
- #endif
-
- #ifdef __TURBOC__
- #define ASM asm
- #else
- #define ASM _asm
- #endif
-
- #ifdef __TURBOC__
- #define GETVECT(x) getvect(x)
- #else
- #define GETVECT(x) _dos_getvect(x)
- #endif
-
- #pragma pack(1)
-
- typedef struct {
- BYTE type; /* 'M'=in chain; 'Z'=at end */
- WORD owner; /* PSP of the owner */
- WORD size; /* in 16-byte paragraphs */
- BYTE unused[3];
- BYTE dos4[8];
- } MCB;
-
- #define MCB_FM_SEG(seg) ((seg) - 1)
- #define IS_PSP(mcb) (FP_SEG(mcb) + 1 == (mcb)->owner)
- #define ENV_FM_PSP(psp_seg) (*((WORD far *) MK_FP(psp_seg, 0x2c)))
-
- void fail(char *s) { puts(s); exit(1); }
-
- BOOL belongs(void far *vec, unsigned start, unsigned size);
- void display(MCB far *mcb);
- char far *env(MCB far *mcb);
- void display_progname(MCB far *mcb);
- void display_cmdline(MCB far *mcb);
- void display_vectors(MCB far *mcb);
- unsigned fstrlen(char far *s);
-
- MCB far *get_mcb(void)
- {
- ASM mov ah, 52h
- ASM int 21h
- ASM mov dx, es:[bx-2]
- ASM xor ax, ax
- /* in both Microsoft C and Turbo C, far* returned in DX:AX */
- }
-
- mcb_chk(MCB far *mcb)
- {
- for (;;)
- if (mcb->type == 'M')
- mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);
- else
- return (mcb->type == 'Z');
- }
-
- void walk(MCB far *mcb)
- {
- printf("Seg Owner Size\n");
- for (;;)
- switch (mcb->type)
- {
- case 'M' : /* Mark : belongs to MCB chain */
- display(mcb);
- mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);
- break;
- case 'Z' : /* Zbikowski : end of MCB chain */
- display(mcb);
- return;
- default :
- fail("error in MCB chain");
- }
- }
-
- main(int argc, char *argv[])
- {
- if (argc < 2)
- walk(get_mcb()); /* walk "normal" MCB chain */
- else
- {
- unsigned seg;
- sscanf(argv[1], "%04X", &seg);
- walk(MK_FP(seg, 0)); /* walk arbitrary MCB chain */
- }
-
- return 0;
- }
-
- void display(MCB far *mcb)
- {
- static void far *vect_2e = (void far *) 0;
- unsigned env_seg;
-
- printf("%04X %04X %04X (%6lu) ",
- FP_SEG(mcb), mcb->owner, mcb->size, (long) mcb->size << 4);
-
- if (IS_PSP(mcb))
- {
- void far *e = env(mcb); /* MSC wants lvalue */
- if (env_seg = FP_SEG(e)) printf("%04X ", env_seg);
- else printf(" ");
-
- display_progname(mcb);
- }
-
- if (! vect_2e)
- vect_2e = GETVECT(0x2e); /* do just once */
- if (! mcb->owner)
- printf("free ");
- /* 0008 is not really a PSP; belongs to CONFIG.SYS */
- else if (mcb->owner == 8)
- printf("config ");
- /* INT 2Eh belongs to master COMMAND.COM (or other shell) */
- else if (belongs(vect_2e, FP_SEG(mcb), mcb->size))
- printf("%s ", getenv("COMSPEC"));
-
- /* presence command line is independent of program name */
- if (IS_PSP(mcb))
- display_cmdline(mcb);
- display_vectors(mcb);
- printf("\n");
- }
-
- char far *env(MCB far *mcb)
- {
- char far *e;
- unsigned env_mcb;
- unsigned env_owner;
-
- /*
- if the MCB owner is one more than the MCB segment then
- psp := MCB owner
- env_seg := make_far_pointer(psp, 2Ch)
- e := make_far_pointer(env_seg, 0)
- else
- return NULL
- */
- if (IS_PSP(mcb))
- e = MK_FP(ENV_FM_PSP(mcb->owner), 0);
- else
- return (char far *) 0;
-
- /*
- Does this environment really belong to this PSP? An
- environment is just another memory block, so its MCB is
- located in the preceding paragraph. Make sure the env
- MCB's owner is equal to the PSP whose environment this
- supposedly is! Thanks to Rob Adams of Phar Lap Software
- for pointing out the need for this check; this is a
- good example of the sort of consistency check one must
- do when working with undocumented DOS.
- */
- env_mcb = MCB_FM_SEG(FP_SEG(e));
- env_owner = ((MCB far *) MK_FP(env_mcb, 0))->owner;
- return (env_owner == mcb->owner) ? e : (char far *) 0;
- }
-
- char far *progname_fm_psp(unsigned psp)
- {
- char far *e;
- unsigned len;
-
- /* is there an environment? */
- if (! (e = env(MK_FP(MCB_FM_SEG(psp), 0))))
- return (char far *) 0;
-
- /* program name only available in DOS 3+ */
- if (_osmajor >= 3)
- {
- /* skip past environment variables */
- do e += (len = fstrlen(e)) + 1;
- while (len);
-
- /*
- e now points to WORD containing number of strings following
- environment; check for reasonable value: signed because
- could be FFFFh; will normally be 1
- */
- if ((*((signed far *) e) >= 1) && (*((signed far *) e) < 10))
- {
- e += sizeof(signed);
- if (isalpha(*e))
- return e; /* could make canonical with INT 21h AH=60h */
- }
- }
-
- return (char far *) 0;
- }
-
- void display_progname(MCB far *mcb)
- {
- char far *s;
- if (IS_PSP(mcb))
- if (s = progname_fm_psp((FP_SEG(mcb) + 1)))
- printf("%Fs ", s);
- }
-
- BOOL belongs(void far *vec, unsigned start, unsigned size)
- {
- unsigned seg = FP_SEG(vec) + (FP_OFF(vec) >> 4); /* normalize */
- return (seg >= start) && (seg <= (start + size));
- }
-
- void display_cmdline(MCB far *mcb)
- {
- /*
- psp := MCB owner
- cmdline_len := psp[80h]
- cmdline := psp[81h]
- print cmdline (display width := cmdline_len)
- */
- int len = *((BYTE far *) MK_FP(mcb->owner, 0x80));
- char far *cmdline = MK_FP(mcb->owner, 0x81);
- printf("%.*Fs ", len, cmdline);
- }
-
- void display_vectors(MCB far *mcb)
- {
- static void far **vec = (void far **) 0;
- WORD vec_seg;
- int i;
- int did_one=0;
-
- if (! vec)
- {
- if (! (vec = calloc(256, sizeof(void far *))))
- fail("insufficient memory");
- for (i=0; i<256; i++)
- vec[i] = GETVECT(i);
- }
-
- for (i=0; i<256; i++)
- if (vec[i] && belongs(vec[i], FP_SEG(mcb), mcb->size))
- {
- if (! did_one) { did_one++; printf("["); }
- printf("%02X ", i);
- vec[i] = 0;
- }
- if (did_one) printf("]");
- }
-
- unsigned fstrlen(char far *s)
- {
- #if defined(_MSC_VER) && (_MSC_VER >= 600)
- return _fstrlen(s);
- #else
- unsigned len = 0;
- while (*s++)
- len++;
- return len;
- #endif
- }
-
-