]> git.ipfire.org Git - ipfire-2.x.git/blame - src/install+setup/install/hw.c
installer: Make function to determine the amount of system memory.
[ipfire-2.x.git] / src / install+setup / install / hw.c
CommitLineData
f0fa1795
MT
1/*#############################################################################
2# #
3# IPFire - An Open Source Firewall Distribution #
4# Copyright (C) 2014 IPFire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <assert.h>
d7dd283b
MT
22#include <blkid/blkid.h>
23#include <fcntl.h>
f0fa1795 24#include <libudev.h>
d7dd283b 25#include <math.h>
f0fa1795
MT
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
d7dd283b 29#include <sys/ioctl.h>
f0fa1795
MT
30#include <sys/mount.h>
31#include <unistd.h>
32
d7dd283b
MT
33#include <linux/fs.h>
34
f0fa1795
MT
35#include "hw.h"
36
37struct hw* hw_init() {
38 struct hw* hw = malloc(sizeof(*hw));
39 assert(hw);
40
41 // Initialize libudev
42 hw->udev = udev_new();
43 if (!hw->udev) {
44 fprintf(stderr, "Could not create udev instance\n");
45 exit(1);
46 }
47
48 return hw;
49}
50
51void hw_free(struct hw* hw) {
52 if (hw->udev)
53 udev_unref(hw->udev);
54
55 free(hw);
56}
57
58static int strstartswith(const char* a, const char* b) {
59 return (strncmp(a, b, strlen(b)) == 0);
60}
61
62int hw_mount(const char* source, const char* target, int flags) {
63 return mount(source, target, "iso9660", flags, NULL);
64}
65
66int hw_umount(const char* target) {
67 return umount2(target, MNT_DETACH);
68}
69
70static int hw_test_source_medium(const char* path) {
71 int ret = hw_mount(path, SOURCE_MOUNT_PATH, MS_RDONLY);
72
73 // If the source could not be mounted we
74 // cannot proceed.
75 if (ret)
76 return ret;
77
78 // Check if the test file exists.
79 ret = access(SOURCE_TEST_FILE, F_OK);
80
81 // Umount the test device.
82 hw_umount(SOURCE_MOUNT_PATH);
83
84 return ret;
85}
86
87char* hw_find_source_medium(struct hw* hw) {
88 char* ret = NULL;
89
90 struct udev_enumerate* enumerate = udev_enumerate_new(hw->udev);
91
92 udev_enumerate_add_match_subsystem(enumerate, "block");
93 udev_enumerate_scan_devices(enumerate);
94
95 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
96
97 struct udev_list_entry* dev_list_entry;
98 udev_list_entry_foreach(dev_list_entry, devices) {
99 const char* path = udev_list_entry_get_name(dev_list_entry);
100 struct udev_device* dev = udev_device_new_from_syspath(hw->udev, path);
101
102 const char* dev_path = udev_device_get_devnode(dev);
103
104 // Skip everything what we cannot work with
105 if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") ||
106 strstartswith(dev_path, "/dev/ram"))
107 continue;
108
109 if (hw_test_source_medium(dev_path)) {
110 ret = strdup(dev_path);
111 }
112
113 udev_device_unref(dev);
114
115 // If a suitable device was found the search will end.
116 if (ret)
117 break;
118 }
119
120 udev_enumerate_unref(enumerate);
121
122 return ret;
123}
d7dd283b
MT
124
125static struct hw_disk** hw_create_disks() {
126 struct hw_disk** ret = malloc(sizeof(*ret) * (HW_MAX_DISKS + 1));
127
128 return ret;
129}
130
131static unsigned long long hw_block_device_get_size(const char* dev) {
132 int fd = open(dev, O_RDONLY);
133 if (fd < 0)
134 return 0;
135
136 unsigned long long size = blkid_get_dev_size(fd);
137 close(fd);
138
139 return size;
140}
141
142struct hw_disk** hw_find_disks(struct hw* hw) {
143 struct hw_disk** ret = hw_create_disks();
144 struct hw_disk** disks = ret;
145
146 struct udev_enumerate* enumerate = udev_enumerate_new(hw->udev);
147
148 udev_enumerate_add_match_subsystem(enumerate, "block");
149 udev_enumerate_scan_devices(enumerate);
150
151 struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
152
153 struct udev_list_entry* dev_list_entry;
154 unsigned int i = HW_MAX_DISKS;
155 udev_list_entry_foreach(dev_list_entry, devices) {
156 const char* path = udev_list_entry_get_name(dev_list_entry);
157 struct udev_device* dev = udev_device_new_from_syspath(hw->udev, path);
158
159 const char* dev_path = udev_device_get_devnode(dev);
160
161 // Skip everything what we cannot work with
162 if (strstartswith(dev_path, "/dev/loop") || strstartswith(dev_path, "/dev/fd") ||
163 strstartswith(dev_path, "/dev/ram") || strstartswith(dev_path, "/dev/sr")) {
164 udev_device_unref(dev);
165 continue;
166 }
167
168 // DEVTYPE must be disk (otherwise we will see all sorts of partitions here)
169 const char* devtype = udev_device_get_property_value(dev, "DEVTYPE");
170 if (devtype && (strcmp(devtype, "disk") != 0)) {
171 udev_device_unref(dev);
172 continue;
173 }
174
175 // Skip all source mediums
176 if (hw_test_source_medium(dev_path) == 0) {
177 udev_device_unref(dev);
178 continue;
179 }
180
181 // Skip devices with a size of zero
182 unsigned long long size = hw_block_device_get_size(dev_path);
183 if (size == 0) {
184 udev_device_unref(dev);
185 continue;
186 }
187
188 struct hw_disk* disk = malloc(sizeof(*disk));
189 if (disk == NULL)
190 return NULL;
191
192 disk->ref = 1;
193
194 strncpy(disk->path, dev_path, sizeof(disk->path));
195
196 disk->size = size;
197
198 // Vendor
199 const char* vendor = udev_device_get_property_value(dev, "ID_VENDOR");
200 if (!vendor)
201 vendor = udev_device_get_sysattr_value(dev, "vendor");
202 if (!vendor)
203 vendor = udev_device_get_sysattr_value(dev, "manufacturer");
204 if (!vendor)
205 vendor = "N/A";
206
207 strncpy(disk->vendor, vendor, sizeof(disk->vendor));
208
209 // Model
210 const char* model = udev_device_get_property_value(dev, "ID_MODEL");
211 if (!model)
212 model = udev_device_get_sysattr_value(dev, "model");
213 if (!model)
214 model = udev_device_get_sysattr_value(dev, "product");
215 if (!model)
216 model = "N/A";
217
218 strncpy(disk->model, model, sizeof(disk->model));
219
220 snprintf(disk->description, sizeof(disk->description),
221 "%4.1fGB %s - %s", (double)disk->size / pow(1024, 3),
222 disk->vendor, disk->model);
223
224 *disks++ = disk;
225
226 if (--i == 0)
227 break;
228
229 udev_device_unref(dev);
230 }
231
232 udev_enumerate_unref(enumerate);
233
234 *disks = NULL;
235
236 return ret;
237}
238
239void hw_free_disks(struct hw_disk** disks) {
240 struct hw_disk** disk = disks;
241
242 while (*disk != NULL) {
243 if (--(*disk)->ref == 0)
244 free(*disk);
245
246 disk++;
247 }
248
249 free(disks);
250}
251
252unsigned int hw_count_disks(struct hw_disk** disks) {
253 unsigned int ret = 0;
254
255 while (*disks++)
256 ret++;
257
258 return ret;
259}
260
261struct hw_disk** hw_select_disks(struct hw_disk** disks, int* selection) {
262 struct hw_disk** ret = hw_create_disks();
263 struct hw_disk** selected_disks = ret;
264
265 unsigned int num_disks = hw_count_disks(disks);
266
267 for (unsigned int i = 0; i < num_disks; i++) {
268 if (selection && selection[i]) {
269 struct hw_disk *selected_disk = disks[i];
270 selected_disk->ref++;
271
272 *selected_disks++ = selected_disk;
273 }
274 }
275
276 // Set sentinel
277 *selected_disks = NULL;
278
279 return ret;
280}
281
282struct hw_destination* hw_make_destination(int part_type, struct hw_disk** disks) {
283 struct hw_destination* dest = malloc(sizeof(*dest));
284
285 if (part_type == HW_PART_TYPE_NORMAL) {
286 dest->disk1 = *disks;
287 dest->disk2 = NULL;
288
289 strncpy(dest->path, dest->disk1->path, sizeof(dest->path));
290
291 } else if (part_type == HW_PART_TYPE_RAID1) {
292 dest->disk1 = *disks++;
293 dest->disk2 = *disks;
294
295 snprintf(dest->path, sizeof(dest->path), "/dev/md0");
296 }
297
298 // Is this a RAID device?
299 dest->is_raid = (part_type > HW_PART_TYPE_NORMAL);
300
301 // Set partition names
302 char path[DEV_SIZE];
303 snprintf(path, sizeof(path), "%s%s", dest->path, (dest->is_raid) ? "p" : "");
304 snprintf(dest->part_boot, sizeof(dest->part_boot), "%s1", path);
305 snprintf(dest->part_swap, sizeof(dest->part_swap), "%s2", path);
306 snprintf(dest->part_root, sizeof(dest->part_root), "%s3", path);
307 snprintf(dest->part_data, sizeof(dest->part_data), "%s4", path);
308
309 if (dest->is_raid) {
310 dest->size = (dest->disk1->size >= dest->disk2->size) ?
311 dest->disk1->size : dest->disk2->size;
312 } else {
313 dest->size = dest->disk1->size;
314 }
315
316 return dest;
317}
c4e96674
MT
318
319unsigned long long hw_memory() {
320 FILE* handle = NULL;
321 char line[STRING_SIZE];
322
323 unsigned long long memory = 0;
324
325 /* Calculate amount of memory in machine */
326 if ((handle = fopen("/proc/meminfo", "r"))) {
327 while (fgets(line, sizeof(line), handle)) {
328 if (!sscanf (line, "MemTotal: %llu kB", memory)) {
329 memory = 0;
330 }
331 }
332
333 fclose(handle);
334 }
335
336 return memory * 1024;
337}