23

On my systems that are running MS-DOS, I change the default command.com to 4DOS for more features.

How was the shell system designed and how did it with the operating system in MS-DOS that it enabled you to swap in a different one?

  • 1
    en.wikipedia.org/wiki/COMMAND.COM Short answer is that there is an API for DOS commands to talk to the OS, and command.com is also a chunk of not easily relocatable code that was launched by the boot process so that it could, in turn, be the parent of every program launched from that point on. Both of these operations are very well known, which leads to easy drop-in replacements. – user12 Apr 26 '16 at 19:22
43

Traditionally, operating shells are relatively independent of the operating system’s function and the operating system can operate without a shell. Most shells have two modes of operation, interactive mode where they manage the command line and execute commands entered interactively, and batch mode where they run scripts. They’re “standard” programs which handle whatever the input and output system is, and provide their features with no extra special sauce.

In DOS, the “kernel” is provided by two files, typically IO.SYS and MSDOS.SYS (or IBMBIO.COM and IBMDOS.COM). These are loaded at boot-up; they read CONFIG.SYS for configuration, and once all the device drivers have loaded and initialised, they load the shell and start running it. By default the shell is COMMAND.COM on the boot disk, but this can be overridden by the SHELL directive in CONFIG.SYS.

In theory you’d expect the IO and DOS portions of the kernel to provide the “real” operating system, and then COMMAND.COM to follow the standard model of shell design on top of that, but in DOS the distinction between the three parts of the core operating system aren’t as well delineated as you might hope. Because of the way DOS works, with no protection between processes, and using fairly well-documented (or reverse-engineered) functions via the 0x21 interrupt, operating system functions could be implemented in various places, and extended by any number of programs, so the “kernel”, command interpreter and extension TSRs ended up constituting a closely-tied ecosystem... Over the course of its history, DOS ended up relying on COMMAND.COM for certain features, and some of the features DOS provided to COMMAND.COM ended up being extended in ways users expected to find; replacement DOS shells had to provide the former, and ideally respect the latter.

Some examples will hopefully help understand the kinds of issues involved better.

  • COMMAND.COM uses a DOS function, 0x210A (“Buffered Keyboard Input”), to read command lines; as standard this provides basic command-line editing capabilities (move the cursor around, insert/delete handling, and F3 command recall), but many TSRs were available to extend this: CMDEDIT, DOS 5's own DOSKEY... As an added subtlety, starting with DOS 3.3, function 0x210A indirectly checked the passage of time to handle midnight — imagine you left a DOS computer sitting at the command prompt overnight; whose job is it to notice that the date has to change? Obviously it’s the operating system’s responsibility, but in single-tasking DOS this required the co-operation of whatever software was running. DOSKEY hooked 0x210A to provide its enhanced command-line handling (adding history), and re-implemented most of the time-related features — but it does not handle midnight, so a DOS 5 computer running DOSKEY can lose a day if it’s sitting at the command prompt at midnight.
  • COMMAND.COM allows other programs to run its internal commands (in DOS, even commands such as DIR and COPY are implemented in the command processor); replacement shells ideally need to implement this too. Some third-party programs used this to call internal commands or even add new internal commands to DOS, so replacement shells need to support the same mechanism (interrupt 0x2E — invoking this allows internal commands to be run from outside the shell, and hooking this allows internal commands to be added — and the installable command functions 0x2FAE¹).
  • COMMAND.COM installs a CtrlC/CtrlBreak handler and a critical error handler, and replacement shells should do this too.
  • COMMAND.COM splits itself into multiple sections: one (small part) for the primary shell, which is always resident (and accessed via function 0x2F55), one containing initialisation code, and finally the so-called transient part which implements most of the functionality. The transient part isn’t needed during execution of other programs (unless they call interrupt 0x2E...), so to provide more memory for applications, it is designed so that it can remain in memory opportunistically without using any allocated memory. The way this works is that it is relocated to the top of memory (with hooks so the other parts of COMMAND.COM can find it), with some sort of signature. Programs which run without using much memory won’t overwrite any of this, and when COMMAND.COM regains control, it checks its transient portion and can then just reuse it without reloading anything. Programs which use enough memory will overwrite the transient portion; when COMMAND.COM regains control, it notices this and reloads its transient portion from disk (which may involve swapping floppies; the COMSPEC variable was used to point COMMAND.COM to the right file).
  • In MS-DOS 1.x, program loading is implemented in COMMAND.COM, so anything related to that also lives in COMMAND.COM — for example, interrupt 0x27 (“Terminate and Stay Resident”)!

Most of this was documented at the time, and what wasn’t was quickly discovered. Nowadays you can read the source code for FreeCOM or 4DOS, or even MS-DOS itself, if you’re curious to see exactly how a DOS shell works...


¹ See this PC Magazine Tutor article, “Replacing internal DOS commands”, for details.

  • 6
    You can download the MS-DOS 1.1 and 2.0 source code from computerhistory.org/atchm/microsoft-ms-dos-early-source-code (yes, completely legally!). That includes the command interpreter (what once compiled became command.com). – a CVn Dec 19 '16 at 19:47
  • "no protection between processes" - well... DOS didn't even have the concept of processes (plural). It was a single-task O/S. DOS extenders could allow you to run concurrent tasks. Even Windows 3 was still essentially single-user, single-tasking (concurrently running programs had to co-operatively multi-task i.e. periodically explicitly yield to the O/S to allow other tasks to run). Because of all this, there was no real need to clearly separate the layers, and you could directly work with devices via TSRs. It allowed for all kinds of messy but expedient stuff. – Anthony X Sep 29 at 3:02
  • @Anthony DOS does have the concept of processes (plural). You can see them for example with MEM /D. Processes aren’t only useful with multi-tasking systems; as soon as you want to allow program A to start a program B, and resume execution when B finishes, with some level of resource management, you need some concept of processes. – Stephen Kitt Sep 29 at 16:27
  • Perhaps it depends on your definition of "process". Defined as an isolated, secure memory space, what DOS offered does not qualify because any program could read or write any location in physical memory and perform any I/O operation. If defined as an allocated region of physical memory with CPU registers (stack pointer, PC, etc.) suitably initialized, then OK. – Anthony X Sep 29 at 16:47
  • @Anthony yes, the latter, which is exactly why I wrote “no protection between processes” ;-). – Stephen Kitt Sep 29 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.