dosutils: add maintainer helpers and compare-ready tools

Add maintainer-only support used by the automated DOS compatibility
tests.

This introduces the MAINTAINER_BUILD option for the DOS tools. In
maintainer builds, LOGIN accepts the hidden /PWD: and /PASSWORD:
arguments for automated test relogin, and the DLYSTRT helper is built to
delay-start DOS batch files after the invoking batch has returned to the
prompt.

Add the WHOAMI utility and wire it into the NET command dispatch. Also
adjust SLIST and RIGHTS output to match Novell behavior more closely,
including server-not-found handling, path formatting, Supervisor rights,
missing-path errors and usage text.

Extend the test scripts to compare NPUBLIC Novell baselines against the
PUBLIC implementations. LOGIN/LOGOUT can now run automatically via
DLYSTRT and the maintainer LOGIN password option. RIGHTS gains an
additional NOPASSUSER effective-rights matrix that covers single rights,
mixed rights, Supervisor rights, ALL/N and file trustee cases.

Normal builds remain free of maintainer-only helpers and hidden password
handling.
This commit is contained in:
Mario Fetka
2026-05-27 20:14:01 +02:00
parent f214e89d69
commit 4ad455c6df
21 changed files with 1704 additions and 322 deletions

173
dlystrt.c Normal file
View File

@@ -0,0 +1,173 @@
/* dlystrt.c - maintainer-only delayed DOS command starter.
*
* This is a tiny TSR helper for login/logout tests. It waits a short
* time, then stuffs a command line into the BIOS keyboard buffer. The
* command is therefore executed by the command processor after the batch
* file that installed DLYSTRT has already returned to the DOS prompt.
*
* Example:
* DLYSTRT /T:2 C:\\LGNTC.BAT
*
* The tool is intended for MAINTAINER_BUILD only and is not installed in
* normal builds.
*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <i86.h>
#ifndef MAINTAINER_BUILD
int main(void)
{
puts("DLYSTRT is only available in maintainer builds.");
return 1;
}
#else
#define MAX_CMD 126
#define BIOS_SEG 0x0040
#define KB_HEAD 0x001a
#define KB_TAIL 0x001c
#define KB_BUF 0x001e
#define KB_END 0x003e
typedef void (__interrupt __far *intr_fn)(void);
static intr_fn old_int1c;
static volatile unsigned wait_ticks;
static volatile unsigned pos;
static volatile unsigned done;
static char command[MAX_CMD + 3];
static int strnicmp_local(const char *a, const char *b, int n)
{
int ca, cb;
while (n-- > 0) {
ca = toupper((unsigned char)*a++);
cb = toupper((unsigned char)*b++);
if (ca != cb || ca == 0 || cb == 0) return ca - cb;
}
return 0;
}
static int kb_put_char(char ch)
{
unsigned far *headp = (unsigned far *)MK_FP(BIOS_SEG, KB_HEAD);
unsigned far *tailp = (unsigned far *)MK_FP(BIOS_SEG, KB_TAIL);
unsigned far *bufp;
unsigned head = *headp;
unsigned tail = *tailp;
unsigned next = tail + 2;
if (next >= KB_END) next = KB_BUF;
if (next == head) return 0; /* keyboard buffer full */
bufp = (unsigned far *)MK_FP(BIOS_SEG, tail);
*bufp = (unsigned)((unsigned char)ch); /* scan code 0, ASCII ch */
*tailp = next;
return 1;
}
static void raw_restore_vector(void)
{
intr_fn __far *vecp;
if (!old_int1c) return;
/* Do not call DOS from the timer interrupt. Restore the IVT entry
* directly, then leave the TSR out of the interrupt path before the
* delayed command is executed.
*/
_disable();
vecp = (intr_fn __far *)MK_FP(0x0000, 0x1c * 4);
*vecp = old_int1c;
_enable();
}
static void __interrupt __far dly_int1c(void)
{
intr_fn prev = old_int1c;
if (!done) {
if (wait_ticks) {
wait_ticks--;
} else {
if (command[pos]) {
if (kb_put_char(command[pos])) pos++;
} else {
/* One-shot: unhook before pressing Enter so the command that gets
* started by COMMAND.COM runs without DLYSTRT still sitting on INT 1Ch.
*/
done = 1;
raw_restore_vector();
kb_put_char('\r');
}
}
}
if (prev) prev();
}
static void usage(void)
{
puts("Usage: DLYSTRT [/T:seconds] command [args]");
puts("Maintainer helper: delay-start a command after returning to DOS.");
}
static void build_command(int argc, char **argv, int first)
{
int i;
command[0] = '\0';
for (i = first; i < argc; i++) {
if (command[0]) strncat(command, " ", MAX_CMD - strlen(command));
strncat(command, argv[i], MAX_CMD - strlen(command));
}
command[MAX_CMD] = '\0';
}
int main(int argc, char **argv)
{
unsigned seconds = 2;
int first = 1;
unsigned paras;
if (argc < 2) {
usage();
return 1;
}
if (!strnicmp_local(argv[first], "/T:", 3)) {
seconds = (unsigned)atoi(argv[first] + 3);
if (seconds == 0) seconds = 1;
first++;
}
if (first >= argc) {
usage();
return 1;
}
build_command(argc, argv, first);
wait_ticks = seconds * 18;
pos = 0;
done = 0;
old_int1c = _dos_getvect(0x1c);
_dos_setvect(0x1c, dly_int1c);
printf("DLYSTRT installed: %s\n", command);
/* Keep a small fixed amount resident. This maintainer helper is tiny;
* 256 paragraphs = 4 KiB is enough for code, data and the command buffer
* in the small DOS model used here.
*/
paras = 256;
_dos_keep(0, paras);
return 0;
}
#endif /* MAINTAINER_BUILD */