Intro

In Part 1, we got OpenStep 4.2 installed, patched, and running cleanly on modern hardware.
In this sequel, we’ll finish the job — replicating the complete OVA Appliance build published on Archive.org. This guide assumes that you are building your own VM and have completed Part1. If you downloaded the OVA Appliance, these steps are already complete.

By the end, you’ll have a full OpenStep workstation: compiler toolchain, X11, shells, text utilities, and even a few Easter eggs.

Let’s Unix!


Developer Tools

We’ll start by installing the Developer Tools.

You can download the iso from here or from archive.org.

Steps

  1. Log in as root after setting a password (see Set Password).

  2. Attach or insert the Developer CD ISO.

  3. Navigate to:

    /NextCD/Packages/
    
  4. Install the following packages in order:

    DeveloperTools.pkg
    DeveloperLibs.pkg
    GNUSource.pkg
    ProfileLibs.pkg
    DeveloperDoc.pkg
    

    When logged in as root you merely double-click on each pkg file to run the installer.

    You could also launch the installer from the terminal with /NextAdmin/Installer.app/Installer /DeveloperCDname/NextCD/DevloperTools.pkg

  5. Reboot or log out/in once finished.

Verify Developer Tools Installation

After rebooting or logging back in, confirm the compiler toolchain is working:

# Check that the C compiler (cc) is available and functioning
cc -v

# Expected output (varies slightly by build)
# Reading specs from /lib/i386/specs
# NeXT Software, Inc. version cc-744.13, gcc version 2.7.2.1

perl -v

# Expected output
#
# This is perl, version 5.001
#
#        Unofficial patchlevel 1m.
#
# Copyright 1987-1994, Larry Wall
#
# Perl may be copied only under the terms of either the Artistic License or the
# GNU General Public License, which may be found in the Perl 5.0 source kit.

# Confirm other key tools exist
which cc
which ld
which make
which ar

# Check library and include directories
ls /NextDeveloper/Headers
ls /NextDeveloper/Lib

Example: Build and run a NeXT-friendly Hello World test

After installing the Developer Tools, verify that cc is working with this simple C program:

/*
 * hello.c — NeXT-friendly Hello World demo
 * Compatible with OPENSTEP/NeXTSTEP cc
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/param.h>

/* Try to include uname if it exists */
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif

int main()
{
    time_t now;
    char *timestr;
    FILE *fp;
    char buf[256];

#ifdef HAVE_SYS_UTSNAME_H
    struct utsname sys;
#endif

    now = time((time_t *)0);
    timestr = ctime(&now);
    if (timestr && timestr[strlen(timestr) - 1] == '\n')
        timestr[strlen(timestr) - 1] = '\0';

    printf("=====================================\n");
    printf("   Hello from NeXT/OpenStep Unix!\n");
    printf("=====================================\n\n");

#ifdef HAVE_SYS_UTSNAME_H
    if (uname(&sys) == 0)
        printf("System: %s %s (%s)\nNode: %s\n",
               sys.sysname, sys.release, sys.machine, sys.nodename);
    else
        printf("System information unavailable.\n");
#else
    printf("System information unavailable (no uname support).\n");
#endif

    printf("Date:   %s\n\n", timestr ? timestr : "(unknown)");

    printf("Running 'whoami' and 'uptime'...\n\n");

    fp = popen("whoami", "r");
    if (fp) {
        if (fgets(buf, sizeof(buf), fp) != NULL) {
            buf[strcspn(buf, "\n")] = '\0';
            printf("User:   %s\n", buf);
        }
        pclose(fp);
    }

    fp = popen("uptime", "r");
    if (fp) {
        if (fgets(buf, sizeof(buf), fp) != NULL)
            printf("Uptime: %s", buf);
        pclose(fp);
    }

    printf("\nAll systems nominal.\n");
    printf("=====================================\n");

    return 0;
}

Compile and run it to confirm your toolchain is functioning:

cc hello.c -o hello
./hello

You should see system info, the current date, and your user details — proof your NeXT compiler and environment are alive and kicking.

=====================================
   Hello from NeXT/OpenStep Unix!
=====================================

System information unavailable (no uname support).
Date:   Tue Nov  4 19:32:19 2025

Running 'whoami' and 'uptime'...

User:   me
Uptime:   7:32pm  up  9:31,  3 users,  load average: 2.99, 2.33, 1.73

All systems nominal.
=====================================


Bash shell

Install a better shell and set your account to use it.

You can download a working pkg to install bash2 from bash.2.0.NIHS.b.tar.gz. This contemporary version supports tab completion and many other niceties over csh.

You can also grab a copy of tcsh if you prefer from tcsh.6.06.NIHS.b.gz

TIP When browsing archives of NeXT software, you are looking for NIHS or NI or I versions where the I stands for Intel and b denotes that the tarball contains a binary or pkg installer or bs meaning it contains binaries and source.

To Install

  • use FileZilla to ftp to the IP or hostname of the VM using your me credentials and transfer the shell tarballs to /me/src/
  • on NeXT, login as root and run the bash.pkg in /me/src

This will install bash to /usr/gnu/bin/bash


Bash Startup Dotfiles

You’ll also need a good .bashrc and .bash_profile

TIP before building vim and termcap, :set paste will not be available in vi and pasting into your editor from telnet will mess up the formatting. It might be easiest to create the following file and ftp it to /me. Just remember to use ASCII and do it on Linux or run dos2unix on it before ftp’ing.

Alternative: Create .bashrc via heredoc in telnet (before vim is installed)

If you don’t have a working editor yet, you can create the .bashrc file directly from the shell using a heredoc:

cat > ~/.bashrc << 'EOF'
# ~/.bashrc  OPENSTEP BASH2 QOL
export HISTFILE=~/.bash_history
export HISTSIZE=5000
export EDITOR=vim
export VISUAL=vim
export PAGER=less
export TERMCAP=/etc/termcap
export TERM=openstep-safe
export PATH="/usr/local/bin:/usr/etc:/usr/ucb:/usr/gnu/bin:/usr/local/games:/usr/bin:/bin:$PATH"
export MANPATH=/usr/local/man:/usr/man

# Prompt
#PS1='\[\033[1;36m\]\u@\h:\w\$ \[\033[0m\]'

# ANSI-safe color codes
USER_COLOR='\[\033[1;36m\]'      # Cyan
AT_COLOR='\[\033[1;34m\]'        # Blue
HOST_COLOR='\[\033[1;36m\]'      # Cyan again
FRAME_COLOR='\[\033[1;33m\]'     # Yellow brackets
PATH_COLOR='\[\033[0;37m\]'      # Normal white path
RESET='\[\033[0m\]'

# Final PS1
#PS1="${FRAME_COLOR}[ ${USER_COLOR}\u${AT_COLOR}@${HOST_COLOR}\h${FRAME_COLOR} ]${PATH_COLOR}:\w ${RESET}\\$ "
PS1="${FRAME_COLOR}[ ${USER_COLOR}\u${AT_COLOR}@${HOST_COLOR}\h${FRAME_COLOR} ]${PATH_COLOR}:\w ${RESET}\\$ ${RESET} "

stty erase '^?'
eval `dircolors`

# Aliases
alias ls='ls --color=auto -F'
alias ll='ls -lagF'
alias la='ls -aF'
alias cls='clear'
alias termcheck='od -c'      # Inspect key sequences
alias vtest='TERM=openstep-safe vim -u NONE -N'   # Launch Vim with minimal config

# Enable some shell options
set -o emacs               # emacs-style command line (default)
shopt -s histappend        # preserve history between sessions
shopt -s checkwinsize      # auto resize terminal columns

# Functions (yes, bash 2 has these!)
extract() {
  if [ -f "$1" ]; then
    case "$1" in
      *.tar.bz2)   bzip2 -dc "$1" | tar xf -    ;;
      *.tar.gz)    gzip -dc "$1" | tar xf -     ;;
      *.bz2)       bunzip2 "$1"                 ;;
      *.gz)        gunzip "$1"                  ;;
      *.tar)       tar xf "$1"                  ;;
      *.zip)       unzip "$1"                   ;;
      *.Z)         uncompress "$1"              ;;
      *.tar.Z)     uncompress -c "$1" | tar xf - ;;
      *)           echo "Unknown archive format." ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}

if [ -x /usr/local/games/fortune ]; then
    echo
    /usr/local/games/fortune
    echo
fi
EOF

# Also create .bash_profile
cat > ~/.bash_profile << 'EOF'
[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"
EOF

# Source it to apply changes
source ~/.bashrc

.bashrc

# ~/.bashrc  OPENSTEP BASH2 QOL
export HISTFILE=~/.bash_history
export HISTSIZE=5000
export EDITOR=vim
export VISUAL=vim
export PAGER=less
export TERMCAP=/etc/termcap
export TERM=openstep-safe
export PATH="/usr/local/bin:/usr/etc:/usr/ucb:/usr/gnu/bin:/usr/local/games:/usr/bin:/bin:$PATH"
export MANPATH=/usr/local/man:/usr/man

# Prompt
#PS1='\[\033[1;36m\]\u@\h:\w\$ \[\033[0m\]'

# ANSI-safe color codes
USER_COLOR='\[\033[1;36m\]'      # Cyan
AT_COLOR='\[\033[1;34m\]'        # Blue
HOST_COLOR='\[\033[1;36m\]'      # Cyan again
FRAME_COLOR='\[\033[1;33m\]'     # Yellow brackets
PATH_COLOR='\[\033[0;37m\]'      # Normal white path
RESET='\[\033[0m\]'

# Final PS1
#PS1="${FRAME_COLOR}[ ${USER_COLOR}\u${AT_COLOR}@${HOST_COLOR}\h${FRAME_COLOR} ]${PATH_COLOR}:\w ${RESET}\\$ "
PS1="${FRAME_COLOR}[ ${USER_COLOR}\u${AT_COLOR}@${HOST_COLOR}\h${FRAME_COLOR} ]${PATH_COLOR}:\w ${RESET}\\$ ${RESET} "

stty erase '^?'
eval `dircolors`

# Aliases
alias ls='ls --color=auto -F'
alias ll='ls -lagF'
alias la='ls -aF'
alias cls='clear'
alias termcheck='od -c'      # Inspect key sequences
alias vtest='TERM=openstep-safe vim -u NONE -N'   # Launch Vim with minimal config


# Enable some shell options
set -o emacs               # emacs-style command line (default)
shopt -s histappend        # preserve history between sessions
shopt -s checkwinsize      # auto resize terminal columns

# Functions (yes, bash 2 has these!)
extract() {
  if [ -f "$1" ]; then
    case "$1" in
      *.tar.bz2)   bzip2 -dc "$1" | tar xf -    ;;
      *.tar.gz)    gzip -dc "$1" | tar xf -     ;;
      *.bz2)       bunzip2 "$1"                 ;;
      *.gz)        gunzip "$1"                  ;;
      *.tar)       tar xf "$1"                  ;;
      *.zip)       unzip "$1"                   ;;
      *.Z)         uncompress "$1"              ;;
      *.tar.Z)     uncompress -c "$1" | tar xf - ;;
      *)           echo "Unknown archive format." ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}

if [ -x /usr/local/games/fortune ]; then
    echo
        /usr/local/games/fortune
        echo
fi

.bash_profile

[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"

You should now have bash available which is much nicer to use than csh.

NOTEIf you get a message about with the prompt TERM= in your shell, just type vt100. We’ll fix that in the next section with a new termcap and TERM setting.


Setting Shell for Your User Account

You can change your shell with the `/NextAdmin/UserManager.app` Long Form

After installing Bash, you can set it as your login shell using UserManager.app.

  1. Open /NextAdmin/UserManager.app as root.

  2. From the menu, choose
    User ▸ Open, then double-click your account (me).

  3. In the User Information window, locate the Login shell field and replace the existing entry with /usr/gnu/bin/bash

  4. Choose User ▸ Save, confirm in the pop-up dialog, and click OK.

  5. Repeat the process for the root account if desired.

  6. Edit /etc/shells and append /usr/gnu/bin/bash This ensures Bash is recognized as a valid shell.

  7. Log out and log back in to start a new Bash session.

You should now see the Bash prompt and our PS1 from the .bashrc above:

Editor – Vim 5.3 & Termcap Fixes

“Real editors never die; they just :q!”
— NeXT OpenStep Restoration Project, 2025


Overview

This guide explains how to install a fully working Vim 5.3 on NeXTSTEP / OpenStep 4.2 (Intel) using a prebuilt GNU Termcap bundle. It replaces NeXT’s broken libtermlib with a proper libtermcap.a and eliminates arrow-key and Delete/Backspace issues.

This was relatively difficult to port but it makes the system so much nicer to use that it was well worth it. If you want to see what I did you can download an unmodified copy of vim 5.3 and diff with mine. There are numerous edits and shims to get it to work. Running vim --version will show the compile options. I wouldn’t recommend it as a good time.

The result: Vim is a useful editor and a huge upgrade over the built-in, barebones vi

This will make your Y2K code review much easier 🤣

Required Sources

Before beginning, grab the two prepared packages from the restoration project:

📦 GNU Termcap 1.3.1 (for OpenStep)

termcap131_openstep_bundle — Archive.org
Includes libtermcap.a, headers, and man pages rebuilt for OpenStep 4.2 (Intel).
This replaces NeXT’s broken libtermlib.a and restores full key-sequence support.

🧰 Vim 5.3 (native OpenStep build)

vim-5.3-openstep-intel — Archive.org
Contains a fully compiled Vim 5.3 binary, runtime tree, and manual page — ready to install.

These contain the standard source file plus my modifications to get them to build and binaries ready to copy into place.


Install the GNU Termcap Bundle

Download from Archive.org, ftp to /me/src on the VM and extract:

su
cd /me/src
gunzip termcap_openstep_bundle.tar.gz
tar -xvf termcap_openstep_bundle.tar

mkdir /usr/local
mkdir /usr/local/lib
mkdir /usr/local/include

cp /me/src/termcap_openstep_bundle/termcap-1.3.1/libtermcap.a /usr/local/lib/
cp /me/src/termcap_openstep_bundle/termcap-1.3.1/termcap.h     /usr/local/include/

cat /me/src/termcap_openstep_bundle/etc_termcap.openstep-safe >> /etc/termcap

Setting the Environment Variables

echo 'export TERMCAP=/etc/termcap'   >> ~/.bashrc
echo 'export TERM=openstep-safe'     >> ~/.bashrc
. ~/.bashrc

(If mkdir reports “File exists,” you can safely ignore it.)


Install Vim 5.3

Download from archive.org, ftp the tarball to /me/src on the VM and extract:

su
cd /me/src

# Extract 
gunzip vim5.3-OpenStep-Intel.tar.gz
tar -xvf vim5.3-OpenStep-Intel.tar
cd vim5.3-OpenStep/


# Create destination paths (no -p on NeXT)
mkdir /usr/local
mkdir /usr/local/bin
mkdir /usr/local/share
mkdir /usr/local/share/vim
mkdir /usr/local/man
mkdir /usr/local/man/man1

# Copy the compiled Vim binary into place
cp src/vim /usr/local/bin/vim
chmod 755 /usr/local/bin/vim

# Copy runtime and support files
cp menu.vim bugreport.vim vimrc_example gvimrc_example /usr/local/share/vim/
cp -R macros syntax termcap tutor /usr/local/share/vim/

# Copy documentation and manpage
cp -R doc /usr/local/share/vim/
cp doc/vim.1 /usr/local/man/man1/
chmod 644 /usr/local/man/man1/vim.1

# Verify the installation
/usr/local/bin/vim --version

Ensure /etc/termcap includes the openstep-safe entry
(from the termcap_openstep_bundle.tar.gz package).

NOTE Make sure to set your ftp transfer mode correctly during these steps. If you set ASCII and then transfer binary content it will be corrupt. If you set binary when tranferring things like .bashrc or .vimrc, you will see artifacts like ^M and oddly rendered invalid characters. check that if a file doesn’t work at first and try again

Configure the Terminal Environment

Update .bashrc

Your .bashrc should already exist from earlier steps Part 1, but confirm that it includes the following lines:

export TERMCAP=/etc/termcap
export TERM=openstep-safe
export PATH="/usr/local/bin:/usr/etc:/usr/ucb:/usr/gnu/bin:/usr/local/games:/usr/local/bin:/usr/bin:/bin:$PATH"
stty erase '^?'

If these are missing, add them manually with vi or cat >> ~/.bashrc.

Add man page path

You should already have this in your .bashrc but if you didn’t use the one in Part 1 then make sure to add the following to yours

echo 'export MANPATH=/usr/local/man:/usr/man' >> ~/.bashrc

Reload your configuration:

. ~/.bashrc

(Remember that stty erase '^?' ensures the Delete key behaves properly when editing.)


Configure Vim Key Behavior

One of several issues we are working around with these steps involves these ACS artifacts next to the line numbers

Now that we have a better termcap and the openstep-safe profile to use as our $TERM, we can add a .vimrc to establish some decent settings and most importantly to fix some problem behaviors involving how the cursor, backspace, and delete keys are handled and to suppress some ugly ACS artifacts when displaying line numbers with :set numbers

Alternative: Create .vimrc via heredoc (no editor required)

If you don’t yet have Vim running or prefer to create the configuration non-interactively, you can generate your .vimrc using a heredoc:

cat > ~/.vimrc << 'EOF'
" ======================================================================
" ~/.vimrc --  Vim 5.3 on OPENSTEP 4.2
" forfaxx@adminjitsu.com
" ======================================================================

" ----- Core behavior -----
set nocompatible
set autoindent
set smartindent
set showmode
set ruler
set number
set nowrap
set noerrorbells
set visualbell
set laststatus=2
set incsearch
set ignorecase
set smartcase
set hlsearch
set tabstop=4
set shiftwidth=4
set expandtab
set modeline
set showcmd
set backspace=2

" ----- Terminal & key behavior -----
" Backspace/Delete fix
execute "map! " . nr2char(127) . " <BS>"
execute "nmap " . nr2char(127) . " X"
inoremap <BS> <Del>

" ----- Paste mode toggle -----
" Vim 5.3 lacks 'pastetoggle', emulate manually
nmap <C-P> :set invpaste paste?<CR>
imap <C-P> <C-O>:set invpaste paste?<CR>
set paste

" ----- Visual tweaks -----
if has("syntax")
  syntax on
endif
set background=dark
set t_Co=8

" Disable ACS line-drawing artifacts (no fillchars in 5.3)
"if &term == "openstep-safe"
"  set vt100
"endif

" ----- File handling -----
set nobackup
set nowritebackup
set noswapfile
set hidden

" ----- Convenience mappings -----
nmap <F2> :w<CR>
nmap <F3> :q<CR>
nmap <F4> :wq<CR>
nmap <F12> :e $HOME/.vimrc<CR>
EOF

.vimrc

" ======================================================================
" ~/.vimrc --  Vim 5.3 on OPENSTEP 4.2
" forfaxx@adminjitsu.com
" ======================================================================

" ----- Core behavior -----
set nocompatible
set autoindent
set smartindent
set showmode
set ruler
set number
set nowrap
set noerrorbells
set visualbell
set laststatus=2
set incsearch
set ignorecase
set smartcase
set hlsearch
set tabstop=4
set shiftwidth=4
set expandtab
set modeline
set showcmd
set backspace=2

" ----- Terminal & key behavior -----
" Backspace/Delete fix
"map! ^? <BS>           " make DEL behave like Backspace
"map  ^? X              " delete left in normal mode
"map! <BS> <Del>        " optional: swap behavior if needed

execute "map! " . nr2char(127) . " <BS>"
execute "nmap " . nr2char(127) . " X"
inoremap <BS> <Del>



" ----- Paste mode toggle -----
" Vim 5.3 lacks 'pastetoggle', emulate it manually
nmap <C-P> :set invpaste paste?<CR>
imap <C-P> <C-O>:set invpaste paste?<CR>
set paste

" ----- Visual tweaks -----
if has("syntax")
  syntax on
endif
set background=dark
set t_Co=8

" Disable ACS line-drawing artifacts (no fillchars in 5.3)
"if &term == "openstep-safe"
"  set vt100
"endif

" ----- File handling -----
set nobackup
set nowritebackup
set noswapfile
set hidden

" ----- Convenience mappings -----
nmap <F2> :w<CR>
nmap <F3> :q<CR>
nmap <F4> :wq<CR>
nmap <F12> :e $HOME/.vimrc<CR>

At this point you should have a working vim with good termcap behaviors just like in the VirtualBox ova appliance. One thing that really helps when trying to copy and paste through vim over telnet is to hit escape to enter command mode then the colon and the command :set paste. You can then paste in long text passages like the .vimrc and .bashrc without vim mangling the indentation. When you’re done you can save with :wq or :w and enter :set nopaste to disable.

In the .vimrc above, I have mapped Ctrl-P to toggle between paste modes (which disables auto-indent and line wrapping and other insert mode features that get in the way)


TIP Before experimenting further, make a snapshot of your VM. OpenStep’s filesystems can be delicate — you’ll thank yourself later.


Adding Fileutils and Textutils

To complete the core UNIX userland on OPENSTEP 4.2, you’ll want modern implementations of the GNU Fileutils and Textutils packages. These provide many of the essential commands expected on a contemporary UNIX system — including ls, cp, mv, sort, uniq, and more — all built natively for the NeXT environment.

Required Sources

Both archives are available from GNU mirrors or preservation repositories (such as ftp.gnu.org mirrors or Archive.org).

Building and Installing

fileutils

su
gunzip fileutils-3.16.tar.gz
tar xvf fileutils-3.16.tar
cd fileutils-3.16
sh ./configure --prefix=/usr/local
make
make install
cd ..

textutils

gunzip textutils-1.19.tar.gz
tar xvf textutils-1.19.tar
cd textutils-1.19
sh ./configure --prefix=/usr/local
make
make install
exit

Installed Tools

After installation, /usr/local/bin should contain a full suite of GNU utilities, including:

cat        comm       df         fmt        ln         mknod      pr         strfile    touch      vdir
chgrp      cp         dir        fold       ls         mv         rm         sum        tr         vim
chmod      csplit     dircolors  head       md5sum     nl         rmdir      sync       unexpand   wc
chown      cut        du         install    mkdir      od         sort       tac        uniq
cksum      dd         expand     join       mkfifo     paste      split      tail       unstr

With these installed, OPENSTEP behaves much more like a late-90s GNU environment, allowing most shell scripts and build tools to run without modification.

TIP If you’ve followed this tutorial in order, /usr/local/bin should appear at the beginning of your $PATH.
On NeXT, the which command uses hard-coded search paths — instead, run:

echo $PATH

dos2unix and unix2dos

Before beginning, grab the prepared package from the restoration project:

🧩 dos2unix 5.2 (OPENSTEP Port) dos2unix-5.2-openstep — Archive.org
Includes fully working dos2unix and unix2dos binaries, source code, and corrected Makefile for OPENSTEP 4.2 (Intel).
This port fixes missing libgen.h and mode_t definitions, adds compatibility stubs for querycp, and ensures clean builds using NeXT’s native cc and /usr/bin/install.

# Clean any previous object files or binaries
make clean

# Build both dos2unix and unix2dos
make

# Install the binaries and man pages as root
su
make install
exit

The updated Makefile for OPENSTEP automatically handles:

  • Ensuring /usr/local/bin and /usr/local/man/man1 exist before installation
  • Installing the binaries:
    • /usr/local/bin/dos2unix
    • /usr/local/bin/unix2dos
  • Installing the manpage (if present):
    • /usr/local/man/man1/dos2unix.1
    • (Unix2dos uses the same manpage; it’s symlinked internally)

You can verify both tools work:

# Create a DOS-style test file
echo -e "Hello world.\r\nThis is a DOS line.\r\nAnd another.\r\n" > test_dos.txt

# Convert it to Unix format
/usr/local/bin/dos2unix test_dos.txt

# Inspect it
od -c test_dos.txt

# Convert it back to DOS
/usr/local/bin/unix2dos test_dos.txt

# Inspect it again
od -c test_dos.txt

Notes

  • Both programs are fully self-contained and compile cleanly under the OPENSTEP developer tools.
  • The Makefile uses /usr/bin/install for compatibility with NeXT’s environment (no -p flag).
  • NeXT lacks pod2man so I bundled the resulting manpage from linux.
  • This version replaces the missing libgen.h, mode_t, and querycp functions with portable local definitions.
  • You can safely re-run make install; it will overwrite binaries but not break the environment.

Replacing the Broken grep with GNU grep 2.2

The stock grep shipped with OpenStep 4.2 is badly broken — -q, -v, and long options fail outright.
We can replace it with a working GNU grep 2.2 built natively using the NeXT toolchain.

Download the verified working build from Archive.org:

📦 Download grep-2.2-openstep-intel

Upload the tarball to /me/src on your VM using binary mode FTP

Steps

cd ~/src
gunzip grep-2.2.tar.gz
tar -xvf grep-2.2.tar
cd grep-2.2

# fix timestamps and permissions
find . -exec touch {} \;
chmod u+x configure

# configure and build
./configure --prefix=/usr/local --disable-nls
make CC="/bin/cc" LD="/bin/ld" \
     CFLAGS="-O2 -arch i486 -traditional-cpp" \
     LDFLAGS="-lSystem -lc"

# test the result
cd src
./grep --version
echo foo | ./grep -q foo && echo "grep works"

# install
su
make install
exit

This installs the new binaries and manpages to:

/usr/local/bin/grep
/usr/local/bin/egrep
/usr/local/bin/fgrep
/usr/local/man/man1/grep.1

NOTE
No need to replace the system binary — as long as /usr/local/bin appears before /bin in your $PATH, your shell will automatically prefer the new version. If you’ve followed the earlier bash configuration, you’re already covered.

Verification

grep --version
grep -q foo <<< foo && echo OK
echo -e "foo\nbar" | grep -v foo

Expected output:

grep (GNU grep) 2.2
OK
bar

✅ Your OpenStep environment now has a fully functional grep with standard GNU options, completing the core text-processing toolchain alongside textutils and fileutils.


top

Now we’ll add top to make it easier to keep an eye on resource usage and processes.

top is exactly the kind of thing a 90s NeXT admin would have downloaded and run

You can grab a prebuilt binary from 🔗 fsck.technology

Transfer it to /me/src on your VM and unpack:

su
cd /me/src
gunzip top.0.5.NI.b.tar.gz
tar -xvf top.0.5.NI.b.tar
cd top-v0.5

Copy the binary and set the proper ownership and permissions so it can read kernel memory:

NOTE You don’t see this much on modern systems — with sudo, privilege separation, and ACLs doing the heavy lifting — but setuid binaries were once a common (and slightly terrifying) way to let normal users perform privileged actions safely.

cp top /usr/local/bin/top
chmod 4755 /usr/local/bin/top
chown root.kmem /usr/local/bin/top
ls -al /usr/local/bin/top

There’s also a man page included — install it to /usr/local/man/man1:

mkdir /usr/local/man/man1 2>/dev/null
cp top.1 /usr/local/man/man1/
chmod 644 /usr/local/man/man1/top.1

Test it:

man top
top

If everything’s right, you’ll see a live process list with CPU and memory stats.
Press q to exit.


CUBX X11R6

X11R6 on NeXT is a nice retro-modern addition to the system.

This was easy to set up. Just grab the iso and serial number from archive.org or from the NeXT archive here

Steps

  • login as root
  • attach the iso to Virtualbox
  • when it appears in the file viewer, click on the cd and double-click on ISInstaller.app This will prompt for the serial number
  • You probably want to choose Client when prompted.
  • The installer will then install and configure the system

NOTE When installing CUB’X Windows 5, you can choose Server (to receive remote X11 apps drawn on your OpenStep desktop) or Client (to send X apps from OpenStep to another display).
Use the server mode if you want to integrate modern Unix apps into your NeXT workspace; use the client mode if you prefer to open OpenStep X programs on another host’s screen.

See X11 display forwarding explained for a solid overview of how exported displays work.

This gives you xterm which is much nicer to use than the built in Terminal as well as a host of standard x11 apps and the ability to build more (you’ll want to look for releases from 1994-1999 typically that would have been contemporaneous )

Try running xeyes & and enjoy having xterm available.

TIP Before experimenting further, make a snapshot of your VM. This is a good place to save.


w3c-httpd

This is version 3.0A of the original CERN httpd web server — the first web server developed by Tim Berners-Lee on NeXTSTEP.
This port has been rebuilt and tested natively under OPENSTEP 4.2 Intel, using the original toolchain (cc = gcc 2.7.2.1) with no GNU dependencies.


Required Sources

Download the verified working build from Archive.org:

📦 Download w3c-httpd-3.0A.next.i486.tar.gz

https://archive.org/download/w3c-httpd-3.0A.next.i486/w3c-httpd-3.0A.next.i486.tar.gz

Upload the tarball to /me/src on your VM using binary mode (FTP or NFS).


Installing CERN httpd 3.0A

# Navigate to your source directory
cd /me/src

# Extract the source archive
gunzip cern-httpd-3.0A-openstep-bin.tar.gz
tar -xvf cern-httpd-3.0A-openstep-bin.tar
cd w3c-httpd-3.0A

# Become root
su

Create the target install layout:

mkdir -p /usr/local/httpd/bin
mkdir -p /usr/local/httpd/lib
mkdir -p /usr/local/httpd/conf
mkdir -p /usr/local/httpd/logs
mkdir -p /usr/local/httpd/html

NOTE If you haven’t followed the previous steps in this tutorial and installed fileutils, you will need to run mkdir without -p and create both /usr, /usr/local and /usr/local/httpd manually before creating the subdirs in the steps above.

Install the compiled binaries and library:

install -m 0755 Daemon/next/httpd /usr/local/httpd/bin/httpd
install -m 0755 Daemon/next/htadm /usr/local/httpd/bin/htadm
install -m 0755 Daemon/next/htimage /usr/local/httpd/bin/htimage
install -m 0755 Daemon/next/cgiparse /usr/local/httpd/bin/cgiparse
install -m 0755 Daemon/next/cgiutils /usr/local/httpd/bin/cgiutils
install -m 0644 Library/next/libwww.a /usr/local/httpd/lib/libwww.a

Create a working configuration file for port 80 and user pages:

WARNING About Port 80 and the nobody user:
Binding to port 80 requires root privileges, but the daemon drops to the nobody user after startup for security. The HostName directive should match your VM’s actual IP address — adjust 192.168.1.50 to your network configuration. If you prefer to avoid running as root, change Port 80 to Port 8080 (or any port above 1024) and start the daemon as a regular user.

cat >/usr/local/httpd/conf/httpd.conf <<'EOF'
ServerRoot   /usr/local/httpd
Port         80
User         nobody
Group        nobody
HostName     192.168.1.50

DocumentRoot /usr/local/httpd/html
LogFile      /usr/local/httpd/logs/access_log
ErrorLog     /usr/local/httpd/logs/error_log

Protect      / none
Pass         /      /usr/local/httpd/html/*
Pass         /~me*  /me/public_html/*
Protect      /~me*  none
EOF

And a test HTML document:

mkdir -p /me/public_html
chmod 755 /me /me/public_html

cat >/usr/local/httpd/html/index.html <<'EOF'
<!DOCTYPE html>
<html><body><h1>Welcome to CERN httpd 3.0A on OpenStep!</h1></body></html>
EOF

cat >/me/public_html/index.html <<'EOF'
<!DOCTYPE html>
<html><body><h1>Hello from ~me on OpenStep!</h1></body></html>
EOF

Running the Server

Start the daemon manually:

/usr/local/httpd/bin/httpd &

You should see output similar to:

............ This is CERN-HTTPD, version 3.0A, using libwww version 2.17
ServerType.. standalone
Reading..... /usr/local/httpd/conf/httpd.conf

Verify the process:

ps aux | grep httpd

Check logs:

tail -n 5 /usr/local/httpd/logs/error_log

Testing

From your host or another VM:

curl http://192.168.1.50/
curl http://192.168.1.50/~me/

Expected result:

<h1>Welcome to CERN httpd 3.0A on OpenStep!</h1>
<h1>Hello from ~me on OpenStep!</h1>

If you’re using OmniWeb, Mosaic, or an early Netscape build, both pages should render correctly.

You too can have a 90s website again! Just need some flashing under construction gifs

Auto-start at Boot

Add CERN httpd to /etc/rc.local so it launches automatically after networking:

WARNING Security consideration:
This configuration runs httpd as root initially to bind port 80, then drops to nobody. On a private network VM this is acceptable, but never expose this server to the public internet — it lacks modern security features and uses unencrypted HTTP only. Consider using port 8080 or adding this VM to an isolated network segment.

cat >>/etc/rc.local <<'EOF'

# Start CERN httpd 3.0A
if [ -x /usr/local/httpd/bin/httpd ]; then
    echo "Starting CERN httpd 3.0A..." >/dev/console
    /usr/local/httpd/bin/httpd &
fi
EOF

chmod +x /etc/rc.local

You can test immediately without rebooting:

/etc/rc.local

Confirm it’s running:

ps aux | grep httpd

At the next reboot, the daemon will start automatically and serve your pages from
http://192.168.1.50/ and http://192.168.1.50/~me/.


Notes

  • This build uses native OpenStep tools only — no GNU Make, no bash, no BSD ports.
  • Configuration format matches CERN httpd 3.x syntax exactly.
  • Runs safely in standalone mode on port 80.
  • Logs and HTML documents live under /usr/local/httpd/ for simplicity.

You now have a fully installed and operational CERN httpd 3.0A daemon, serving web content from OpenStep just like the first webserver.

TIP This is another friendly reminder to save a snapshot in VirtualBox!


fortune-mod 9708 & Custom Sets

A UNIX system without fortune is a sterile, joyless place. I even wrote an entire post celebrating its shenanigans —
Fortune Favors the Sysadmin.

So naturally, we’re going to need a working copy on OPENSTEP.

There is a fortune for NeXT pkg out there but it installs a gui app with some hard-coded fortunes.
Neat but we'll be installing fortune-mod with everything included

Required Sources

Start by grabbing my fortune-mod-9708 port from archive.org

📦 Download fortune-mod-9708 for OPENSTEP 4.2



Building and Installing fortune-mod-9708 port

Set FTP transfer mode to binary and upload fortune-mod-9708-openstep.tar.gz to /me/src on the VM.

# Navigate to your source directory
cd /me/src

# Extract the source archive
gunzip fortune-mod-9708-openstep.tar.gz
tar -xvf fortune-mod-9708-openstep.tar
cd fortune-mod-9708-openstep


# Clean any previous builds
make clean

# Build the binaries and cookie databases
make

# Install everything as root (fortune, utilities, manpages, and data)
su
make install
exit

The install target now handles everything automatically:

  • Creates required directories if they don’t exist:

    • /usr/local/games
    • /usr/local/share/games/fortunes
    • /usr/local/bin
    • /usr/local/man/man6
    • /usr/local/man/man1
  • Installs the compiled binaries:

    • /usr/local/games/fortune
    • /usr/local/bin/strfile
    • /usr/local/bin/unstr
  • Generates and installs the manpages:

    • /usr/local/man/man6/fortune.6
    • /usr/local/man/man1/strfile.1 (with unstr.1 symlink)
  • Copies all fortune cookie databases (*.dat and subdirs) into /usr/local/share/games/fortunes/.


Verify it works as expected

You can verify it works:

/usr/local/games/fortune
/usr/local/games/fortune startrek
/usr/local/games/fortune zippy

If you want to add your own fortune sets, place them in datfiles/, then rebuild the indexes:

cd datfiles
/usr/local/bin/strfile myfortunes

Your new set appears automatically under /usr/local/share/games/fortunes/myfortunes.


Notes

  • This Makefile is OPENSTEP-compatible and idempotent: re-running make install won’t break existing installs.
  • You no longer need to manually copy files or run strfile — the build handles everything.
  • Manpages and directories are generated cleanly with the correct permissions.

“Absolutum obsoletum. (If it works, it’s out of date.)” – Stafford Beer


Installing GUI Apps & Packages

There are a ton of downloads available on archive.org and fsck.technology. They tend to come in a few flavors:

  • tarballs (file.tar.gz)

    • you want ones with NIHS, NI and/or b or bs in the title
    • These will contain a README or INSTALL with instructions
    • typically you’ll use something like make install as directed by the documentation in the archive.
  • tarballs containing source only, not ported to NeXT. You’ll have to figure these out. Some are easy, some aren’t. Try to find releases from around 1995-1998

  • .pkg files. Login as root and double-click the .pkg file to run the installer alternatively you can launch with /NextAdmin/Installer.app/Installer packagename.pkg

  • .app bundles As long as it contains an Intel Mach binary, these can be run from anywhere. You probably want to copy these to either /me/Apps or /LocalApps or even /NextApps


Running nmap Against nextcube

When you scan nextcube from a modern host:

nmap -A -p- -T4 -v nextcube

It lights up like a slot machine of open ports — Telnet, FTP, Finger, rlogin, exec, SMTP, and friends.
A living exhibit of 90s networking.

Show full Nmap scan output for nextcube.darkstar.home
┌──[ grumble@shinobi ]:~/codelab/adminjitsu  (main)
└─$ nmap -A -p- -T4 -v nextcube.darkstar.home
Starting Nmap 7.80 ( https://nmap.org ) at 2025-11-03 17:14 CST
NSE: Loaded 151 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 17:14
Completed NSE at 17:14, 0.00s elapsed
Initiating Ping Scan at 17:14
Scanning nextcube.darkstar.home (192.168.1.50) [2 ports]
Completed Ping Scan at 17:14, 0.20s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 17:14
Completed Parallel DNS resolution of 1 host. at 17:14, 0.01s elapsed
Initiating Connect Scan at 17:14
Scanning nextcube.darkstar.home (192.168.1.50) [65535 ports]
Discovered open port 23/tcp on 192.168.1.50
Discovered open port 111/tcp on 192.168.1.50
Discovered open port 25/tcp on 192.168.1.50
Discovered open port 21/tcp on 192.168.1.50
Discovered open port 19/tcp on 192.168.1.50
Discovered open port 7/tcp on 192.168.1.50
Discovered open port 79/tcp on 192.168.1.50
Discovered open port 2453/tcp on 192.168.1.50
Discovered open port 706/tcp on 192.168.1.50
Discovered open port 13/tcp on 192.168.1.50
Discovered open port 513/tcp on 192.168.1.50
Discovered open port 515/tcp on 192.168.1.50
Discovered open port 514/tcp on 192.168.1.50
Discovered open port 37/tcp on 192.168.1.50
Discovered open port 512/tcp on 192.168.1.50
Discovered open port 9/tcp on 192.168.1.50
Discovered open port 709/tcp on 192.168.1.50
Discovered open port 178/tcp on 192.168.1.50
Completed Connect Scan at 17:25, 677.52s elapsed (65535 total ports)
Initiating Service scan at 17:25
Scanning 18 services on nextcube.darkstar.home (192.168.1.50)
Completed Service scan at 17:28, 163.85s elapsed (18 services on 1 host)
NSE: Script scanning 192.168.1.50.
Initiating NSE at 17:28
Completed NSE at 17:28, 29.77s elapsed
Nmap scan report for nextcube.darkstar.home (192.168.1.50)
Host is up (0.0054s latency).
Not shown: 65497 closed ports
PORT      STATE    SERVICE    VERSION
7/tcp     open     echo
9/tcp     open     discard?
13/tcp    open     daytime    Sun Solaris daytime
19/tcp    open     chargen
21/tcp    open     ftp
| fingerprint-strings:
|   GenericLines:
|     220 nextcube FTP server (Version 5.1 (NeXT 1.0) Tue Jan 26, 1999) ready.
|     command not understood.
|     command not understood.
|   NULL, SMBProgNeg:
|     220 nextcube FTP server (Version 5.1 (NeXT 1.0) Tue Jan 26, 1999) ready.
|   SSLSessionReq:
|     220 nextcube FTP server (Version 5.1 (NeXT 1.0) Tue Jan 26, 1999) ready.
|_    command not understood.
| ftp-syst:
|   SYST: Version: BSD-43
|   STAT:
|  nextcube FTP server status:
|      Version 5.1 (NeXT 1.0) Tue Jan 26, 1999
|      Connected to 192.168.1.51 (192.168.1.51)
|      Waiting for user name
|      TYPE: ASCII, FORM: Nonprint; STRUcture: File; transfer MODE: Stream
|      No data connection
|_End of status
23/tcp    open     telnet     IRIX telnetd 6.X
25/tcp    open     smtp       Sendmail NX5.67g/NX3.0S
|_smtp-commands: SMTP: EHLO 500 Command unrecognized\x0D
37/tcp    open     time       (32 bits)
|_rfc868-time: 2025-11-03T17:28:07
79/tcp    open     finger     SGI IRIX or NeXTSTEP fingerd
| finger: Login       Name              TTY Idle    When            Office\x0D
|_me       My Account            co   1d Mon 00:48 \x0D
111/tcp   open     rpcbind    2 (RPC #100000)
178/tcp   open     nextstep?
512/tcp   open     exec?
| fingerprint-strings:
|   Kerberos, SMBProgNeg, afp, oracle-tns:
|_    Login incorrect.
513/tcp   open     login      OpenBSD or Solaris rlogind
514/tcp   open     tcpwrapped
515/tcp   open     printer    lpd (path: /usr/lib/lpd; error: ....: Malformed from address)
706/tcp   open     rpcbind
709/tcp   open     rpcbind
2453/tcp  open     madge-ltd?
2968/tcp  filtered enpp
8649/tcp  filtered unknown
10553/tcp filtered unknown
12263/tcp filtered unknown
12651/tcp filtered unknown
13523/tcp filtered unknown
27087/tcp filtered unknown
27860/tcp filtered unknown
30923/tcp filtered unknown
32979/tcp filtered unknown
34521/tcp filtered unknown
35920/tcp filtered unknown
46067/tcp filtered unknown
46934/tcp filtered unknown
47204/tcp filtered unknown
52006/tcp filtered unknown
56233/tcp filtered unknown
62708/tcp filtered unknown
64492/tcp filtered unknown
64498/tcp filtered unknown

2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port21-TCP:V=7.80%I=7%D=11/3%Time=690939E9%P=x86_64-pc-linux-gnu%r(NULL
SF:,4A,"220\x20nextcube\x20FTP\x20server\x20\(Version\x205\.1\x20\(NeXT\x2
SF:01\.0\)\x20Tue\x20Jan\x2026,\x201999\)\x20ready\.\r\n")%r(GenericLines,
SF:8C,"220\x20nextcube\x20FTP\x20server\x20\(Version\x205\.1\x20\(NeXT\x20
SF:1\.0\)\x20Tue\x20Jan\x2026,\x201999\)\x20ready\.\r\n500\x20'':\x20comma
SF:nd\x20not\x20understood\.\r\n500\x20'':\x20command\x20not\x20understood
SF:\.\r\n")%r(SSLSessionReq,6D,"220\x20nextcube\x20FTP\x20server\x20\(Vers
SF:ion\x205\.1\x20\(NeXT\x201\.0\)\x20Tue\x20Jan\x2026,\x201999\)\x20ready
SF:\.\r\n500\x20'\x16\x03':\x20command\x20not\x20understood\.\r\n")%r(SMBP
SF:rogNeg,4A,"220\x20nextcube\x20FTP\x20server\x20\(Version\x205\.1\x20\(N
SF:eXT\x201\.0\)\x20Tue\x20Jan\x2026,\x201999\)\x20ready\.\r\n");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port512-TCP:V=7.80%I=7%D=11/3%Time=69093A18%P=x86_64-pc-linux-gnu%r(Ker
SF:beros,12,"\x01Login\x20incorrect\.\n")%r(SMBProgNeg,12,"\x01Login\x20in
SF:correct\.\n")%r(oracle-tns,12,"\x01Login\x20incorrect\.\n")%r(afp,12,"\
SF:x01Login\x20incorrect\.\n");
Service Info: OSs: Solaris, IRIX, Unix; CPE: cpe:/o:sun:sunos, cpe:/o:sgi:irix

Host script results:
|_clock-skew: -6h00m02s

NSE: Script Post-scanning.
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 876.65 seconds

WARNING
Keep nextcube off the public internet. It’s historically authentic and hilariously insecure by design.


These install correctly without modification:

Prepared packages and binaries with required modifications:

Software highlights in the collection:


Conclusion

At this point, you have a pretty complete OpenStep 4.2 workstation — developer tools, X11, shells, GNU utilities, and the full retro Unix experience.

In the next installment, we’ll publish a short User Guide for the Appliance:
filesystem map, compile examples, file sharing tips, and snapshot management.

It’s been nice having the nextcube VM now that I’ve gotten it to this point. I’d love to hear any feedback if this guide helped you or if I missed something feedback@adminjitsu.com