Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

SmbiosItem.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
00003  *
00004  * Copyright (C) 2005 Dell Inc.
00005  *  by Michael Brown <Michael_E_Brown@dell.com>
00006  * Licensed under the Open Software License version 2.1
00007  *
00008  * Alternatively, you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published
00010  * by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012 
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  */
00018 
00019 // compat header should always be first header if including system headers
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022 
00023 #include <iomanip>
00024 
00025 #include "SmbiosImpl.h"
00026 // message.h should be included last.
00027 #include "smbios/message.h"
00028 
00029 using namespace smbiosLowlevel;
00030 using namespace std;
00031 
00032 namespace smbios
00033 {
00034     ISmbiosItem::~ISmbiosItem()
00035     {}
00036 
00037     ISmbiosItem::ISmbiosItem()
00038     {}
00039 
00040     //
00041     // COPY CONSTRUCTOR
00042     //
00043     SmbiosItem::SmbiosItem (const SmbiosItem & source)
00044             : ISmbiosItem(), header (source.header), header_size(source.header_size)
00045     {
00046         // only one allocation here. If it fails, there is
00047         // nothing to rollback, so we are exception safe.
00048         // if we add another allocation, we need to restructure this.
00049         u8 *newSmbiosItem = new u8[ header_size ];
00050         memcpy (newSmbiosItem, source.header, header_size);
00051         header = reinterpret_cast<const smbios_structure_header *>(newSmbiosItem);
00052 
00053         // don't deref header if it isn't valid
00054         // the world is not right if this happens.
00055         if (!header)
00056         {
00057             InternalErrorImpl internalError;
00058             internalError.setMessageString(_("Not a valid header. header is zero."));
00059             throw internalError;
00060         }
00061 
00062     }
00063 
00064     //
00065     // REGULAR CONSTRUCTOR
00066     //
00067     SmbiosItem::SmbiosItem (const smbios_structure_header *init_header)
00068             : ISmbiosItem(), header(init_header), header_size(0)
00069     {
00070         // we need to copy all of our data out of the SmbiosTable
00071         // so that we have our own copy. This effectively lets
00072         // smbiosItem have a separate lifetime from it's containing
00073         // table.
00074         //
00075         // we do all of the stuff below, up to the "new", to figure
00076         // out the size of the item.
00077 
00078         // don't deref header if it isn't valid
00079         // the world is not right if this happens.
00080         if (!header)
00081         {
00082             InternalErrorImpl internalError;
00083             internalError.setMessageString(_("Not a valid header. header is zero."));
00084             throw internalError;
00085         }
00086 
00087         // hop over to the next struct using smbios parsing rules
00088         // see smbiostable code for more details
00089         const u8 *nextStruct = reinterpret_cast<const u8 *>(header)  + header->length ;
00090 
00091         // skip over the strings in the string table. It ends with a double null
00092         while (*nextStruct || nextStruct[1])
00093             nextStruct++;
00094 
00095         // skip over the actual double null
00096         nextStruct += 2;
00097 
00098         // now we are at the next struct, we know the size
00099         // of the struct we are supposed to be pointing at.
00100         header_size = nextStruct - reinterpret_cast<const u8 *>(header);
00101 
00102         // only one allocation here. If it fails, there is
00103         // nothing to rollback, so we are safe.
00104         // if we add another allocation, we need to restructure this.
00105         u8 *newSmbiosItem = new u8[header_size];
00106         memcpy (newSmbiosItem, header, header_size);
00107         header = reinterpret_cast<const smbios_structure_header *>(newSmbiosItem);
00108     }
00109 
00110     SmbiosItem::~SmbiosItem ()
00111     {
00112         // its ugly because microsoft vc++ 6 sucks so much.
00113         delete [] const_cast<u8 *>(reinterpret_cast<const u8 *>(header));
00114         header = 0;
00115     }
00116 
00117     // gcc workaround. overprotective git. #!#$J@*(&$%
00118     // This is only used to format informational output stuff.
00119     // it loses precision, so don't do it except for display
00120     static u32 force_u64_to_u32(u64 orig)
00121     {
00122         // only gives correct results for little endian (I think)
00123         // but shouldn't matter, as it is for information purposes only.
00124         // 
00125         // use union to fix gcc type-punned pointer warning
00126         union 
00127         {
00128             u64 orig;
00129             u32 recast;
00130         } temp;
00131 
00132         temp.orig = orig;
00133         return temp.recast;
00134     }
00135 
00136     // Lifetime of returned char* is the same as the SmbiosItem
00137     // FIXME: This function needs to make sure it doesn't run past the end of the table for
00138     // malformed strings.
00139     //
00140     // Invariant: will always return a valid const char * or throw an exception
00141     const char *SmbiosItem::getStringByStringNumber (u8 which) const
00142     {
00143         const char *string_pointer = reinterpret_cast<const char *>(header);
00144 
00145         //  either user is an idiot and should go read the spec,
00146         //  _or_ there is a '\0' in the table, indicating
00147         //  the string does not exist. :-(
00148         //  In either case, we throw an exception.
00149         if (!which)     //strings are numbered beginning with 1
00150         {
00151             throw StringUnavailableImpl(_("String does not exist."));
00152         }
00153 
00154         // start out at the end of the header. This is where
00155         // the first string starts
00156         string_pointer += header->length;
00157 
00158         for (; which > 1; which--)
00159         {
00160             string_pointer += strlen (string_pointer);
00161             string_pointer++;  // skip past '\0'
00162 
00163             // check that we don't overflow this item
00164             //  additionally, split test into temp vars outside if() to work
00165             //  around astyle formatting bug where it will break code.
00166             const u8 *cur_loc = reinterpret_cast<const u8 *>(string_pointer);
00167             const u8 *base_loc =  reinterpret_cast<const u8 *>(header);
00168             if( cur_loc >= base_loc + header_size)
00169             {
00170                 ParseExceptionImpl parseException;
00171                 parseException.setMessageString(_("Overflow while getting byte data at location: cur_loc >= base_loc + header_size\n cur_loc : %(cur_loc)i\n base_loc : %(base_loc)i\n header_size : %(header_size)i "));
00172                 parseException.setParameter("cur_loc",    force_u64_to_u32(reinterpret_cast<u64>(cur_loc)));
00173                 parseException.setParameter("base_loc",   force_u64_to_u32(reinterpret_cast<u64>(base_loc)));
00174                 parseException.setParameter("header_size",static_cast<u32>(header_size));
00175                 throw parseException;
00176             }
00177 
00178             // if it is still '\0', that means we are
00179             // at the end of this item and should stop.
00180             // user gave us a bad index
00181             if( ! *string_pointer )
00182             {
00183                 throw StringUnavailableImpl(_("The string does not exist. Bad index caused this error"));
00184             }
00185         }
00186 
00187         return string_pointer;
00188     }
00189 
00190     std::auto_ptr<const ISmbiosItem> SmbiosItem::clone() const
00191     {
00192         return auto_ptr<const ISmbiosItem>(new SmbiosItem (*this));
00193     }
00194 
00195     std::auto_ptr<ISmbiosItem> SmbiosItem::clone()
00196     {
00197         return auto_ptr<ISmbiosItem>(new SmbiosItem (*this));
00198     }
00199 
00200     u8 SmbiosItem::getType () const
00201     {
00202         return header->type;
00203     }
00204 
00205     u8 SmbiosItem::getLength () const
00206     {
00207         return header->length;
00208     }
00209 
00210     u16 SmbiosItem::getHandle () const
00211     {
00212         return header->handle;
00213     }
00214 
00215     void checkItemBounds( size_t total_size, size_t length, size_t offset, size_t size)
00216     {
00217         DataOutOfBoundsImpl dataOutOfBounds;
00218         dataOutOfBounds.setParameter("offset",static_cast<int>(offset));
00219         dataOutOfBounds.setParameter("header_length",static_cast<int>(total_size));
00220 
00221         // tricky.  Need all three tests here in this order to avoid security hole
00222         if( offset > length )
00223         {
00224             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00225             throw dataOutOfBounds;
00226         }
00227 
00228         if( offset + size < offset )
00229         {
00230             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00231             throw dataOutOfBounds;
00232         }
00233 
00234         if( offset + size > length )
00235         {
00236             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00237             throw dataOutOfBounds;
00238         }
00239 
00240         if( offset >= total_size ) // world gone mad check.
00241             // data is inside what the header says is
00242             // the length, but outside the range of the
00243             // buffer we are using to hold the header.
00244             // Impossible?
00245         {
00246             dataOutOfBounds.setMessageString(_("Attempt to access data outside header buffer. Impossible situation! offset : %(offset)i, header_length : %(header_length)i"));
00247             throw dataOutOfBounds;
00248         }
00249 
00250     }
00251 
00252     void SmbiosItem::getData(unsigned int offset, void *out, size_t size ) const
00253     {
00254         checkItemBounds( header_size, header->length, offset, size );
00255         memcpy(out, reinterpret_cast<const u8 *>(header)+offset, size);
00256     }
00257 
00258     const u8 *SmbiosItem::getBufferCopy(size_t &size) const
00259     {
00260         size = header_size;
00261 
00262         const u8 *newBuffer = new u8[ size ];
00263         memcpy (const_cast<u8 *>(newBuffer), header, size);
00264         return newBuffer;
00265     }
00266 
00267     const size_t SmbiosItem::getBufferSize() const
00268     {
00269         return header_size;
00270     }
00271 
00272     void SmbiosItem::fixup( const SmbiosWorkaroundTable *workaround ) const
00273     {
00274         u8 *buffer = const_cast<u8 *>(reinterpret_cast<const u8 *>(header));
00275         workaround->fixupItem( this, buffer, header_size );
00276     }
00277 
00278     ostream & SmbiosItem::streamify (ostream & cout) const
00279     {
00280         if (header == 0)  // violates class invariant, should never happen
00281             cout << "operator << on an uninitialized SmbiosItem!";
00282         else
00283         {
00284             std::ios::fmtflags old_opts = cout.flags ();
00285             cout << "Handle 0x" << hex << setfill ('0') <<
00286             setw (4) << getHandle () << endl;
00287             cout << "\tDMI type 0x" << static_cast<int>(getType()) << dec <<
00288             ", " << static_cast<int>(getLength()) << " bytes." <<
00289             endl;
00290             cout.flags (old_opts);
00291         }
00292         return cout;
00293     }
00294 
00295 
00296     /**************************************************************************
00297      *  OUT OF LINE HELPERS
00298      *************************************************************************/
00299 
00300     u8 getItemType(const ISmbiosItem &item)
00301     {
00302         return getU8_FromItem(item, 0);
00303     }
00304 
00305     u8 getItemLength(const ISmbiosItem &item)
00306     {
00307         return getU8_FromItem(item, 1);
00308     }
00309 
00310     u16 getItemHandle(const ISmbiosItem &item)
00311     {
00312         return getU16_FromItem(item, 2);
00313     }
00314 
00315     u8 getU8_FromItem(const ISmbiosItem &item, unsigned int offset)
00316     {
00317         u8 retval = 0;
00318         item.getData(offset, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00319         return retval;
00320     }
00321 
00322     u16 getU16_FromItem(const ISmbiosItem &item, unsigned int offset)
00323     {
00324         u16 retval = 0;
00325         item.getData(offset, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00326         return retval;
00327     }
00328 
00329     u32 getU32_FromItem(const ISmbiosItem &item, unsigned int offset)
00330     {
00331         u32 retval = 0;
00332         item.getData(offset, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00333         return retval;
00334     }
00335 
00336     u64 getU64_FromItem(const ISmbiosItem &item, unsigned int offset)
00337     {
00338         u64 retval = 0;
00339         item.getData(offset, reinterpret_cast<u8 *>(&retval), sizeof(retval));
00340         return retval;
00341     }
00342 
00343     const char *getString_FromItem(const ISmbiosItem &item, unsigned int offset)
00344     {
00345         u8 stringNum = 0;
00346         getData(item, offset, stringNum);
00347         return item.getStringByStringNumber(stringNum);
00348     }
00349 
00350     void *getBits_FromItem ( const ISmbiosItem &item, unsigned int offset, void *out, unsigned int lsb, unsigned int msb )
00351     {
00352         u64 bitfield = 0;
00353 
00354         //If msb is less/equal to lsb, they are only requesting a single bit
00355         if(msb <= lsb)
00356             msb=lsb;
00357 
00358         if(msb > 63)
00359         {
00360             DataOutOfBoundsImpl dataOutOfBounds;
00361             dataOutOfBounds.setParameter("lsb",lsb);
00362             dataOutOfBounds.setParameter("msb",msb);
00363             dataOutOfBounds.setMessageString(_("The total length of bit field is out of bounds. The largest accessible bit is 63. lsb: %(lsb)i , msb: %(msb)i"));
00364             throw  dataOutOfBounds;
00365         }
00366 
00367         // calculate length of bit field based on msb/lsb
00368         unsigned int fieldLen = ((msb+1)/8) + (((msb+1)%8)?1:0);
00369 
00370         // request data from item
00371         item.getData(offset, &bitfield, fieldLen);
00372 
00373         // mask off everything but requested bits and shift down
00374         unsigned int bitlen = (msb-lsb) + 1;
00375         bitfield = (bitfield >> lsb) & ((1<<bitlen)-1);
00376 
00377         if(out)
00378             memcpy(out, &bitfield, ((bitlen)/8) + (((bitlen)%8)?1:0));
00379 
00380         return out;
00381     }
00382 
00383     bool isBitSet(const ISmbiosItem *itemPtr, unsigned int offset, unsigned int bitToTest)
00384     {
00385         bool retval = false;
00386 
00387         unsigned int byte = bitToTest / 8;
00388         u8 fieldValue = getU8_FromItem(*itemPtr, offset + byte );
00389         if (fieldValue & (1 << (bitToTest%8)))
00390             retval = true;
00391 
00392         return retval;
00393     }
00394 
00395     ostream & operator << (ostream & cout, const ISmbiosItem & item)
00396     {
00397         return item.streamify (cout);
00398     }
00399 }

Generated on Wed Apr 11 16:25:10 2007 for SMBIOS Library by doxygen 1.3.5