# DOSINST – install programs from an FTP server Wiki: https://wiki.teletypegames.org/others/dosinst DOSINST installs, updates and removes programs on DOS machines from a read-only FTP share. Every folder in the share is one program, described by its `INFO.INI`. DOSINST lists them with the server's and the installed version, and copies the folder you pick to the local disk. There are two builds of the same source: `DOSINST.EXE` for DOS (mTCP over a packet driver) and `DOSINSTW.EXE` for Windows 95 and later (Winsock, in a console window). They look and work the same; DOSINSTW is for Windows machines, where a DOS program does not reach the network. ![DOSINST program list](screenshot.png) ## The FTP share ``` /APPS/ (PATH in DOSINST.CFG) HELLO/ INFO.INI <- name, description, version FILES.LST <- optional: CRC32 and size of every file (server/mkfiles.sh) HELLO.EXE DATA/LEVEL1.DAT <- subfolders are copied too OTHER/ INFO.INI ... ``` ```ini [program] name=Hello World description=The description, in one line. version=1.0 platform=DOS ``` - Folders without an `INFO.INI` are skipped. - `platform` is optional: `DOS` or `WIN32`. DOSINST.EXE does not list `WIN32` programs; DOSINSTW lists both, since Windows runs DOS programs too. - File and folder names must be DOS 8.3 names (`HELLO.EXE`, not `hello-world.exe`). DOSINST stops with an error when it finds another name. - `FILES.LST` (`crc32 size path` per line) lets DOSINST check every download. `server/mkfiles.sh FOLDER` writes it; run it whenever the folder changes. Without it, DOSINST checks only the size, with the FTP `SIZE` command. - The server must allow passive mode (`PASV`). DOSINST connects to the data port on the server's own address and ignores the address in the PASV reply, so it also works behind NAT. ## Installing, updating, removing - **Install**: the folder is first downloaded to `_DINEW` next to the target folder and every file is checked (CRC32 and size from `FILES.LST`, or the size). Only when all of it arrived intact are the files moved to `DEST\`, `INFO.INI` last. A broken or interrupted download leaves the installed program as it was. - **Update**: if the installed `INFO.INI` has a different version than the server's, the program is shown as `UPDATE`. Installing again replaces its files. `INSTALL.LST` in the program's folder lists what DOSINST installed, so an update deletes the files the new version no longer has; files that exist only locally (saves, settings) are kept. - **DOSINST itself**: the store's `DOSINST` folder is the DOS build and `DOSINSTW` the Win32 build; each build lists only its own. It is installed into the folder of the running executable (not `DEST`), so DOSINST shows and installs its own updates; `DOSINST.CFG` is never overwritten, and DOSINST does not remove itself. Start it again after an update. Windows does not let a running program be overwritten, so DOSINSTW moves the new executable in as `DOSINSTW.NEW`; when DOSINSTW exits, `DOSINSTW.NEW /REPLACE` waits for it and copies itself over `DOSINSTW.EXE`, and the next start deletes `DOSINSTW.NEW`. - **Remove**: deletes `DEST\` with everything in it. - A program that is installed but no longer on the server is shown as `local only`; it can be removed. ## Usage ``` DOSINST menu DOSINST LIST list the programs DOSINST INSTALL folder install or update a program DOSINST REMOVE folder remove an installed program ``` Keys in the menu: Up/Down/PgUp/PgDn/Home/End select, **Enter** installs or updates, **Del** removes (asks first), **F5** reloads the list, **Esc** quits. Ctrl+Break stops a running transfer. ## Settings: DOSINST.CFG `DOSINST.CFG` is read from the folder of `DOSINST.EXE`. | Key | Default | | |---|---|---| | `SERVER` | – | FTP server name or IP address (required) | | `PORT` | `21` | | | `USER`, `PASSWORD` | `anonymous`, `dosinst@` | | | `PATH` | `/APPS` | folder on the server that holds the program folders | | `DEST` | `C:\APPS` | programs are installed to `DEST\` | ## Network setup DOSINST needs a packet driver and the mTCP configuration (`MTCPCFG`, filled in by mTCP's `DHCP.EXE`). **DOSBox Staging** (`C:\MTCP` holds mTCP and the Crynwr `NE2000.COM`): ``` [ethernet] ne2000 = on [autoexec] C:\MTCP\NE2000.COM 0x60 3 0x300 > NUL SET MTCPCFG=C:\MTCP\MTCP.CFG C:\MTCP\DHCP.EXE ``` From DOSBox the Mac is `10.0.2.2`; only connections started from DOS work, which is all DOSINST needs. **A real machine** needs the packet driver of its own network card instead of `NE2000.COM`, then the same `MTCPCFG` and `DHCP.EXE` lines. DOSINST.EXE does not work in a DOS window of Windows 95/98, because Windows owns the network card there: use `DOSINSTW.EXE` there, which needs nothing but Windows' own TCP/IP. ## The server The store is the `APPS` folder of the Teletype Games FTP server, `ftp://ftp.teletypegames.org/APPS` ([infra/ftp-server](https://git.teletypegames.org/infra/ftp-server)): anonymous, read-only, passive mode only. Ports: `21` (control) and `30000-30019` (passive data). DOSINST connects to the data port on the server's own address, so it needs no masquerading. A tag of a program's repository publishes it there (its pipeline's `store` step, `/srv/stacks/ftp-server/root/APPS` on the server). By hand: copy the folder into `/srv/stacks/ftp-server/root/APPS/` and run `server/mkfiles.sh` on it; no restart is needed. The root of the server has only `APPS` and `WIKI`. A DOSINST older than 0.6.0 has `PATH=/` in its `DOSINST.CFG`, which an update never changes: set `PATH=/APPS` in it by hand. ## Building The build needs [Open Watcom v2](https://github.com/open-watcom/open-watcom-v2) (the `ow-snapshot.tar.xz` release has macOS and Linux binaries). Unpack it to `~/.local/opt/watcom`, or set `WATCOM`, then: ```sh SOURCE/build.sh ``` It builds both executables from the same layers; only the platform under them differs: | | DOS: `DOSINST.EXE` | Win32: `DOSINSTW.EXE` | |---|---|---| | Code | 16-bit, 8086, large model | 32-bit, 386, Windows 95 and later | | Entry | `SOURCE/main_dos.cpp` | `SOURCE/main_win32.cpp` | | Network | mTCP (`SOURCE/MTCP`) over a packet driver: `platform/dos/mtcp_network` | Winsock 1.1: `platform/win32/winsock_network` | | Screen, keys | video memory, BIOS (`lib/platform/dos`) | a console screen buffer of its own (`lib/platform/win32`) | ## Structure The code is in layers; each one uses only the ones below it, and only through their interfaces (`SOURCE/lib/tools/check_layers.py` checks the includes): | Folder | Layer | |---|---| | `SOURCE/model` | The data and its rules, no I/O: `Program`, `ProgramList`, `Manifest` (FILES.LST), `InstallList` (INSTALL.LST), `Config`, `BuildProfile` (what differs between the DOS and the Win32 build). | | `SOURCE/repository` | Interfaces of the storage: the store on the server (`RemoteProgramRepository`), the installed programs, the staging area of an install, the configuration. Their implementations: `repository/ftp` (the store over FTP) and `repository/fs` (the disk). | | `SOURCE/service` | What DOSINST does: `CatalogService` (the program list), `InstallService` (download, check, replace, delete the stale files, update itself), `RemoveService`. | | `SOURCE/controller` | The menu (`MenuController`) and the command line (`CliController`): keys and commands become service calls. | | `SOURCE/view` | The menu screen and the command line output. | | `SOURCE/platform` | DOSINST's own ports (`SelfUpdater`, `exeDir`) and their DOS / Win32 implementations, the network adapters. | | `SOURCE/app` | `runDosinst`: puts the layers together for a machine. | | `SOURCE/lib` | DOSLIB, shared with [GMENU](https://git.teletypegames.org/dos/gmenu): strings, INI, CRC-32, the FTP client, the screen and the keyboard, the file system, the test helpers. | The rules of the code (C++98 for Open Watcom, interfaces, names, format) are in `SOURCE/lib/README.md`. ## Tests `SOURCE/test/unit/run.sh` runs the unit tests on the host with its C++ compiler: every layer above the platform, on a fake store and an in-memory disk (the catalog, an install with a bad checksum, an update that deletes the stale files, a self update with a locked executable, the menu with scripted keys). It needs no DOSBox and checks the layers first. ```sh SOURCE/test/unit/run.sh # all SOURCE/test/unit/run.sh install # the tests with "install" in their name ``` `SOURCE/test/run.sh` serves `SOURCE/test/repo` as `APPS` with `SOURCE/test/ftpserver.py` on the host (needs `pip install pyftpdlib`) and runs DOSINST.EXE in a headless DOSBox Staging: it lists, installs, updates and removes programs from the command line and from the menu, checks the copied files byte by byte, breaks a download on purpose and updates DOSINST itself. The menu is tested with a test build (`build.sh test`) that takes its keys from `TESTKEYS` and saves the screen when they run out. `SOURCE/test/runw32.sh` does the same with DOSINSTW.EXE under Wine, from the command line. ```sh PYTHON=/path/to/python-with-pyftpdlib SOURCE/test/run.sh PYTHON=/path/to/python-with-pyftpdlib SOURCE/test/runw32.sh # needs Wine ``` To try it against a local server, start `FTP_ROOT=SOURCE/test/repo python3 SOURCE/test/ftpserver.py` and set `SERVER=10.0.2.2`, `PORT=2121` and `PATH=/` in `DOSINST.CFG`. ## Releases Woodpecker (`.woodpecker.yaml`) builds and tests every push: `scripts/ci-toolchain.sh` installs the pinned Open Watcom, DOSBox Staging and clang-format, and Wine, into a Debian image, `scripts/ci-check.sh` checks the code style and the layers and runs the unit tests, `scripts/ci-build.sh` builds both executables, `scripts/ci-test.sh` runs `SOURCE/test/run.sh` and `SOURCE/test/runw32.sh`. A `vX.Y.Z` tag, which has to match `Version` in `SOURCE/app/version.h`, also publishes a Gitea release with `RELEASE_NOTES.md` as its text and four files: `DOSINST-vX.Y.Z.zip` and `DOSINSTW-vX.Y.Z.zip` (the folders to install on DOS and on Windows) and `DOSINST.EXE` and `DOSINSTW.EXE` (to update an installed one by hand). The same tag puts both builds into the store (the `DOSINST` and `DOSINSTW` folders) (`scripts/ci-store.sh`, the `store` step, which needs the repository trusted for volumes), so installed copies update themselves. The upload (`scripts/ci-upload.sh`) uses the `gitea_token` repository secret, or Woodpecker's forge credential when there is one. ```sh git tag v0.1.0 git push origin v0.1.0 ``` ## License DOSINST uses the [mTCP](http://www.brutman.com/mTCP/) TCP/IP library by Michael B. Brutman, which is GPLv3, so DOSINST is GPLv3 too (see `LICENSE`).