@@ -182,158 +182,158 @@ def mem_info(self):
182182 response = input (
183183 "You can feel free to respond with 'N' if you don't wish to proceed with this! Or 'Y' if you do: "
184184 )
185+
186+ if "n" in response .lower ():
187+ print ("Cancelled, bailing memory detection..." )
188+ return
185189
186- if "y" in response .lower ():
187-
188- # DMI table dump of memory slot entries.
189- #
190- # Type 17 indicates a memory slot device.
191- parent_dir = [
192- p
193- for p in os .scandir ("/sys/firmware/dmi/entries" )
194- if "17-" in p .path .split ("/" )[- 1 ]
195- ]
190+ # DMI table dump of memory slot entries.
191+ #
192+ # Type 17 indicates a memory slot device.
193+ parent_dir = [
194+ p
195+ for p in os .scandir ("/sys/firmware/dmi/entries" )
196+ if "17-" in p .path .split ("/" )[- 1 ]
197+ ]
198+
199+ for child_dir in parent_dir :
200+
201+ # The contents of the binary file.
202+ value = subprocess .check_output (
203+ [
204+ "sudo" ,
205+ "cat" ,
206+ f"{ child_dir .path } /raw" ,
207+ ]
208+ )
209+ data = {}
210+ part_no = ""
196211
197- for child_dir in parent_dir :
212+ if "dimm" in value .upper ().decode ("latin-1" ).strip ().lower ():
213+ length_field = value [0x1 ]
214+ strings = value [length_field : len (value )].split (b"\0 " )
198215
199- # The contents of the binary file.
200- value = subprocess .check_output (
201- [
202- "sudo" ,
203- "cat" ,
204- f"{ child_dir .path } /raw" ,
205- ]
206- )
207- data = {}
208- part_no = ""
216+ try :
217+ """
218+ ---------------------
219+ | Part Number |
220+ ---------------------
221+
222+ Obtains the value at offset 1Ah, which indicates at which index, pre-sanitisation,
223+ in the `strings` list the real string value is stored.
224+
225+ Which is: `strings[value[0x1A] - 1]`, after obtaining it, it decodes it to `ascii`.
226+
227+ Special thanks to [Quist](https://github.com/nadiaholmquist) for this.
228+ """
229+ part_no = get_string_entry (strings , value [0x1A ]).strip () + " (Part Number)"
230+ data [part_no ] = {}
231+ except Exception as e :
232+ self .logger .warning (
233+ f"Unable to determine part number for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
234+ __file__ ,
235+ )
236+ continue
237+
238+ try :
239+ # The type value is stored at offset 12h
240+ type = MEMORY_TYPE [value [0x12 ]]
241+
242+ data [part_no ]["Type" ] = type
243+ except Exception as e :
244+ self .logger .warning (
245+ f"Unable to determine type of memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^{ str (e )} " ,
246+ __file__ ,
247+ )
248+ data [part_no ]["Type" ] = "UNKNOWN"
209249
210- if "dimm" in value .upper ().decode ("latin-1" ).strip ().lower ():
211- length_field = value [0x1 ]
212- strings = value [length_field : len (value )].split (b"\0 " )
250+ try :
251+ # Explanation same as for Part Number.
252+ channel = get_string_entry (strings , value [0x10 ])
253+ bank = get_string_entry (strings , value [0x11 ])
213254
214- try :
215- """
216- ---------------------
217- | Part Number |
218- ---------------------
219-
220- Obtains the value at offset 1Ah, which indicates at which index, pre-sanitisation,
221- in the `strings` list the real string value is stored.
222-
223- Which is: `strings[value[0x1A] - 1]`, after obtaining it, it decodes it to `ascii`.
224-
225- Special thanks to [Quist](https://github.com/nadiaholmquist) for this.
226- """
227- part_no = get_string_entry (strings , value [0x1A ]).strip () + " (Part Number)"
228- data [part_no ] = {}
229- except Exception as e :
230- self .logger .warning (
231- f"Unable to determine part number for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
232- __file__ ,
233- )
234- continue
235-
236- try :
237- # The type value is stored at offset 12h
238- type = MEMORY_TYPE [value [0x12 ]]
239-
240- data [part_no ]["Type" ] = type
241- except Exception as e :
242- self .logger .warning (
243- f"Unable to determine type of memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^{ str (e )} " ,
244- __file__ ,
245- )
246- data [part_no ]["Type" ] = "UNKNOWN"
247-
248- try :
249- # Explanation same as for Part Number.
250- channel = get_string_entry (strings , value [0x10 ])
251- bank = get_string_entry (strings , value [0x11 ])
252-
253- data [part_no ]["Slot" ] = {"Channel" : channel , "Bank" : bank }
254- except Exception as e :
255- self .logger .warning (
256- f"Unable to determine slot location for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
257- __file__ ,
258- )
259- continue
255+ data [part_no ]["Slot" ] = {"Channel" : channel , "Bank" : bank }
256+ except Exception as e :
257+ self .logger .warning (
258+ f"Unable to determine slot location for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
259+ __file__ ,
260+ )
261+ continue
260262
261- try :
262- # Explanation same as for Part Number.
263- manufacturer = get_string_entry (strings , value [0x17 ])
263+ try :
264+ # Explanation same as for Part Number.
265+ manufacturer = get_string_entry (strings , value [0x17 ])
264266
265- data [part_no ]["Manufacturer" ] = manufacturer
266- except Exception as e :
267- self .logger .warning (
268- f"Unable to determine manufacturer for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^^^^{ str (e )} " ,
269- __file__ ,
270- )
271- continue
267+ data [part_no ]["Manufacturer" ] = manufacturer
268+ except Exception as e :
269+ self .logger .warning (
270+ f"Unable to determine manufacturer for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^^^^{ str (e )} " ,
271+ __file__ ,
272+ )
273+ continue
272274
273- try :
274- """
275- ---------------------
276- | CAPACITY |
277- ---------------------
275+ try :
276+ """
277+ ---------------------
278+ | CAPACITY |
279+ ---------------------
278280
279- Looks at the 2 bytes at offset 0Ch to hopefully determine its size;
280- in case the of these 2 bytes is equal to 0x7FFF, it looks at the 4 bytes
281- at offset 1Ch.
281+ Looks at the 2 bytes at offset 0Ch to hopefully determine its size;
282+ in case the of these 2 bytes is equal to 0x7FFF, it looks at the 4 bytes
283+ at offset 1Ch.
282284
283- In the case that the value at offset 0Ch is equal to 0xFFFF,
284- it would mean that the size is unknown.
285- """
285+ In the case that the value at offset 0Ch is equal to 0xFFFF,
286+ it would mean that the size is unknown.
287+ """
286288
287- """
288- 2 bytes, at offset 0Ch
289-
290- We convert it into an integer from the bytes values, specifying
291- that it is in LE (little endian) format.
292-
293- Meaning, it will properly accommodate the values to represent its BE (big endian)
294- value in the end.
295-
296- For example,
297- ( Little ) ( Big )
298- '\x00 \x10 ' -> '\x10 \x00 '
299-
300- Finally, '\x10 \x00 ' will yield `4096` in decimal (0x1000 in hexadecimal);
301- which is correct. This was done on a system with 4x4GB memory modules.
289+ """
290+ 2 bytes, at offset 0Ch
291+
292+ We convert it into an integer from the bytes values, specifying
293+ that it is in LE (little endian) format.
294+
295+ Meaning, it will properly accommodate the values to represent its BE (big endian)
296+ value in the end.
297+
298+ For example,
299+ ( Little ) ( Big )
300+ '\x00 \x10 ' -> '\x10 \x00 '
302301
303- Aka, 4x4096MB modules, in this case--since the 15th bit value is `0`,
304- meaning it's represented in MB, and not KB.
305- """
306- size = int .from_bytes (value [0x0C :0x0E ], "little" )
307-
308- if size == 0xFFFF :
309- data ["Capacity" ] = "UNKNOWN SIZE"
310-
311- # In cases where the individual memory module's
312- # capacity is `n >= (32GB-1MB)`, the value at 0Ch
313- # will be `0x7FFF`; meaning we should look at 1Ch instead.
314- elif size == 0x7FFF :
315- # 4 bytes, at offset 1Ch
316- size = int (
317- "" .join (reversed (value .hex ()[0x1C : 0x1C + 0x4 ])), 16
318- )
319-
320- # Whether or not the value is represented in KB or MB
321- #
322- # 0 - MB
323- # 1 - KB
324- rep = "MB" if (size >> 15 ) & 1 == 0 else "KB"
325-
326- data [part_no ]["Capacity" ] = f"{ size } { rep } "
327- except Exception as e :
328- self .logger .warning (
329- f"Unable to determine size for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
330- __file__ ,
302+ Finally, '\x10 \x00 ' will yield `4096` in decimal (0x1000 in hexadecimal);
303+ which is correct. This was done on a system with 4x4GB memory modules.
304+
305+ Aka, 4x4096MB modules, in this case--since the 15th bit value is `0`,
306+ meaning it's represented in MB, and not KB.
307+ """
308+ size = int .from_bytes (value [0x0C :0x0E ], "little" )
309+
310+ if size == 0xFFFF :
311+ data ["Capacity" ] = "UNKNOWN SIZE"
312+
313+ # In cases where the individual memory module's
314+ # capacity is `n >= (32GB-1MB)`, the value at 0Ch
315+ # will be `0x7FFF`; meaning we should look at 1Ch instead.
316+ elif size == 0x7FFF :
317+ # 4 bytes, at offset 1Ch
318+ size = int (
319+ "" .join (reversed (value .hex ()[0x1C : 0x1C + 0x4 ])), 16
331320 )
332- continue
333321
334- self .info ["Memory" ].append (data )
335- else :
336- print ("Cancelled, bailing memory detection..." )
322+ # Whether or not the value is represented in KB or MB
323+ #
324+ # 0 - MB
325+ # 1 - KB
326+ rep = "MB" if (size >> 15 ) & 1 == 0 else "KB"
327+
328+ data [part_no ]["Capacity" ] = f"{ size } { rep } "
329+ except Exception as e :
330+ self .logger .warning (
331+ f"Unable to determine size for memory (RAM) module (SYS_FS/DMI)\n \t ^^^^^^^^^{ str (e )} " ,
332+ __file__ ,
333+ )
334+ continue
335+
336+ self .info ["Memory" ].append (data )
337337
338338 def net_info (self ):
339339 for file in os .listdir ("/sys/class/net" ):
0 commit comments