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 2006 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 <alloca.h> 37 #include <limits.h> 38 #include <unistd.h> 39 #include <strings.h> 40 #include <stdlib.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 44 #pragma init(smb_init) 45 static void 46 smb_init(void) 47 { 48 _smb_debug = getenv("SMB_DEBUG") != NULL; 49 } 50 51 static smbios_hdl_t * 52 smb_fileopen(int fd, int version, int flags, int *errp) 53 { 54 smbios_entry_t *ep = alloca(SMB_ENTRY_MAXLEN); 55 smbios_hdl_t *shp = NULL; 56 ssize_t n, elen; 57 void *stbuf; 58 59 if ((n = pread64(fd, ep, sizeof (*ep), 0)) != sizeof (*ep)) 60 return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOHDR)); 61 62 if (strncmp(ep->smbe_eanchor, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN)) 63 return (smb_open_error(shp, errp, ESMB_HEADER)); 64 65 elen = MIN(ep->smbe_elen, SMB_ENTRY_MAXLEN); 66 67 if ((n = pread64(fd, ep, elen, 0)) != elen) 68 return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOHDR)); 69 70 if ((stbuf = smb_alloc(ep->smbe_stlen)) == NULL) 71 return (smb_open_error(shp, errp, ESMB_NOMEM)); 72 73 if ((n = pread64(fd, stbuf, ep->smbe_stlen, 74 (off64_t)ep->smbe_staddr)) != ep->smbe_stlen) { 75 smb_free(stbuf, ep->smbe_stlen); 76 return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOSTAB)); 77 } 78 79 shp = smbios_bufopen(ep, stbuf, ep->smbe_stlen, version, flags, errp); 80 81 if (shp != NULL) 82 shp->sh_flags |= SMB_FL_BUFALLOC; 83 else 84 smb_free(stbuf, ep->smbe_stlen); 85 86 return (shp); 87 } 88 89 static smbios_hdl_t * 90 smb_biosopen(int fd, int version, int flags, int *errp) 91 { 92 smbios_entry_t *ep = alloca(SMB_ENTRY_MAXLEN); 93 smbios_hdl_t *shp = NULL; 94 size_t pgsize, pgmask, pgoff; 95 void *stbuf, *bios, *p, *q; 96 97 bios = mmap(NULL, SMB_RANGE_LIMIT - SMB_RANGE_START + 1, 98 PROT_READ, MAP_SHARED, fd, (uint32_t)SMB_RANGE_START); 99 100 if (bios == MAP_FAILED) 101 return (smb_open_error(shp, errp, ESMB_MAPDEV)); 102 103 q = (void *)((uintptr_t)bios + SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 104 105 for (p = bios; p < q; p = (void *)((uintptr_t)p + 16)) { 106 if (strncmp(p, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN) == 0) 107 break; 108 } 109 110 if (p >= q) { 111 (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 112 return (smb_open_error(NULL, errp, ESMB_NOTFOUND)); 113 } 114 115 bcopy(p, ep, sizeof (smbios_entry_t)); 116 ep->smbe_elen = MIN(ep->smbe_elen, SMB_ENTRY_MAXLEN); 117 bcopy(p, ep, ep->smbe_elen); 118 (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 119 120 pgsize = getpagesize(); 121 pgmask = ~(pgsize - 1); 122 pgoff = ep->smbe_staddr & ~pgmask; 123 124 bios = mmap(NULL, ep->smbe_stlen + pgoff, 125 PROT_READ, MAP_SHARED, fd, ep->smbe_staddr & pgmask); 126 127 if (bios == MAP_FAILED) 128 return (smb_open_error(shp, errp, ESMB_MAPDEV)); 129 130 if ((stbuf = smb_alloc(ep->smbe_stlen)) == NULL) { 131 (void) munmap(bios, ep->smbe_stlen + pgoff); 132 return (smb_open_error(shp, errp, ESMB_NOMEM)); 133 } 134 135 bcopy((char *)bios + pgoff, stbuf, ep->smbe_stlen); 136 (void) munmap(bios, ep->smbe_stlen + pgoff); 137 shp = smbios_bufopen(ep, stbuf, ep->smbe_stlen, version, flags, errp); 138 139 if (shp != NULL) 140 shp->sh_flags |= SMB_FL_BUFALLOC; 141 else 142 smb_free(stbuf, ep->smbe_stlen); 143 144 return (shp); 145 } 146 147 smbios_hdl_t * 148 smbios_fdopen(int fd, int version, int flags, int *errp) 149 { 150 struct stat64 st1, st2; 151 152 if (stat64(SMB_BIOS_DEVICE, &st1) == 0 && fstat64(fd, &st2) == 0 && 153 S_ISCHR(st2.st_mode) && st1.st_rdev == st2.st_rdev) 154 return (smb_biosopen(fd, version, flags, errp)); 155 else 156 return (smb_fileopen(fd, version, flags, errp)); 157 } 158 159 smbios_hdl_t * 160 smbios_open(const char *file, int version, int flags, int *errp) 161 { 162 smbios_hdl_t *shp; 163 int fd; 164 165 if ((fd = open64(file ? file : SMB_SMBIOS_DEVICE, O_RDONLY)) == -1) { 166 if ((errno == ENOENT || errno == ENXIO) && 167 (file == NULL || strcmp(file, SMB_SMBIOS_DEVICE) == 0)) 168 errno = ESMB_NOTFOUND; 169 return (smb_open_error(NULL, errp, errno)); 170 } 171 172 shp = smbios_fdopen(fd, version, flags, errp); 173 (void) close(fd); 174 return (shp); 175 } 176 177 static int 178 smbios_xwrite(smbios_hdl_t *shp, int fd, const void *buf, size_t buflen) 179 { 180 ssize_t resid = buflen; 181 ssize_t len; 182 183 while (resid != 0) { 184 if ((len = write(fd, buf, resid)) <= 0) 185 return (smb_set_errno(shp, errno)); 186 resid -= len; 187 buf = (uchar_t *)buf + len; 188 } 189 190 return (0); 191 } 192 193 int 194 smbios_write(smbios_hdl_t *shp, int fd) 195 { 196 smbios_entry_t ep; 197 off64_t off = lseek64(fd, 0, SEEK_CUR) + P2ROUNDUP(sizeof (ep), 16); 198 199 if (off > UINT32_MAX) 200 return (smb_set_errno(shp, EOVERFLOW)); 201 202 bcopy(&shp->sh_ent, &ep, sizeof (ep)); 203 ep.smbe_staddr = (uint32_t)off; 204 smbios_checksum(shp, &ep); 205 206 if (smbios_xwrite(shp, fd, &ep, sizeof (ep)) == -1 || 207 lseek64(fd, off, SEEK_SET) != off || 208 smbios_xwrite(shp, fd, shp->sh_buf, shp->sh_buflen) == -1) 209 return (-1); 210 211 return (0); 212 } 213