OSDN Git Service

Make a platform ACPI root parser separate from PCI roots.
[android-x86/external-efivar.git] / src / linux.c
1 /*
2  * libefiboot - library for the manipulation of EFI boot variables
3  * Copyright 2012-2015 Red Hat, Inc.
4  * Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of the
9  * License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #include "fix_coverity.h"
23
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <inttypes.h>
28 #include <limits.h>
29 #include <linux/ethtool.h>
30 #include <linux/version.h>
31 #include <linux/sockios.h>
32 #include <net/if.h>
33 #include <scsi/scsi.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/sysmacros.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43
44 #include "efiboot.h"
45
46 int HIDDEN
47 find_parent_devpath(const char * const child, char **parent)
48 {
49         int ret;
50         char *node;
51         char *linkbuf;
52
53         /* strip leading /dev/ */
54         node = strrchr(child, '/');
55         if (!node)
56                 return -1;
57         node++;
58
59         /* look up full path symlink */
60         ret = sysfs_readlink(&linkbuf, "class/block/%s", node);
61         if (ret < 0 || !linkbuf)
62                 return ret;
63
64         /* strip child */
65         node = strrchr(linkbuf, '/');
66         if (!node)
67                 return -1;
68         *node = '\0';
69
70         /* read parent */
71         node = strrchr(linkbuf, '/');
72         if (!node)
73                 return -1;
74         *node = '\0';
75         node++;
76
77         /* write out new path */
78         ret = asprintf(parent, "/dev/%s", node);
79         if (ret < 0)
80                 return ret;
81
82         return 0;
83 }
84
85 int HIDDEN
86 set_part_name(struct device *dev, const char * const fmt, ...)
87 {
88         ssize_t rc;
89         va_list ap;
90         int error;
91
92         if (dev->part <= 0)
93                 return 0;
94
95         va_start(ap, fmt);
96         rc = vasprintf(&dev->part_name, fmt, ap);
97         error = errno;
98         va_end(ap);
99         errno = error;
100         if (rc < 0)
101                 efi_error("could not allocate memory");
102
103         return rc;
104 }
105
106 int HIDDEN
107 reset_part_name(struct device *dev)
108 {
109         char *part = NULL;
110         int rc;
111
112         if (dev->part_name) {
113                 free(dev->part_name);
114                 dev->part_name = NULL;
115         }
116
117         if (dev->part < 1)
118                 return 0;
119
120         if (dev->probes[dev->n_probes]->make_part_name) {
121                 part = dev->probes[dev->n_probes]->make_part_name(dev);
122                 dev->part_name = part;
123                 rc = 0;
124         } else {
125                 rc = asprintf(&dev->part_name, "%s%d",
126                               dev->disk_name, dev->part);
127                 if (rc < 0)
128                         efi_error("could not allocate memory");
129         }
130         return rc;
131 }
132
133 int HIDDEN
134 set_part(struct device *dev, int value)
135 {
136         int rc;
137
138         if (dev->part == value)
139                 return 0;
140
141         dev->part = value;
142         rc = reset_part_name(dev);
143         if (rc < 0)
144                 efi_error("reset_part_name() failed");
145
146         return rc;
147 }
148
149 int HIDDEN
150 set_disk_name(struct device *dev, const char * const fmt, ...)
151 {
152         ssize_t rc;
153         va_list ap;
154         int error;
155
156         va_start(ap, fmt);
157         rc = vasprintf(&dev->disk_name, fmt, ap);
158         error = errno;
159         va_end(ap);
160         errno = error;
161         if (rc < 0)
162                 efi_error("could not allocate memory");
163
164         return rc;
165 }
166
167 int HIDDEN
168 set_disk_and_part_name(struct device *dev)
169 {
170         /*
171          * results are like such:
172          * maj:min -> ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
173          */
174
175         char *ultimate = pathseg(dev->link, -1);
176         char *penultimate = pathseg(dev->link, -2);
177         char *approximate = pathseg(dev->link, -3);
178         char *proximate = pathseg(dev->link, -4);
179
180         errno = 0;
181         debug(DEBUG, "dev->disk_name:%p dev->part_name:%p", dev->disk_name, dev->part_name);
182         debug(DEBUG, "dev->part:%d", dev->part);
183         debug(DEBUG, "ultimate:\"%s\"", ultimate ? : "");
184         debug(DEBUG, "penultimate:\"%s\"", penultimate ? : "");
185         debug(DEBUG, "approximate:\"%s\"", approximate ? : "");
186         debug(DEBUG, "proximate:\"%s\"", proximate ? : "");
187
188         if (ultimate && penultimate &&
189             ((proximate && !strcmp(proximate, "nvme")) ||
190              (approximate && !strcmp(approximate, "block")))) {
191                 /*
192                  * 259:1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1/nvme0n1p1
193                  * 8:1 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda/sda1
194                  * 8:33 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
195                  * 252:1 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda/vda1
196                  * 259:3 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s/pmem11s1
197                  */
198                 set_disk_name(dev, "%s", penultimate);
199                 set_part_name(dev, "%s", ultimate);
200                 debug(DEBUG, "disk:%s part:%s", penultimate, ultimate);
201         } else if (ultimate && approximate && !strcmp(approximate, "nvme")) {
202                 /*
203                  * 259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
204                  */
205                 set_disk_name(dev, "%s", ultimate);
206                 set_part_name(dev, "%sp%d", ultimate, dev->part);
207                 debug(DEBUG, "disk:%s part:%sp%d", ultimate, ultimate, dev->part);
208         } else if (ultimate && penultimate && !strcmp(penultimate, "block")) {
209                 /*
210                  * 253:0 -> ../../devices/virtual/block/dm-0 (... I guess)
211                  * 8:0 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda
212                  * 11:0 -> ../../devices/pci0000:00/0000:00:11.5/ata3/host2/target2:0:0/2:0:0:0/block/sr0
213                  * 8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc
214                  * 252:0 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda
215                  * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region9/btt9.0/block/pmem9s
216                  * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s
217                  */
218                 set_disk_name(dev, "%s", ultimate);
219                 set_part_name(dev, "%s%d", ultimate, dev->part);
220                 debug(DEBUG, "disk:%s part:%s%d", ultimate, ultimate, dev->part);
221         } else if (ultimate && approximate && !strcmp(approximate, "mtd")) {
222                 /*
223                  * 31:0 -> ../../devices/platform/1e000000.palmbus/1e000b00.spi/spi_master/spi32766/spi32766.0/mtd/mtd0/mtdblock0
224                  */
225                 set_disk_name(dev, "%s", ultimate);
226                 debug(DEBUG, "disk:%s", ultimate);
227         }
228
229         return 0;
230 }
231
232 static struct dev_probe *dev_probes[] = {
233         /*
234          * pmem needs to be before PCI, so if it provides root it'll
235          * be found first.
236          */
237         &pmem_parser,
238         &acpi_root_parser,
239         &pci_root_parser,
240         &pci_parser,
241         &virtblk_parser,
242         &sas_parser,
243         &sata_parser,
244         &nvme_parser,
245         &ata_parser,
246         &scsi_parser,
247         &i2o_parser,
248         NULL
249 };
250
251 static inline bool
252 supports_iface(struct dev_probe *probe, enum interface_type iftype)
253 {
254         for (unsigned int i = 0; probe->iftypes[i] != unknown; i++)
255                 if (probe->iftypes[i] == iftype)
256                         return true;
257         return false;
258 }
259
260 void HIDDEN
261 device_free(struct device *dev)
262 {
263         if (!dev)
264                 return;
265         if (dev->link)
266                 free(dev->link);
267
268         if (dev->device)
269                 free(dev->device);
270
271         if (dev->driver)
272                 free(dev->driver);
273
274         if (dev->probes)
275                 free(dev->probes);
276
277         if (dev->acpi_root.acpi_hid_str)
278                 free(dev->acpi_root.acpi_hid_str);
279         if (dev->acpi_root.acpi_uid_str)
280                 free(dev->acpi_root.acpi_uid_str);
281         if (dev->acpi_root.acpi_cid_str)
282                 free(dev->acpi_root.acpi_cid_str);
283
284         if (dev->interface_type == network) {
285                 if (dev->ifname)
286                         free(dev->ifname);
287         } else {
288                 if (dev->disk_name)
289                         free(dev->disk_name);
290                 if (dev->part_name)
291                         free(dev->part_name);
292         }
293
294         for (unsigned int i = 0; i < dev->n_pci_devs; i++)
295                 if (dev->pci_dev[i].driverlink)
296                         free(dev->pci_dev[i].driverlink);
297
298         if (dev->pci_dev)
299                 free(dev->pci_dev);
300
301         memset(dev, 0, sizeof(*dev));
302         free(dev);
303 }
304
305 struct device HIDDEN
306 *device_get(int fd, int partition)
307 {
308         struct device *dev;
309         char *linkbuf = NULL, *tmpbuf = NULL;
310         unsigned int i, n = 0;
311         int rc;
312
313         size_t nmemb = (sizeof(dev_probes)
314                         / sizeof(dev_probes[0])) + 1;
315
316         dev = calloc(1, sizeof(*dev));
317         if (!dev) {
318                 efi_error("could not allocate %zd bytes", sizeof(*dev));
319                 return NULL;
320         }
321
322         dev->part = partition;
323         debug(DEBUG, "partition:%d dev->part:%d", partition, dev->part);
324         dev->probes = calloc(nmemb, sizeof(struct dev_probe *));
325         if (!dev->probes) {
326                 efi_error("could not allocate %zd bytes",
327                           nmemb * sizeof(struct dev_probe *));
328                 goto err;
329         }
330
331         rc = fstat(fd, &dev->stat);
332         if (rc < 0) {
333                 efi_error("fstat(%d) failed", fd);
334                 goto err;
335         }
336
337         dev->pci_root.pci_domain = 0xffff;
338         dev->pci_root.pci_bus = 0xff;
339
340         if (S_ISBLK(dev->stat.st_mode)) {
341                 dev->major = major(dev->stat.st_rdev);
342                 dev->minor = minor(dev->stat.st_rdev);
343         } else if (S_ISREG(dev->stat.st_mode)) {
344                 dev->major = major(dev->stat.st_dev);
345                 dev->minor = minor(dev->stat.st_dev);
346         } else {
347                 efi_error("device is not a block device or regular file");
348                 goto err;
349         }
350
351         rc = sysfs_readlink(&linkbuf, "dev/block/%"PRIu64":%"PRIu32,
352                             dev->major, dev->minor);
353         if (rc < 0 || !linkbuf) {
354                 efi_error("readlink of /sys/dev/block/%"PRIu64":%"PRIu32" failed",
355                           dev->major, dev->minor);
356                 goto err;
357         }
358
359         dev->link = strdup(linkbuf);
360         if (!dev->link) {
361                 efi_error("strdup(\"%s\") failed", linkbuf);
362                 goto err;
363         }
364         debug(DEBUG, "dev->link: %s", dev->link);
365
366         if (dev->part == -1) {
367                 rc = read_sysfs_file(&tmpbuf, "dev/block/%s/partition", dev->link);
368                 if (rc < 0 || !tmpbuf) {
369                         efi_error("device has no /partition node; not a partition");
370                 } else {
371                         rc = sscanf((char *)tmpbuf, "%d\n", &dev->part);
372                         if (rc != 1)
373                                 efi_error("couldn't parse partition number for %s", tmpbuf);
374                 }
375         }
376
377         rc = set_disk_and_part_name(dev);
378         if (rc < 0) {
379                 efi_error("could not set disk and partition names");
380                 goto err;
381         }
382         debug(DEBUG, "dev->disk_name: %s", dev->disk_name);
383         debug(DEBUG, "dev->part_name: %s", dev->part_name);
384
385         rc = sysfs_readlink(&tmpbuf, "block/%s/device", dev->disk_name);
386         if (rc < 0 || !tmpbuf) {
387                 efi_error("readlink of /sys/block/%s/device failed",
388                           dev->disk_name);
389                 goto err;
390         }
391
392         dev->device = strdup(tmpbuf);
393         if (!dev->device) {
394                 efi_error("strdup(\"%s\") failed", tmpbuf);
395                 goto err;
396         }
397
398         rc = sysfs_readlink(&tmpbuf, "block/%s/device/driver", dev->disk_name);
399         if (rc < 0 || !tmpbuf) {
400                 if (errno == ENOENT) {
401                         /*
402                          * nvme, for example, will have nvme0n1/device point
403                          * at nvme0, and we need to look for device/driver
404                          * there.
405                          */
406                         rc = sysfs_readlink(&tmpbuf,
407                                             "block/%s/device/device/driver",
408                                             dev->disk_name);
409                 }
410                 if (rc < 0 || !tmpbuf) {
411                         efi_error("readlink of /sys/block/%s/device/driver failed",
412                                   dev->disk_name);
413                         goto err;
414                 }
415         }
416
417         linkbuf = pathseg(tmpbuf, -1);
418         if (!linkbuf) {
419                 efi_error("could not get segment -1 of \"%s\"", tmpbuf);
420                 goto err;
421         }
422
423         dev->driver = strdup(linkbuf);
424         if (!dev->driver) {
425                 efi_error("strdup(\"%s\") failed", linkbuf);
426                 goto err;
427         }
428
429         const char *current = dev->link;
430         bool needs_root = true;
431
432         debug(DEBUG, "searching for device nodes in %s", dev->link);
433         for (i = 0; dev_probes[i] && dev_probes[i]->parse; i++) {
434                 struct dev_probe *probe = dev_probes[i];
435                 ssize_t pos;
436
437                 if (!needs_root && (probe->flags & DEV_PROVIDES_ROOT)) {
438                         debug(DEBUG, "not testing %s because flags is 0x%x", probe->name, probe->flags);
439                         continue;
440                 }
441
442                 debug(DEBUG, "trying %s", probe->name);
443                 pos = probe->parse(dev, current, dev->link);
444                 if (pos < 0) {
445                         efi_error("parsing %s failed", probe->name);
446                         goto err;
447                 } else if (pos == 0) {
448                         continue;
449                 }
450                 debug(DEBUG, "%s matched %s", probe->name, current);
451
452                 if (probe->flags & DEV_PROVIDES_HD || probe->flags & DEV_PROVIDES_ROOT)
453                         needs_root = false;
454                 dev->probes[n++] = dev_probes[i];
455                 current += pos;
456                 debug(DEBUG, "current:%s", current);
457
458                 if (!*current || !strncmp(current, "block/", 6))
459                         break;
460         }
461
462         if (dev->interface_type == unknown) {
463                 efi_error("unknown storage interface");
464                 errno = ENOSYS;
465                 goto err;
466         }
467
468         return dev;
469 err:
470         device_free(dev);
471         return NULL;
472 }
473
474 int HIDDEN
475 make_blockdev_path(uint8_t *buf, ssize_t size, struct device *dev)
476 {
477         ssize_t off = 0;
478
479         debug(DEBUG, "entry buf:%p size:%zd", buf, size);
480
481         for (unsigned int i = 0; dev->probes[i] &&
482                                  dev->probes[i]->parse; i++) {
483                 struct dev_probe *probe = dev->probes[i];
484                 ssize_t sz;
485
486                 if (!probe->create)
487                         continue;
488
489                 sz = probe->create(dev, buf + off, size ? size - off : 0, 0);
490                 if (sz < 0) {
491                         efi_error("could not create %s device path",
492                                   probe->name);
493                         return sz;
494                 }
495                 off += sz;
496         }
497
498         debug(DEBUG, "= %zd", off);
499
500         return off;
501 }
502
503 ssize_t HIDDEN
504 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
505 {
506         struct ifreq ifr;
507         struct ethtool_drvinfo drvinfo = { 0, };
508         int fd = -1, rc;
509         ssize_t ret = -1, sz, off = 0;
510         char busname[PATH_MAX+1] = "";
511         struct device dev;
512
513         memset(&dev, 0, sizeof (dev));
514         dev.interface_type = network;
515         dev.ifname = strdupa(ifname);
516         if (!dev.ifname)
517                 return -1;
518
519         /*
520          * find the device link, which looks like:
521          * ../../devices/$PCI_STUFF/net/$IFACE
522          */
523         rc = sysfs_readlink(&dev.link, "class/net/%s", ifname);
524         if (rc < 0 || !dev.link)
525                 goto err;
526
527         memset(&ifr, 0, sizeof (ifr));
528         strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
529         ifr.ifr_name[IF_NAMESIZE-1] = '\0';
530         drvinfo.cmd = ETHTOOL_GDRVINFO;
531         ifr.ifr_data = (caddr_t)&drvinfo;
532
533         fd = socket(AF_INET, SOCK_DGRAM, 0);
534         if (fd < 0)
535                 goto err;
536
537         rc = ioctl(fd, SIOCETHTOOL, &ifr);
538         if (rc < 0)
539                 goto err;
540
541         strncpy(busname, drvinfo.bus_info, PATH_MAX);
542
543         rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
544         if (rc < 0)
545                 goto err;
546
547         sz = pci_parser.create(&dev, buf, size, off);
548         if (sz < 0)
549                 goto err;
550         off += sz;
551
552         sz = efidp_make_mac_addr(buf+off, size?size-off:0,
553                                  ifr.ifr_ifru.ifru_hwaddr.sa_family,
554                                  (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
555                                  sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));
556         if (sz < 0)
557                 goto err;
558
559         off += sz;
560         ret = off;
561 err:
562         if (fd >= 0)
563                 close(fd);
564         return ret;
565 }
566
567 /************************************************************
568  * get_sector_size
569  * Requires:
570  *  - filedes is an open file descriptor, suitable for reading
571  * Modifies: nothing
572  * Returns:
573  *  sector size, or 512.
574  ************************************************************/
575 int UNUSED
576 get_sector_size(int filedes)
577 {
578         int rc, sector_size = 512;
579
580         rc = ioctl(filedes, BLKSSZGET, &sector_size);
581         if (rc)
582                 sector_size = 512;
583         return sector_size;
584 }