This is os-sunos.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/os-sunos.c,v 1.34 1992/11/24 04:05:57 mcooper Exp mcooper $"; #endif /* * $Log: os-sunos.c,v $ * Revision 1.34 1992/11/24 04:05:57 mcooper * New/cleaner KVM/nlist interface. * * Revision 1.33 1992/11/12 19:12:43 mcooper * Add declaration of OpenPROMTraverse(). * * Revision 1.32 1992/08/11 01:33:14 mcooper * Adjust format of Error() message. * * Revision 1.31 1992/07/07 22:25:06 mcooper * Add Auspex support from Guy Harris (guy@auspex.com) as well * as some cleanup of code format and phrasing of device information: * Added an entry for the SPARCengine 1E (6U Eurocard based on the * SPARCstation 1; there are also SS2-based and, coming up, SS10-based * SPARCengines, although they're not VME cards). * * Changed the description of the FPA from "Wietek FPA" to "Sun-3 FPA" (it * uses Weitek - not "Wietek" chips, but it's a Sun product), and expanded * the extra description to note that it's Weitek-based. * * Added support for various devices on Auspex systems (which required * adding a hack to get around a botch in the "mb_device" table in our * current drivers for some of those devices). * * Separated disks from CD-ROMS, giving each its own probe routine; the * disk probe routine will, if a CD-ROM in the drive happens to have a * label (as some Sun CD-ROMs do, and as the Auspex system software * distribution CD-ROM does), act as if the label is something it should * report (it shouldn't; for example, it should report the disk as a * CD-ROM, not whatever glop appears in the label). * * Fixed "ProbeTapeDrive()" to use the no-rewind device, so that it doesn't * run the risk of rewinding the tape out from under somebody. * * Put comments at the front of the probe routines for tapes and CD-ROMs to * indicate that they may fail even if the device exists - i.e., if there's * no medium in the drive, or if somebody's using the tape drive; * unfortunately, I don't know of a good fix for that problem. * * Revision 1.30 1992/04/26 23:51:53 mcooper * Add some comments. * * Revision 1.28 1992/04/19 23:17:46 mcooper * Suppress CodeCenter warning about "romp". * * Revision 1.27 1992/04/19 23:07:23 mcooper * Update GetRomVer() to be more portable. * * Revision 1.26 1992/04/18 20:48:18 mcooper * Add #ifdef HAVE_SUNROMVEC around GetRomVer. * * Revision 1.25 1992/04/17 23:27:51 mcooper * Add support for ROM Version information (Sun only for now). * * Revision 1.24 1992/04/17 01:07:59 mcooper * More de-linting * * Revision 1.23 1992/04/16 02:25:39 mcooper * Bug fixes, de-linting, and other changes found with CodeCenter. * * Revision 1.22 1992/04/15 02:46:34 mcooper * - Add better MainBus() and OPENPROM() build debug messages. * - Make GetKernArchName() use "cpu" kernel symbol like GetModelName(). * * Revision 1.21 1992/04/15 02:02:17 mcooper * Change GetMemoryStr() to GetMemory(). * * Revision 1.20 1992/04/12 22:03:56 mcooper * - Change GetModelName() to use kernel symbol "cpu" instead * of gethostid() to be more portable to other SPARC clones. * - Update GetKernArchName() to support Solbourne CPU_TYPE. * - Add HAVE_IPI kludge for "id" disks. * - Various other cleanup bits. * * Revision 1.19 1992/03/31 01:55:17 mcooper * Use new CheckNlist to check nlist success. * * Revision 1.18 1992/03/31 00:45:27 mcooper * Fixed GetKernArchName() to use CPU_ARCH mask. * * Revision 1.17 1992/03/31 00:15:09 mcooper * Add error check for nlist.n_type. * * Revision 1.16 1992/03/25 03:28:32 mcooper * Skip partitions that have 0 size. * * Revision 1.15 1992/03/25 03:20:14 mcooper * Only read partition info we we're going to print it later. * * Revision 1.14 1992/03/22 00:20:10 mcooper * Major cleanup and re-org. * * Revision 1.13 1992/03/09 01:23:42 mcooper * Add need include files for NIT stuff. * * Revision 1.12 1992/03/08 04:58:30 mcooper * Move probe_generic() to devices.c. * * Revision 1.11 1992/03/06 18:37:26 mcooper * Move some general functions to devices.c. * * Revision 1.10 1992/03/05 22:36:35 mcooper * Cleanup format. * * Revision 1.9 1992/03/05 05:12:10 mcooper * Cleanup build_mainbus(). * * Revision 1.8 1992/03/01 23:30:15 mcooper * More more SunOS specific code from sysinfo.c to here. * * Revision 1.7 1992/02/27 22:01:22 mcooper * Add support for getting CPU info for sun4m. * * Revision 1.6 1992/02/27 20:36:52 mcooper * Remove \n from error() messages. * * Revision 1.5 1992/02/26 19:07:21 mcooper * Add a debug statement. * * Revision 1.4 1992/02/25 00:59:35 mcooper * Move tape info to local MTINFO. * * Revision 1.3 1992/02/25 00:17:45 mcooper * Lots of fixes and changes. * * Revision 1.2 1992/02/22 02:30:29 mcooper * Fix fbtab stuff. * * Revision 1.1 1992/02/22 02:20:19 mcooper * Initial revision * * Revision 1.5 1992/02/19 22:30:44 mcooper * Fix calling problem. * * Revision 1.4 1992/02/17 01:00:23 mcooper * - More portability and support for solbourne. * * Revision 1.3 1992/02/17 00:24:22 mcooper * Update frame buffers. * * Revision 1.2 1992/02/16 22:55:44 mcooper * Add netif support. * * Revision 1.1 1991/11/30 23:28:53 mcooper * Initial revision * */ #include <stdio.h> #include "system.h" #include "defs.h" #include <mntent.h> #include <nlist.h> #include <sys/param.h> #include <sys/types.h> #include <sys/buf.h> #include <sys/stat.h> #include <sys/mtio.h> #include <sun/dkio.h> #include <sun/dklabel.h> #include <sun/fbio.h> /* * Name of frame buffer "indirect" device. */ #define FBDEVICE "fb" /* * Name of generic magnetic tape device. */ #define MTNAME "mt" /* * Generally used variables */ static kvm_t *kd = NULL; static struct stat StatBuf; static DEVICE *Device; static char Buf[BUFSIZ]; extern char CpuSYM[]; extern char RomVecSYM[]; static int OpenPROMTraverse(); #if defined(HAVE_MAINBUS) /* * Build a device tree by searching the MainBus */ #include <sundev/mbvar.h> #define DV_SIZE (sizeof(struct mb_device)) #define DR_SIZE (sizeof(struct mb_driver)) extern char MainBusSYM[]; /* * Build device tree by looking at mainbus (mb) devices */ static int BuildMainBus(TreePtr) DEVICE **TreePtr; { static struct nlist nlistbuf; struct nlist *nlptr; static struct mb_device Device; static struct mb_driver Driver; static char CtlrName[BUFSIZ], DevName[BUFSIZ]; static DEVDATA DevData; u_long Addr, DeviceAddr; DEVICE *Dev; /* * Read table address from kernel */ if (!(kd = KVMopen())) return(-1); if ((nlptr = KVMnlist(kd, MainBusSYM, &nlistbuf)) == NULL) return(-1); if (CheckNlist(nlptr)) return(-1); /* * Read each device table entry. A NULL device.mb_driver * indicates that we're at the end of the table. */ for (DeviceAddr = nlptr->n_value; DeviceAddr; DeviceAddr += DV_SIZE) { /* * Read this device */ if (KVMread(kd, DeviceAddr, (char *) &Device, DV_SIZE)) { if (Debug) Error("Cannot read mainbus device from address 0x%x.", DeviceAddr); KVMclose(kd); return(-1); } /* * See if we're done. */ if (!Device.md_driver) break; /* * Read the driver structure */ Addr = (u_long) Device.md_driver; if (KVMread(kd, Addr, (char *) &Driver, DR_SIZE)) { if (Debug) Error("Cannot read driver for mainbus address 0x%x.", Addr); continue; } /* * Get the device name */ if (Addr = (u_long) Driver.mdr_dname) { if (KVMread(kd, Addr, (char *) DevName, sizeof(DevName))) { if (Debug) Error("Cannot read device name from address 0x%x.", Addr); continue; } } else DevName[0] = C_NULL; /* * Get the controller name * XXX - not if "Device.md_ctlr" is -1; work around botch * in current Auspex releases, where some boards (File Processor, * Primary Memory, etc.) have both a device and a controller name, * despite the fact that there's not both a controller and a * set of 1 or more devices. */ if ((Addr = (u_long) Driver.mdr_cname) && Device.md_ctlr != -1) { if (KVMread(kd, Addr, (char *) CtlrName, sizeof(CtlrName))) { if (Debug) Error("Cannot read controller name from address 0x%x.", Addr); continue; } } else CtlrName[0] = C_NULL; /* Make sure devdata is clean */ bzero(&DevData, sizeof(DEVDATA)); /* Set what we know */ if (DevName[0]) { DevData.dd_devname = strdup(DevName); DevData.dd_devunit = Device.md_unit; } if (CtlrName[0]) { DevData.dd_ctlrname = strdup(CtlrName); DevData.dd_ctlrunit = Device.md_ctlr; } /* * Mainbus devices such, as SCSI targets, may not exist * but the controller reports them as present */ if (Device.md_alive) DevData.dd_flags |= DD_MAYBE_ALIVE; if (Debug) printf("MainBus: Found \"%s\" (Unit %d) on \"%s\" (Unit %d) %s\n", DevData.dd_devname, DevData.dd_devunit, DevData.dd_ctlrname, DevData.dd_ctlrunit, (DevData.dd_flags & DD_MAYBE_ALIVE) ? "[MAYBE-ALIVE]" : ""); /* Probe and add device */ if (Dev = ProbeDevice(&DevData, TreePtr)) AddDevice(Dev, TreePtr); } KVMclose(kd); return(0); } #endif /* HAVE_MAINBUS */ #if defined(HAVE_OPENPROM) /* * OpenPROM stuff */ #include <sun/openprom.h> extern char OpenPROMSYM[]; /* * Build device tree by looking at OpenPROM (op) */ static int BuildOpenPROM(TreePtr) DEVICE **TreePtr; { static struct nlist nlistbuf; struct nlist *nlptr; static struct dev_info Root, *PtrRoot; u_long Addr; if (!(kd = KVMopen())) return(-1); if ((nlptr = KVMnlist(kd, OpenPROMSYM, &nlistbuf)) == NULL) return(-1); if (CheckNlist(nlptr)) return(-1); /* * Read pointer to "top_devinfo" from kernel */ Addr = nlptr->n_value; if (KVMread(kd, Addr, (char *) &PtrRoot, sizeof(struct dev_info *))) { if (Debug) Error("Cannot read openprom devinfo pointer from kernel"); return(-1); } if (KVMread(kd, (u_long)PtrRoot, (char *)&Root, sizeof(struct dev_info))) { if (Debug) Error("Cannot read openprom devinfo root from kernel"); return(-1); } return(OpenPROMTraverse(&Root, NULL, TreePtr)); } /* * Check an OpenPROM device. */ static int CheckOpenPROMDevice(DevInfo, Parent, TreePtr) struct dev_info *DevInfo; struct dev_info *Parent; DEVICE **TreePtr; { static DEVDATA DevData; DEVICE *Device; /* Make sure devdata is clean */ bzero(&DevData, sizeof(DEVDATA)); /* Set what we know */ if (DevInfo && DevInfo->devi_name) { DevData.dd_devname = DevInfo->devi_name; DevData.dd_devunit = DevInfo->devi_unit; } if (Parent && Parent->devi_name) { DevData.dd_ctlrname = Parent->devi_name; DevData.dd_ctlrunit = Parent->devi_unit; } /* * OpenPROM nodes that have a driver ALWAYS exist. * Some nodes may exist, without a driver, however. */ if (DevInfo->devi_driver) DevData.dd_flags |= DD_IS_ALIVE; if (Debug) printf("OPENPROM: Found \"%s\" (Unit %d) on \"%s\" (Unit %d) %s\n", DevData.dd_devname, DevData.dd_devunit, DevData.dd_ctlrname, DevData.dd_ctlrunit, (DevData.dd_flags & DD_IS_ALIVE) ? "[ALIVE]" : ""); /* Probe and add device */ if (Device = (DEVICE *) ProbeDevice(&DevData, TreePtr)) AddDevice(Device, TreePtr); } /* * Recursively traverse and descend the OpenPROM devinfo tree. */ static int OpenPROMTraverse(DevPtr, Parent, TreePtr) struct dev_info *DevPtr; struct dev_info *Parent; DEVICE **TreePtr; { static char Name[BUFSIZ]; struct dev_info *Ptr; /* * If node name is a valid pointer, read the name from kernel space * and call openprom_probe to handle checking the device. */ if (DevPtr->devi_name) { if (KVMread(kd, (u_long) DevPtr->devi_name, (char *) Name, sizeof(Name))) { Error("Cannot read openprom device name."); Name[0] = C_NULL; } else { DevPtr->devi_name = (char *) strdup(Name); CheckOpenPROMDevice(DevPtr, Parent, TreePtr); } } /* * If this node has slaves, read the slave data from kernel space * and descend. */ if (DevPtr->devi_slaves) { Ptr = (struct dev_info *) xcalloc(1, sizeof(struct dev_info)); if (KVMread(kd, (u_long) DevPtr->devi_slaves, (char *) Ptr, sizeof(struct dev_info))) { Error("Cannot read openprom slave data for %s.", Name); } else { DevPtr->devi_slaves = (struct dev_info *) Ptr; OpenPROMTraverse(DevPtr->devi_slaves, DevPtr, TreePtr); } } /* * If this node has a next pointer, read the next data from kernel space * and traverse. */ if (DevPtr->devi_next) { Ptr = (struct dev_info *) xcalloc(1, sizeof(struct dev_info)); if (KVMread(kd, (u_long) DevPtr->devi_next, (char *) Ptr, sizeof(struct dev_info))) { Error("Cannot read openprom next data for %s.", Name); } else { DevPtr->devi_next = (struct dev_info *) Ptr; OpenPROMTraverse(DevPtr->devi_next, Parent, TreePtr); } } return(0); } #endif /* HAVE_OPENPROM */ /* * Build device tree using TreePtr. * Calls bus and method specific functions to * search for devices. */ extern int BuildDevicesSunOS(TreePtr) DEVICE **TreePtr; { int Found = 1; #if defined(HAVE_OPENPROM) if (BuildOpenPROM(TreePtr) == 0) Found = 0; #endif /* HAVE_OPENPROM */ #if defined(HAVE_MAINBUS) if (BuildMainBus(TreePtr) == 0) Found = 0; #endif /* HAVE_MAINBUS */ return(Found); } /* * Scan the Disk Controller table looking for * a specific type. */ static DKCTLRTAB *GetDkCtlrTab(DkCtrlType) int DkCtrlType; { extern DKCTLRTAB DkCtlrTab[]; register int i; for (i = 0; DkCtlrTab[i].ct_model; ++i) { if (DkCtrlType == DkCtlrTab[i].ct_ctype) return(&DkCtlrTab[i]); } return((DKCTLRTAB *) NULL); } /* * Scan the Frame Buffer table looking for * a specific fb type. */ static NAMETAB *GetFBTab(FBType) int FBType; { extern NAMETAB FBTab[]; register int i; for (i = 0; FBTab[i].name; ++i) { if (FBType == FBTab[i].value) return(&FBTab[i]); } return((NAMETAB *) NULL); } /* * Get disk info structure. */ static struct dk_info *GETdk_info(d, file) int d; char *file; { static struct dk_info dk_info; if (ioctl(d, DKIOCINFO, &dk_info) < 0) { if (Debug) Error("%s: DKIOCINFO: %s.", file, SYSERR); return(NULL); } return(&dk_info); } /* * Get disk configuration structure. */ static struct dk_conf *GETdk_conf(d, file) int d; char *file; { static struct dk_conf dk_conf; if (ioctl(d, DKIOCGCONF, &dk_conf) < 0) { if (Debug) Error("%s: DKIOCGCONF: %s.", file, SYSERR); return(NULL); } return(&dk_conf); } /* * Get disk geometry structure. */ static struct dk_geom *GETdk_geom(d, file) int d; char *file; { static struct dk_geom dk_geom; if (ioctl(d, DKIOCGGEOM, &dk_geom) < 0) { if (Debug) Error("%s: DKIOCGGEOM: %s.", file, SYSERR); return(NULL); } return(&dk_geom); } /* * Get disk type structure. */ static struct dk_type *GETdk_type(d, file) int d; char *file; { static struct dk_type dk_type; if (ioctl(d, DKIOCGTYPE, &dk_type) < 0) { if (errno != ENOTTY) if (Debug) Error("%s: DKIOCGTYPE: %s.", file, SYSERR); return(NULL); } return(&dk_type); } /* * Check the checksum of a disklabel. */ static int DkLblCheckSum(DkLabel) struct dk_label *DkLabel; { register short *Ptr, Sum = 0; register short Count; Count = (sizeof (struct dk_label)) / (sizeof (short)); Ptr = (short *)DkLabel; /* * Take the xor of all the half-words in the label. */ while (Count--) Sum ^= *Ptr++; /* * The total should be zero for a correct checksum */ return(Sum); } /* * Get label information from label on disk. * The label is stored in the first sector of the disk. * We use the driver specific "read" flag with the DKIOCSCMD * ioctl to read the first sector. There should be a special * ioctl to just read the label. */ static struct dk_label *GETdk_label(d, file, dk_info) int d; char *file; struct dk_info *dk_info; { static struct dk_label dk_label; struct dk_cmd dk_cmd; struct dkctlrtab *pct; if (!file || !dk_info) return((struct dk_label *) NULL); if (!(pct = GetDkCtlrTab((int) dk_info->dki_ctype))) { Error("Controller type %d is unknown.", dk_info->dki_ctype); return((struct dk_label *) NULL); } if (pct->ct_rdcmd < 0) { if (Debug) Error("Read block on controller type \"%s\" is unsupported.", pct->ct_model); return((struct dk_label *) NULL); } bzero((char *) &dk_cmd, sizeof(dk_cmd)); dk_cmd.dkc_cmd = pct->ct_rdcmd; dk_cmd.dkc_flags = DK_SILENT | DK_ISOLATE; dk_cmd.dkc_blkno = (daddr_t)0; dk_cmd.dkc_secnt = 1; dk_cmd.dkc_bufaddr = (char *) &dk_label; dk_cmd.dkc_buflen = SECSIZE; if (ioctl(d, DKIOCSCMD, &dk_cmd) < 0) { if (Debug) Error("%s: DKIOCSCMD: %s.", file, SYSERR); return((struct dk_label *) NULL); } if (dk_label.dkl_magic != DKL_MAGIC) { Error("%s: Disk not labeled.", file); return((struct dk_label *) NULL); } if (DkLblCheckSum(&dk_label)) { Error("%s: Bad label checksum.", file); return((struct dk_label *) NULL); } return(&dk_label); } /* * Get the name of a disk (i.e. sd0). */ static char *GetDiskName(name, dk_conf, dk_info) char *name; struct dk_conf *dk_conf; struct dk_info *dk_info; { if (!dk_conf || !dk_info) { if (name) return(name); return((char *) NULL); } #if defined(DKI_HEXUNIT) if (FLAGS_ON(dk_info->dki_flags, DKI_HEXUNIT)) (void) sprintf(Buf, "%s%3.3x", dk_conf->dkc_dname, dk_conf->dkc_unit); else #endif /* DKI_HEXUNIT */ (void) sprintf(Buf, "%s%d", dk_conf->dkc_dname, dk_conf->dkc_unit); return(strdup(Buf)); } /* * Get the name of the controller for a disk. */ static char *GetDkCtlrName(dk_conf) struct dk_conf *dk_conf; { if (!dk_conf) return((char *) NULL); (void) sprintf(Buf, "%s%d", dk_conf->dkc_cname, dk_conf->dkc_cnum); return(strdup(Buf)); } /* * Get the disk controller model name from a disk. */ static char *GetDkCtlrModel(dk_info) struct dk_info *dk_info; { struct dkctlrtab *pct; if (!dk_info) return((char *) NULL); if (!(pct = GetDkCtlrTab(dk_info->dki_ctype))) return(NULL); return(pct->ct_model); } /* * Get a disk controller device from disk info. */ static DEVICE *GetDkCtlrDevice(DevData, dk_info, dk_conf) DEVDATA *DevData; struct dk_info *dk_info; struct dk_conf *dk_conf; { DEVICE *MkMasterFromDevData(); DEVICE *dkctlr; if ((dkctlr = NewDevice(NULL)) == NULL) return((DEVICE *) NULL); bzero((char *) dkctlr, sizeof(*dkctlr)); dkctlr->dv_type = DT_DISKCTLR; /* * Get name of controller from devdata if available */ if (DevData && DevData->dd_ctlrname) { dkctlr = MkMasterFromDevData(DevData); } if (dk_conf) { if (!dkctlr->dv_name) { dkctlr->dv_name = GetDkCtlrName(dk_conf); dkctlr->dv_unit = dk_conf->dkc_cnum; } dkctlr->dv_addr = dk_conf->dkc_addr; dkctlr->dv_prio = dk_conf->dkc_prio; dkctlr->dv_vec = dk_conf->dkc_vec; } if (dk_info) { dkctlr->dv_model = GetDkCtlrModel(dk_info); } return(dkctlr); } /* * Get disk label info from the extracted dk_label info. */ static char *GetDiskLabel(dk_label) struct dk_label *dk_label; { register char *p; if (!dk_label) return((char *) NULL); (void) strcpy(Buf, dk_label->dkl_asciilabel); /* * The label normally has geometry information in it we don't want * to see, so we trim out anything starting with " cyl". */ for (p = Buf; p && *p; ++p) { if (*p == ' ' && strncasecmp(p, " cyl", 4) == 0) *p = C_NULL; } return(strdup(Buf)); } /* * Get filesystem mount info for a partition. */ static char *GetMountInfo(name, part) char *name; char *part; { FILE *mf; struct mntent *mntent; char *file; if (!name) return((char *) NULL); file = GetCharFile(name, part); if ((mf = setmntent(MNTTAB, "r")) == NULL) { Error("%s: Cannot open for reading: %s.", MNTTAB, SYSERR); return(NULL); } while (mntent = getmntent(mf)) { if (strcmp(mntent->mnt_fsname, file) == 0) break; } endmntent(mf); return((mntent) ? mntent->mnt_dir : (char *) NULL); } /* * Extract the disk partition info from a disk. */ static DISKPART *ExtractDiskPart(name, part, dk_conf, dk_geom) char *name; char *part; struct dk_conf *dk_conf; struct dk_geom *dk_geom; { static DISKPART diskpart; struct dk_map dk_map; char *file; char *p; int d; if (!name || !dk_conf || !dk_geom) return((DISKPART *) NULL); file = GetRawFile(name, part); if (stat(file, &StatBuf) != 0) { if (Debug) Error("%s: No such partition.", file); return((DISKPART *) NULL); } if ((d = open(file, O_RDONLY)) < 0) { if (Debug) Error("%s: Cannot open for read: %s.", file, SYSERR); return((DISKPART *) NULL); } if (ioctl(d, DKIOCGPART, &dk_map) != 0) { Error("%s: Cannot extract partition info: %s.", file, SYSERR); return((DISKPART *) NULL); } (void) close(d); /* * Skip empty partitions */ if (!dk_map.dkl_nblk) { if (Debug) Error("%s: partition has no size.", file); return((DISKPART *) NULL); } bzero((char *) &diskpart, sizeof(DISKPART)); diskpart.dp_name = strdup(part); if (p = GetMountInfo(name, part)) diskpart.dp_mnt = strdup(p); /* * If this is the "b" partition on the root device, * then assume it's swap */ else if (dk_conf->dkc_unit == 0 && strcmp(part, "b") == 0) diskpart.dp_mnt = "swap"; diskpart.dp_stsect = dk_map.dkl_cylno * (dk_geom->dkg_nhead * dk_geom->dkg_nsect); diskpart.dp_nsect = dk_map.dkl_nblk; return(&diskpart); } /* * Translate disk partition information from basic * extracted disk info. */ static DISKPART *GetDiskPart(name, dk_conf, dk_geom) char *name; struct dk_conf *dk_conf; struct dk_geom *dk_geom; { extern char PartChars[]; register DISKPART *pdp, *dp; register int i; static char pname[2]; DISKPART *base = NULL; if (!name || !dk_conf || !dk_geom) return((DISKPART *) NULL); pname[1] = C_NULL; for (i = 0; PartChars[i]; ++i) { pname[0] = PartChars[i]; if (dp = ExtractDiskPart(name, pname, dk_conf, dk_geom)) { if (base) { for (pdp = base; pdp && pdp->dp_nxt; pdp = pdp->dp_nxt); pdp->dp_nxt = NewDiskPart(dp); } else { base = NewDiskPart(dp); } } } return(base); } /* * Convert all we've learned about a disk to a DEVICE. */ static DEVICE *dkToDiskDevice(name, DevData, dk_info, dk_label, dk_conf, dk_geom, dk_type) char *name; DEVDATA *DevData; struct dk_info *dk_info; struct dk_label *dk_label; struct dk_conf *dk_conf; struct dk_geom *dk_geom; struct dk_type *dk_type; { DEVICE *Device, *dkctlr; DISKDRIVE *diskdrive; if ((Device = NewDevice(NULL)) == NULL) { Error("Cannot create new device entry."); return((DEVICE *) NULL); } if ((dkctlr = NewDevice(NULL)) == NULL) { Error("Cannot create new dkctlr device entry."); return((DEVICE *) NULL); } if ((diskdrive = NewDiskDrive(NULL)) == NULL) { Error("Cannot create new diskdrive entry."); return((DEVICE *) NULL); } Device->dv_name = GetDiskName(name, dk_conf, dk_info); Device->dv_type = DT_DISKDRIVE; /* * Only read partition info we we're going to print it later. */ if (VL_ALL) diskdrive->dd_part = GetDiskPart(name, dk_conf, dk_geom); diskdrive->dd_label = GetDiskLabel(dk_label); Device->dv_model = diskdrive->dd_label; if (dk_conf) { diskdrive->dd_unit = dk_conf->dkc_unit; diskdrive->dd_slave = dk_conf->dkc_slave;; } if (dk_geom) { diskdrive->dd_dcyl = dk_geom->dkg_ncyl; diskdrive->dd_pcyl = dk_geom->dkg_pcyl; diskdrive->dd_acyl = dk_geom->dkg_acyl; diskdrive->dd_heads = dk_geom->dkg_nhead; diskdrive->dd_sect = dk_geom->dkg_nsect; diskdrive->dd_apc = dk_geom->dkg_apc; diskdrive->dd_rpm = dk_geom->dkg_rpm; diskdrive->dd_intrlv = dk_geom->dkg_intrlv; } if (dk_type) { diskdrive->dd_psect = dk_type->dkt_hsect; diskdrive->dd_promrev = dk_type->dkt_promrev; } if (dk_info) { #if defined(DKI_HEXUNIT) if (FLAGS_ON(dk_info->dki_flags, DKI_HEXUNIT)) diskdrive->dd_flags |= DF_HEXUNIT; #endif /* DKI_HEXUNIT */ } diskdrive->dd_secsize = SECSIZE; if (diskdrive->dd_dcyl && diskdrive->dd_sect && diskdrive->dd_heads) { static char Buf[BUFSIZ]; diskdrive->dd_size = nsect_to_bytes(diskdrive->dd_dcyl * diskdrive->dd_sect * diskdrive->dd_heads, diskdrive->dd_secsize); (void) sprintf(Buf, "%.2f MB capacity", (float) bytes_to_mbytes(diskdrive->dd_size)); Device->dv_desc = strdup(Buf); } dkctlr = GetDkCtlrDevice(DevData, dk_info, dk_conf); Device->dv_devspec = (caddr_t *) diskdrive; Device->dv_master = dkctlr; return(Device); } /* * Convert all we've learned about a CD-ROM drive to a DEVICE. */ static DEVICE *dkToCDROMDevice(name, DevData, dk_info, dk_conf, dk_geom, dk_type) char *name; DEVDATA *DevData; struct dk_info *dk_info; struct dk_conf *dk_conf; struct dk_geom *dk_geom; struct dk_type *dk_type; { DEVICE *Device, *dkctlr; DISKDRIVE *diskdrive; if ((Device = NewDevice(NULL)) == NULL) { Error("Cannot create new device entry."); return((DEVICE *) NULL); } if ((dkctlr = NewDevice(NULL)) == NULL) { Error("Cannot create new dkctlr device entry."); return((DEVICE *) NULL); } if ((diskdrive = NewDiskDrive(NULL)) == NULL) { Error("Cannot create new diskdrive entry."); return((DEVICE *) NULL); } Device->dv_name = GetDiskName(name, dk_conf, dk_info); Device->dv_type = DT_DISKDRIVE; /* * Only read partition info we we're going to print it later. */ if (VL_ALL) diskdrive->dd_part = GetDiskPart(name, dk_conf, dk_geom); diskdrive->dd_label = NULL; Device->dv_model = "CD-ROM"; if (dk_conf) { diskdrive->dd_unit = dk_conf->dkc_unit; diskdrive->dd_slave = dk_conf->dkc_slave;; } if (dk_geom) { diskdrive->dd_dcyl = dk_geom->dkg_ncyl; diskdrive->dd_pcyl = dk_geom->dkg_pcyl; diskdrive->dd_acyl = dk_geom->dkg_acyl; diskdrive->dd_heads = dk_geom->dkg_nhead; diskdrive->dd_sect = dk_geom->dkg_nsect; diskdrive->dd_apc = dk_geom->dkg_apc; diskdrive->dd_rpm = dk_geom->dkg_rpm; diskdrive->dd_intrlv = dk_geom->dkg_intrlv; } if (dk_type) { diskdrive->dd_psect = dk_type->dkt_hsect; diskdrive->dd_promrev = dk_type->dkt_promrev; } diskdrive->dd_secsize = SECSIZE; if (diskdrive->dd_dcyl && diskdrive->dd_sect && diskdrive->dd_heads) { static char Buf[BUFSIZ]; diskdrive->dd_size = nsect_to_bytes(diskdrive->dd_dcyl * diskdrive->dd_sect * diskdrive->dd_heads, diskdrive->dd_secsize); (void) sprintf(Buf, "%.2f MB capacity", (float) bytes_to_mbytes(diskdrive->dd_size)); Device->dv_desc = strdup(Buf); } dkctlr = GetDkCtlrDevice(DevData, dk_info, dk_conf); Device->dv_devspec = (caddr_t *) diskdrive; Device->dv_master = dkctlr; return(Device); } /* * Query and learn about a disk. */ extern DEVICE *ProbeDiskDrive(name, DevData, DevDataTab) /*ARGSUSED*/ char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { DEVICE *diskdevice; struct dk_info *dk_info = NULL; struct dk_conf *dk_conf = NULL; struct dk_type *dk_type = NULL; struct dk_label *dk_label = NULL; struct dk_geom *dk_geom = NULL; char *rfile; int d; if (!name) return((DEVICE *) NULL); #if defined(HAVE_IPI) /* * XXX - Kludge for IPI "id" disks. */ if (EQ(DevData->dd_devname, "id")) { static char Buf[BUFSIZ]; (void) sprintf(Buf, "%s%3.3x", DevData->dd_devname, DevData->dd_devunit); name = Buf; } #endif /* HAVE_IPI */ if (stat(rfile = GetRawFile(name, NULL), &StatBuf) != 0) { /* * Get the name of the whole disk raw device. */ rfile = GetRawFile(name, "c"); } if ((d = open(rfile, O_RDONLY)) < 0) { if (Debug) Error("%s: Cannot open for reading: %s.", rfile, SYSERR); /* * If we know for sure this drive is present and we * know something about it, then create a minimal device. */ if ((DevDataTab->ddt_model || DevDataTab->ddt_desc) && FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE)) { Device = NewDevice((DEVICE *) NULL); Device->dv_name = strdup(name); Device->dv_unit = DevData->dd_devunit; Device->dv_master = MkMasterFromDevData(DevData); Device->dv_type = DT_DISKDRIVE; Device->dv_model = DevDataTab->ddt_model; Device->dv_desc = DevDataTab->ddt_desc; return(Device); } else return((DEVICE *) NULL); } if ((dk_conf = GETdk_conf(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_conf failed.", rfile); } if ((dk_info = GETdk_info(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_info failed.", rfile); } if ((dk_geom = GETdk_geom(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_geom failed.", rfile); } if ((dk_label = GETdk_label(d, rfile, dk_info)) == NULL) { if (Debug) Error("%s: get dk_label failed.", rfile); } /* * Not all controllers support dk_type */ dk_type = GETdk_type(d, rfile); close(d); if (!(diskdevice = dkToDiskDevice(name, DevData, dk_info, dk_label, dk_conf, dk_geom, dk_type))) { Error("%s: Cannot convert diskdrive information.", name); return((DEVICE *) NULL); } return(diskdevice); } /* * Probe a tape device * XXX - this loses if somebody's using the tape, as tapes are exclusive-open * devices, and our open will therefore fail. * This also loses if there's no tape in the drive, as the open will fail. * The above probably applies to most other flavors of UNIX. */ extern DEVICE *ProbeTapeDrive(name, DevData, DevDataTab) /*ARGSUSED*/ char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { extern NAMETAB MtInfo[]; DEVICE *Device; char *file; char *model = NULL; char rfile[BUFSIZ]; static char Buf[BUFSIZ]; struct mtget mtget; register int i; int d; /* * Don't use GetRawFile; that'll just stick an "r" in front of the * device name, meaning it'll return the rewind-on-close device. * Somebody may have left the tape positioned somewhere other than * at the BOT to, for example, write a dump there later in the * evening; it'd be rather rude to reposition it out from under them. * * The above probably applies to most other flavors of UNIX. */ if (!name) file = NULL; else { (void) sprintf(rfile, "/dev/nr%s", name); file = rfile; } if ((d = open(file, O_RDONLY)) < 0) { if (Debug) Error("%s Cannot open for read: %s.", file, SYSERR); /* * --RECURSE-- * If we haven't tried the "mt" name yet, try it now */ if (strncmp(name, MTNAME, strlen(MTNAME)) != 0) { (void) sprintf(Buf, "%s%d", MTNAME, DevData->dd_devunit); Device = ProbeTapeDrive(Buf, DevData, DevDataTab); if (Device) return(Device); } /* * If we know for sure this drive is present and we * know something about it, then create a minimal device. */ if ((DevDataTab->ddt_model || DevDataTab->ddt_desc) && FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE)) { Device = NewDevice((DEVICE *) NULL); /* * Recreate name from devdata since we might have had to * call ourself with name "rmt?" */ (void) sprintf(Buf, "%s%d", DevData->dd_devname, DevData->dd_devunit); Device->dv_name = strdup(Buf); Device->dv_unit = DevData->dd_devunit; Device->dv_master = MkMasterFromDevData(DevData); Device->dv_type = DT_TAPEDRIVE; Device->dv_model = DevDataTab->ddt_model; Device->dv_desc = DevDataTab->ddt_desc; return(Device); } else return((DEVICE *) NULL); } if (ioctl(d, MTIOCGET, &mtget) != 0) { Error("%s: Cannot extract tape status: %s.", file, SYSERR); return((DEVICE *) NULL); } (void) close(d); model = "unknown"; for (i = 0; MtInfo[i].name; ++i) { if ((MtInfo[i].value == mtget.mt_type)) { model = MtInfo[i].name; break; } } /* * Create and set device info */ Device = NewDevice(NULL); Device->dv_name = strdup(name); Device->dv_type = DT_TAPEDRIVE; if (model) Device->dv_model = model; else 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); } /* * Query and learn about a CD-ROM drive. * We don't just use ProbeDisk Drive so that we don't get confused if * the CD-ROM in the drive has a label. * XXX - this loses if there's no caddy in the drive, as the open will fail. */ extern DEVICE *ProbeCDROMDrive(name, DevData, DevDataTab) /*ARGSUSED*/ char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { DEVICE *diskdevice; struct dk_info *dk_info = NULL; struct dk_conf *dk_conf = NULL; struct dk_type *dk_type = NULL; struct dk_geom *dk_geom = NULL; char *rfile; int d; if (!name) return((DEVICE *) NULL); rfile = GetRawFile(name, NULL); if ((d = open(rfile, O_RDONLY)) < 0) { if (Debug) Error("%s: Cannot open for reading: %s.", rfile, SYSERR); /* * If we know for sure this drive is present and we * know something about it, then create a minimal device. */ if ((DevDataTab->ddt_model || DevDataTab->ddt_desc) && FLAGS_ON(DevData->dd_flags, DD_IS_ALIVE)) { Device = NewDevice((DEVICE *) NULL); Device->dv_name = strdup(name); Device->dv_unit = DevData->dd_devunit; Device->dv_master = MkMasterFromDevData(DevData); Device->dv_type = DT_DISKDRIVE; Device->dv_model = DevDataTab->ddt_model; Device->dv_desc = DevDataTab->ddt_desc; return(Device); } else return((DEVICE *) NULL); } if ((dk_conf = GETdk_conf(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_conf failed.", rfile); } if ((dk_info = GETdk_info(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_info failed.", rfile); } if ((dk_geom = GETdk_geom(d, rfile)) == NULL) { if (Debug) Error("%s: get dk_geom failed.", rfile); } /* * Not all controllers support dk_type */ dk_type = GETdk_type(d, rfile); close(d); if (!(diskdevice = dkToCDROMDevice(name, DevData, dk_info, dk_conf, dk_geom, dk_type))) { Error("%s: Cannot convert CD-ROM drive information.", name); return((DEVICE *) NULL); } return(diskdevice); } /* * Query and learn about a device attached to an Auspex Storage Processor. * They'll show up as "ad" in the Mainbus info structure, but that * merely reflects the way the slots are set up in the config file. * We need to find out what type of device it is at this particular * instant (it's subject to change - perhaps even while we're running, * but there's not a heck of a lot we can do about that). * * We do that by trying it as a CD-ROM first, then as a disk, then as * a tape; that loses if it's a tape and somebody's using it, but * tapes on most if not all UNIX systems can't be probed by us if * somebody's using it. * The reason why we try it first as a CD-ROM is that if the CD has a * partition table, the Auspex driver lets you open the partitions as * if it were a disk. */ extern DEVICE *ProbeSPDrive(name, DevData, DevDataTab) /*ARGSUSED*/ char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { DEVICE *thedevice; char devname[BUFSIZ]; /* * Try it first as a CD-ROM. */ (void) sprintf(devname, "acd%d", DevData->dd_devunit); DevData->dd_devname = "acd"; DevDataTab->ddt_model = "CD-ROM"; if (thedevice = ProbeCDROMDrive(devname, DevData, DevDataTab)) return(thedevice); /* * Not a CD-ROM. Try a disk. */ (void) sprintf(devname, "ad%d", DevData->dd_devunit); DevData->dd_devname = "ad"; DevDataTab->ddt_model = NULL; if (thedevice = ProbeDiskDrive(devname, DevData, DevDataTab)) return(thedevice); /* * Not a disk. Try a tape. */ (void) sprintf(devname, "ast%d", DevData->dd_devunit); DevData->dd_devname = "ast"; if (thedevice = ProbeTapeDrive(devname, DevData, DevDataTab)) return(thedevice); /* * None of the above. Who knows? */ return((DEVICE *) NULL); } /* * Probe a CPU. * * This function really "fakes" up an entry. * * XXX Currently the info only comes from the OpenPROM. This should * be converted to use the kernel mach_info and mod_info structures. */ extern DEVICE *ProbeCPU(name, DevData, DevDataTab) /*ARGSUSED*/ char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { static int num_cpus = 0; Device = NewDevice(NULL); (void) sprintf(Buf, "cpu%d", num_cpus++); Device->dv_name = strdup(Buf); Device->dv_type = DT_CPU; Device->dv_model = strdup(name); Device->dv_desc = DevDataTab->ddt_desc; Device->dv_master = MkMasterFromDevData(DevData); return(Device); } /* * Probe a FrameBuffer. */ extern DEVICE *ProbeFrameBuffer(name, DevData, DevDataTab) char *name; DEVDATA *DevData; DEVDATATAB *DevDataTab; { DEVICE *fbdevice; FRAMEBUFFER *fb; NAMETAB *fbtab; struct fbgattr fbattr; #ifdef FBIOGXINFO struct cg6_info cg6_info; #endif char *file, Buf[BUFSIZ]; int d; if (!name) return((DEVICE *) NULL); /* * Check the device file. If the stat fails because * the device doesn't exist, trying the default framebuffer * device /dev/fb. */ file = GetCharFile(name, NULL); if (stat(file, &StatBuf) != 0) { if (errno == ENOENT && !EQ(name, FBDEVICE)) { if (Debug) Error("Framebuffer device %s does not exist. Trying `fb'.", name); return(ProbeFrameBuffer(FBDEVICE, DevData, DevDataTab)); } } if ((d = open(file, O_RDONLY)) < 0) { if (Debug) Error("%s: Cannot open for reading: %s.", file, SYSERR); return((DEVICE *) NULL); } if (ioctl(d, FBIOGATTR, &fbattr) != 0) { if (ioctl(d, FBIOGTYPE, &fbattr.fbtype) != 0) { if (Debug) Error("%s: FBIOGATTR/FBIOGTYPE: %s.", file, SYSERR); return((DEVICE *) NULL); } } Buf[0] = C_NULL; #if defined(FBIOGXINFO) if (ioctl(d, FBIOGXINFO, &cg6_info) == 0) { sprintf(Buf, "SBus Slot %d, Revision %d", cg6_info.slot, cg6_info.boardrev); if (cg6_info.hdb_capable) (void) strcat(Buf, ", double buffered"); else (void) strcat(Buf, ", single buffered"); } else { bzero((char *) &cg6_info, sizeof(struct cg6_info)); if (Debug) Error("%s: FBIOGXINFO: %s.", file, SYSERR); } #endif /* FBIOGXINFO */ close(d); if (!(fb = NewFrameBuffer(NULL))) { Error("Cannot create new frame buffer."); return((DEVICE *) NULL); } if (!(fbdevice = NewDevice(NULL))) { Error("Cannot create new frame buffer device entry."); return((DEVICE *) NULL); } if (!(fbtab = GetFBTab(fbattr.fbtype.fb_type))) { Error("Device %s is an unknown type (%d) of frame buffer.", name, fbattr.fbtype.fb_type); } fbdevice->dv_name = name; fbdevice->dv_type = DT_FRAMEBUFFER; fbdevice->dv_devspec = (caddr_t *) fb; if (Buf[0]) fbdevice->dv_desc = strdup(Buf); if (fbtab) { fbdevice->dv_model = fbtab->name; } else { fbdevice->dv_model = "UNKNOWN"; } fb->fb_height = fbattr.fbtype.fb_height; fb->fb_width = fbattr.fbtype.fb_width; fb->fb_depth = fbattr.fbtype.fb_depth; fb->fb_size = fbattr.fbtype.fb_size; fb->fb_cmsize = fbattr.fbtype.fb_cmsize; #if defined(FBIOGXINFO) if (cg6_info.vmsize) fb->fb_vmsize = mbytes_to_bytes(cg6_info.vmsize); #endif /* FBIOGXINFO */ fbdevice->dv_master = MkMasterFromDevData(DevData); return(fbdevice); } /* * Determine our cpu model name. * * We lookup the kernel symbol "cpu" instead of using gethostid() * because some SPARC vendors do not encode cpu/model info in gethostid(). */ extern char *GetModelName() { extern NAMETAB ModelTab[]; struct nlist *nlptr; register int i; int Cpu; kvm_t *kd; if (!(kd = KVMopen())) return((char *) NULL); if ((nlptr = KVMnlist(kd, CpuSYM, (struct nlist *)NULL)) == NULL) return((char *) NULL); if (CheckNlist(nlptr)) return((char *) NULL); if (KVMread(kd, (u_long) nlptr->n_value, (char *) &Cpu, sizeof(Cpu))) { if (Debug) Error("Cannot read cpu from kernel."); return((char *) NULL); } KVMclose(kd); for (i = 0; ModelTab[i].name; ++i) if (Cpu == ModelTab[i].value) return(ModelTab[i].name); if (Debug) Error("No model found; CPU = 0x%x.", Cpu); return((char *) NULL); } #if defined(CPU_ARCH) /* Sun */ #define ARCH_MASK CPU_ARCH #endif /* CPU_ARCH */ #if defined(CPU_TYPE) /* Solbourne */ #define ARCH_MASK CPU_TYPE #endif /* CPU_TYPE */ /* * Determine our kernel architecture name from our hostid. */ extern char *GetKernArchName() { #if defined(ARCH_MASK) extern NAMETAB KernArchTab[]; struct nlist *nlptr; kvm_t *kd; int Cpu; register int i; if (!(kd = KVMopen())) return((char *) NULL); if ((nlptr = KVMnlist(kd, CpuSYM, (struct nlist *)NULL)) == NULL) return((char *) NULL); if (CheckNlist(nlptr)) return((char *) NULL); if (KVMread(kd, (u_long) nlptr->n_value, (char *) &Cpu, sizeof(Cpu))) { if (Debug) Error("Cannot read cpu from kernel."); return((char *) NULL); } KVMclose(kd); for (i = 0; KernArchTab[i].name; ++i) if ((Cpu & ARCH_MASK) == KernArchTab[i].value) return(KernArchTab[i].name); if (Debug) Error("Kernel Arch 0x%x not defined; Cpu = 0x%x Mask = 0x%x", Cpu & ARCH_MASK, Cpu, ARCH_MASK); #endif /* ARCH_MASK */ return((char *) NULL); } #if defined(HAVE_NIT) #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <net/nit_if.h> /* * Find and set the MAC info using the Network Interface Tap (NIT) */ extern void SetMacInfoNIT(DevName, NetIf) char *DevName; NETIF *NetIf; { register struct sockaddr *SockAddr; struct ifreq ifreq; char *ether_ntoa(), Buf[MAXHOSTNAMLEN+1]; int Desc; if (!NetIf) return; if ((Desc = open("/dev/nit", O_RDONLY)) == SYSFAIL) { if (Debug) Error("open /dev/nit failed"); return; } /* * Bind to NIT for DevName */ strncpy(ifreq.ifr_name, DevName, sizeof ifreq.ifr_name); if (ioctl(Desc, NIOCBIND, (caddr_t) &ifreq) < 0) { if (Debug) Error("ioctl: NIOCBIND"); return; } /* * Get address */ if (ioctl(Desc, SIOCGIFADDR, (caddr_t)&ifreq) < 0) { if (Debug) Error("ioctl (SIOCGIFADDR)"); return; } (void) close(Desc); SockAddr = (struct sockaddr *)&ifreq.ifr_addr; NetIf->ni_macaddr = strdup(ether_ntoa((struct ether_addr *) SockAddr->sa_data)); if (ether_ntohost(Buf, (struct ether_addr *) SockAddr->sa_data) == 0) NetIf->ni_macname = strdup(Buf); } #endif /* HAVE_NIT */ /* * Get kernel version string from kernel symbol "version". */ extern char *GetKernelVersionStr() { return(GetKernelVersionFromVersion()); } /* * Get amount of physical memory using kernel symbol "physmem". */ extern char *GetMemory() { return(GetMemoryFromPhysmem()); } /* * Get system serial number */ extern char *GetSerialNoStr() { /* No support */ return((char *) NULL); } /* * Get name of OS */ extern char *GetOSNameStr() { return(GetOSNameFromUname()); } /* * Get version of OS */ extern char *GetOSVersionStr() { return(GetOSVersionFromUname()); } #if defined(HAVE_SUNROMVEC) /* * Be backwards compatible with pre-4.1.2 code */ #include <mon/sunromvec.h> #if defined(OPENPROMS) && !(defined(ROMVEC_VERSION) && \ (ROMVEC_VERSION == 0 || ROMVEC_VERSION == 1)) #define v_mon_id op_mon_id #endif #endif /* HAVE_SUNROMVEC */ /* * Get ROM Version number * * If "romp" is "defined" (in <mon/sunromvec.h>), then take that * as the address of the kernel pointer to "rom" (struct sunromvec). * Otherwise, nlist "romp" from the kernel. */ extern char *GetRomVer() { static char RomRev[16]; struct nlist *nlptr; #if defined(HAVE_SUNROMVEC) static struct sunromvec Rom; register char *p; register char *Addr; kvm_t *kd; #if !defined(romp) struct sunromvec *romp; if (!(kd = KVMopen())) return((char *) NULL); if ((nlptr = KVMnlist(kd, RomVecSYM, (struct nlist *)NULL)) == NULL) return((char *) NULL); if (CheckNlist(nlptr)) return((char *) NULL); /* * Read the kernel pointer to the sunromvec structure. */ if (KVMread(kd, (u_long) nlptr->n_value, (char *) &romp, sizeof(romp))) { if (Debug) Error("Cannot read sunromvec pointer from kernel."); return((char *) NULL); } #else /* romp */ if (!(kd = KVMopen())) return((char *) NULL); #endif /* romp */ /* * Read the sunromvec structure from the kernel */ /*SUPPRESS 25*/ if (KVMread(kd, (u_long) romp, (char *) &Rom, sizeof(struct sunromvec))) { if (Debug) Error("Cannot read sunromvec from kernel."); return((char *) NULL); } #if !defined(romp) /* * XXX Hardcoded values */ (void) sprintf(RomRev, "%d.%d", Rom.v_mon_id >> 16, Rom.v_mon_id & 0xFFFF); #else /* romp */ /* * Read the version string from the address indicated by Rom.v_mon_id. * Read 1 byte at a time until '\0' is encountered. */ p = RomRev; Addr = Rom.v_mon_id; do { if (KVMread(kd, (u_long) Addr++, p, 1)) break; } while (p < &RomRev[sizeof(RomRev)-1] && *p++); *p = C_NULL; #endif /* romp */ KVMclose(kd); #endif /* HAVE_SUNROMVEC */ return((RomRev[0]) ? RomRev : (char *) NULL); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.