chat(8) scripts a modem conversation so a PPP dial-up connection can reset, dial and log in without a human watching the lights. You will finish with a small, repeatable script that resets a modem, dials a number, rejects common failure responses, and hands a successful connection to the next PPP step. This guide targets the chat supplied by Ubuntu's ppp package, version 2.4.9-1+1.1ubuntu4. Allow 20 to 30 minutes if the modem, serial device and provider details are already known.
You need a working modem or terminal adapter, its serial device, a telephone number or other dialling target, and permission to access the device. You also need the expected prompts and credentials from the remote system. This is a connection script, not a modem driver: it cannot make an unavailable serial device or telephone service work.
Have a way to test without interrupting a production PPP connection. Dialling can incur charges and can drop an existing call. Do not put a real password in a command copied into a terminal: command arguments can be visible to other users through process inspection. The examples use obvious placeholders.
A file is easier to review than a long command line. The -f option reads one or more lines of expect-send pairs, separated by spaces or horizontal tabs. It cannot be combined with script parameters on the same invocation.
install -m 600 /dev/null "$HOME/ppp-chat-provider"
editor "$HOME/ppp-chat-provider"
The first command is an ordinary user command and creates an empty, owner-readable file. If the script will be read by a service account, create it in the service's protected configuration directory instead and set ownership to that account. Avoid making a credential-bearing script world-readable.
Checkpoint: The file exists and its permissions do not grant access to other users.
stat -c '%A %U:%G %n' "$HOME/ppp-chat-provider"
Start with abort conditions, then reset and dial. An empty expect string sends immediately. A normal reply receives a carriage return after it; add \c at the end when the modem must not receive that trailing return.
ABORT BUSY
ABORT 'NO CARRIER'
ABORT 'NO DIAL TONE'
'' ATZ
OK ATDT<PHONE_NUMBER>
CONNECT ''
Replace <PHONE_NUMBER> with the approved number, without the angle brackets. The quotes around NO CARRIER keep the two-word response as one string. If the modem answers with BUSY, NO CARRIER or NO DIAL TONE, chat stops instead of waiting until a generic timeout. Those responses are abort conditions, so they also produce a non-zero result.
Do not add a password until the modem reliably reaches the remote prompt. This separates a serial or dialling fault from an authentication fault.
If the remote system asks for a login, append pairs for the prompts it actually sends. Prompts often arrive with a damaged first character during the initial exchange, so a stable identifying fragment such as ogin: can be more reliable than login:. Do not expect a changing timestamp or network banner.
ogin: <ACCOUNT_NAME>
ssword: <PASSWORD>
$ \c
Replace each placeholder before use. The final $ \c waits for a shell prompt and sends no extra carriage return. If this is a PPP peer rather than an interactive shell, use the peer's documented prompt and hand-off sequence instead. A script that waits for a prompt the remote never sends will finish with a timeout.
For a first attempt, keep echoing off and use SAY for non-secret progress messages. Verbose modes can expose received text and sent strings, including credentials. If you must diagnose a failure, use the shortest possible test window and protect the resulting logs.
The installed implementation starts with a 45-second expect timeout. Set a shorter value while checking local wiring, or set a longer value for a slow telephone connection. The setting remains in force until another -t option or TIMEOUT directive changes it.
chat -S -V -t 15 -f "$HOME/ppp-chat-provider"
printf 'chat exit status: %s\n' "$?"
This uses stderr for verbose output and avoids syslog. It is suitable for an attended test, but the verbose output may include sensitive modem traffic. Remove -V for normal operation. The command needs permission to open the modem device; use elevated privileges only if the device permissions require it.
Checkpoint: A successful script ends with exit status 0. Exit status 3 means an expect string timed out without a fallback send string. Status 4 and later identify abort strings in their order of declaration. Status 1 indicates invalid parameters or an oversized expect string; status 2 indicates an I/O, signal or other execution error.
A subexpect-subsend pair gives the remote one recovery action when the first prompt is missed. The hyphen separates the fallback expect and send strings. This example sends a break, then looks for the login prompt again.
ogin:-BREAK-ogin: <ACCOUNT_NAME>
Use this only when the remote system is known to accept a break. For a login prompt that is commonly revived by a blank line, an empty fallback send is another option:
ogin:--ogin: <ACCOUNT_NAME>
Do not add retries to every step. A repeated dial or authentication attempt can lock an account, redial a chargeable number, or hide a real wiring fault. Keep the fallback close to the expect string it repairs.
Once the script succeeds on its own, give the same file to the PPP configuration that starts the connection. The exact device, permissions and PPP options depend on the local setup. Keep this change separate from editing the chat script, so you can undo it without losing the known-good conversation.
If a service runs the script as another user, verify that user can read the file and open the serial device. A manual test as root can give a false sense of success when the daemon later lacks those permissions. After changing service configuration, restart only the affected connection and watch its logs for the chat exit status.
Warning: Stop an unwanted dialling or PPP attempt before editing a live script. Restore the previous configuration file or remove the new PPP reference to undo the integration. The chat file itself can then be retained for diagnosis or deleted once you have confirmed no service references it.
\r.\c to the end of that send string. This is the documented way to suppress the normal trailing carriage return.'NO CARRIER', or use the script's quoting rules consistently.-V, avoid -v, and do not use REPORT for secrets. REPORT writes matching modem text to its report destination and does not change the completion status.-E. When enabled, an unset variable becomes an empty string, so check the environment before relying on it.0.