Roadshow Commands and usergroup.library¶
NDK 3.2 ships, in SANA+RoadshowTCP-IP/, the sources of the shell commands that configure and monitor the Roadshow TCP/IP stack, plus the SFD, headers and catalog descriptions of the companion usergroup.library. This article explains what each command does and which bsdsocket.library calls it uses, so you can treat them as worked examples, and then documents the usergroup.library API from its AmiTCP SDK 4.3 autodoc (doc/usergroup.doc) and the Roadshow SFD.
For the socket API itself see Roadshow — bsdsocket TCP/IP Stack. For SocketBaseTagList() details see AmiTCP net.lib and SocketBaseTagList Tags.
The command sources¶
source_code/Roadshow/README describes the directory as "the source code of the programs that call into the Roadshow bsdsocket.library to configure the TCP/IP stack and to query status information", meant "merely ... as a demonstration". The copyright lets you reuse techniques and parts of the code, but not take the code as a whole as your own. Each .c file starts with an autodoc-style block (NAME, FORMAT, TEMPLATE, OPTIONS, NOTES) and has a *_rev.h file with its version.
| Command | Version | Template | Purpose |
|---|---|---|---|
AddNetInterface |
4.57 (10.6.2019) | INTERFACE/M,QUIET/S,TIMEOUT/K/N |
Add interfaces from configuration files and configure them (like ifconfig). |
ConfigureNetInterface |
4.39 (10.6.2019) | INTERFACE/A,QUIET/S,ADDRESS/K,NETMASK/K,BROADCASTADDR/K,DESTINATION=DESTINATIONADDR/K,METRIC/K/N,MTU/K/N,ALIASADDR/K,DELETEADDR/K,ONLINE/S,OFFLINE/S,UP/S,DOWN/S,DEBUG/K,COMPLETE/K,CONFIGURE/K,LEASE/K,RELEASE=RELEASEADDRESS/S,ID/K,TIMEOUT/K/N,DHCPUNICAST/K |
Change the parameters of an interface that has already been added. |
RemoveNetInterface |
4.3 (11.3.2009) | INTERFACE/K,QUIET/S,FORCE/S |
Make the stack forget an interface so it can be re-added with other parameters. |
AddNetRoute |
4.8 (11.3.2009) | QUIET/S,DST=DESTINATION/K,HOSTDST=HOSTDESTINATION/K,NETDST=NETDESTINATION/K,VIA=GATEWAY/K,DEFAULT=DEFAULTGATEWAY/K |
Add routes to hosts or networks. |
DeleteNetRoute |
4.8 (11.3.2009) | QUIET/S,DST=DESTINATION/K,DEFAULT=DEFAULTGATEWAY/K |
Remove a route. |
GetNetStatus |
4.9 (11.3.2009) | CHECK/K,QUIET/S |
Script test: is the network operational? |
ShowNetStatus |
4.28 (11.3.2009) | INTERFACE/M,INTERFACES/S,ARPCACHE=ARP/S,ROUTES/S,DNS=DOMAINNAMESERVERS/S,ICMP/S,IGMP/S,IP/S,MB=MEMORY/S,MR=MULTICASTROUTING/S,RT=ROUTING/S,TCP/S,UDP/S,TCPSOCKETS/S,UDPSOCKETS/S,NAMES/S,ALL/S,REPEAT/S,QUIET/S |
Display interfaces, routes, DNS servers and protocol statistics (like netstat). |
RoadshowControl |
4.9 (23.4.2017) | SAVE/S,QUIET/S,GET/K,SET/K/F |
Show or change internal stack options. |
SampleNetSpeed |
4.5 (10.11.2016) | INTERFACE,LEFT/N,TOP/N,WIDTH/N,HEIGHT/N,SCREEN/K |
Window that graphs throughput once per second. |
NetShutdown |
4.8 (20.7.2017) | TIMEOUT/N,QUIET/S |
Shut the stack down in an orderly fashion. |
Online |
4.1 (29.4.2017) | NAME/A,UNIT/N,TIMEOUT/N |
Put a SANA-II driver unit online. |
Offline |
4.1 (29.4.2017) | NAME/A,UNIT/N,TIMEOUT/N |
Take a SANA-II driver unit offline (for hardware diagnostics). |
rsh |
4.10 (29.11.2019) | -n=NULL/S,-l=USERNAME/K,TIMEOUT/K/N,HOST/A,COMMAND/A/F |
Run a command on a remote host via the shell/tcp service (port 514). |
Support files: assert.c/assert.h (debug macros), compiler.h, macros.h, roadshow.h (CatComp-generated string IDs for roadshow.catalog), and swap_stack.asm/swap_stack.h.
API used by each command¶
| Command | Key calls |
|---|---|
AddNetInterface |
SocketBaseTagList() probes SBTC_HAVE_INTERFACE_API, SBTC_HAVE_ROUTING_API, SBTC_HAVE_ADDRESS_CONVERSION_API; AddInterfaceTagList() with IFA_* tags; ConfigureInterfaceTagList(); BeginInterfaceConfig()/AbortInterfaceConfig() for DHCP; AddRouteTagList() (RTA_DefaultGateway, RTA_Destination); AddDomainNameServer(); SetDefaultDomainName() |
ConfigureNetInterface |
The same interface, routing and DNS calls, without AddInterfaceTagList() |
RemoveNetInterface |
RemoveInterface(name, force) |
AddNetRoute / DeleteNetRoute |
AddRouteTagList() / DeleteRouteTagList() with RTA_Destination, RTA_DestinationHost, RTA_DestinationNet, RTA_Gateway, RTA_DefaultGateway |
GetNetStatus |
One SocketBaseTags(SBTM_GETREF(SBTC_SYSTEM_STATUS), &status, TAG_END) query; tests SBSYSSTAT_* bits |
ShowNetStatus |
ObtainInterfaceList()/QueryInterfaceTagList() with IFQ_* tags, GetRouteInfo()/FreeRouteInfo(), ObtainDomainNameServerList(), GetDefaultDomainName(), GetNetworkStatistics() with NETSTATUS_* types |
RoadshowControl |
ObtainRoadshowData(), ChangeRoadshowData(), ReleaseRoadshowData() |
SampleNetSpeed |
SBTC_GET_BYTES_RECEIVED/SBTC_GET_BYTES_SENT (stack totals) or QueryInterfaceTagList() with IFQ_GetBytesIn/IFQ_GetBytesOut (one interface) |
NetShutdown |
No library calls: a message to the "TCP/IP Control" port |
Online / Offline |
Pure SANA-II: S2_ONLINE/S2_OFFLINE plus S2_ONEVENT |
rsh |
gethostbyname(), getservbyname("shell","tcp"), WaitSelect(), IoctlSocket(), and usergroup.library getcredentials() for the local login name |
Every command that uses a Roadshow extension first checks the matching SBTC_HAVE_*_API tag and prints a "bsdsocket.library has no ... API" error if the query fails. Follow the same pattern in your own code, because AmiTCP-compatible stacks do not have these functions.
Interface configuration files¶
AddNetInterface reads text files from DEVS:NetInterfaces or SYS:Storage/NetInterfaces. The file name becomes the interface name (case-insensitive, at most 15 characters for historic reasons), and wildcards are allowed. Each line is one keyword, and lines starting with # or ; are comments. Unknown keywords are reported with the file name and line number.
| Keyword | Default / notes |
|---|---|
DEVICE/K |
Required SANA-II driver; a bare name is looked up in DEVS:Networks. |
UNIT/K/N |
0 |
IPTYPE/K/N, ARPTYPE/K/N |
2048 and 2054 (Ethernet packet types). |
IPREQUESTS/K/N, WRITEREQUESTS/K/N, ARPREQUESTS/K/N |
32, 32, 4 queued requests. |
HARDWAREADDRESS/K |
e.g. 00:60:30:00:11:22; usually only the first configuration sticks until reboot. |
POINTTOPOINT, MULTICAST, DEBUG |
YES/NO |
DOWNGOESOFFLINE |
YES: marking the interface down or stopping the stack sends S2_OFFLINE. |
REPORTOFFLINE |
YES: notify when the driver goes offline (dial-up cost control). |
REQUIRESINITDELAY |
YES by default: about one second of delay before the first packet (original Ariadne I). |
COPYMODE |
SLOW (16-bit transfers, Ariadne I safe) or FAST. |
FILTER |
OFF, LOCAL (default), IPANDARP, EVERYTHING; the last two need promiscuous mode. |
ADDRESS, NETMASK |
Dotted decimal or DHCP. |
ALIAS/K/M, STATE, DESTINATION, METRIC, MTU |
STATE is up/down/online/offline. MTU can only lower the driver's value. |
CONFIGURE |
DHCP (address, routes and DNS), AUTO (ZeroConf) or FASTAUTO (wireless). |
LEASE, ID, DHCPUNICAST |
DHCP lease request (300, 30min, 2hours, infinite…), client name (2–255 chars), unicast replies. |
Configuration runs in two passes: all interfaces are added first, then configured. An error in pass 1 stops everything. DHCP works only on Ethernet. The default DHCP timeout is 10 seconds, and TIMEOUT cannot make it shorter. The command can also be the default tool of a project icon (at least 4000 bytes of stack), with QUIET, TIMEOUT and PRI/PRIORITY tool types. Priority sorts the interfaces; otherwise they are sorted by name.
Stack gotcha: on AmigaOS 2.x/3.x
AddNetInterfaceneeds at least 8000 bytes of stack. If the current stack is smaller, it allocates a new one and switches to it withexec.library/StackSwap()(wrapped inswap_stack.asm). Copy this pattern if your own network tool runs deep parsing or DHCP code.
Shutting down the stack: NetShutdown¶
NetShutdown shows the stack's control port protocol from <libraries/bsdsocket.h>:
#define NETWORK_CONTROLLER_PORT_NAME "TCP/IP Control"
#define NCPM_Cookie 0x20040306
struct NetControlPort { struct MsgPort ncp_Port; ULONG ncp_Magic; };
struct NetShutdownMessage
{
struct Message nsm_Message;
ULONG nsm_Command; /* NSMC_Shutdown (1) or NSMC_Cancel (2) */
APTR nsm_Data; /* Shutdown: ULONG * for active client count;
Cancel: the shutdown message to recall */
ULONG nsm_Length;
LONG nsm_Error; /* NSME_Success 0, Aborted 1, InUse 2,
Ignored 3, NotFound 4 */
ULONG nsm_Actual;
};
The header says to find the port under Forbid(), check ncp_Magic and only then PutMsg(). If the cookie is missing, the controller may not be listening:
Forbid();
control_port = (struct NetControlPort *)FindPort(NETWORK_CONTROLLER_PORT_NAME);
if (control_port != NULL && control_port->ncp_Magic == NCPM_Cookie)
{
network_in_use = TRUE;
PutMsg(&control_port->ncp_Port, (struct Message *)shutdown_message);
}
else
network_in_use = FALSE;
Permit();
The command then waits for the reply, a timer.device timeout (5 seconds by default) or Ctrl-C. On timeout or break it sends an NSMC_Cancel message whose nsm_Data points at the shutdown message. The shutdown cannot be stopped once it has started, and it can take longer while clients still hold network resources.
RoadshowControl and the RoadshowData API¶
ObtainRoadshowData(ORD_ReadAccess or ORD_WriteAccess) returns a struct List of RoadshowDataNode (rdn_Name, rdn_Flags with RDNF_ReadOnly, rdn_Type = RDNT_Integer, rdn_Length, rdn_Data). ChangeRoadshowData(list, name, length, data) sets a value, and ReleaseRoadshowData(list) gives the list back. With SAVE, the command also stores the value permanently. The equivalent environment variables are ENV:Roadshow/<group>/<name>, for example SetEnv SAVE Roadshow/ip/forwarding 1. Deleting ENVARC:Roadshow removes all saved settings. Documented option names include bpf.bufsize, icmp.maskrepl, icmp.processecho, icmp.procesststamp, if.receive.useclusters, if.minclustersize (default 208), ip.defttl, ip.forwarding, ip.sendredirects, ip.subnetsarelocal, task.controller.priority (−128..127, default 0), tcp.do_rfc1323, tcp.do_timestamps, tcp.do_win_scale, tcp.mssdflt, tcp.recvspace, tcp.rttdflt, tcp.sendspace, tcp.use_mssdflt_for_remote, udp.cksum, udp.recvspace and udp.sendspace. The source warns that wrong values "may render the TCP/IP inoperable".
GetNetStatus for scripts¶
CHECK takes a comma-separated list of INTERFACES, PTPINTERFACES, BCASTINTERFACES, RESOLVER, ROUTES and DEFAULTROUTE, which map one-to-one onto SBSYSSTAT_Interfaces … SBSYSSTAT_DefaultRoute. If any condition is false, the command exits with return code 5 (IF WARN). With no CHECK it prints the version and the state of every condition.
Online/Offline¶
These two commands talk to the SANA-II driver directly, not through the stack. They open the driver with a plain CreateIORequest(port, sizeof(struct IOSana2Req)) and no buffer-management tags, retrying with DEVS:Networks/ if needed. Then they queue S2_ONEVENT for the target state and send the command. They also contain string tables for every IOERR_*, S2ERR_* and S2WERR_* code. See SANA-II Device Driver Reference for the event logic.
Catalogs¶
The locale/ drawer has catalog descriptions and English/German translations for the stack and its tools:
.cd file |
Version | Strings | Catalog |
|---|---|---|---|
bsdsocket.cd |
4.15 (21.12.2013) | 237 | bsdsocket.catalog |
roadshow.cd |
4.47 (12.12.2015) | 534 | roadshow.catalog (opened by the commands) |
usergroup.cd |
4.1 (28.11.2002) | 81 | usergroup.catalog (errno texts for ug_StrError()) |
ppp-serial.cd |
2.24 (18.1.2005) | 234 | PPP serial driver |
ppp-ethernet.cd |
2.27 (18.1.2005) | 252 | PPPoE driver |
The commands open roadshow.catalog with OpenCatalogA(NULL, "roadshow.catalog", NULL) when locale.library is available. roadshow.h is the CatComp output with MSG_* IDs grouped per command (ADDNETINTERFACE_CATALOG_STRINGS …). See CatComp and Installer and Writing Localized Applications.
usergroup.library¶
usergroup.library provides a BSD-style interface to user and group IDs, the account and group databases, password checking and login records. It was created by the AmiTCP/IP Group (NSDi) and contains 4.3BSD Net2 code. Roadshow ships a compatible library (sfd/usergroup_lib.sfd, netinclude/libraries/usergroup.h).
Obsolete. Roadshow's
<libraries/usergroup.h>states: "The usergroup.library API must be considered obsolete and should not be used in new software. It is provided solely for backwards compatibility and legacy application software." Use it only to port or maintain AmiTCP-era code.
Library model¶
- Each
OpenLibrary()creates a new library base instance holding the static buffers and the signals of the opening task. Only the owner task may call most functions and only the owner may close it. Ownership can be passed withUGT_OWNER. - Any task may call
getuid(),geteuid(),getgid()andgetegid(). Any task may also callgetgroups(),setreuid(),setuid(),setregid(),setgid(),setgroups(),setsid()andsetlogin(), but non-owners cannot recover error codes. - Credentials are a real UID/GID, an effective UID and up to
NGROUPS(32) group IDs. In the AmiTCP implementation all tasks share one session andsetsid()does nothing. The user logs in withlogin -fat boot. - User and group data come from
netinfo.device(AmiTCP:db/passwd,AmiTCP:db/group). See netinfo.device and sana2.lib. - The AmiTCP autodoc warns that this library is not compatible with
multiuser.library: the ID conventions differ and multiuser uses the AS225r2 password encoding instead of Unixcrypt().
Function table¶
Base _UserGroupBase, bias 30. Roadshow's SFD has the same functions in the same order as the AmiTCP SDK 4.3 fd/usergroup_lib.fd.
| LVO | Function | Registers |
|---|---|---|
| −30 | LONG ug_SetupContextTagList(STRPTR name, struct TagItem *tags) |
A0, A1 |
| −36 | LONG ug_GetErr(void) |
— |
| −42 | STRPTR ug_StrError(LONG err) |
D1 |
| −48 | LONG getuid(void) |
— |
| −54 | LONG geteuid(void) |
— |
| −60 | LONG setreuid(LONG real, LONG effective) |
D0, D1 |
| −66 | LONG setuid(LONG uid) |
D0 |
| −72 | LONG getgid(void) |
— |
| −78 | LONG getegid(void) |
— |
| −84 | LONG setregid(LONG real, LONG effective) |
D0, D1 |
| −90 | LONG setgid(LONG gid) |
D0 |
| −96 | LONG getgroups(LONG gidsetlen, LONG *gidset) |
D0, A1 |
| −102 | LONG setgroups(LONG gidsetlen, LONG *gidset) |
D0, A1 |
| −108 | LONG initgroups(STRPTR name, LONG basegid) |
A1, D0 |
| −114 | struct passwd *getpwnam(STRPTR login) |
A1 |
| −120 | struct passwd *getpwuid(LONG uid) |
D0 |
| −126 | VOID setpwent(void) |
— |
| −132 | struct passwd *getpwent(void) |
— |
| −138 | VOID endpwent(void) |
— |
| −144 | struct group *getgrnam(STRPTR name) |
A1 |
| −150 | struct group *getgrgid(LONG gid) |
D0 |
| −156 | VOID setgrent(void) |
— |
| −162 | struct group *getgrent(void) |
— |
| −168 | VOID endgrent(void) |
— |
| −174 | UBYTE *crypt(UBYTE *key, UBYTE *set) |
A0, A1 |
| −180 | UBYTE *ug_GetSalt(struct passwd *user, UBYTE *buf, ULONG size) |
A0, A1, D0 |
| −186 | STRPTR getpass(STRPTR prompt) |
A1 |
| −192 | ULONG umask(UWORD mask) |
D0 |
| −198 | ULONG getumask(void) |
— |
| −204 | LONG setsid(void) |
— |
| −210 | LONG getpgrp(void) |
— |
| −216 | STRPTR getlogin(void) |
— |
| −222 | LONG setlogin(STRPTR name) |
A1 |
| −228 | VOID setutent(void) |
— |
| −234 | struct utmp *getutent(void) |
— |
| −240 | VOID endutent(void) |
— |
| −246 | struct lastlog *getlastlog(LONG uid) |
D0 |
| −252 | LONG setlastlog(LONG uid, STRPTR name, STRPTR host) |
D0, A0, A1 |
| −258 | struct UserGroupCredentials *getcredentials(struct Task *task) |
A0 |
ug_SetupContextTags(name, ...) is the varargs stub. Treat the FD/SFD as the authority over the autodoc text. For example, the autodoc's setlastlog() synopsis shows a fourth console argument, while the FD and SFD both define the three-argument form above.
Setting up the context¶
#define UGT_ERRNOBPTR 0x80000001
#define UGT_ERRNOWPTR 0x80000002
#define UGT_ERRNOLPTR 0x80000004
#define UGT_ERRNOPTR(size) /* picks one of the three from sizeof(errno) */
#define UGT_OWNER 0x80000011
#define UGT_INTRMASK 0x80000010
| Tag | Meaning |
|---|---|
UGT_ERRNOPTR(sizeof(errno)) |
Redirect the library's error code into your errno (1, 2 or 4 bytes). NULL stops redirection. The header encodes the size in the tag, where the autodoc's text speaks of a separate size tag. |
UGT_INTRMASK |
Signal mask that interrupts blocking calls. The signals are not cleared. Do not include the library's own signal. |
UGT_OWNER |
Hand the instance to another task (or NULL, after which any task can claim it with UGT_OWNER, FindTask(NULL)). |
The call returns 0 on success, or −1 with the code available from ug_GetErr(). On error the old context is cleared. AmiTCP's net.lib sets up the context like this when linked with usr.lib:
if (UserGroupBase = OpenLibrary(USERGROUPNAME, USERGROUPVERSION)) {
if (ug_SetupContextTags(_ProgramName,
UGT_INTRMASK, SIGBREAKB_CTRL_C,
UGT_ERRNOPTR(sizeof(errno)), &errno,
TAG_END) == 0)
return 0;
}
USERGROUPNAME is "usergroup.library" in the Roadshow header and "AmiTCP:libs/usergroup.library" in the AmiTCP SDK header.
Data structures¶
struct UserGroupCredentials /* <libraries/usergroup.h> */
{
LONG cr_ruid;
LONG cr_rgid;
UWORD cr_umask;
LONG cr_euid;
WORD cr_ngroups;
LONG cr_groups[NGROUPS]; /* NGROUPS = 32 */
LONG cr_session;
TEXT cr_login[MAXLOGNAME]; /* MAXLOGNAME = 32 */
};
struct passwd (pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell) is in <pwd.h>. struct group (gr_name, gr_passwd, gr_gid, gr_mem) is in <grp.h>. struct utmp (ut_time, ut_sid, ut_name, ut_line, ut_host) and struct lastlog (ll_time, ll_uid, ll_name, ll_line, ll_host) are in <utmp.h>. Other constants: _PASSWORD_LEN 128 (maximum getpass() length), _PASSWORD_EFMT1 '_' (extended crypt() format).
ID conversion with MultiUser. UG2MU(id) and MU2UG(id) convert between the two conventions: the super-user is 0 in usergroup and 65535 in MultiUser, and nobody is −2 in usergroup and 0 in MultiUser. IDs that do not fit in a UWORD are truncated.
Behaviour notes¶
- Static results:
getpw*(),getgr*(),getutent(),getlastlog(),getcredentials(),crypt()andgetpass()return pointers to internal static buffers that the next call overwrites. For re-entrant access, the autodoc points tonetinfo.device. getpwnam()/getgrnam()etc. open the netinfo unit as needed. Callendpwent()/endgrent()when you are done.[ENOENT]meansnetinfo.devicecould not be opened, and other netinfo I/O errors come fromug_GetErr().crypt(key, setting): a 9-byte setting (_+ 4 bytes iteration count + 4 bytes salt) gives the extended DES format and a 20-byte result. A 2-byte salt gives Version 7 compatibility (25 iterations, 8 key characters, 13-byte result).ug_GetSalt()generates a setting in a buffer of at least 12 bytes, Version 7 style by default.getpass()reads fromCONSOLE:with echo off, or from stdin/stderr if that is unavailable. Zero the returned password as soon as possible.umask()defaults to022. Its 9 low bits are used by Unix-like filesystems such as NFS.setgroups(),setlogin()and changes of other users' IDs need super-user rights ([EPERM]).getlastlog()/setlastlog()store only the latest user, and the utmp database allows one concurrent login.ug_StrError()also understands negative Exec I/O error codes. In Roadshow its texts come fromusergroup.catalog.
rsh is the NDK example that uses the library. It opens usergroup.library, calls getcredentials(NULL) and sends cr_login as the local user name to the remote rshd. Remote and local user names are truncated to 16 characters on the wire.
See Also¶
- Roadshow — bsdsocket TCP/IP Stack
- AmiTCP net.lib and SocketBaseTagList Tags
- netinfo.device and sana2.lib
- SANA-II Device Driver Reference
- CatComp and Installer
Sources: NDK 3.2 R4 SANA+RoadshowTCP-IP/source_code/Roadshow/.c, _rev.h, README, swap_stack.asm, roadshow.h; SANA+RoadshowTCP-IP/sfd/usergroup_lib.sfd; SANA+RoadshowTCP-IP/netinclude/libraries/usergroup.h, netinclude/libraries/bsdsocket.h; SANA+RoadshowTCP-IP/locale/*.cd; AmiTCP SDK 4.3 doc/usergroup.doc, netinclude/fd/usergroup_lib.fd, netinclude/libraries/usergroup.h, src/netlib/init_usergroup.c Updated: 2026-11-13