home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / sysinfo-1.0 / part01 / os-sunos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-10  |  37.7 KB  |  1,591 lines

  1. /*
  2.  * Copyright (c) 1992 Michael A. Cooper.
  3.  * This software may be freely distributed provided it is not sold for 
  4.  * profit and the author is credited appropriately.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *RCSid = "$Header: /src/common/usc/bin/sysinfo/RCS/os-sunos.c,v 1.30 1992/04/26 23:51:53 mcooper Exp $";
  9. #endif
  10.  
  11. /*
  12.  * $Log: os-sunos.c,v $
  13.  * Revision 1.30  1992/04/26  23:51:53  mcooper
  14.  * Add some comments.
  15.  *
  16.  * Revision 1.28  1992/04/19  23:17:46  mcooper
  17.  * Suppress CodeCenter warning about "romp".
  18.  *
  19.  * Revision 1.27  1992/04/19  23:07:23  mcooper
  20.  * Update GetRomVer() to be more portable.
  21.  *
  22.  * Revision 1.26  1992/04/18  20:48:18  mcooper
  23.  * Add #ifdef HAVE_SUNROMVEC around GetRomVer.
  24.  *
  25.  * Revision 1.25  1992/04/17  23:27:51  mcooper
  26.  * Add support for ROM Version information (Sun only for now).
  27.  *
  28.  * Revision 1.24  1992/04/17  01:07:59  mcooper
  29.  * More de-linting
  30.  *
  31.  * Revision 1.23  1992/04/16  02:25:39  mcooper
  32.  * Bug fixes, de-linting, and other changes found with CodeCenter.
  33.  *
  34.  * Revision 1.22  1992/04/15  02:46:34  mcooper
  35.  * - Add better MainBus() and OPENPROM() build debug messages.
  36.  * - Make GetKernArchName() use "cpu" kernel symbol like GetModelName().
  37.  *
  38.  * Revision 1.21  1992/04/15  02:02:17  mcooper
  39.  * Change GetMemoryStr() to GetMemory().
  40.  *
  41.  * Revision 1.20  1992/04/12  22:03:56  mcooper
  42.  * - Change GetModelName() to use kernel symbol "cpu" instead
  43.  *   of gethostid() to be more portable to other SPARC clones.
  44.  * - Update GetKernArchName() to support Solbourne CPU_TYPE.
  45.  * - Add HAVE_IPI kludge for "id" disks.
  46.  * - Various other cleanup bits.
  47.  *
  48.  * Revision 1.19  1992/03/31  01:55:17  mcooper
  49.  * Use new CheckNlist to check nlist success.
  50.  *
  51.  * Revision 1.18  1992/03/31  00:45:27  mcooper
  52.  * Fixed GetKernArchName() to use CPU_ARCH mask.
  53.  *
  54.  * Revision 1.17  1992/03/31  00:15:09  mcooper
  55.  * Add error check for nlist.n_type.
  56.  *
  57.  * Revision 1.16  1992/03/25  03:28:32  mcooper
  58.  * Skip partitions that have 0 size.
  59.  *
  60.  * Revision 1.15  1992/03/25  03:20:14  mcooper
  61.  * Only read partition info we we're going to print it later.
  62.  *
  63.  * Revision 1.14  1992/03/22  00:20:10  mcooper
  64.  * Major cleanup and re-org.
  65.  *
  66.  * Revision 1.13  1992/03/09  01:23:42  mcooper
  67.  * Add need include files for NIT stuff.
  68.  *
  69.  * Revision 1.12  1992/03/08  04:58:30  mcooper
  70.  * Move probe_generic() to devices.c.
  71.  *
  72.  * Revision 1.11  1992/03/06  18:37:26  mcooper
  73.  * Move some general functions to devices.c.
  74.  *
  75.  * Revision 1.10  1992/03/05  22:36:35  mcooper
  76.  * Cleanup format.
  77.  *
  78.  * Revision 1.9  1992/03/05  05:12:10  mcooper
  79.  * Cleanup build_mainbus().
  80.  *
  81.  * Revision 1.8  1992/03/01  23:30:15  mcooper
  82.  * More more SunOS specific code from sysinfo.c to here.
  83.  *
  84.  * Revision 1.7  1992/02/27  22:01:22  mcooper
  85.  * Add support for getting CPU info for sun4m.
  86.  *
  87.  * Revision 1.6  1992/02/27  20:36:52  mcooper
  88.  * Remove \n from error() messages.
  89.  *
  90.  * Revision 1.5  1992/02/26  19:07:21  mcooper
  91.  * Add a debug statement.
  92.  *
  93.  * Revision 1.4  1992/02/25  00:59:35  mcooper
  94.  * Move tape info to local MTINFO.
  95.  *
  96.  * Revision 1.3  1992/02/25  00:17:45  mcooper
  97.  * Lots of fixes and changes.
  98.  *
  99.  * Revision 1.2  1992/02/22  02:30:29  mcooper
  100.  * Fix fbtab stuff.
  101.  *
  102.  * Revision 1.1  1992/02/22  02:20:19  mcooper
  103.  * Initial revision
  104.  *
  105.  * Revision 1.5  1992/02/19  22:30:44  mcooper
  106.  * Fix calling problem.
  107.  *
  108.  * Revision 1.4  1992/02/17  01:00:23  mcooper
  109.  * - More portability and support for solbourne.
  110.  *
  111.  * Revision 1.3  1992/02/17  00:24:22  mcooper
  112.  * Update frame buffers.
  113.  *
  114.  * Revision 1.2  1992/02/16  22:55:44  mcooper
  115.  * Add netif support.
  116.  *
  117.  * Revision 1.1  1991/11/30  23:28:53  mcooper
  118.  * Initial revision
  119.  *
  120.  */
  121.  
  122. #include <stdio.h>
  123. #include "system.h"
  124. #include "defs.h"
  125.  
  126. #include <mntent.h>
  127. #include <nlist.h>
  128. #include <sys/param.h>
  129. #include <sys/types.h>
  130. #include <sys/buf.h>
  131. #include <sys/stat.h>
  132. #include <sys/mtio.h>
  133. #include <sun/dkio.h>
  134. #include <sun/dklabel.h>
  135. #include <sun/fbio.h>
  136.  
  137. /*
  138.  * Name of frame buffer "indirect" device.
  139.  */
  140. #define FBDEVICE    "fb"
  141.  
  142. /*
  143.  * Name of generic magnetic tape device.
  144.  */
  145. #define MTNAME        "mt"
  146.  
  147. /*
  148.  * Generally used variables
  149.  */
  150. static kvm_t             *kd = NULL;
  151. static struct stat          StatBuf;
  152. static DEVICE             *Device;
  153. static char              Buf[BUFSIZ];
  154.  
  155. #if    defined(HAVE_MAINBUS)
  156. /*
  157.  * Build a device tree by searching the MainBus
  158.  */
  159. #include <sundev/mbvar.h>
  160.  
  161. #define DV_SIZE    (sizeof(struct mb_device))
  162. #define DR_SIZE (sizeof(struct mb_driver))
  163.  
  164. /*
  165.  * Build device tree by looking at mainbus (mb) devices
  166.  */
  167. static int BuildMainBus(TreePtr)
  168.     DEVICE                **TreePtr;
  169. {
  170.     extern struct nlist      MainBusNL[];
  171.     static struct mb_device      Device;
  172.     static struct mb_driver      Driver;
  173.     static char          CtlrName[BUFSIZ], DevName[BUFSIZ];
  174.     static DEVDATA          DevData;
  175.     u_long              Addr, DeviceAddr;
  176.     DEVICE             *Dev;
  177.  
  178.     /*
  179.      * Read table address from kernel
  180.      */
  181.     if (!(kd = KVM_open(MainBusNL))) {
  182.     if (Debug) Error("Cannot open & nlist mainbus device table.");
  183.     return(-1);
  184.     }
  185.  
  186.     /*
  187.      * See if we got a valid entry
  188.      */
  189.     if (CheckNlist(&MainBusNL[0]))
  190.     return(-1);
  191.  
  192.     /*
  193.      * Read each device table entry.  A NULL device.mb_driver
  194.      * indicates that we're at the end of the table.
  195.      */
  196.     for (DeviceAddr = MainBusNL[0].n_value; DeviceAddr; 
  197.      DeviceAddr += DV_SIZE) {
  198.  
  199.     /*
  200.      * Read this device
  201.      */
  202.     if (KVM_read(kd, DeviceAddr, (char *) &Device, DV_SIZE)) {
  203.         if (Debug) 
  204.         Error("Cannot read mainbus device from address 0x%x.", 
  205.               DeviceAddr);
  206.         KVM_close(kd);
  207.         return(-1);
  208.     }
  209.  
  210.     /*
  211.      * See if we're done.
  212.      */
  213.     if (!Device.md_driver)
  214.         break;
  215.  
  216.     /*
  217.      * Read the driver structure
  218.      */
  219.     Addr = (u_long) Device.md_driver;
  220.     if (KVM_read(kd, Addr, (char *) &Driver, DR_SIZE)) {
  221.         if (Debug) 
  222.         Error("Cannot read driver for mainbus address 0x%x.", Addr);
  223.         continue;
  224.     }
  225.  
  226.     /*
  227.      * Get the device name
  228.      */
  229.     if (Addr = (u_long) Driver.mdr_dname) {
  230.         if (KVM_read(kd, Addr, (char *) DevName, sizeof(DevName))) {
  231.         if (Debug)
  232.             Error("Cannot read device name from address 0x%x.", Addr);
  233.         continue;
  234.         }
  235.     } else
  236.         DevName[0] = C_NULL;
  237.  
  238.     /*
  239.      * Get the controller name
  240.      */
  241.     if (Addr = (u_long) Driver.mdr_cname) {
  242.         if (KVM_read(kd, Addr, (char *) CtlrName, sizeof(CtlrName))) {
  243.         if (Debug)
  244.             Error(
  245.               "Cannot read controller name from address 0x%x.", Addr);
  246.         continue;
  247.         }
  248.     } else
  249.         CtlrName[0] = C_NULL;
  250.  
  251.     /* Make sure devdata is clean */
  252.     bzero(&DevData, sizeof(DEVDATA));
  253.  
  254.     /* Set what we know */
  255.     if (DevName[0]) {
  256.         DevData.dd_devname = strdup(DevName);
  257.         DevData.dd_devunit = Device.md_unit;
  258.     }
  259.     if (CtlrName[0]) {
  260.         DevData.dd_ctlrname = strdup(CtlrName);
  261.         DevData.dd_ctlrunit = Device.md_ctlr;
  262.     }
  263.     /* 
  264.      * Mainbus devices such, as SCSI targets, may not exist
  265.      * but the controller reports them as present
  266.      */
  267.     if (Device.md_alive)
  268.         DevData.dd_flags |= DD_MAYBE_ALIVE;
  269.  
  270.     if (Debug)
  271.         printf("MainBus: Found \"%s\" (Unit %d) on \"%s\" (Unit %d) %s\n", 
  272.            DevData.dd_devname, DevData.dd_devunit,
  273.            DevData.dd_ctlrname, DevData.dd_ctlrunit,
  274.            (DevData.dd_flags & DD_MAYBE_ALIVE) ? "[MAYBE-ALIVE]" : "");
  275.  
  276.     /* Probe and add device */
  277.     if (Dev = ProbeDevice(&DevData, TreePtr))
  278.         AddDevice(Dev, TreePtr);
  279.     }
  280.  
  281.     KVM_close(kd);
  282.     return(0);
  283. }
  284. #endif    /* HAVE_MAINBUS */
  285.  
  286. #if     defined(HAVE_OPENPROM)
  287. /*
  288.  * OpenPROM stuff
  289.  */
  290. #include <sun/openprom.h>
  291.  
  292. /*
  293.  * Build device tree by looking at OpenPROM (op)
  294.  */
  295. static int BuildOpenPROM(TreePtr)
  296.     DEVICE               **TreePtr;
  297. {
  298.     static struct dev_info     Root, *PtrRoot;
  299.     extern struct nlist     OpenPROMNL[];
  300.     u_long             Addr;
  301.  
  302.     if (!(kd = KVM_open(OpenPROMNL))) {
  303.     if (Debug) Error("Cannot open kernel and read openprom devinfo");
  304.     return(-1);
  305.     }
  306.  
  307.     /*
  308.      * See if we got a valid entry
  309.      */
  310.     if (CheckNlist(&OpenPROMNL[0]))
  311.     return(-1);
  312.  
  313.     /*
  314.      * Read pointer to "top_devinfo" from kernel
  315.      */
  316.     Addr = OpenPROMNL[0].n_value;
  317.     if (KVM_read(kd, Addr, (char *) &PtrRoot, sizeof(struct dev_info *))) {
  318.     if (Debug) Error("Cannot read openprom devinfo pointer from kernel");
  319.     return(-1);
  320.     }
  321.  
  322.     if (KVM_read(kd, (u_long)PtrRoot, (char *)&Root, 
  323.          sizeof(struct dev_info))) {
  324.     if (Debug) Error("Cannot read openprom devinfo root from kernel");
  325.     return(-1);
  326.     }
  327.  
  328.     return(OpenPROMTraverse(&Root, NULL, TreePtr));
  329. }
  330.  
  331. /*
  332.  * Check an OpenPROM device.
  333.  */
  334. static int CheckOpenPROMDevice(DevInfo, Parent, TreePtr)
  335.     struct dev_info         *DevInfo;
  336.     struct dev_info         *Parent;
  337.     DEVICE                **TreePtr;
  338. {
  339.     static DEVDATA          DevData;
  340.     DEVICE             *Device;    
  341.  
  342.     /* Make sure devdata is clean */
  343.     bzero(&DevData, sizeof(DEVDATA));
  344.  
  345.     /* Set what we know */
  346.     if (DevInfo && DevInfo->devi_name) {
  347.     DevData.dd_devname = DevInfo->devi_name;
  348.     DevData.dd_devunit = DevInfo->devi_unit;
  349.     }
  350.     if (Parent && Parent->devi_name) {
  351.     DevData.dd_ctlrname = Parent->devi_name;
  352.     DevData.dd_ctlrunit = Parent->devi_unit;
  353.     }
  354.     /* 
  355.      * OpenPROM nodes that have a driver ALWAYS exist.
  356.      * Some nodes may exist, without a driver, however.
  357.      */
  358.     if (DevInfo->devi_driver)
  359.     DevData.dd_flags |= DD_IS_ALIVE;
  360.  
  361.     if (Debug)
  362.     printf("OPENPROM: Found \"%s\" (Unit %d) on \"%s\" (Unit %d) %s\n", 
  363.            DevData.dd_devname, DevData.dd_devunit,
  364.            DevData.dd_ctlrname, DevData.dd_ctlrunit,
  365.            (DevData.dd_flags & DD_IS_ALIVE) ? "[ALIVE]" : "");
  366.  
  367.     /* Probe and add device */
  368.     if (Device = (DEVICE *) ProbeDevice(&DevData, TreePtr))
  369.     AddDevice(Device, TreePtr);
  370. }
  371.  
  372. /*
  373.  * Recursively traverse and descend the OpenPROM devinfo tree.
  374.  */
  375. static int OpenPROMTraverse(DevPtr, Parent, TreePtr)
  376.     struct dev_info         *DevPtr;
  377.     struct dev_info         *Parent;
  378.     DEVICE                **TreePtr;
  379. {
  380.     static char          Name[BUFSIZ];
  381.     struct dev_info         *Ptr;
  382.  
  383.     /*
  384.      * If node name is a valid pointer, read the name from kernel space
  385.      * and call openprom_probe to handle checking the device.
  386.      */
  387.     if (DevPtr->devi_name) {
  388.     if (KVM_read(kd, (u_long) DevPtr->devi_name, (char *) Name, 
  389.              sizeof(Name))) {
  390.         Error("Cannot read openprom device name.");
  391.         Name[0] = C_NULL;
  392.     } else {
  393.         DevPtr->devi_name = (char *) strdup(Name);
  394.         CheckOpenPROMDevice(DevPtr, Parent, TreePtr);
  395.     }
  396.     }
  397.  
  398.     /*
  399.      * If this node has slaves, read the slave data from kernel space
  400.      * and descend.
  401.      */
  402.     if (DevPtr->devi_slaves) {
  403.     Ptr = (struct dev_info *) xcalloc(1, sizeof(struct dev_info));
  404.     if (KVM_read(kd, (u_long) DevPtr->devi_slaves, (char *) Ptr,
  405.              sizeof(struct dev_info))) {
  406.         Error("Cannot read openprom slave data for %s.", Name);
  407.     } else {
  408.         DevPtr->devi_slaves = (struct dev_info *) Ptr;
  409.         OpenPROMTraverse(DevPtr->devi_slaves, DevPtr, TreePtr);
  410.     }
  411.     }
  412.  
  413.     /*
  414.      * If this node has a next pointer, read the next data from kernel space
  415.      * and traverse.
  416.      */
  417.     if (DevPtr->devi_next) {
  418.     Ptr = (struct dev_info *) xcalloc(1, sizeof(struct dev_info));
  419.     if (KVM_read(kd, (u_long) DevPtr->devi_next, (char *) Ptr,
  420.              sizeof(struct dev_info))) {
  421.         Error("Cannot read openprom next data for %s.", Name);
  422.     } else {
  423.         DevPtr->devi_next = (struct dev_info *) Ptr;
  424.         OpenPROMTraverse(DevPtr->devi_next, Parent, TreePtr);
  425.     }
  426.     }
  427.  
  428.     return(0);
  429. }
  430. #endif /* HAVE_OPENPROM */
  431.  
  432. /*
  433.  * Build device tree using TreePtr.
  434.  * Calls bus and method specific functions to
  435.  * search for devices.
  436.  */
  437. extern int BuildDevicesSunOS(TreePtr)
  438.     DEVICE                **TreePtr;
  439. {
  440.     int              Found = 1;
  441.  
  442. #if    defined(HAVE_OPENPROM)
  443.     if (BuildOpenPROM(TreePtr) == 0)
  444.     Found = 0;
  445. #endif    /* HAVE_OPENPROM */
  446.  
  447. #if    defined(HAVE_MAINBUS)
  448.     if (BuildMainBus(TreePtr) == 0)
  449.     Found = 0;
  450. #endif    /* HAVE_MAINBUS */
  451.  
  452.     return(Found);
  453. }
  454.  
  455. /*
  456.  * Scan the Disk Controller table looking for
  457.  * a specific type.
  458.  */
  459. static DKCTLRTAB *GetDkCtlrTab(DkCtrlType)
  460.     int             DkCtrlType;
  461. {
  462.     extern DKCTLRTAB         DkCtlrTab[];
  463.     register int         i;
  464.  
  465.     for (i = 0; DkCtlrTab[i].ct_model; ++i) {
  466.     if (DkCtrlType == DkCtlrTab[i].ct_ctype)
  467.         return(&DkCtlrTab[i]);
  468.     }
  469.  
  470.     return((DKCTLRTAB *) NULL);
  471. }
  472.  
  473. /*
  474.  * Scan the Frame Buffer table looking for 
  475.  * a specific fb type.
  476.  */
  477. static NAMETAB *GetFBTab(FBType)
  478.     int             FBType;
  479. {
  480.     extern NAMETAB         FBTab[];
  481.     register int         i;
  482.  
  483.     for (i = 0; FBTab[i].name; ++i) {
  484.     if (FBType == FBTab[i].value)
  485.         return(&FBTab[i]);
  486.     }
  487.  
  488.     return((NAMETAB *) NULL);
  489. }
  490.  
  491. /*
  492.  * Get disk info structure.
  493.  */
  494. static struct dk_info *GETdk_info(d, file)
  495.     int             d;
  496.     char                *file;
  497. {
  498.     static struct dk_info     dk_info;
  499.  
  500.     if (ioctl(d, DKIOCINFO, &dk_info) < 0) {
  501.     if (Debug) Error("%s: DKIOCINFO: %s.", file, SYSERR);
  502.     return(NULL);
  503.     }
  504.  
  505.     return(&dk_info);
  506. }
  507.  
  508. /*
  509.  * Get disk configuration structure.
  510.  */
  511. static struct dk_conf *GETdk_conf(d, file)
  512.     int             d;
  513.     char                *file;
  514. {
  515.     static struct dk_conf     dk_conf;
  516.  
  517.     if (ioctl(d, DKIOCGCONF, &dk_conf) < 0) {
  518.     if (Debug) Error("%s: DKIOCGCONF: %s.", file, SYSERR);
  519.     return(NULL);
  520.     }
  521.  
  522.     return(&dk_conf);
  523. }
  524.  
  525. /*
  526.  * Get disk geometry structure.
  527.  */
  528. static struct dk_geom *GETdk_geom(d, file)
  529.     int             d;
  530.     char                *file;
  531. {
  532.     static struct dk_geom     dk_geom;
  533.  
  534.     if (ioctl(d, DKIOCGGEOM, &dk_geom) < 0) {
  535.     if (Debug) Error("%s: DKIOCGGEOM: %s.", file, SYSERR);
  536.     return(NULL);
  537.     }
  538.  
  539.     return(&dk_geom);
  540. }
  541.  
  542. /*
  543.  * Get disk type structure.
  544.  */
  545. static struct dk_type *GETdk_type(d, file)
  546.     int             d;
  547.     char                *file;
  548. {
  549.     static struct dk_type     dk_type;
  550.  
  551.     if (ioctl(d, DKIOCGTYPE, &dk_type) < 0) {
  552.     if (errno != ENOTTY)
  553.         if (Debug) Error("%s: DKIOCGTYPE: %s.", file, SYSERR);
  554.     return(NULL);
  555.     }
  556.  
  557.     return(&dk_type);
  558. }
  559.  
  560. /*
  561.  * Check the checksum of a disklabel.
  562.  */
  563. static int DkLblCheckSum(DkLabel)
  564.     struct dk_label            *DkLabel;
  565. {
  566.     register short            *Ptr, Sum = 0;
  567.     register short         Count;
  568.  
  569.     Count = (sizeof (struct dk_label)) / (sizeof (short));
  570.     Ptr = (short *)DkLabel;
  571.  
  572.     /*
  573.      * Take the xor of all the half-words in the label.
  574.      */
  575.     while (Count--)
  576.     Sum ^= *Ptr++;
  577.  
  578.     /*
  579.      * The total should be zero for a correct checksum
  580.      */
  581.     return(Sum);
  582. }
  583.  
  584. /*
  585.  * Get label information from label on disk.
  586.  * The label is stored in the first sector of the disk.
  587.  * We use the driver specific "read" flag with the DKIOCSCMD
  588.  * ioctl to read the first sector.  There should be a special
  589.  * ioctl to just read the label.
  590.  */
  591. static struct dk_label *GETdk_label(d, file, dk_info)
  592.     int             d;
  593.     char                *file;
  594.     struct dk_info            *dk_info;
  595. {
  596.     static struct dk_label     dk_label;
  597.     struct dk_cmd         dk_cmd;
  598.     struct dkctlrtab            *pct;
  599.  
  600.     if (!file || !dk_info)
  601.     return((struct dk_label *) NULL);
  602.  
  603.     if (!(pct = GetDkCtlrTab((int) dk_info->dki_ctype))) {
  604.     Error("Controller type %d is unknown.", 
  605.           dk_info->dki_ctype);
  606.     return((struct dk_label *) NULL);
  607.     }
  608.  
  609.     if (pct->ct_rdcmd < 0) {
  610.     if (Debug)
  611.         Error("Read block on controller type \"%s\" is unsupported.",
  612.           pct->ct_model);
  613.     return((struct dk_label *) NULL);
  614.     }
  615.  
  616.     bzero((char *) &dk_cmd, sizeof(dk_cmd));
  617.     dk_cmd.dkc_cmd = pct->ct_rdcmd;
  618.     dk_cmd.dkc_flags = DK_SILENT | DK_ISOLATE;
  619.     dk_cmd.dkc_blkno = (daddr_t)0;
  620.     dk_cmd.dkc_secnt = 1;
  621.     dk_cmd.dkc_bufaddr = (char *) &dk_label;
  622.     dk_cmd.dkc_buflen = SECSIZE;
  623.  
  624.     if (ioctl(d, DKIOCSCMD, &dk_cmd) < 0) {
  625.     if (Debug) Error("%s: DKIOCSCMD: %s.", file, SYSERR);
  626.     return((struct dk_label *) NULL);
  627.     }
  628.  
  629.     if (dk_label.dkl_magic != DKL_MAGIC) {
  630.     Error("%s: Disk not labeled.", file);
  631.     return((struct dk_label *) NULL);
  632.     }
  633.  
  634.     if (DkLblCheckSum(&dk_label)) {
  635.     Error("%s: Bad label checksum.", file);
  636.     return((struct dk_label *) NULL);
  637.     }
  638.  
  639.     return(&dk_label);
  640. }
  641.  
  642. /*
  643.  * Get the name of a disk (i.e. sd0).
  644.  */
  645. static char *GetDiskName(name, dk_conf, dk_info)
  646.     char                *name;
  647.     struct dk_conf            *dk_conf;
  648.     struct dk_info            *dk_info;
  649. {
  650.     if (!dk_conf || !dk_info) {
  651.     if (name)
  652.         return(name);
  653.     return((char *) NULL);
  654.     }
  655.  
  656. #if    defined(DKI_HEXUNIT)
  657.     if (FLAGS_ON(dk_info->dki_flags, DKI_HEXUNIT))
  658.     (void) sprintf(Buf, "%s%3.3x", dk_conf->dkc_dname, dk_conf->dkc_unit);
  659.     else
  660. #endif     /* DKI_HEXUNIT */
  661.     (void) sprintf(Buf, "%s%d", dk_conf->dkc_dname, dk_conf->dkc_unit);
  662.  
  663.     return(strdup(Buf));
  664. }
  665.  
  666. /*
  667.  * Get the name of the controller for a disk.
  668.  */
  669. static char *GetDkCtlrName(dk_conf)
  670.     struct dk_conf            *dk_conf;
  671. {
  672.     if (!dk_conf)
  673.     return((char *) NULL);
  674.  
  675.     (void) sprintf(Buf, "%s%d", dk_conf->dkc_cname, dk_conf->dkc_cnum);
  676.  
  677.     return(strdup(Buf));
  678. }
  679.  
  680. /*
  681.  * Get the disk controller model name from a disk.
  682.  */
  683. static char *GetDkCtlrModel(dk_info)
  684.     struct dk_info            *dk_info;
  685. {
  686.     struct dkctlrtab            *pct;
  687.  
  688.     if (!dk_info)
  689.     return((char *) NULL);
  690.  
  691.     if (!(pct = GetDkCtlrTab(dk_info->dki_ctype)))
  692.     return(NULL);
  693.  
  694.     return(pct->ct_model);
  695. }
  696.  
  697. /*
  698.  * Get a disk controller device from disk info.
  699.  */
  700. static DEVICE *GetDkCtlrDevice(DevData, dk_info, dk_conf)
  701.     DEVDATA                *DevData;
  702.     struct dk_info            *dk_info;
  703.     struct dk_conf            *dk_conf;
  704. {
  705.     DEVICE                *MkMasterFromDevData();
  706.     DEVICE                *dkctlr;
  707.  
  708.     if ((dkctlr = NewDevice(NULL)) == NULL)
  709.     return((DEVICE *) NULL);
  710.  
  711.     bzero((char *) dkctlr, sizeof(*dkctlr));
  712.  
  713.     dkctlr->dv_type = DT_DISKCTLR;
  714.  
  715.     /*
  716.      * Get name of controller from devdata if available
  717.      */
  718.     if (DevData && DevData->dd_ctlrname) {
  719.     dkctlr = MkMasterFromDevData(DevData);
  720.     }
  721.  
  722.     if (dk_conf) {
  723.     if (!dkctlr->dv_name) {
  724.         dkctlr->dv_name = GetDkCtlrName(dk_conf);
  725.         dkctlr->dv_unit = dk_conf->dkc_cnum;
  726.     }
  727.     dkctlr->dv_addr = dk_conf->dkc_addr;
  728.     dkctlr->dv_prio = dk_conf->dkc_prio;
  729.     dkctlr->dv_vec = dk_conf->dkc_vec;
  730.     }
  731.  
  732.     if (dk_info) {
  733.     dkctlr->dv_model = GetDkCtlrModel(dk_info);
  734.     }
  735.  
  736.     return(dkctlr);
  737. }
  738.  
  739. /*
  740.  * Get disk label info from the extracted dk_label info.
  741.  */
  742. static char *GetDiskLabel(dk_label)
  743.     struct dk_label            *dk_label;
  744. {
  745.     register char            *p;
  746.  
  747.     if (!dk_label)
  748.     return((char *) NULL);
  749.  
  750.     (void) strcpy(Buf, dk_label->dkl_asciilabel);
  751.  
  752.     /*
  753.      * The label normally has geometry information in it we don't want
  754.      * to see, so we trim out anything starting with " cyl".
  755.      */
  756.     for (p = Buf; p && *p; ++p) {
  757.     if (*p == ' ' && strncasecmp(p, " cyl", 4) == 0)
  758.         *p = C_NULL;
  759.     }
  760.  
  761.     return(strdup(Buf));
  762. }
  763.  
  764. /*
  765.  * Get filesystem mount info for a partition.
  766.  */
  767. static char *GetMountInfo(name, part)
  768.     char                *name;
  769.     char                *part;
  770. {
  771.     FILE                *mf;
  772.     struct mntent            *mntent;
  773.     char                *file;
  774.  
  775.     if (!name)
  776.     return((char *) NULL);
  777.  
  778.     file = GetCharFile(name, part);
  779.  
  780.     if ((mf = setmntent(MNTTAB, "r")) == NULL) {
  781.     Error("%s: Cannot open for reading: %s.", MNTTAB, SYSERR);
  782.     return(NULL);
  783.     }
  784.  
  785.     while (mntent = getmntent(mf)) {
  786.     if (strcmp(mntent->mnt_fsname, file) == 0)
  787.         break;
  788.     }
  789.  
  790.     endmntent(mf);
  791.  
  792.     return((mntent) ? mntent->mnt_dir : (char *) NULL);
  793. }
  794.  
  795. /*
  796.  * Extract the disk partition info from a disk.
  797.  */
  798. static DISKPART *ExtractDiskPart(name, part, dk_conf, dk_geom)
  799.     char                *name;
  800.     char                *part;
  801.     struct dk_conf            *dk_conf;
  802.     struct dk_geom            *dk_geom;
  803. {
  804.     static DISKPART         diskpart;
  805.     struct dk_map         dk_map;
  806.     char                *file;
  807.     char                *p;
  808.     int             d;
  809.  
  810.     if (!name || !dk_conf || !dk_geom)
  811.     return((DISKPART *) NULL);
  812.  
  813.     file = GetRawFile(name, part);
  814.  
  815.     if (stat(file, &StatBuf) != 0) {
  816.     if (Debug) Error("%s: No such partition.", file);
  817.     return((DISKPART *) NULL);
  818.     }
  819.  
  820.     if ((d = open(file, O_RDONLY)) < 0) {
  821.     if (Debug)
  822.         Error("%s: Cannot open for read: %s.", file, SYSERR);
  823.     return((DISKPART *) NULL);
  824.     }
  825.  
  826.     if (ioctl(d, DKIOCGPART, &dk_map) != 0) {
  827.     Error("%s: Cannot extract partition info: %s.", 
  828.         file, SYSERR);
  829.     return((DISKPART *) NULL);
  830.     }
  831.  
  832.     (void) close(d);
  833.  
  834.     /*
  835.      * Skip empty partitions
  836.      */
  837.     if (!dk_map.dkl_nblk) {
  838.     if (Debug) Error("%s: partition has no size.", file);
  839.     return((DISKPART *) NULL);
  840.     }
  841.  
  842.     bzero((char *) &diskpart, sizeof(DISKPART));
  843.  
  844.     diskpart.dp_name = strdup(part);
  845.  
  846.     if (p = GetMountInfo(name, part))
  847.     diskpart.dp_mnt = strdup(p);
  848.     /* 
  849.      * If this is the "b" partition on the root device, 
  850.      *  then assume it's swap 
  851.      */
  852.     else if (dk_conf->dkc_unit == 0 && strcmp(part, "b") == 0)
  853.     diskpart.dp_mnt = "swap";
  854.  
  855.     diskpart.dp_stsect = dk_map.dkl_cylno *
  856.     (dk_geom->dkg_nhead * dk_geom->dkg_nsect);
  857.     diskpart.dp_nsect = dk_map.dkl_nblk;
  858.  
  859.     return(&diskpart);
  860. }
  861.  
  862. /*
  863.  * Translate disk partition information from basic
  864.  * extracted disk info.
  865.  */
  866. static DISKPART *GetDiskPart(name, dk_conf, dk_geom)
  867.     char                *name;
  868.     struct dk_conf            *dk_conf;
  869.     struct dk_geom            *dk_geom;
  870. {
  871.     extern char         PartChars[];
  872.     register DISKPART            *pdp, *dp;
  873.     register int         i;
  874.     static char         pname[2];
  875.     DISKPART                *base = NULL;
  876.  
  877.     if (!name || !dk_conf || !dk_geom)
  878.     return((DISKPART *) NULL);
  879.  
  880.     pname[1] = C_NULL;
  881.     for (i = 0; PartChars[i]; ++i) {
  882.     pname[0] = PartChars[i];
  883.     if (dp = ExtractDiskPart(name, pname, dk_conf, dk_geom)) {
  884.         if (base) {
  885.         for (pdp = base; pdp && pdp->dp_nxt; pdp = pdp->dp_nxt);
  886.         pdp->dp_nxt = NewDiskPart(dp);
  887.         } else {
  888.         base = NewDiskPart(dp);
  889.         }
  890.     }
  891.     }
  892.  
  893.     return(base);
  894. }
  895.  
  896. /*
  897.  * Convert all we've learned about a disk to a DEVICE.
  898.  */
  899. static DEVICE *dkToDiskDevice(name, DevData,
  900.                   dk_info, dk_label, dk_conf, dk_geom, dk_type)
  901.     char                *name;
  902.     DEVDATA                *DevData;
  903.     struct dk_info            *dk_info;
  904.     struct dk_label            *dk_label;
  905.     struct dk_conf            *dk_conf;
  906.     struct dk_geom            *dk_geom;
  907.     struct dk_type            *dk_type;
  908. {
  909.     DEVICE                *Device, *dkctlr;
  910.     DISKDRIVE                *diskdrive;
  911.  
  912.     if ((Device = NewDevice(NULL)) == NULL) {
  913.     Error("Cannot create new device entry.");
  914.     return((DEVICE *) NULL);
  915.     }
  916.  
  917.     if ((dkctlr = NewDevice(NULL)) == NULL) {
  918.     Error("Cannot create new dkctlr device entry.");
  919.     return((DEVICE *) NULL);
  920.     }
  921.  
  922.     if ((diskdrive = NewDiskDrive(NULL)) == NULL) {
  923.     Error("Cannot create new diskdrive entry.");
  924.     return((DEVICE *) NULL);
  925.     }
  926.  
  927.     Device->dv_name = GetDiskName(name, dk_conf, dk_info);
  928.     Device->dv_type = DT_DISKDRIVE;
  929.     /*
  930.      * Only read partition info we we're going to print it later.
  931.      */
  932.     if (VL_ALL)
  933.     diskdrive->dd_part = GetDiskPart(name, dk_conf, dk_geom);
  934.     diskdrive->dd_label = GetDiskLabel(dk_label);
  935.     Device->dv_model = diskdrive->dd_label;
  936.  
  937.     if (dk_conf) {
  938.     diskdrive->dd_unit = dk_conf->dkc_unit;
  939.     diskdrive->dd_slave = dk_conf->dkc_slave;;
  940.     }
  941.     if (dk_geom) {
  942.     diskdrive->dd_dcyl = dk_geom->dkg_ncyl;
  943.     diskdrive->dd_pcyl = dk_geom->dkg_pcyl;
  944.     diskdrive->dd_acyl = dk_geom->dkg_acyl;
  945.     diskdrive->dd_heads = dk_geom->dkg_nhead;
  946.     diskdrive->dd_sect = dk_geom->dkg_nsect;
  947.     diskdrive->dd_apc = dk_geom->dkg_apc;
  948.     diskdrive->dd_rpm = dk_geom->dkg_rpm;
  949.     diskdrive->dd_intrlv = dk_geom->dkg_intrlv;
  950.     }
  951.     if (dk_type) {
  952.     diskdrive->dd_psect = dk_type->dkt_hsect;
  953.     diskdrive->dd_promrev = dk_type->dkt_promrev;
  954.     }
  955.     if (dk_info) {
  956. #if    defined(DKI_HEXUNIT)
  957.     if (FLAGS_ON(dk_info->dki_flags, DKI_HEXUNIT))
  958.         diskdrive->dd_flags |= DF_HEXUNIT;
  959. #endif     /* DKI_HEXUNIT */
  960.     }
  961.  
  962.     diskdrive->dd_secsize = SECSIZE;
  963.     if (diskdrive->dd_dcyl && diskdrive->dd_sect && diskdrive->dd_heads) {
  964.     static char Buf[BUFSIZ];
  965.  
  966.     diskdrive->dd_size = nsect_to_bytes(diskdrive->dd_dcyl * 
  967.                          diskdrive->dd_sect * 
  968.                          diskdrive->dd_heads, 
  969.                         diskdrive->dd_secsize);
  970.  
  971.     (void) sprintf(Buf, "%.2f MB capacity", 
  972.                (float) bytes_to_mbytes(diskdrive->dd_size));
  973.     Device->dv_desc = strdup(Buf);
  974.     }
  975.  
  976.     dkctlr = GetDkCtlrDevice(DevData, dk_info, dk_conf);
  977.  
  978.     Device->dv_devspec = (caddr_t *) diskdrive;
  979.     Device->dv_master = dkctlr;
  980.  
  981.     return(Device);
  982. }
  983.  
  984. /*
  985.  * Query and learn about a disk.
  986.  */
  987. extern DEVICE *ProbeDiskDrive(name, DevData, DevDataTab)
  988.      /*ARGSUSED*/
  989.     char                *name;
  990.     DEVDATA                *DevData;
  991.     DEVDATATAB                     *DevDataTab;
  992. {
  993.     DEVICE                *diskdevice;
  994.     struct dk_info            *dk_info = NULL;
  995.     struct dk_conf            *dk_conf = NULL;
  996.     struct dk_type            *dk_type = NULL;
  997.     struct dk_label            *dk_label = NULL;
  998.     struct dk_geom            *dk_geom = NULL;
  999.     char                *rfile;
  1000.     int             d;
  1001.  
  1002.     if (!name)
  1003.     return((DEVICE *) NULL);
  1004.  
  1005. #if    defined(HAVE_IPI)
  1006.     /*
  1007.      * XXX - Kludge for IPI "id" disks.
  1008.      */
  1009.     if (EQ(DevData->dd_devname, "id")) {
  1010.     static char        Buf[BUFSIZ];
  1011.  
  1012.     (void) sprintf(Buf, "%s%3.3x", 
  1013.                DevData->dd_devname, DevData->dd_devunit);
  1014.     name = Buf;
  1015.     }
  1016. #endif    /* HAVE_IPI */
  1017.  
  1018.     if (stat(rfile = GetRawFile(name, NULL), &StatBuf) != 0) {
  1019.     /*
  1020.      * Get the name of the whole disk raw device.
  1021.      */
  1022.     rfile = GetRawFile(name, "c");
  1023.     }
  1024.  
  1025.     if ((d = open(rfile, O_RDONLY)) < 0) {
  1026.     if (Debug) Error("%s: Cannot open for reading: %s.", rfile, SYSERR);
  1027.     /*
  1028.      * If we know for sure this drive is present and we
  1029.      * know something about it, then create a minimal device.
  1030.      */
  1031.     if ((DevDataTab->ddt_model || DevDataTab->ddt_desc) &&
  1032.         FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE)) {
  1033.         Device = NewDevice((DEVICE *) NULL);
  1034.         Device->dv_name = strdup(name);
  1035.         Device->dv_unit = DevData->dd_devunit;
  1036.         Device->dv_master = MkMasterFromDevData(DevData);
  1037.         Device->dv_type = DT_DISKDRIVE;
  1038.         Device->dv_model = DevDataTab->ddt_model;
  1039.         Device->dv_desc = DevDataTab->ddt_desc;
  1040.         return(Device);
  1041.     } else
  1042.         return((DEVICE *) NULL);
  1043.     }
  1044.  
  1045.     if ((dk_conf = GETdk_conf(d, rfile)) == NULL) {
  1046.     if (Debug) Error("%s: get dk_conf failed.", rfile);
  1047.     }
  1048.  
  1049.     if ((dk_info = GETdk_info(d, rfile)) == NULL) {
  1050.     if (Debug) Error("%s: get dk_info failed.", rfile);
  1051.     }
  1052.  
  1053.     if ((dk_geom = GETdk_geom(d, rfile)) == NULL) {
  1054.     if (Debug) Error("%s: get dk_geom failed.", rfile);
  1055.     }
  1056.  
  1057.     if ((dk_label = GETdk_label(d, rfile, dk_info)) == NULL) {
  1058.     if (Debug) Error("%s: get dk_label failed.", rfile);
  1059.     }
  1060.  
  1061.     /*
  1062.      * Not all controllers support dk_type
  1063.      */
  1064.     dk_type = GETdk_type(d, rfile);
  1065.  
  1066.     close(d);
  1067.  
  1068.     if (!(diskdevice = dkToDiskDevice(name, DevData,
  1069.                     dk_info, dk_label, 
  1070.                     dk_conf, dk_geom, dk_type))) {
  1071.     Error("%s: Cannot convert diskdrive information.", name);
  1072.     return((DEVICE *) NULL);
  1073.     }
  1074.  
  1075.     return(diskdevice);
  1076. }
  1077.  
  1078. /*
  1079.  * Probe a tape device
  1080.  */
  1081. extern DEVICE *ProbeTapeDrive(name, DevData, DevDataTab)
  1082.      /*ARGSUSED*/
  1083.     char                *name;
  1084.     DEVDATA                *DevData;
  1085.     DEVDATATAB                *DevDataTab;
  1086. {
  1087.     extern NAMETAB        MtInfo[];
  1088.     DEVICE                *Device;
  1089.     char                *file;
  1090.     char                *model = NULL;
  1091.     static char         Buf[BUFSIZ];
  1092.     struct mtget         mtget;
  1093.     register int         i;
  1094.     int             d;
  1095.  
  1096.     file = GetRawFile(name, NULL);
  1097.  
  1098.     if ((d = open(file, O_RDONLY)) < 0) {
  1099.     if (Debug)
  1100.         Error("%s Cannot open for read: %s.", file, SYSERR);
  1101.  
  1102.     /*
  1103.      * --RECURSE--
  1104.      * If we haven't tried the "mt" name yet, try it now
  1105.      */
  1106.     if (strncmp(name, MTNAME, strlen(MTNAME)) != 0) {
  1107.         (void) sprintf(Buf, "%s%d", MTNAME, DevData->dd_devunit);
  1108.         Device = ProbeTapeDrive(Buf, DevData, DevDataTab);
  1109.         if (Device)
  1110.         return(Device);
  1111.     }
  1112.  
  1113.     /*
  1114.      * If we know for sure this drive is present and we
  1115.      * know something about it, then create a minimal device.
  1116.      */
  1117.     if ((DevDataTab->ddt_model || DevDataTab->ddt_desc) &&
  1118.         FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE)) {
  1119.         Device = NewDevice((DEVICE *) NULL);
  1120.         /* 
  1121.          * Recreate name from devdata since we might have had to
  1122.          * call ourself with name "rmt?"
  1123.          */
  1124.         (void) sprintf(Buf, "%s%d", DevData->dd_devname, 
  1125.                DevData->dd_devunit);
  1126.         Device->dv_name = strdup(Buf);
  1127.         Device->dv_unit = DevData->dd_devunit;
  1128.         Device->dv_master = MkMasterFromDevData(DevData);
  1129.         Device->dv_type = DT_TAPEDRIVE;
  1130.         Device->dv_model = DevDataTab->ddt_model;
  1131.         Device->dv_desc = DevDataTab->ddt_desc;
  1132.         return(Device);
  1133.     } else
  1134.         return((DEVICE *) NULL);
  1135.     }
  1136.  
  1137.     if (ioctl(d, MTIOCGET, &mtget) != 0) {
  1138.     Error("%s: Cannot extract tape status: %s.", file, SYSERR);
  1139.     return((DEVICE *) NULL);
  1140.     }
  1141.  
  1142.     (void) close(d);
  1143.  
  1144.     model = "unknown";
  1145.  
  1146.     for (i = 0; MtInfo[i].name; ++i) {
  1147.     if ((MtInfo[i].value == mtget.mt_type)) {
  1148.         model = MtInfo[i].name;
  1149.         break;
  1150.     }
  1151.     }
  1152.  
  1153.     /*
  1154.      * Create and set device info
  1155.      */
  1156.     Device = NewDevice(NULL);
  1157.     Device->dv_name = strdup(name);
  1158.     Device->dv_type = DT_TAPEDRIVE;
  1159.     if (model)
  1160.     Device->dv_model = model;
  1161.     else
  1162.     Device->dv_model = DevDataTab->ddt_model;
  1163.     Device->dv_desc = DevDataTab->ddt_desc;
  1164.     Device->dv_unit = DevData->dd_devunit;
  1165.     Device->dv_master = MkMasterFromDevData(DevData);
  1166.  
  1167.     return(Device);
  1168. }
  1169.  
  1170. /*
  1171.  * Probe a CPU.  
  1172.  *
  1173.  * This function really "fakes" up an entry.
  1174.  *
  1175.  * Currently the info only comes from the OpenPROM.  We could
  1176.  * use the kernel mach_info and mod_info structures, but they
  1177.  * don't provide the model of CPU.  Maybe in a future release.
  1178.  */
  1179. extern DEVICE *ProbeCPU(name, DevData, DevDataTab)
  1180.      /*ARGSUSED*/
  1181.     char                *name;
  1182.     DEVDATA                *DevData;
  1183.     DEVDATATAB                *DevDataTab;
  1184. {
  1185.     static int             num_cpus = 0;
  1186.  
  1187.     Device = NewDevice(NULL);
  1188.     (void) sprintf(Buf, "cpu%d", num_cpus++);
  1189.     Device->dv_name = strdup(Buf);
  1190.     Device->dv_type = DT_CPU;
  1191.     Device->dv_model = strdup(name);
  1192.     Device->dv_desc = DevDataTab->ddt_desc;
  1193.     Device->dv_master = MkMasterFromDevData(DevData);
  1194.  
  1195.     return(Device);
  1196. }
  1197.  
  1198. /*
  1199.  * Probe a FrameBuffer.
  1200.  */
  1201. extern DEVICE *ProbeFrameBuffer(name, DevData, DevDataTab)
  1202.     char                *name;
  1203.     DEVDATA                *DevData;
  1204.     DEVDATATAB                *DevDataTab;
  1205. {
  1206.     DEVICE                *fbdevice;
  1207.     FRAMEBUFFER            *fb;
  1208.     NAMETAB                *fbtab;
  1209.     struct fbgattr         fbattr;
  1210. #ifdef FBIOGXINFO
  1211.     struct cg6_info         cg6_info;
  1212. #endif
  1213.     char                *file, Buf[BUFSIZ];
  1214.     int             d;
  1215.  
  1216.     if (!name)
  1217.     return((DEVICE *) NULL);
  1218.  
  1219.     /*
  1220.      * Check the device file.  If the stat fails because
  1221.      * the device doesn't exist, trying the default framebuffer
  1222.      * device /dev/fb.
  1223.      */
  1224.     file = GetCharFile(name, NULL);
  1225.     if (stat(file, &StatBuf) != 0) {
  1226.     if (errno == ENOENT && !EQ(name, FBDEVICE)) {
  1227.         if (Debug) 
  1228.         Error("Framebuffer device %s does not exist.  Trying `fb'.",
  1229.               name);
  1230.         return(ProbeFrameBuffer(FBDEVICE, DevData, DevDataTab));
  1231.     }
  1232.     }
  1233.  
  1234.     if ((d = open(file, O_RDONLY)) < 0) {
  1235.     if (Debug) Error("%s: Cannot open for reading: %s.", file, SYSERR);
  1236.     return((DEVICE *) NULL);
  1237.     }
  1238.  
  1239.     if (ioctl(d, FBIOGATTR, &fbattr) != 0) {
  1240.     if (ioctl(d, FBIOGTYPE, &fbattr.fbtype) != 0) {
  1241.         if (Debug) Error("%s: FBIOGATTR/FBIOGTYPE: %s.", 
  1242.                  file, SYSERR);
  1243.         return((DEVICE *) NULL);
  1244.     }
  1245.     }
  1246.  
  1247.     Buf[0] = C_NULL;
  1248. #if    defined(FBIOGXINFO)
  1249.     if (ioctl(d, FBIOGXINFO, &cg6_info) == 0) {
  1250.     sprintf(Buf, "SBus Slot %d, Revision %d",
  1251.         cg6_info.slot, cg6_info.boardrev);
  1252.     if (cg6_info.hdb_capable)
  1253.         (void) strcat(Buf, ", double buffered");
  1254.     else
  1255.         (void) strcat(Buf, ", single buffered");
  1256.     } else {
  1257.     bzero((char *) &cg6_info, sizeof(struct cg6_info));
  1258.     if (Debug) Error("%s: FBIOGXINFO: %s.", file, SYSERR);
  1259.     }
  1260. #endif     /* FBIOGXINFO */
  1261.  
  1262.     close(d);
  1263.  
  1264.     if (!(fb = NewFrameBuffer(NULL))) {
  1265.     Error("Cannot create new frame buffer.");
  1266.     return((DEVICE *) NULL);
  1267.     }
  1268.  
  1269.     if (!(fbdevice = NewDevice(NULL))) {
  1270.     Error("Cannot create new frame buffer device entry.");
  1271.     return((DEVICE *) NULL);
  1272.     }
  1273.  
  1274.     if (!(fbtab = GetFBTab(fbattr.fbtype.fb_type))) {
  1275.     Error("Device %s is an unknown type (%d) of frame buffer.",
  1276.           name, fbattr.fbtype.fb_type);
  1277.     }
  1278.  
  1279.     fbdevice->dv_name = name;
  1280.     fbdevice->dv_type = DT_FRAMEBUFFER;
  1281.     fbdevice->dv_devspec = (caddr_t *) fb;
  1282.  
  1283.     if (Buf[0])
  1284.     fbdevice->dv_desc = strdup(Buf);
  1285.  
  1286.     if (fbtab) {
  1287.     fbdevice->dv_model = fbtab->name;
  1288.     } else {
  1289.     fbdevice->dv_model = "UNKNOWN";
  1290.     }
  1291.  
  1292.     fb->fb_height = fbattr.fbtype.fb_height;
  1293.     fb->fb_width = fbattr.fbtype.fb_width;
  1294.     fb->fb_depth = fbattr.fbtype.fb_depth;
  1295.     fb->fb_size = fbattr.fbtype.fb_size;
  1296.     fb->fb_cmsize = fbattr.fbtype.fb_cmsize;
  1297. #if    defined(FBIOGXINFO)
  1298.     if (cg6_info.vmsize)
  1299.     fb->fb_vmsize = mbytes_to_bytes(cg6_info.vmsize);
  1300. #endif /* FBIOGXINFO */
  1301.  
  1302.     fbdevice->dv_master = MkMasterFromDevData(DevData);
  1303.  
  1304.     return(fbdevice);
  1305. }
  1306.  
  1307. /*
  1308.  * Determine our cpu model name.
  1309.  *
  1310.  * We lookup the kernel symbol "cpu" instead of using gethostid()
  1311.  * because some SPARC vendors do not encode cpu/model info in gethostid().
  1312.  */
  1313. extern char *GetModelName()
  1314. {
  1315.     extern NAMETAB         ModelTab[];
  1316.     extern struct nlist        CpuNL[];
  1317.     register int         i;
  1318.     int                Cpu;
  1319.     kvm_t               *kd;
  1320.  
  1321.     if (!(kd = KVM_open(CpuNL))) {
  1322.     if (Debug) Error("Cannot find cpu symbol in kernel.");
  1323.     return((char *) NULL);
  1324.     }
  1325.  
  1326.     /*
  1327.      * See if we got a valid entry
  1328.      */
  1329.     if (CheckNlist(&CpuNL[0]))
  1330.     return((char *) NULL);
  1331.  
  1332.     if (KVM_read(kd, (u_long) CpuNL[0].n_value, (char *) &Cpu, sizeof(Cpu))) {
  1333.     if (Debug) Error("Cannot read cpu from kernel.");
  1334.     return((char *) NULL);
  1335.     }
  1336.  
  1337.     KVM_close(kd);
  1338.  
  1339.     for (i = 0; ModelTab[i].name; ++i)
  1340.     if (Cpu == ModelTab[i].value)
  1341.         return(ModelTab[i].name);
  1342.  
  1343.     if (Debug)
  1344.     Error("No model found; CPU = 0x%x.", Cpu);
  1345.  
  1346.     return((char *) NULL);
  1347. }
  1348.  
  1349. #if     defined(CPU_ARCH) /* Sun */
  1350. #define    ARCH_MASK CPU_ARCH
  1351. #endif    /* CPU_ARCH */
  1352. #if     defined(CPU_TYPE) /* Solbourne */
  1353. #define ARCH_MASK CPU_TYPE
  1354. #endif    /* CPU_TYPE */
  1355. /*
  1356.  * Determine our kernel architecture name from our hostid.
  1357.  */
  1358. extern char *GetKernArchName()
  1359. {
  1360. #if    defined(ARCH_MASK)
  1361.     extern NAMETAB         KernArchTab[];
  1362.     extern struct nlist        CpuNL[];
  1363.     kvm_t               *kd;
  1364.     int                Cpu;
  1365.     register int         i;
  1366.  
  1367.     if (!(kd = KVM_open(CpuNL))) {
  1368.     if (Debug) Error("Cannot find cpu symbol in kernel.");
  1369.     return((char *) NULL);
  1370.     }
  1371.  
  1372.     /*
  1373.      * See if we got a valid entry
  1374.      */
  1375.     if (CheckNlist(&CpuNL[0]))
  1376.     return((char *) NULL);
  1377.  
  1378.     if (KVM_read(kd, (u_long) CpuNL[0].n_value, (char *) &Cpu, sizeof(Cpu))) {
  1379.     if (Debug) Error("Cannot read cpu from kernel.");
  1380.     return((char *) NULL);
  1381.     }
  1382.  
  1383.     KVM_close(kd);
  1384.  
  1385.     for (i = 0; KernArchTab[i].name; ++i)
  1386.     if ((Cpu & ARCH_MASK) == KernArchTab[i].value)
  1387.         return(KernArchTab[i].name);
  1388.  
  1389.     if (Debug)
  1390.     Error("Kernel Arch 0x%x not defined; Cpu = 0x%x Mask = 0x%x", 
  1391.           Cpu & ARCH_MASK, Cpu, ARCH_MASK);
  1392. #endif    /* ARCH_MASK */
  1393.  
  1394.     return((char *) NULL);
  1395. }
  1396.  
  1397. #if    defined(HAVE_NIT)
  1398.  
  1399. #include <sys/time.h>
  1400. #include <sys/types.h>
  1401. #include <sys/socket.h>
  1402. #include <net/if.h>
  1403. #include <net/nit_if.h>
  1404.  
  1405. /*
  1406.  * Find and set the MAC info using the Network Interface Tap (NIT)
  1407.  */
  1408. extern void SetMacInfoNIT(DevName, NetIf)
  1409.     char                *DevName;
  1410.     NETIF                *NetIf;
  1411. {
  1412.     register struct sockaddr   *SockAddr;
  1413.     struct ifreq             ifreq;
  1414.     char                *ether_ntoa(), Buf[MAXHOSTNAMLEN+1];
  1415.     int                 Desc;
  1416.  
  1417.     if (!NetIf)
  1418.     return;
  1419.  
  1420.     if ((Desc = open("/dev/nit", O_RDONLY)) == SYSFAIL) {
  1421.     if (Debug) Error("open /dev/nit failed");
  1422.     return;
  1423.     }
  1424.  
  1425.     /*
  1426.      * Bind to NIT for DevName
  1427.      */
  1428.     strncpy(ifreq.ifr_name, DevName, sizeof ifreq.ifr_name);
  1429.     if (ioctl(Desc, NIOCBIND, (caddr_t) &ifreq) < 0) {
  1430.     if (Debug) Error("ioctl:  NIOCBIND");
  1431.     return;
  1432.     }
  1433.  
  1434.     /*
  1435.      * Get address
  1436.      */
  1437.     if (ioctl(Desc, SIOCGIFADDR, (caddr_t)&ifreq) < 0) {
  1438.     if (Debug) Error("ioctl (SIOCGIFADDR)");
  1439.     return;
  1440.     }
  1441.  
  1442.     (void) close(Desc);
  1443.  
  1444.     SockAddr = (struct sockaddr *)&ifreq.ifr_addr;
  1445.     NetIf->ni_macaddr = strdup(ether_ntoa((struct ether_addr *) 
  1446.                       SockAddr->sa_data));
  1447.  
  1448.     if (ether_ntohost(Buf, (struct ether_addr *) SockAddr->sa_data) == 0)
  1449.     NetIf->ni_macname = strdup(Buf);
  1450. }
  1451. #endif    /* HAVE_NIT */
  1452.  
  1453. /*
  1454.  * Get kernel version string from kernel symbol "version".
  1455.  */
  1456. extern char *GetKernelVersionStr()
  1457. {
  1458.     return(GetKernelVersionFromVersion());
  1459. }
  1460.  
  1461. /*
  1462.  * Get amount of physical memory using kernel symbol "physmem".
  1463.  */
  1464. extern char *GetMemory()
  1465. {
  1466.     return(GetMemoryFromPhysmem());
  1467. }
  1468.  
  1469. /*
  1470.  * Get system serial number
  1471.  */
  1472. extern char *GetSerialNoStr()
  1473. {
  1474.     /* No support */
  1475.     return((char *) NULL);
  1476. }
  1477.  
  1478. /*
  1479.  * Get name of OS
  1480.  */
  1481. extern char *GetOSNameStr()
  1482. {
  1483.     return(GetOSNameFromUname());
  1484. }
  1485.  
  1486. /*
  1487.  * Get version of OS
  1488.  */
  1489. extern char *GetOSVersionStr()
  1490. {
  1491.     return(GetOSVersionFromUname());
  1492. }
  1493.  
  1494. #if    defined(HAVE_SUNROMVEC)
  1495. /*
  1496.  * Be backwards compatible with pre-4.1.2 code
  1497.  */
  1498. #include <mon/sunromvec.h>
  1499. #if    defined(OPENPROMS) && !(defined(ROMVEC_VERSION) && \
  1500.                 (ROMVEC_VERSION == 0 || ROMVEC_VERSION == 1))
  1501. #define v_mon_id op_mon_id
  1502. #endif
  1503. #endif    /* HAVE_SUNROMVEC */
  1504.  
  1505. /*
  1506.  * Get ROM Version number
  1507.  *
  1508.  * If "romp" is "defined" (in <mon/sunromvec.h>), then take that
  1509.  * as the address of the kernel pointer to "rom" (struct sunromvec).
  1510.  * Otherwise, nlist "romp" from the kernel.
  1511.  */
  1512. extern char *GetRomVer()
  1513. {
  1514.     static char            RomRev[16];
  1515. #if    defined(HAVE_SUNROMVEC)
  1516.     static struct sunromvec    Rom;
  1517.     register char           *p;
  1518.     register char           *Addr;
  1519.     kvm_t               *kd;
  1520. #if    !defined(romp)
  1521.     struct sunromvec           *romp;
  1522.     extern struct nlist        RomVecNL[];
  1523.  
  1524.     if (!(kd = KVM_open(RomVecNL))) {
  1525.     if (Debug) Error("Cannot find romvec symbol in kernel.");
  1526.     return((char *) NULL);
  1527.     }
  1528.  
  1529.     /*
  1530.      * See if we got a valid entry
  1531.      */
  1532.     if (CheckNlist(&RomVecNL[0]))
  1533.     return((char *) NULL);
  1534.  
  1535.     /*
  1536.      * Read the kernel pointer to the sunromvec structure.
  1537.      */
  1538.     if (KVM_read(kd, (u_long) RomVecNL[0].n_value, (char *) &romp, 
  1539.          sizeof(romp))) {
  1540.     if (Debug) Error("Cannot read sunromvec pointer from kernel.");
  1541.     return((char *) NULL);
  1542.     }
  1543.  
  1544. #else    /* romp */
  1545.  
  1546.     if (!(kd = KVM_open((struct nlist *) NULL))) {
  1547.     if (Debug) Error("KVM_open failed.");
  1548.     return((char *) NULL);
  1549.     }
  1550.  
  1551. #endif    /* romp */
  1552.  
  1553.     /*
  1554.      * Read the sunromvec structure from the kernel
  1555.      */
  1556.     /*SUPPRESS 25*/
  1557.     if (KVM_read(kd, (u_long) romp, (char *) &Rom, sizeof(struct sunromvec))) {
  1558.     if (Debug) Error("Cannot read sunromvec from kernel.");
  1559.     return((char *) NULL);
  1560.     }
  1561.  
  1562. #if    !defined(romp)
  1563.  
  1564.     /*
  1565.      * XXX Hardcoded values
  1566.      */
  1567.     (void) sprintf(RomRev, "%d.%d", Rom.v_mon_id >> 16, Rom.v_mon_id & 0xFFFF);
  1568.  
  1569. #else    /* romp */
  1570.  
  1571.     /*
  1572.      * Read the version string from the address indicated by Rom.v_mon_id.
  1573.      * Read 1 byte at a time until '\0' is encountered.
  1574.      */
  1575.     p = RomRev;
  1576.     Addr = Rom.v_mon_id;
  1577.     do {
  1578.     if (KVM_read(kd, (u_long) Addr++, p, 1))
  1579.         break;
  1580.     } while (p < &RomRev[sizeof(RomRev)-1] && *p++);
  1581.     *p = C_NULL;
  1582.  
  1583. #endif    /* romp */
  1584.  
  1585.     KVM_close(kd);
  1586.  
  1587. #endif    /* HAVE_SUNROMVEC */
  1588.  
  1589.     return((RomRev[0]) ? RomRev : (char *) NULL);
  1590. }
  1591.