SMBIOS Library
SmbiosTable.cpp
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
3  *
4  * Copyright (C) 2005 Dell Inc.
5  * by Michael Brown <Michael_E_Brown@dell.com>
6  * Licensed under the Open Software License version 2.1
7  *
8  * Alternatively, you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12 
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  */
18 
19 // compat header should always be first header if including system headers
20 #define LIBSMBIOS_SOURCE
21 #include "smbios/compat.h"
22 
23 #include <sstream>
24 #include <string.h>
25 
26 #include "SmbiosImpl.h"
27 
28 // message.h should be included last.
29 #include "smbios/message.h"
30 
31 using namespace smbiosLowlevel;
32 using namespace std;
33 
34 #if defined(DEBUG_SMBIOS)
35 # define DCOUT(line) do { cout << line; } while(0)
36 # define DCERR(line) do { cerr << line; } while(0)
37 #else
38 # define DCOUT(line) do {} while(0)
39 # define DCERR(line) do {} while(0)
40 #endif
41 
42 namespace smbios
43 {
44 
45  ISmbiosTable::ISmbiosTable()
46  {}
47 
48  ISmbiosTable::~ISmbiosTable()
49  {}
50 
51  // Regular CONSTRUCTOR NOT ALLOWED!
52  // This is marked "protected:" in the header (only to be used by derived classes)
53  SmbiosTable::SmbiosTable ()
54  : ISmbiosTable(), itemList(), initializing(true), strictValidationMode(false), workaround(0), smbiosBuffer (0)
55  {
56  memset (
57  const_cast<smbios_table_entry_point *>(&table_header),
58  0,
59  sizeof (table_header)
60  );
61  }
62 
63  // Regular Constructor
64  SmbiosTable::SmbiosTable(std::vector<SmbiosStrategy *> initStrategyList, bool strictValidation)
65  :ISmbiosTable(), itemList(), initializing(true), strictValidationMode(strictValidation), workaround(0), smbiosBuffer (0), strategyList(initStrategyList)
66  {
67  // clearItemCache(); // works fine if we call here.
68  reReadTable(); // may throw
69  }
70 
71  // DESTRUCTOR
73  {
75 
76  if (0 != smbiosBuffer)
77  {
78  memset ( const_cast<u8 *>(smbiosBuffer), 0, sizeof (*smbiosBuffer));
79  delete [] const_cast<u8 *>(smbiosBuffer);
80  smbiosBuffer = 0;
81  }
82 
83  memset (
84  const_cast<smbios_table_entry_point *>(&table_header),
85  0,
86  sizeof (table_header)
87  );
88 
89  std::vector< SmbiosStrategy *>::iterator strategy;
90  for( strategy = strategyList.begin(); strategy != strategyList.end(); ++strategy )
91  {
92  delete *strategy;
93  }
94  }
95 
96  ISmbiosItem *SmbiosTable::getCachedItem( const void * itemPtr ) const
97  {
98  ISmbiosItem *ret = 0;
99  if ((itemList.find (itemPtr) !=
100  itemList.end ()))
101  {
102  if( 0 != itemList[itemPtr] )
103  {
104  ret = itemList[itemPtr];
105  }
106  else
107  {
108  throw InternalErrorImpl(_("No null pointers should ever leak into the itemList"));
109  }
110  }
111  return ret;
112  }
113 
114  void SmbiosTable::cacheItem( const void *ptr, ISmbiosItem &newitem ) const
115  {
116  // The following two lines are equivalent to:
117  //table->itemList[current] = newitem;
118  // but are more efficient
119  pair < const void *, ISmbiosItem * >myPair (ptr, &newitem);
120  itemList.insert (itemList.begin (), myPair);
121  }
122 
124  {
125  return SmbiosTable::iterator (this);
126  }
127 
129  {
130  return SmbiosTable::const_iterator (this);
131  }
132 
134  {
135  return SmbiosTable::iterator ();
136  }
137 
139  {
140  return SmbiosTable::const_iterator ();
141  }
142 
144  {
145  return SmbiosTable::iterator (this, type);
146  }
147 
149  {
150  return SmbiosTable::const_iterator (this, type);
151  }
152 
154  {
155  throw NotImplementedImpl(_("This is an enhanced function call that is not available in the base Smbios library. You must be using an enhanced library such as SmbiosXml to use this API"));
156  }
157 
159  {
160  throw NotImplementedImpl(_("This is an enhanced function call that is not available in the base Smbios library. You must be using an enhanced library such as SmbiosXml to use this API"));
161  }
162 
164  {
165  bool gotTable = false;
166  // make sure there are no cached objects.
167  // MSVC++ crashes here if you remove the if(). No idea why, works on
168  // GCC.
169  if( ! initializing )
170  clearItemCache();
171 
172  // go through our strategies one-by-one and ask them if they can
173  // fulfill the request.
174  DCERR("calling strategy code to read table" << endl);
175  std::vector< SmbiosStrategy *>::iterator strategy;
176  for( strategy = strategyList.begin(); strategy != strategyList.end(); ++strategy )
177  {
178  try
179  {
180  DCERR(" strategy: 0x" << hex << (int)(*strategy) << endl);
181  if( (*strategy)->getSmbiosTable(&smbiosBuffer, &table_header, getStrictValidationMode()) )
182  {
183  DCERR(" RETURNED SUCCESS" << endl);
184  gotTable = true;
185  break;
186  }
187  }
188  catch(...)
189  {
190  // nil
191  }
192  }
193  DCERR("TABLE HEADER DUMP: " << endl << *this << endl);
194  DCERR("TABLE BUFFER: 0x" << hex << (int)smbiosBuffer << endl);
195 
196  if (! gotTable)
197  {
198  // manually delete allocated stuff here because the destructor
199  // does not get called and this stuff will not be freed.
200  std::vector< SmbiosStrategy *>::iterator strategy;
201  for( strategy = strategyList.begin(); strategy != strategyList.end(); ++strategy )
202  {
203  delete *strategy;
204  }
205  throw InternalErrorImpl(_("Could not instantiate SMBIOS table."));
206  }
207  }
208 
210  {
211  // crap code to work around compiler bugs in:
212  // -- gcc 2.96
213  // -- msvc++ 6.0
214  //
215  const SmbiosWorkaroundTable *ptr = workaround.get();
216  workaround.release();
217  delete const_cast<SmbiosWorkaroundTable *>(ptr);
218  std::auto_ptr<SmbiosWorkaroundTable> foo(
219  SmbiosWorkaroundFactory::getFactory()->makeNew( this ));
220  workaround = foo;
221 
222  // after initializing the workaround object, go through and delete
223  // all existing items.
224  //
225  // have to do this because items are possibly created with wrong
226  // type. Types higher than SmbiosTableMemory
227  // call this through constructor, and this call happens before
228  // we enter the constructor for the higher level type.
229  //
230  // For example, if we are supposed to initializing an Xml Table,
231  // The items here _should_ be SmbiosItemAccess objects, but instead
232  // they turn out to be regular SmbiosItem objects.
233  clearItemCache();
234 
235  initializing = false;
236  }
237 
238  void SmbiosTable::rawMode(bool m) const
239  {
240  initializing = m;
241  }
242 
244  {
245  // Delete everything in itemList
246  std::map < const void *, ISmbiosItem * >::iterator position;
247  for (position = itemList.begin ();
248  position != itemList.end (); ++position)
249  {
250  delete position->second;
251  }
252  // clear the item list.
253  itemList.clear();
254  }
255 
256  // Restrict the validation of table entry point
258  {
259  strictValidationMode = mode;
260  }
261 
263  {
264  return strictValidationMode;
265  }
266 
267  // Get an Item
269  const void *header) const
270  {
271  const smbios_structure_header *structure =
272  reinterpret_cast<const smbios_structure_header *>(header);
273  ISmbiosItem *item = new SmbiosItem( structure );
274  if( ! initializing )
275  {
276  dynamic_cast<SmbiosItem*>(item)->fixup( workaround.get() );
277  }
278  return *item;
279  }
280 
281  const ISmbiosItem & SmbiosTable::getSmbiosItem (const u8 *current) const
282  {
283  return const_cast<SmbiosTable *>(this)->getSmbiosItem(current);
284  }
285 
287  {
288  if (0 == current)
289  {
290  throw ItemNotFoundImpl("Could not de-reference a null item");
291  }
292 
293  ISmbiosItem *item = this->getCachedItem( current );
294  if ( 0 != item )
295  return *(item);
296 
297  ISmbiosItem &newitem = this->makeItem( current );
298 
299  this->cacheItem( current, newitem );
300 
301  return newitem;
302  }
303 
304  const u8 *SmbiosTable::nextSmbiosStruct (const u8* current) const
305  {
306  const smbios_structure_header *currStruct =
307  reinterpret_cast<const smbios_structure_header *>(current);
308  const u8 *data = 0;
309 
310  //If we are called on an uninitialized smbiosBuffer, return 0;
311  if (0 == smbiosBuffer || (currStruct && 0x7f == currStruct->type))
312  goto out1;
313 
314  data = smbiosBuffer;
315 
316  // currStruct == 0, that means we return the first struct
317  if (0 == currStruct)
318  goto out1;
319 
320  // start out at the end of the currStruct structure.
321  // The only things that sits between us and the next struct
322  // are the strings for the currStruct structure.
323  data = reinterpret_cast<const u8 *>(currStruct) + currStruct->length;
324 
325  // skip past strings at the end of the formatted structure,
326  // go until we hit double NULL "\0"
327  // add a check to make sure we don't walk off the buffer end
328  // for broken BIOSen.
329  // The (3) is to take into account the deref at the end "data[0] ||
330  // data[1]", and to take into account the "data += 2" on the next line.
331  while (((data - smbiosBuffer) < (table_header.dmi.table_length - 3)) && (*data || data[1]))
332  data++;
333 
334  // ok, skip past the actual double null.
335  data += 2;
336 
337  // add code specifically to work around crap bios implementations
338  // that do not have the _required_ 0x7f end-of-table entry
339  // note: (4) == sizeof a std header.
340  if ( (data - smbiosBuffer) > (table_header.dmi.table_length - 4))
341  {
342  // really should output some nasty message here... This is very
343  // broken
344  data = 0;
345  goto out1;
346  }
347 
348 out1:
349  return data;
350  }
351 
352 
354  {
356  }
357 
359  {
360  return table_header;
361  }
362 
363  ostream & SmbiosTable::streamify(ostream & cout) const
364  {
365  cout << "\nSMBIOS table " << endl;
366  cout << "\tversion : ";
367  cout << static_cast<int>(table_header.major_ver) << ".";
368  cout << static_cast<int>(table_header.minor_ver) << endl;
369  cout << hex ;
370  cout << "\taddress : " << table_header.dmi.table_address << endl;
371  cout << dec;
372  cout << "\tlength : " << table_header.dmi.table_length << endl;
373  cout << "\tnum structs: " << table_header.dmi.table_num_structs << endl;
374  cout << endl;
375 
376  SmbiosTable::const_iterator position = begin();
377  while (position != end())
378  {
379  cout << *position << endl;
380  ++position;
381  }
382  return cout;
383  }
384 
385  ostream & operator << (ostream & cout, const ISmbiosTable & table)
386  {
387  table.streamify( cout );
388  return cout;
389  }
390 
391 }