OSDN Git Service

cleanup
[openpts/openpts.git] / src / smbios.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/smbios.c
26  * \brief parse SMBIOS info
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-08-29
29  * cleanup 2012-01-05 SM
30  *
31  * SMBIOS Info in BIOS IML -> platform properties
32  *
33  * TODO not work yet:-(
34  *      SMBIOS info in the IML has been masked.
35  *      It masks sensitive information in the SMBIOS data blob.
36  *      However this makes hard to parse the ASN.1 structure.
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <netdb.h>
43 #include <errno.h>
44
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49 #include <fcntl.h>
50
51 #include <unistd.h>
52 #include <sys/wait.h>
53 #include <dirent.h>
54
55 #include <openpts.h>
56
57 #define SMBIOS_MAX_SIZE   4096
58 #define SMBIOS_MAX_HANDLE 0x50
59 #define DMIDECODE_PATH    "/usr/sbin/dmidecode"
60 #define DMIDECODE         "dmidecode"
61
62 /**
63  * dmidecode --dump-bin dmidecode.bin
64  */
65 int genSmbiosFileByDmidecode(char * filename) {
66     pid_t pid;
67     int status;
68     int uid;
69
70     /* must be a root user */
71     uid = getuid();
72     if (uid != 0) {
73         DEBUG("must be a root user to run dmidecode\n");
74         return PTS_FATAL;
75     }
76
77     /* exec dmidecode */
78     pid = fork();
79     if (pid < 0) {
80         LOG(LOG_ERR, "fork() fail");
81         return  PTS_FATAL;
82     }
83     if (pid == 0) {
84         /* child */
85         execl(DMIDECODE_PATH, DMIDECODE, "--dump-bin", filename,  NULL);
86
87         /* execl failed */
88         exit(-1);
89     } else {
90         /* parent */
91         waitpid(pid, &status, 0);
92         // DEBUG("status = %d\n", status);
93         if (WIFEXITED(status)) {
94             /* 1 : OK */
95             LOG(LOG_TODO, "Exit status %d\n", WEXITSTATUS(status));
96             return PTS_SUCCESS;  // 1
97         } else if (WIFSIGNALED(status)) {
98             LOG(LOG_ERR, "Signal status %d\n", WIFSIGNALED(status));
99             return PTS_FATAL;
100         } else {
101             LOG(LOG_ERR, "Bad exit");
102             return  PTS_FATAL;
103         }
104     }
105
106     return PTS_SUCCESS;
107 }
108
109
110 /**
111  * read SMBIOS File
112  * 
113  *  dmidecode --dump-bin dmidecode.bin
114  *
115  * SMBIOS data -> malloc -> data
116  * 
117  */
118 int readSmbiosFile(char * filename, BYTE **data, int *len) {
119     FILE *fp;
120     int size;
121     BYTE *buf;
122     int rc = PTS_SUCCESS;
123
124     /* check */
125     if (filename == NULL) {
126         LOG(LOG_ERR, "null input");
127         return PTS_FATAL;
128     }
129
130     // TODO(munetoh) check the file size
131     buf = xmalloc(SMBIOS_MAX_SIZE);
132     if (buf == NULL) {
133         LOG(LOG_ERR, "no memory");
134         return PTS_FATAL;
135     }
136
137     if ((fp = fopen(filename, "rb")) == NULL) {
138         LOG(LOG_ERR, "%s missing\n", filename);
139         rc = PTS_INTERNAL_ERROR;
140         goto error;
141     }
142
143     size = fread(buf, 1, SMBIOS_MAX_SIZE, fp);
144
145     fclose(fp);
146
147     *len = size;
148     *data = buf;
149     return rc;
150
151   error:
152     xfree(buf);
153     return rc;
154 }
155
156 /**
157  * print SMBIOS info
158  *
159  * http://en.wikipedia.org/wiki/System_Management_BIOS
160  * http://dmtf.org/standards/smbios
161  *
162  * Lenovo - sensitive data of SMBIOS in IML is masked 
163  */
164 int printSmbios(BYTE *data, int length) {
165     BYTE type;
166     BYTE len;
167     int handle;
168     int handle_old = -1;
169     BYTE *ptr = data;
170     BYTE *strings;
171     BYTE *eod = data + length;
172     int str_length;
173     int str_num;
174     int cnt = 0;
175
176     if ((ptr[0] == 0x5f) && (ptr[1] == 0x53) && (ptr[2] == 0x4d) && (ptr[3] == 0x5f)) {
177         /* */
178         str_length = ptr[0x16] + (ptr[0x17]<<8);
179         str_num = ptr[0x1C] + (ptr[0x1D]<<8);
180         eod = ptr + str_length + 32;
181         // SKIP Head
182         ptr += 32;
183     }
184
185     while (1) {
186         type = ptr[0];
187         len = ptr[1];
188         handle = ptr[2] + ptr[3]*256;
189
190         if (type == 127) {
191             // End Of Table
192             break;
193         }
194
195         ptr += len;
196         strings = ptr;
197
198         if (handle != handle_old +1) {
199             break;
200         }
201
202         if (ptr >  eod) {
203             // End Of Table
204             break;
205         }
206
207         /* skip zero*/
208         while (!((*ptr == 0) && (*(ptr+1) == 0) && (*(ptr + 2) != 0))) {
209             ptr++;
210             if (ptr > eod) {
211                 break;
212             }
213         }
214         ptr++;
215         ptr++;
216
217         if (ptr > eod) {
218             break;
219         }
220
221         cnt++;
222         if (cnt > SMBIOS_MAX_HANDLE) {
223             break;
224         }
225
226         handle_old = handle;
227     }
228
229     return 0;
230 }
231
232
233
234 #define SMBIOS_MAX_HANDLE 0x50
235 /**
236  * SMBIOS -> properties 
237  *
238  * IR:core:ComponentID  < Core Integrity Schema 3.1.2
239  * ---------------------------------------
240  * Id
241  * SimpleName           BIOS
242  * ModelName          
243  * ModelNumber          
244  * ModelSerialNumber
245  * ModelSystemClass
246  * VersionMajor         bios.version.major=3
247  * VersionMinor         bios.version.minor=8
248  * VersionBuild         bios.date=08/20/2009
249  * VersionString        bios.version=6DET58WW (3.08 )
250  * MfgData
251  * PatchLevel
252  * DiscreatePatches
253  * ----------------------------------------
254  * IR:core:VendorID
255  * ---------------------------------------
256  * Name                 bios.vendor.name=LENOVO
257  *
258  * IR:core:SmiVendorID  bios.vendor.smi=19046 << IANA.ORG
259  * ---------------------------------------
260  *
261  * # => PTS_ComponentId
262  *
263  */
264 int parseSmbios(OPENPTS_CONTEXT *ctx, BYTE *data, int length) {
265     BYTE type;
266     BYTE len;
267     int handle;
268     int handle_old = -1;
269     BYTE *ptr = data;
270     BYTE *strings[10];  // TODO size
271     BYTE *eod = data + length;
272     int str_length;
273     int cnt = 0;
274     int scnt;
275     OPENPTS_CONFIG *conf = ctx->conf;
276
277     /* skip header */
278     if ((ptr[0] == 0x5f) && (ptr[1] == 0x53) && (ptr[2] == 0x4d) && (ptr[3] == 0x5f)) {
279         /* */
280         str_length = ptr[0x16] + (ptr[0x17]<<8);
281         // str_num = ptr[0x1C] + (ptr[0x1D]<<8);
282         eod = ptr + str_length + 32;
283         // SKIP Head
284         ptr += 32;
285     }
286
287     /* initialize */
288     strings[0] = NULL;
289     strings[1] = NULL;
290
291     /* walk on structures */
292     while (1) {
293         type = ptr[0];
294         len = ptr[1];
295         handle = ptr[2] + ptr[3]*256;
296
297         if (type == 127) {
298             // End Of Table
299             break;
300         }
301
302         ptr += len;
303         strings[0] = ptr;
304         scnt = 0;
305
306         if (handle != handle_old +1) {
307             break;
308         }
309
310         if (ptr >  eod) {
311             break;
312         }
313
314         /* skip zero*/
315         while (!((*ptr == 0) && (*(ptr+1) == 0) && (*(ptr + 2) != 0))) {
316             ptr++;
317             if (ptr > eod) {
318                 break;
319             }
320             if ((*ptr != 0) && (*(ptr+1) == 0)) {
321                 scnt++;  // TODO check max
322                 strings[scnt] = ptr + 2;
323             }
324         }
325         ptr++;
326         ptr++;
327
328         /* to config  */
329         switch (type) {
330             case 0x0: /* BIOS Information */
331                 conf->bios_vendor = smalloc_assert((char*)strings[0]);
332                 conf->bios_version = smalloc_assert((char*)strings[1]);
333                 break;
334             default:
335                 break;
336         }
337
338
339         if (ptr > eod) {
340             break;
341         }
342
343         cnt++;
344         if (cnt > SMBIOS_MAX_HANDLE) {
345             break;
346         }
347
348         handle_old = handle;
349     }
350
351     return 0;
352 }