34

I have this MS-DOS 6.22 machine which maps a network drive to a SAMBA share on a Raspberry PI. The PI is powered by a USB lead from the DOS machine, so the two power up together.

The mapping starts when this happens near the end of AUTOEXEC.BAT

net logon samba mypassword /yes

As you can imagine there is a bit of a race with both computers booting up, and often the mapping will be attempted before Samba is ready.

Googling for "delay in batch file" gives links like this, but quickly going through the options:

  • PAUSE - needs a key-press, no keyboard is attached on site
  • SLEEP - not in this version of DOS
  • TIMEOUT - ditto
  • PING 127.0.0.1 -n 10 - this ping ignores -n

The other suggestions listed are all for Windows.

How can I put a delay in, or otherwise wait for Samba to become ready?

(It may be possible to get the PI to boot quicker - that's off topic here but if there's interest in that I'll open another question over here)

3
  • Does your version of NET.EXE know the DIAG command? Then you can do something like NET DIAG /PING localhost which consumes about 5 seconds.
    – tofro
    Nov 10, 2018 at 16:42
  • 15
    If the net logon command returns an error value then you should be able to access it in %ERRORLEVEL%, and then you can do a goto loop that goes on until it succeeds.
    – Tomas By
    Nov 10, 2018 at 17:28
  • 1
    Can you make the DOS machine do a full/slow/longer memory test on boot to delay it?
    – Criggie
    Nov 11, 2018 at 1:38

8 Answers 8

58

Since you are using MS-DOS 6.22 you can abuse the CHOICE command to introduce a set timed delay by piping the output of a REM statement to the choice command, leaving it with no way to complete other than via the /T timeout option.

Example from Rob van der Woulde's Scripting Pages:

REM | CHOICE /C:AB /T:A,10 >NUL

The CHOICE command never actually gets to complete with either of the choices defined with the /C parameter because the piped input is a REM statement. Instead, it will wait for the defined /T timeout parameter (in seconds) to elapse.

This command is available natively in MS-DOS 6 through MS-DOS 7, and is also available for use in Windows NT 4, 2000, and XP if you install the Windows NT 4 Resource Kit.

9
  • 12
    That's ridiculously clever.
    – Geo...
    Nov 10, 2018 at 19:19
  • 4
    Isn't REM used for comments? Why isn't the whole line ignored?
    – isanae
    Nov 10, 2018 at 21:52
  • 2
    Oh no: "if the line contains a pipe (|) or redirection (<, >, >>) symbol, everything up to the symbol is ignored BUT the symbol itself and everything following is interpreted as a command line entry"
    – isanae
    Nov 10, 2018 at 21:57
  • 15
    @isanae It works because COMMAND.COM treats REM as a full normal command to be executed, so its output can be redirected normally. This won't work under CMD.EXE as it actually treats everything after the REM as a comment the way you'd expect it to. To do this trick in CMD.EXE (like under Windows XP with the NT4 Resource Kit installed), you'd have to use "TYPE NUL | CHOICE ..." instead.
    – mnem
    Nov 10, 2018 at 23:27
  • 1
    Playing with this on win7 without extensions: (i) the syntax has changed, to require the default and timeout separately CHOICE /C:AB /D:A /T:10 (ii) piping TYPE NUL to CHOICE gives "ERROR: The file is either empty or does not contain the valid choices." But without piping TYPE NUL you can still get a delay. (just in case anyone is playing on modern systems)
    – Chris H
    Nov 12, 2018 at 10:32
14

If you do any programming, it would probably be trivial to create a small C executable that calls Sleep() to pause the thread for a specified timeout. However, it stands to reason you are not the first person to need such a tool.

Some very quick googling turned up this page: https://www.computerhope.com/dutil.htm which, if you scroll down, offers a Sleep.exe that will work on MS-DOS 5.x or higher. I am not endorsing this page or the Sleep.exe utility it hosts; if it deletes your hard drive, don't blame me. ;-)

4
  • 1
    Yeah I've been to that page - I think I was running out of time or something. I've just tried building it from source as per computerhope.com/rdebug.htm and it seems to work under freeDOS at least. As for building a C program - clearly it's a one liner but not sure how "trivial" it is getting set up with a tool chain - and whether the supplied libraries would include the sleep() function - is not too clear.
    – Rodney
    Nov 10, 2018 at 17:14
  • 2
    I never did a lot of DOS programming back in the day (I was an Amiga guy and didn't have much good to say about anything PC related); but I remember having Borland C++ 2.0 installed and doing some simple command line stuff. As I remember it, install and the make process were dirt simple. You might try starting there if you want to roll your own. - but mnem's idea about abusing the CHOICE command is a pretty cool hack.
    – Geo...
    Nov 10, 2018 at 19:23
  • 2
    not sure how "trivial" it is getting set up with a tool chain ... MS-DOS 6.22 contains two tools that could be useful: QBasic (which can run a program from the command line with the QBASIC /RUN FILENAME.BAS option) or DEBUG.EXE which can be used to generate a .COM file from assembly source code; the answers to this question can be used to write an appropriate program using this tool -- see this page for details on how to use it.
    – Jules
    Nov 11, 2018 at 23:32
  • See my answer for a DEBUG.COM solution.
    – Artelius
    Nov 13, 2018 at 0:55
8

tl;dr you can create a tiny text file, and use a tiny comes-with-DOS utility to do this.

There's a lovely utility called DEBUG.COM which I believe is included in every version of DOS, that lets you turn assembly language instructions into machine code, shove them into memory, and execute them. It's very lightweight—early versions of DEBUG were about 7kb ;)

The BIOS provides a "system call" to get current system time; details are here or here. So you can construct a loop that checks this over and over until a certain number of seconds have passed.

Here is how you do it:

A
xor ax, ax  ; zero out ax
int 1a      ; timer -> DX
mov bx, dx  ; initial timer value -> BX
hlt         ; don't waste CPU cycles
xor ax, ax  ; zero out ax
int 1a      ; timer -> DX
sub dx, bx  ; elapsed time -> DX
cmp dx, 222 ; THIS IS IN HEX! 0x222 = 546 == 30 seconds * 18.2 ticks per second
jl 0106     ; if not enough elapsed time repeat loop
ret ; return control to DEBUG.COM

U 0100 0120
G =0100
q

Save this to a file (e.g. DELAY.TXT) and put the following into your AUTOEXEC.BAT:

DEBUG <DELAY.TXT

This will assemble and run the code every time you boot.

The U command is just for debugging purposes - it disassembles what previously went into RAM. You can remove it. The A command actually does the assembly, and the G command means "go".

Adjust the 222 to however much time you need. It is in hex, and needs to be the number of seconds * 18.2 because that is the clock frequency.

This method allows you to add any functionality you want—break on keyboard input, keep trying to open a network file in a loop, display a countdown timer... there's an interrupt (BIOS or DOS function) for reading from the keyboard, another for reading a file, another for printing a string.

1
  • 1
    This is quite clever, a small com file was what I was considering but building a custom one on the fly adds another dimension of sneakiness :-) You could even put the creation and running of the file into a batch function which accepted the number of seconds and turned that into a tick count each time. Then it's simply call :delay 10 from your user code.
    – user6464
    Nov 16, 2018 at 0:47
3

I'm not sure if the version of the NET command you're using returns meaningful error codes, but if it does you can use something like this in your AUTOEXEC.BAT:

net logon samba mypassword /yes
if NOT ERRORLEVEL 1 goto :noerror
net logon samba mypassword /yes
if NOT ERRORLEVEL 1 goto :noerror
net logon samba mypassword /yes
if NOT ERRORLEVEL 1 goto :noerror
:noerror

Repeat the first two lines as many times as necessary to ensure enough attempts are made.

4
  • 6
    It might be better to place the 'noerror' label before the 'net logon' line, then reverse the comparison (if errorlevel 1 goto :start) so that the code loops until errorlevel is not equal to 1. This is better than 'repeat the first two lines as many times as necessary'. I am assuming that goto can jump backwards as well as forwards. Nov 11, 2018 at 8:47
  • @No'amNewman The goto statement can't jump backwards under MS-DOS. It would be possible to implement something tries as many times as necessary by creating a batch file that invokes itself, but it's not clear that would be desirable. It's probably better that it give up after a certain number of tries, and this is the easiest way to do that under MS-DOS.
    – user722
    Nov 11, 2018 at 16:08
  • 4
    @RossRidge I did a lot of batch work back in the day, and it required making my own loops with GOTO command. You could definitely go backwards with GOTO at least by MS-DOS 6.22.
    – trlkly
    Nov 11, 2018 at 17:45
  • @trlkly Ah, your right. In any case, I still think it would be undesirable to keep trying indefinitely.
    – user722
    Nov 11, 2018 at 17:48
2

What I actually would try is to check if the device you're connecting to is available.

You can try something like this:

:reset
ping 127.0.0.1

IF NOT ERRORLEVEL 1 net logon samba mypassword /yes

IF ERRORLEVEL 1 goto :reset

This way, it will ping the machine until it is available and will try to mount the share.

If it fails, it will keep trying until it mounts successfully.


This way, the autoexec.bat won't do anything else until the required server is up and guarantees that the share is mounted.

This means that, if, for example, the Pi takes 2-3 more seconds to boot (due to, say, updates or whatever), the share will still mount.

You don't need to guestimate how long it will take to boot and have the service started in the Pi.

One thing you can also do, with this method, is to count how many times the net logon command failed and ask for a decision or abort with a message to run the command later.

5
  • The only problem is the Pi will start responding to pings before the Samba server is available.
    – JeremyP
    Nov 13, 2018 at 16:08
  • I know. That's why the net logon command will only run if and only if the Pi responded, and will re-try if it failed to mount. This means that the ping will happen again and will give some delay before the next try. It will leave from there if the mounting succeeded, since IF ERRORLEVEL 1 will be "false". This means that the goto :reset will happen if the ping failed or the net logon failed. So, it really isn't that much of an issue since it will just keep trying to mount and ping until it mounts. Nov 13, 2018 at 16:14
  • Yes, and this has been suggested in a few of the comments. I would replace ping in this solution with a short delay, and yes it would have to abort after a certain number of retries, otherwise the PI becomes a single point of failure for a machine with expensive downtime. You know how to implement a retry count in a batch file? A reminder there is no keyboard except when we are there servicing it... Maybe that's a whole new question
    – Rodney
    Nov 13, 2018 at 16:32
  • Aparently, there's the FOR /L %%parameter IN (start,step,end) DO command syntax (ss64.com/nt/for_l.html) but I can't find anything about it existing or not in MS-DOS. I presume it does, since I didn't found anything saying it doesn't. If this works, you can just jump out of the for with another goto in case the mount succeeds. Nov 13, 2018 at 16:41
  • @IsmaelMiguel That's in the nt section of ss64.com, which isn't a good sign. However, I can confirm that FOR exists in MS-DOS 6.22.
    – wizzwizz4
    Nov 13, 2018 at 17:20
1

There's a DOS version of perl 4 that fits on a floppy. It is the handiest thing.

Perl is a scripting language designed to replace and extend shell scripting on Unix, which is itself more powerful than shell scripting in DOS (such as autoexec.bat). You can use for just that, except it's literally designed to save you from that moment where you say "I can't quite do this in shell". When you need a little more, it extends and extends clear up into a proper computing language. Perl 5 even has OO.

Obviously C:\perl4\perl.exe -e "sleep 10" is no trouble at all, but you can do a lot of other stuff.

Once, we were doing a network rollout with 50 machines with Win3.1 and a third party IP stack or WFW3.11, the former did not support DHCP, so IP addresses were hardcoded into /wherever/etc/hosts. It was on me to change all the config and hosts files. On the same weekend as an unmissable festival. I used perl 4 to make a boot floppy that would find and read the config and hosts file, and rewrite it with corrected IPs. Gave my staff 20 of those disks... and said "power up the machine with this floppy in". Made sure they all could boot a floppy. I was sure it would work, and it did. Great festival!

1
  • 3
    or use on-board stuff, e.g. Qbasic.exe (which can be called with /RUN to execute a source immediately, and also has a "sleep" command )
    – Tommylee2k
    Nov 12, 2018 at 11:01
1

Many DOS PCs have the Norton Utilities suite of software installed. Norton Utilities includes a program called "Batch Enhancer" (BE.EXE) that includes a number of facilities for use from batch files, including delays.

If you have this utility, you can add a delay like this:

BE DELAY nn

where nn is the length of the delay in units of 1/18.2 of a second.

0

I used to (ab)use PING.exe to solve this, I'm not aware of any Windows without this.

ping 127.0.0.1 -w 1000 -n 3 > null

Oops just read the question and notice -n is ignored. Obviously you could put it into a FOR loop and deal with multiples of 4.

2
  • Can you show how to do a for loop in AUTOEXEC.BAT? Nov 13, 2018 at 11:34
  • 1
    MS-DOS 6.22 does not natively come with a PING utility. If you are accessing a SAMBA share using NetBIOS rather than TCP/IP you may not even have an IP stack loaded at all.
    – Ken Gober
    Nov 13, 2018 at 15:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .