1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <sys/types.h> 31 #include <sys/smbios_impl.h> 32 #include <sys/sysmacros.h> 33 #include <sys/stat.h> 34 #include <sys/mman.h> 35 36 #include <limits.h> 37 #include <unistd.h> 38 #include <strings.h> 39 #include <stdlib.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 43 #pragma init(smb_init) 44 static void 45 smb_init(void) 46 { 47 _smb_debug = getenv("SMB_DEBUG") != NULL; 48 } 49 50 static smbios_hdl_t * 51 smb_fileopen(int fd, int version, int flags, int *errp) 52 { 53 smbios_hdl_t *shp = NULL; 54 smbios_entry_t ep; 55 void *stbuf; 56 ssize_t n; 57 58 if ((n = pread64(fd, &ep, sizeof (ep), 0)) != sizeof (ep)) 59 return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOHDR)); 60 61 if (strncmp(ep.smbe_eanchor, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN)) 62 return (smb_open_error(shp, errp, ESMB_HEADER)); 63 64 if ((stbuf = smb_alloc(ep.smbe_stlen)) == NULL) 65 return (smb_open_error(shp, errp, ESMB_NOMEM)); 66 67 if ((n = pread64(fd, stbuf, ep.smbe_stlen, 68 (off64_t)ep.smbe_staddr)) != ep.smbe_stlen) { 69 smb_free(stbuf, ep.smbe_stlen); 70 return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOSTAB)); 71 } 72 73 shp = smbios_bufopen(&ep, stbuf, ep.smbe_stlen, version, flags, errp); 74 75 if (shp != NULL) 76 shp->sh_flags |= SMB_FL_BUFALLOC; 77 else 78 smb_free(stbuf, ep.smbe_stlen); 79 80 return (shp); 81 } 82 83 static smbios_hdl_t * 84 smb_biosopen(int fd, int version, int flags, int *errp) 85 { 86 smbios_hdl_t *shp = NULL; 87 size_t pgsize, pgmask, pgoff; 88 void *stbuf, *bios, *p, *q; 89 smbios_entry_t ep; 90 91 bios = mmap(NULL, SMB_RANGE_LIMIT - SMB_RANGE_START + 1, 92 PROT_READ, MAP_SHARED, fd, (uint32_t)SMB_RANGE_START); 93 94 if (bios == MAP_FAILED) 95 return (smb_open_error(shp, errp, ESMB_MAPDEV)); 96 97 q = (void *)((uintptr_t)bios + SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 98 99 for (p = bios; p < q; p = (void *)((uintptr_t)p + 16)) { 100 if (strncmp(p, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN) == 0) 101 break; 102 } 103 104 if (p >= q) { 105 (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 106 return (smb_open_error(NULL, errp, ESMB_NOTFOUND)); 107 } 108 109 bcopy(p, &ep, sizeof (smbios_entry_t)); 110 (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 111 112 pgsize = getpagesize(); 113 pgmask = ~(pgsize - 1); 114 pgoff = ep.smbe_staddr & ~pgmask; 115 116 bios = mmap(NULL, ep.smbe_stlen + pgoff, 117 PROT_READ, MAP_SHARED, fd, ep.smbe_staddr & pgmask); 118 119 if (bios == MAP_FAILED) 120 return (smb_open_error(shp, errp, ESMB_MAPDEV)); 121 122 if ((stbuf = smb_alloc(ep.smbe_stlen)) == NULL) { 123 (void) munmap(bios, ep.smbe_stlen + pgoff); 124 return (smb_open_error(shp, errp, ESMB_NOMEM)); 125 } 126 127 bcopy((char *)bios + pgoff, stbuf, ep.smbe_stlen); 128 (void) munmap(bios, ep.smbe_stlen + pgoff); 129 shp = smbios_bufopen(&ep, stbuf, ep.smbe_stlen, version, flags, errp); 130 131 if (shp != NULL) 132 shp->sh_flags |= SMB_FL_BUFALLOC; 133 else 134 smb_free(stbuf, ep.smbe_stlen); 135 136 return (shp); 137 } 138 139 smbios_hdl_t * 140 smbios_fdopen(int fd, int version, int flags, int *errp) 141 { 142 struct stat64 st1, st2; 143 144 if (stat64(SMB_BIOS_DEVICE, &st1) == 0 && fstat64(fd, &st2) == 0 && 145 S_ISCHR(st2.st_mode) && st1.st_rdev == st2.st_rdev) 146 return (smb_biosopen(fd, version, flags, errp)); 147 else 148 return (smb_fileopen(fd, version, flags, errp)); 149 } 150 151 smbios_hdl_t * 152 smbios_open(const char *file, int version, int flags, int *errp) 153 { 154 smbios_hdl_t *shp; 155 int fd; 156 157 if ((fd = open64(file ? file : SMB_SMBIOS_DEVICE, O_RDONLY)) == -1) { 158 if ((errno == ENOENT || errno == ENXIO) && 159 (file == NULL || strcmp(file, SMB_SMBIOS_DEVICE) == 0)) 160 errno = ESMB_NOTFOUND; 161 return (smb_open_error(NULL, errp, errno)); 162 } 163 164 shp = smbios_fdopen(fd, version, flags, errp); 165 (void) close(fd); 166 return (shp); 167 } 168 169 static int 170 smbios_xwrite(smbios_hdl_t *shp, int fd, const void *buf, size_t buflen) 171 { 172 ssize_t resid = buflen; 173 ssize_t len; 174 175 while (resid != 0) { 176 if ((len = write(fd, buf, resid)) <= 0) 177 return (smb_set_errno(shp, errno)); 178 resid -= len; 179 buf = (uchar_t *)buf + len; 180 } 181 182 return (0); 183 } 184 185 int 186 smbios_write(smbios_hdl_t *shp, int fd) 187 { 188 smbios_entry_t ep; 189 off64_t off = lseek64(fd, 0, SEEK_CUR) + P2ROUNDUP(sizeof (ep), 16); 190 191 if (off > UINT32_MAX) 192 return (smb_set_errno(shp, EOVERFLOW)); 193 194 bcopy(&shp->sh_ent, &ep, sizeof (ep)); 195 ep.smbe_staddr = (uint32_t)off; 196 smbios_checksum(shp, &ep); 197 198 if (smbios_xwrite(shp, fd, &ep, sizeof (ep)) == -1 || 199 lseek64(fd, off, SEEK_SET) != off || 200 smbios_xwrite(shp, fd, shp->sh_buf, shp->sh_buflen) == -1) 201 return (-1); 202 203 return (0); 204 } 205