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

Generated on Tue Feb 26 14:39:34 2008 for SMBIOS Library by  doxygen 1.3.9.1