Line data Source code
1 : /*
2 : * Copyright (C) 2018 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 2 : import cockpit from "cockpit";
6 :
7 : import * as machine_info from "machine-info.js";
8 2 : const _ = cockpit.gettext;
9 :
10 : // map an info.system key to a /sys/class/dmi/id/* attribute name
11 2 : const InfoDMIKey = {
12 2 : version: "product_version",
13 2 : name: "product_name",
14 2 : alt_version: "board_vendor",
15 2 : alt_name: "board_name",
16 2 : type: "chassis_type_str",
17 2 : bios_vendor: "bios_vendor",
18 2 : bios_version: "bios_version",
19 2 : bios_date: "bios_date",
20 2 : };
21 :
22 2 : const getDMI = info => machine_info.dmi_info()
23 2 : .then(fields => {
24 2 : Object.keys(InfoDMIKey).forEach(key => {
25 2 : info.system[key] = fields[InfoDMIKey[key]];
26 2 : });
27 2 : return true;
28 2 : });
29 :
30 2 : const getDeviceTree = info => machine_info.devicetree_info()
31 2 : .then(fields => {
32 : // if getDMI sets a field first, let that win
33 1 : if (fields.model && !info.system.name)
34 1 : info.system.name = fields.model;
35 2 : return true;
36 2 : });
37 :
38 : // Add info.pci [{slot, cls, vendor, model}] list
39 2 : function findPCI(udevdb, info) {
40 2 : for (const syspath in udevdb) {
41 2 : const props = udevdb[syspath];
42 2 : if (props.SUBSYSTEM === "pci")
43 2 : info.pci.push({
44 1 : slot: props.PCI_SLOT_NAME || syspath.split("/").pop() || "",
45 1 : cls: props.ID_PCI_CLASS_FROM_DATABASE || props.PCI_CLASS.toString() || "",
46 1 : vendor: props.ID_VENDOR_FROM_DATABASE || "",
47 1 : model: props.ID_MODEL_FROM_DATABASE || props.PCI_ID || ""
48 2 : });
49 2 : }
50 2 : }
51 :
52 2 : function findMemoryDevices(udevdb, info) {
53 2 : const memoryArray = [];
54 2 : const dmipath = '/devices/virtual/dmi/id';
55 2 : if (!(dmipath in udevdb))
56 2 : return;
57 :
58 2 : const props = udevdb[dmipath];
59 : // Systemd now exposes memory information in udev, introduced in systemd => 248
60 : // https://github.com/systemd/systemd/blob/main/NEWS#L1713
61 1 : if (!('MEMORY_ARRAY_NUM_DEVICES' in props)) {
62 1 : return;
63 1 : }
64 :
65 2 : const devices = parseInt(props.MEMORY_ARRAY_NUM_DEVICES, 10);
66 2 : for (let slot = 0; slot < devices; slot++) {
67 2 : let memorySize = parseInt(props[`MEMORY_DEVICE_${slot}_SIZE`], 10);
68 2 : if (memorySize) {
69 2 : memorySize = cockpit.format_bytes(memorySize, { base2: true });
70 1 : } else {
71 1 : memorySize = _("Unknown");
72 1 : }
73 :
74 2 : let memoryRank = props[`MEMORY_DEVICE_${slot}_RANK`];
75 1 : if (memoryRank == 1) {
76 1 : memoryRank = _("Single rank");
77 1 : } else if (memoryRank == 2) {
78 1 : memoryRank = _("Dual rank");
79 1 : } else {
80 2 : memoryRank = _("Unknown");
81 2 : }
82 :
83 2 : let speed = props[`MEMORY_DEVICE_${slot}_SPEED_MTS`];
84 1 : if (speed) {
85 1 : speed += ' MT/s';
86 1 : } else {
87 2 : speed = _("Unknown");
88 2 : }
89 :
90 2 : let locator = _("Unknown");
91 2 : if (props[`MEMORY_DEVICE_${slot}_BANK_LOCATOR`] && props[`MEMORY_DEVICE_${slot}_LOCATOR`]) {
92 2 : locator = props[`MEMORY_DEVICE_${slot}_BANK_LOCATOR`] + ': ' + props[`MEMORY_DEVICE_${slot}_LOCATOR`];
93 2 : }
94 :
95 2 : memoryArray.push({
96 2 : locator,
97 2 : technology: props[`MEMORY_DEVICE_${slot}_MEMORY_TECHNOLOGY`] || _("Unknown"),
98 1 : type: props[`MEMORY_DEVICE_${slot}_TYPE`] || _("Unknown"),
99 2 : size: memorySize,
100 1 : state: props[`MEMORY_DEVICE_${slot}_TOTAL_WIDTH`] ? _("Present") : _("Absent"),
101 2 : rank: memoryRank,
102 2 : speed,
103 2 : });
104 2 : }
105 :
106 2 : info.memory = memoryArray;
107 2 : }
108 :
109 2 : export default function detect() {
110 2 : const info = { system: {}, pci: [], memory: [] };
111 2 : const tasks = [];
112 :
113 2 : tasks.push(machine_info.cpu_ram_info()
114 2 : .then(result => {
115 1 : info.system.cpu_model = result.cpu_model || _("unknown");
116 2 : info.system.nproc = result.cpus;
117 2 : return true;
118 2 : }));
119 :
120 2 : tasks.push(getDMI(info)
121 0 : .catch(error => {
122 0 : console.warn("Failed to get DMI information:", error.toString());
123 0 : return true;
124 0 : }));
125 :
126 2 : tasks.push(getDeviceTree(info)
127 0 : .catch(error => {
128 0 : console.debug("Failed to get DeviceTree information:", error.toString());
129 0 : return true;
130 0 : }));
131 :
132 2 : tasks.push(machine_info.udev_info()
133 2 : .then(result => {
134 2 : findPCI(result, info);
135 2 : findMemoryDevices(result, info);
136 2 : return true;
137 2 : })
138 0 : .catch(error => {
139 0 : console.warn("Failed to get udev information:", error.toString());
140 0 : return true;
141 0 : }));
142 :
143 : // Fallback if systemd < 248
144 2 : if (info.memory.length === 0) {
145 2 : tasks.push(machine_info.memory_info()
146 2 : .then(result => {
147 2 : info.memory = result;
148 2 : return true;
149 2 : })
150 0 : .catch(error => {
151 0 : console.warn("Failed to get dmidecode information: ", error.toString());
152 0 : return true;
153 0 : }));
154 2 : }
155 :
156 : // return info after all task promises got done
157 2 : return Promise.all(tasks).then(() => info);
158 2 : }
|