ftp.nice.ch/pub/next/unix/admin/sysinfo.1.1.0.s.tar.gz#/devices.c

This is devices.c in view mode; [Download] [Up]

/*
 * Copyright (c) 1992 Michael A. Cooper.
 * This software may be freely distributed provided it is not sold for 
 * profit and the author is credited appropriately.
 */

#ifndef lint
static char *RCSid = "$Header: /src/common/usc/bin/sysinfo/RCS/devices.c,v 1.26 1992/12/12 23:48:36 mcooper Exp mcooper $";
#endif

/*
 * $Log: devices.c,v $
 * Revision 1.26  1992/12/12  23:48:36  mcooper
 * Add support to MkDevName() to indicate no unit number in the DevDataTab entry.
 *
 * Revision 1.25  1992/12/12  23:11:27  mcooper
 * If a device has a NULL probe routine, ignore it.
 *
 * Revision 1.24  1992/12/02  05:01:26  mcooper
 * Add DT_CPU type.
 * Print dv_desc for devices without a DevTypes entry.
 *
 * Revision 1.23  1992/11/30  01:16:28  mcooper
 * Replace *dv_desc[23] with **dv_desclist.
 *
 * Revision 1.22  1992/11/21  04:35:19  mcooper
 * If device unit number is < 0, don't append to device name.
 * Add more description fields.
 * Add AIX device support.
 *
 * Revision 1.21  1992/08/13  04:48:50  mcooper
 * - Don't print "Device" and "." in device lines for clarity.
 * - Don't add unit number to model if Type == DT_NONE.
 *
 * Revision 1.20  1992/07/31  21:09:35  mcooper
 * Add support for doing GetDevDataTab() compares optionally
 * by length using the DDT_LENCMP flag in DEVDATATAB.
 *
 * Revision 1.19  1992/07/31  20:32:27  mcooper
 * Change GetDevDataTab() to do a normal compare and not
 * a compare by length.
 *
 * Revision 1.18  1992/04/26  23:32:06  mcooper
 * Add Copyright notice
 *
 * Revision 1.17  1992/04/17  01:07:59  mcooper
 * More de-linting
 *
 * Revision 1.16  1992/04/16  02:25:39  mcooper
 * Bug fixes, de-linting, and other changes found with CodeCenter.
 *
 * Revision 1.15  1992/04/15  02:41:37  mcooper
 * Change AddDevice() to check to make sure device doesn't already exist.
 *
 * Revision 1.14  1992/04/12  22:01:11  mcooper
 * Remove kludge for "id".
 *
 * Revision 1.12  1992/03/22  02:03:31  mcooper
 * Call BuildDevicesNeXT().
 *
 * Revision 1.11  1992/03/22  00:20:10  mcooper
 * Major cleanup and re-org.
 *
 * Revision 1.10  1992/03/09  01:25:24  mcooper
 * Print device description on first line if no other info is available.
 *
 * Revision 1.9  1992/03/08  04:57:36  mcooper
 * - Add support for multiple address per netif.
 * - Move probe_generic() here for os-sunos.c.
 *
 * Revision 1.8  1992/03/06  18:36:55  mcooper
 * Move some general functions here from sunos.c.
 *
 * Revision 1.7  1992/03/05  22:36:35  mcooper
 * Cleanup format.
 *
 * Revision 1.6  1992/03/01  21:30:37  mcooper
 * Use dd_secsize from DISKDRIVE instead of SECSIZE macro.
 *
 * Revision 1.5  1992/02/25  00:16:14  mcooper
 * - Major cleanup of printing.
 * - Init new device int's to -1.
 * - Add new device type's.
 *
 * Revision 1.4  1992/02/22  02:20:19  mcooper
 * Major changes to support scanning kernel mainbus and
 * openprom data for device's.
 *
 * Revision 1.3  1992/02/16  23:50:47  mcooper
 * Cleanup newline printing and add verbosity level checking.
 *
 * Revision 1.2  1992/02/16  22:46:03  mcooper
 * Add network interface support.
 *
 * Revision 1.1  1991/11/30  23:28:53  mcooper
 * Initial revision
 *
 */


#include <stdio.h>
#include "system.h"
#include "defs.h"

#define OFFSET 4

static void PrintDiskdrive();
static void PrintFrameBuffer();
static void PrintNetIf();
static void PrintDevice();
static void PrintGeneric();

struct devicetype {
    int				 dt_dtype;	/* Device type */
    char			*dt_desc;	/* Description */
    void		       (*dt_prfunc)();	/* Print function */
};
typedef struct devicetype DEVTYPE;

DEVTYPE DevTypes[] = {
    { DT_GENERIC,	NULL,			PrintGeneric },
    { DT_DISKDRIVE,	"disk drive",		PrintDiskdrive },
    { DT_DISKCTLR,	"disk controller",	PrintGeneric },
    { DT_TAPEDRIVE,	"tape drive",		PrintGeneric },
    { DT_TAPECTLR,	"tape controller",	PrintGeneric },
    { DT_FRAMEBUFFER,	"frame buffer",		PrintFrameBuffer },
    { DT_NETIF,		"network interface",	PrintNetIf },
    { DT_BUS,		"system bus",		PrintGeneric },
    { DT_PSEUDO,	"pseudo device",	PrintGeneric },
    { DT_CPU,		"CPU",			PrintGeneric },
    { 0 },
};

static float 			TotalDisk = 0;

/*
 * Get a device type.
 */
static DEVTYPE *GetDevType(Device)
    DEVICE 		       *Device;
{
    register int 		i;

    if (!Device)
	return((DEVTYPE *) NULL);

    for (i = 0; DevTypes[i].dt_prfunc; ++i)
	if (DevTypes[i].dt_dtype == Device->dv_type)
	    return(&DevTypes[i]);

    return((DEVTYPE *) NULL);
}

/*
 * Print all device info
 */
extern void ShowDevices(MyInfo, SpecInfo)
    SHOWINFO		       *MyInfo;
    SHOWINFO		       *SpecInfo;	/* ARGSUSED */
{
    static DEVICE 	       *RootDev;

#if	defined(sun)
    if (BuildDevicesSunOS(&RootDev) != 0)
	return;
#endif	/* sun */

#if	defined(ultrix)
    if (BuildDevicesUltrix(&RootDev) != 0)
	return;
#endif	/* ultrix */

#if	defined(NeXT)
    if (BuildDevicesNeXT(&RootDev) != 0)
	return;
#endif	/* NeXT */

#if	defined(_AIX)
    if (BuildDevicesAIX(&RootDev) != 0)
	return;
#endif	/* _AIX */

    if (!RootDev) {
	if (Debug)
	    printf("No devices were found.\n");
	return;
    }

    printf("\n\n\t%s\n\n", MyInfo->Label);

    TotalDisk = 0;

    PrintDevice(RootDev, 0);

    if (VL_DESC && TotalDisk > 0)
	printf("\nTotal Disk Capacity is %.2f MB\n", 
	       (float) bytes_to_mbytes(TotalDisk));
}

/*
 * --RECURSE--
 * Print info about a device.  Recursively calls itself for slaves and
 * next elements
 */
static void PrintDevice(Device, OffSet)
    DEVICE 		       *Device;
    int 			OffSet;
{
    DEVTYPE 		       *DevType;

    /*
     * If device->dv_name is not set, this is the root of the device tree
     */

    if (Device->dv_name) {
	if (DevType = GetDevType(Device))
	    (*DevType->dt_prfunc)(Device, DevType, OffSet);
	else
	    PrintGeneric(Device, DevType, OffSet);
    }

    /*
     * Descend
     */
    if (Device->dv_slaves)
	PrintDevice(Device->dv_slaves, (Device->dv_name) ? OffSet+OFFSET : 0);

    /*
     * Traverse
     */
    if (Device->dv_nxt)
	PrintDevice(Device->dv_nxt, (Device->dv_name) ? OffSet : 0);
}

/*
 * Print Off Set space
 */
static void PrOffSet(cnt)
    int 			cnt;
{
    printf("%*s", cnt, "");
}

/*
 * Print a device label
 */
static void PrDevLabel(Name, OffSet)
    char 		       *Name;
    int 			OffSet;
{
    PrOffSet(OffSet);
    if (VL_CONFIG)
	printf("%*s%-18s:", OFFSET, "", Name);
    else
	printf("%*s%18s:", OFFSET, "", Name);
}

/*
 * Print general device information
 */
static void PrintDeviceInfo(Device, DevType, OffSet)
    DEVICE 		       *Device;
    DEVTYPE 		       *DevType;
    int 			OffSet;
{     
    DEVTYPE 		       *mdt;
    register char	      **cpp;

    if (!Device->dv_name)
	return;

    if (VL_CONFIG) printf("\n");
    PrOffSet(OffSet);
    printf("%s", Device->dv_name);

    if (Device->dv_model || (DevType && DevType->dt_desc)) {
	printf(" is a");
	if (Device->dv_model)
	    printf(" \"%s\"", Device->dv_model);

	if (DevType && DevType->dt_desc)
	    printf(" %s", DevType->dt_desc);
	else if (Device->dv_desc)
	    printf(" %s", Device->dv_desc);
    } else if (Device->dv_desc) {
	printf(" is a");
	printf(" %s", Device->dv_desc);
    }

    if (Device->dv_name)
	printf("\n");

    if (VL_DESC || VL_CONFIG) {
	if (Device->dv_desc || Device->dv_desclist) {
	    if (Device->dv_desc) {
		PrDevLabel("Description", OffSet);
		printf(" %s\n", Device->dv_desc);
	    }
	    for (cpp = Device->dv_desclist; cpp && *cpp; ++cpp) {
		PrDevLabel("Description", OffSet);
		printf(" %s\n", *cpp);
	    }
	} else if ((mdt = GetDevType(Device)) && mdt && mdt->dt_desc) {
	    PrDevLabel("Description", OffSet);
	    printf(" %s\n", mdt->dt_desc);
	}

	if (Device->dv_master && Device->dv_master->dv_name) {
	    PrDevLabel("Description", OffSet);
	    if (Device->dv_master->dv_name)
		printf(" Connected to %s", Device->dv_master->dv_name);
	    else if (Device->dv_master->dv_model) {
		printf(" Connected to %s", Device->dv_master->dv_model);
		if (mdt = GetDevType(Device->dv_master))
		    printf(" %s", mdt->dt_desc);
	    }
	    printf("\n");
	}
    }
}

/*
 * Print info about a generic device
 */
static void PrintGeneric(Device, DevType, OffSet)
    DEVICE 		       *Device;
    DEVTYPE 		       *DevType;
    int 			OffSet;
{
    register DEVICE 	       *pd;

    PrintDeviceInfo(Device, DevType, OffSet);

    if (VL_CONFIG) {
	if (Device->dv_unit >= 0 || Device->dv_addr >= 0 || 
	    Device->dv_prio >= 0 || Device->dv_vec >= 0) {
	    PrDevLabel("Configuration", OffSet);
	    if (Device->dv_unit >= 0)
		printf(" Unit %d", Device->dv_unit);
	    if (Device->dv_addr >= 0)
		printf(" Address 0x%x", Device->dv_addr);
	    if (Device->dv_prio >= 0)
		printf(" Priority %d", Device->dv_prio);
	    if (Device->dv_vec >= 0)
		printf(" Vector %d", Device->dv_vec);
	    printf("\n");
	}
    }

    if (VL_CONFIG) {
	if (Device->dv_slaves && (Device->dv_name || Device->dv_model || 
				  (DevType && DevType->dt_desc))) {
	    PrDevLabel("Attached Device(s)", OffSet);
	    for (pd = Device->dv_slaves; pd; pd = pd->dv_nxt)
		printf(" %s", pd->dv_name);
	    printf("\n");
	}
    }
}

/*
 * Print info about disk partitioning.
 */
static void PrintDiskPart(Disk, OffSet)
    DISKDRIVE 		       *Disk;
    int 			OffSet;
{
    register DISKPART 	       *pp;

    printf("\n");
    PrOffSet(OffSet);
    printf("%50s\n", "Partition Information");

    PrOffSet(OffSet);
    printf("%20s %10s %10s %9s\n",
	   "", "START", "NUMBER OF", "SIZE");

    PrOffSet(OffSet);
    printf("%20s %10s %10s %9s %s\n",
	   "PART", "SECTOR", "SECTORS", "(MB)", "USAGE");

    for (pp = Disk->dd_part; pp; pp = pp->dp_nxt) {
	PrOffSet(OffSet);
	printf("%20s %10d %10d %9.2f %s\n",
	       pp->dp_name,
	       pp->dp_stsect,
	       pp->dp_nsect,
	       bytes_to_mbytes(nsect_to_bytes(pp->dp_nsect, Disk->dd_secsize)),
	       (pp->dp_mnt) ? pp->dp_mnt : ""
	       );
    }
}

/*
 * Print info about a disk device.
 */
static void PrintDiskdrive(Device, DevType, OffSet)
    DEVICE 		       *Device;
    DEVTYPE 		       *DevType;
    int 			OffSet;
{
    DISKDRIVE 		       *Disk;

    PrintDeviceInfo(Device, DevType, OffSet);

    if (!Device->dv_devspec)
	return;

    Disk = (DISKDRIVE *) Device->dv_devspec;

    TotalDisk += (float) Disk->dd_size;

    if (VL_CONFIG) {
	PrDevLabel("Configuration", OffSet);
	if (FLAGS_ON(Disk->dd_flags, DF_HEXUNIT))
	    printf(" Unit %3.3x", Disk->dd_unit);
	else
	    printf(" Unit %3d", Disk->dd_unit);

	printf("  Slave %2d  RPM %d  APC %d  Interleave %d\n", 
	       Disk->dd_slave, Disk->dd_rpm, Disk->dd_apc, Disk->dd_intrlv);

	PrDevLabel("Configuration", OffSet);
	printf(" %4d Physical Cylinders  %2d Alternate Cylinders\n", 
	       Disk->dd_pcyl, Disk->dd_acyl);

	PrDevLabel("Geometry", OffSet);
	printf(" %4d Data Cylinders      %2d Heads  %3d Sectors/Track\n",
	       Disk->dd_dcyl, Disk->dd_heads, Disk->dd_sect);

	if (Disk->dd_psect || Disk->dd_promrev) {
	    PrDevLabel("Hardware Info", OffSet);
	    printf(" %4d Hard Sectors  PROM Revision %d\n",
		   Disk->dd_psect, Disk->dd_promrev);
	}
    }

    if (VL_ALL && Disk->dd_part)
	PrintDiskPart(Disk, OffSet);
}

/*
 * Print info about a frame buffer.
 */
static void PrintFrameBuffer(Device, DevType, OffSet)
    DEVICE 		       *Device;
    DEVTYPE 		       *DevType;
    int 			OffSet;
{
    FRAMEBUFFER 	       *fb;

    PrintDeviceInfo(Device, DevType, OffSet);

    if (!Device->dv_devspec)
	return;

    fb = (FRAMEBUFFER *) Device->dv_devspec;

    if (VL_CONFIG) {
	PrDevLabel("Screen Size", OffSet);
	printf(" %d KB  Height %d  Width %d  Depth %d-bit%s\n",
	       bytes_to_kbytes(fb->fb_size),
	       fb->fb_height, fb->fb_width, fb->fb_depth,
	       (fb->fb_depth == 1) ? "" : "s");

	if (fb->fb_vmsize || fb->fb_cmsize) {
	    PrDevLabel("Configuration", OffSet);
	    if (fb->fb_vmsize)
		printf(" Video Memory %d KB ", bytes_to_kbytes(fb->fb_vmsize));
	    if (fb->fb_cmsize)
		printf(" Color Map Size is %d", fb->fb_cmsize);
	    printf("\n");
	}
    }
}

/*
 * Print info about a network interface
 */
static void PrintNetIf(Device, DevType, OffSet)
    DEVICE 		       *Device;
    DEVTYPE 		       *DevType;
    int 			OffSet;
{
    register NETIF	       *ni;

    PrintDeviceInfo(Device, DevType, OffSet);

    if (!Device->dv_devspec)
	return;

    if (VL_CONFIG) {
	for (ni = (NETIF *) Device->dv_devspec; ni; ni = ni->ni_nxt) {
	    if (ni->ni_typename) {
		printf("\n");
		PrDevLabel("Address Type", OffSet);
		printf(" %s\n", ni->ni_typename);
	    }

	    if (ni->ni_hostaddr) {
		PrDevLabel("Host Address", OffSet);
		printf(" %-18s [%s]\n", ni->ni_hostaddr,
		       (ni->ni_hostname) ? ni->ni_hostname : "<unknown>");
	    }

	    if (ni->ni_netaddr) {
		PrDevLabel("Network Address", OffSet);
		printf(" %-18s [%s]\n", ni->ni_netaddr, 
		       (ni->ni_netname) ? ni->ni_netname : "<unknown>");
	    }

	    if (ni->ni_macaddr) {
		PrDevLabel("MAC Address", OffSet);
		printf(" %-18s [%s]\n", ni->ni_macaddr,
		       (ni->ni_macname && ni->ni_macname[0]) 
		       ? ni->ni_macname : "<unknown>");
	    }
	}
    }
}

/*
 * --RECURSE--
 * Create a new DEVICE and optionally copy an old DEVICE.
 */
extern DEVICE *NewDevice(Old)
    DEVICE 		       *Old;
{
    register DEVICE 	       *SlavePtr, *Slave;
    DEVICE 		       *New = NULL;

    New = (DEVICE *) xcalloc(1, sizeof(DEVICE));

    /* Set int's to -1 */
    New->dv_type = New->dv_unit = New->dv_addr = New->dv_prio = 
	New->dv_vec = -1;

    if (!Old)
	return(New);

    /* Bulk copy what we can */
    bcopy((char *) Old, (char *) New, sizeof(DEVICE));

    New->dv_nxt = NULL;

    /* Copy contents of pointers */
    if (Old->dv_name)	New->dv_name = strdup(Old->dv_name);
    if (Old->dv_model)	New->dv_model = strdup(Old->dv_model);
    if (Old->dv_desc)	New->dv_desc = strdup(Old->dv_desc);

    /* Copy Slave info */
    for (Slave = Old->dv_slaves; Slave; Slave = Slave->dv_nxt) {
	/* Find last slave */
	for (SlavePtr = New->dv_slaves; SlavePtr && SlavePtr->dv_nxt; 
	     SlavePtr = SlavePtr->dv_nxt);
	/* Copy Old slave to last new slave device */
	SlavePtr = NewDevice(Slave);
    }

    return(New);
}

/*
 * Create a new DISKPART and optionally copy an old DISKPART.
 */
extern DISKPART *NewDiskPart(Old)
    DISKPART 		       *Old;
{
    DISKPART 		       *New = NULL;

    New = (DISKPART *) xcalloc(1, sizeof(DISKPART));

    if (!Old)
	return(New);

    /* Bulk copy what we can */
    bcopy((char *) Old, (char *) New, sizeof(DISKPART));

    New->dp_nxt = NULL;

    /* Copy contents of pointers */
    if (Old->dp_name)	New->dp_name = strdup(Old->dp_name);
    if (Old->dp_mnt)	New->dp_mnt = strdup(Old->dp_mnt);

    return(New);
}

/*
 * --RECURSE--
 * Create a new DISKDRIVE and optionally copy an old DISKDRIVE.
 */
extern DISKDRIVE *NewDiskDrive(Old)
    DISKDRIVE 		       *Old;
{
    register DISKPART 	       *dp, *pdp;
    DISKDRIVE 		       *New = NULL;

    New = (DISKDRIVE *) xcalloc(1, sizeof(DISKDRIVE));

    if (!Old)
	return(New);

    /* Bulk copy what we can */
    bcopy((char *) Old, (char *) New, sizeof(DISKDRIVE));

    New->dd_nxt = NULL;

    /* Copy contents of pointers */
    if (Old->dd_label)	New->dd_label = strdup(Old->dd_label);
    if (Old->dd_ctlr) 	New->dd_ctlr = NewDevice(Old->dd_ctlr);

    /* Copy partition info */
    for (dp = Old->dd_part; dp; dp = dp->dp_nxt) {
	/* Find last DISKPART */
	for (pdp = New->dd_part; pdp && pdp->dp_nxt; pdp = pdp->dp_nxt);
	/* Copy old DISKPART to last New DISKPART */
	pdp = NewDiskPart(dp);
    }

    return(New);
}

/*
 * Create a new FRAMEBUFFER and optionally copy an old FRAMEBUFFER.
 */
extern FRAMEBUFFER *NewFrameBuffer(Old)
    FRAMEBUFFER 	       *Old;
{
    FRAMEBUFFER 	       *New = NULL;

    New = (FRAMEBUFFER *) xcalloc(1, sizeof(FRAMEBUFFER));

    if (!Old)
	return(New);

    /* Bulk copy what we can */
    bcopy((char *) Old, (char *) New, sizeof(FRAMEBUFFER));

    return(New);
}

/*
 * Create a new NETIF and optionally copy an old NETIF.
 */
extern NETIF *NewNetif(Old)
    NETIF 		       *Old;
{
    NETIF 		       *New = NULL;

    New = (NETIF *) xcalloc(1, sizeof(NETIF));

    if (!Old)
	return(New);

    /* Copy */
    New->ni_hostaddr = strdup(Old->ni_hostaddr);
    New->ni_hostname = strdup(Old->ni_hostname);
    New->ni_macaddr = strdup(Old->ni_macaddr);
    New->ni_macname = strdup(Old->ni_macname);
    New->ni_netaddr = strdup(Old->ni_netaddr);
    New->ni_netname = strdup(Old->ni_netname);

    return(New);
}

/*
 * --RECURSE--
 * Find device named "name" in tree "treeptr".
 * This function recursively calls itself looking for 
 * the device "name".
 */
extern DEVICE *FindDeviceByName(Name, TreePtr)
    char 		       *Name;
    DEVICE 		       *TreePtr;
{
    DEVICE 		       *Ptr;

    if (!Name || !TreePtr)
	return((DEVICE *) NULL);

    if (TreePtr->dv_name && Name && EQ(TreePtr->dv_name, Name))
	return(TreePtr);

    if (TreePtr->dv_slaves)
	if (Ptr = FindDeviceByName(Name, TreePtr->dv_slaves))
	    return(Ptr);

    if (TreePtr->dv_nxt)
	if (Ptr = FindDeviceByName(Name, TreePtr->dv_nxt))
	    return(Ptr);

    return((DEVICE *) NULL);
}

/*
 * Check to see if device's dev1 and dev2 are consistant.
 * If there is a discrepancy between the two due to one
 * device not having it's value set, then set it to the
 * other device's value.  Basically this "fills in the blanks".
 */
static void CheckDevice(Dev1, Dev2)
     DEVICE 		       *Dev1;
     DEVICE 		       *Dev2;
{
#define CHECK(a,b) \
    if (a != b) { \
	if (a) \
	    b = a; \
	else if (b) \
	    a = b; \
    }

    CHECK(Dev1->dv_type, 	Dev2->dv_type);
    CHECK(Dev1->dv_model, 	Dev2->dv_model);
    CHECK(Dev1->dv_desc, 	Dev2->dv_desc);
    CHECK(Dev1->dv_unit, 	Dev2->dv_unit);
    CHECK(Dev1->dv_addr, 	Dev2->dv_addr);
    CHECK(Dev1->dv_prio, 	Dev2->dv_prio);
    CHECK(Dev1->dv_vec, 	Dev2->dv_vec);
    CHECK(Dev1->dv_devspec, 	Dev2->dv_devspec);
    CHECK(Dev1->dv_master, 	Dev2->dv_master);

#undef CHECK
}

/*
 * --RECURSE--
 * Add a device to a device list.
 */
extern int AddDevice(Device, TreePtr)
    DEVICE 		       *Device;
    DEVICE 		      **TreePtr;
{
    register DEVICE 	       *master = NULL, *mp = NULL;

    if (!Device || !TreePtr) {
	Error("Invalid parameter passed to AddDevice()");
	return(-1);
    }

    /*
     * Make sure device hasn't already been added
     */
    if (FindDeviceByName(Device->dv_name, *TreePtr)) {
	if (Debug) 
	    printf("AddDevice: Device '%s' already exists; master = '%s'\n",
		   Device->dv_name, (master) ? master->dv_name : "?");
	return(-1);
    }

    if (Device->dv_name)
	Device->dv_name = strdup(Device->dv_name);

    /*
     * If the device has a master, find the master device.
     * If one doesn't exist in the tree, then add it by recursively
     * calling this function.
     */
    if (Device->dv_master) {
	if (*TreePtr) {
	    master = FindDeviceByName(Device->dv_master->dv_name, *TreePtr);
	    if (master && EQ(master->dv_name, Device->dv_master->dv_name))
		/* Check and fix any differences in info between master's */
		CheckDevice(master, Device->dv_master);
	} else
	    master = NULL;
	if (!master) {
	    if (AddDevice(Device->dv_master, TreePtr) != 0) {
		Error("Cannot add master '%s' to device tree.", 
		      master->dv_name);
		return(-1);
	    }
	    master = Device->dv_master;
	}
    } else {
	if (!*TreePtr)
	    *TreePtr = NewDevice((DEVICE *)NULL);
	master = *TreePtr;
    }

    if (master->dv_name)
	master->dv_name = strdup(master->dv_name);

    if (master->dv_slaves) {
	/* Add to existing list of slaves */
	for (mp = master->dv_slaves; mp && mp->dv_nxt; mp = mp->dv_nxt);
	mp->dv_nxt = Device;
    } else
	/* Create first slave */
	master->dv_slaves = Device;

    return(0);
}

/*
 * Get device data tab entry for "name"
 */
extern DEVDATATAB *GetDevDataTab(Name)
    char 		       *Name;
{
    extern DEVDATATAB 	 	DevDataTab[];
    register int 		i;

    for (i = 0; DevDataTab[i].ddt_name; ++i)
	if (DevDataTab[i].ddt_flags & DDT_LENCMP) {
	    if (EQN(Name, DevDataTab[i].ddt_name, 
		    strlen(DevDataTab[i].ddt_name)))
		return(&DevDataTab[i]);
	} else {
	    if (EQ(Name, DevDataTab[i].ddt_name)) 
		return(&DevDataTab[i]);
	}

    return((DEVDATATAB *) NULL);
}

/*
 * Create a device entry for a generic device
 */
extern DEVICE *ProbeGeneric(Name, DevData, DevDataTab)
     /*ARGSUSED*/
    char 		       *Name;
    DEVDATA 		       *DevData;
    DEVDATATAB	 	       *DevDataTab;
{
    DEVICE		       *Device;

    /*
     * DT_GENERIC devices MUST be marked alive to proceed
     */
    if (DevDataTab->ddt_type == DT_GENERIC && 
	!(FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE) ||
	  FLAGS_ON(DevData->dd_flags, DD_MAYBE_ALIVE)))
	return((DEVICE *) NULL);

    Device = NewDevice((DEVICE *) NULL);
    if (Name)
	Device->dv_name = strdup(Name);
    else
	Device->dv_name = strdup(MkDevName(DevData->dd_devname, 
					   DevData->dd_devunit,
					   DevDataTab->ddt_type,
					   DevDataTab->ddt_flags));
    Device->dv_type = DevDataTab->ddt_type;
    Device->dv_model = DevDataTab->ddt_model;
    Device->dv_desc = DevDataTab->ddt_desc;
    Device->dv_unit = DevData->dd_devunit;
    Device->dv_master = MkMasterFromDevData(DevData);

    return(Device);
}

/*
 * Search for and call an appropriate probe function for this 
 * device
 */
extern DEVICE *ProbeDevice(DevData, TreePtr)
    DEVDATA 		       *DevData;
    DEVICE 		      **TreePtr;
{
    register DEVDATATAB        *pddt;
    register char 	       *Name;
    DEVICE 		       *ProbeUnknown();

    if (pddt = GetDevDataTab(DevData->dd_devname)) {
	if ((*pddt->ddt_probe) == NULL) {
	    if (Debug) printf("Device %s doesn't have a probe routine.\n",
			      pddt->ddt_name);
	    return((DEVICE *) NULL);
	}

	Name = MkDevName(DevData->dd_devname, DevData->dd_devunit,
			 pddt->ddt_type, pddt->ddt_flags);
	if (FindDeviceByName(Name, *TreePtr)) {
	    if (Debug) printf("Device %s already exists.\n", Name);
	    return((DEVICE *) NULL);
	}
	return((*pddt->ddt_probe)(Name, DevData, pddt));
    }

    /*
     * The device is unknown to us.  If it's definetly alive,
     * return a minimal device entry for it.  If it's not alive,
     * ignore it.
     */
    if (DoPrintUnknown && DevData->dd_devname && 
	FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE))
	return(ProbeUnknown(Name, DevData));

    if (Debug)
	printf("Device `%s' is not defined.\n", DevData->dd_devname);

    return((DEVICE *) NULL);
}


/*
 * Make a master device from a DevData controller
 */
extern DEVICE *MkMasterFromDevData(DevData)
    DEVDATA 		       *DevData;
{
    register DEVICE 	       *Device = NULL;
    register DEVDATATAB        *ddt;
    int 			type = 0;
    int 			flags = 0;

    if (DevData->dd_ctlrname) {
	Device = NewDevice(NULL);
	if (ddt = GetDevDataTab(DevData->dd_ctlrname)) {
	    type = ddt->ddt_type;
	    flags = ddt->ddt_flags;
	    Device->dv_desc = ddt->ddt_desc;
	    Device->dv_model = ddt->ddt_model;
	}
	Device->dv_name = MkDevName(DevData->dd_ctlrname,
				    DevData->dd_ctlrunit, 
				    type, flags);
    }

    return(Device);
}

/*
 * Make the file name of the raw device
 */
extern char *GetRawFile(Name, Part)
    char 		       *Name;
    char 		       *Part;
{
    static char 		rfile[BUFSIZ];

    if (!Name)
	return((char *) NULL);

    (void) sprintf(rfile, "/dev/r%s%s", Name, (Part) ? Part : "");

    return(rfile);
}

/*
 * Make the file name of the character device
 */
extern char *GetCharFile(Name, Part)
    char 		       *Name;
    char 		       *Part;
{
    static char 		file[BUFSIZ];

    if (!Name)
	return((char *) NULL);

    (void) sprintf(file, "/dev/%s%s", Name, (Part) ? Part : "");

    return(file);
}

/*
 * Make device name
 */
extern char *MkDevName(Name, Unit, Type, DdtFlags)
    char 		       *Name;
    int 			Unit;
    int 			Type;
    int 			DdtFlags;
{
    static char			Buf[BUFSIZ];

    /*
     * Don't attach unit number if this is a pseudo device.
     */
    if (Unit < 0 || Type == DT_PSEUDO || Type == DT_NONE || 
	(DdtFlags & DDT_NOUNIT))
	sprintf(Buf, "%s", Name);
    else
	sprintf(Buf, "%s%d", Name, Unit);

    return(strdup(Buf));
}

/*
 * Create a minimal device type for an unknown device.
 */
extern DEVICE *ProbeUnknown(Name, DevData)
     /*ARGSUSED*/
    char 		       *Name;
    DEVDATA 		       *DevData;
{
    DEVICE		       *Device;

    Device = NewDevice((DEVICE *) NULL);
    Device->dv_name = strdup(MkDevName(DevData->dd_devname, 
				       DevData->dd_devunit,
				       -1, 0));
    Device->dv_type = DT_GENERIC;
    Device->dv_desc = "unknown device type";
    Device->dv_unit = DevData->dd_devunit;
    Device->dv_master = MkMasterFromDevData(DevData);

    return(Device);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.