OSDN Git Service

Expand tabs on the rest of linux.c
[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 (!strcmp(proximate, "nvme") || !strcmp(approximate, "block")) {
189                 /*
190                  * 259:1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1/nvme0n1p1
191                  * 8:1 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda/sda1
192                  * 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
193                  * 252:1 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda/vda1
194                  * 259:3 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s/pmem11s1
195                  */
196                 set_disk_name(dev, "%s", penultimate);
197                 set_part_name(dev, "%s", ultimate);
198                 debug(DEBUG, "disk:%s part:%s", penultimate, ultimate);
199         } else if (!strcmp(approximate, "nvme")) {
200                 /*
201                  * 259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
202                  */
203                 set_disk_name(dev, "%s", ultimate);
204                 set_part_name(dev, "%sp%d", ultimate, dev->part);
205                 debug(DEBUG, "disk:%s part:%sp%d", ultimate, ultimate, dev->part);
206         } else if (!strcmp(penultimate, "block")) {
207                 /*
208                  * 253:0 -> ../../devices/virtual/block/dm-0 (... I guess)
209                  * 8:0 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda
210                  * 11:0 -> ../../devices/pci0000:00/0000:00:11.5/ata3/host2/target2:0:0/2:0:0:0/block/sr0
211                  * 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
212                  * 252:0 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda
213                  * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region9/btt9.0/block/pmem9s
214                  * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s
215                  */
216                 set_disk_name(dev, "%s", ultimate);
217                 set_part_name(dev, "%s%d", ultimate, dev->part);
218                 debug(DEBUG, "disk:%s part:%s%d", ultimate, ultimate, dev->part);
219         } else if (!strcmp(approximate, "mtd")) {
220                 /*
221                  * 31:0 -> ../../devices/platform/1e000000.palmbus/1e000b00.spi/spi_master/spi32766/spi32766.0/mtd/mtd0/mtdblock0
222                  */
223                 set_disk_name(dev, "%s", ultimate);
224                 debug(DEBUG, "disk:%s", ultimate);
225         }
226
227         return 0;
228 }
229
230 static struct dev_probe *dev_probes[] = {
231         /*
232          * pmem needs to be before PCI, so if it provides root it'll
233          * be found first.
234          */
235         &pmem_parser,
236         &pci_parser,
237         &virtblk_parser,
238         &sas_parser,
239         &sata_parser,
240         &nvme_parser,
241         &ata_parser,
242         &scsi_parser,
243         &i2o_parser,
244         NULL
245 };
246
247 static inline bool
248 supports_iface(struct dev_probe *probe, enum interface_type iftype)
249 {
250         for (unsigned int i = 0; probe->iftypes[i] != unknown; i++)
251                 if (probe->iftypes[i] == iftype)
252                         return true;
253         return false;
254 }
255
256 void HIDDEN
257 device_free(struct device *dev)
258 {
259         if (!dev)
260                 return;
261         if (dev->link)
262                 free(dev->link);
263
264         if (dev->device)
265                 free(dev->device);
266
267         if (dev->driver)
268                 free(dev->driver);
269
270         if (dev->probes)
271                 free(dev->probes);
272
273         if (dev->interface_type == network) {
274                 if (dev->ifname)
275                         free(dev->ifname);
276         } else {
277                 if (dev->disk_name)
278                         free(dev->disk_name);
279                 if (dev->part_name)
280                         free(dev->part_name);
281         }
282
283         if (dev->pci_dev)
284                 free(dev->pci_dev);
285
286         memset(dev, 0, sizeof(*dev));
287         free(dev);
288 }
289
290 struct device HIDDEN
291 *device_get(int fd, int partition)
292 {
293         struct device *dev;
294         char *linkbuf = NULL, *tmpbuf = NULL;
295         unsigned int i, n = 0;
296         int rc;
297
298         size_t nmemb = (sizeof(dev_probes)
299                         / sizeof(dev_probes[0])) + 1;
300
301         dev = calloc(1, sizeof(*dev));
302         if (!dev) {
303                 efi_error("could not allocate %zd bytes", sizeof(*dev));
304                 return NULL;
305         }
306
307         dev->part = partition;
308         debug(DEBUG, "partition:%d dev->part:%d", partition, dev->part);
309         dev->probes = calloc(nmemb, sizeof(struct dev_probe *));
310         if (!dev->probes) {
311                 efi_error("could not allocate %zd bytes",
312                           nmemb * sizeof(struct dev_probe *));
313                 goto err;
314         }
315
316         rc = fstat(fd, &dev->stat);
317         if (rc < 0) {
318                 efi_error("fstat(%d) failed", fd);
319                 goto err;
320         }
321
322         dev->pci_root.pci_root_domain = 0xffff;
323         dev->pci_root.pci_root_bus = 0xff;
324
325         if (S_ISBLK(dev->stat.st_mode)) {
326                 dev->major = major(dev->stat.st_rdev);
327                 dev->minor = minor(dev->stat.st_rdev);
328         } else if (S_ISREG(dev->stat.st_mode)) {
329                 dev->major = major(dev->stat.st_dev);
330                 dev->minor = minor(dev->stat.st_dev);
331         } else {
332                 efi_error("device is not a block device or regular file");
333                 goto err;
334         }
335
336         rc = sysfs_readlink(&linkbuf, "dev/block/%"PRIu64":%"PRIu32,
337                             dev->major, dev->minor);
338         if (rc < 0 || !linkbuf) {
339                 efi_error("readlink of /sys/dev/block/%"PRIu64":%"PRIu32" failed",
340                           dev->major, dev->minor);
341                 goto err;
342         }
343
344         dev->link = strdup(linkbuf);
345         if (!dev->link) {
346                 efi_error("strdup(\"%s\") failed", linkbuf);
347                 goto err;
348         }
349         debug(DEBUG, "dev->link: %s\n", dev->link);
350
351         if (dev->part == -1) {
352                 rc = read_sysfs_file(&tmpbuf, "dev/block/%s/partition", dev->link);
353                 if (rc < 0) {
354                         efi_error("device has no /partition node; not a partition");
355                 } else {
356                         rc = sscanf((char *)tmpbuf, "%d\n", &dev->part);
357                         if (rc != 1)
358                                 efi_error("couldn't parse partition number for %s", tmpbuf);
359                 }
360         }
361
362         rc = set_disk_and_part_name(dev);
363         if (rc < 0) {
364                 efi_error("could not set disk and partition names");
365                 goto err;
366         }
367         debug(DEBUG, "dev->disk_name: %s", dev->disk_name);
368         debug(DEBUG, "dev->part_name: %s", dev->part_name);
369
370         rc = sysfs_readlink(&tmpbuf, "block/%s/device", dev->disk_name);
371         if (rc < 0 || !tmpbuf) {
372                 efi_error("readlink of /sys/block/%s/device failed",
373                           dev->disk_name);
374                 goto err;
375         }
376
377         dev->device = strdup(tmpbuf);
378         if (!dev->device) {
379                 efi_error("strdup(\"%s\") failed", tmpbuf);
380                 goto err;
381         }
382
383         rc = sysfs_readlink(&tmpbuf, "block/%s/device/driver", dev->disk_name);
384         if (rc < 0 || !tmpbuf) {
385                 efi_error("readlink of /sys/block/%s/device/driver failed",
386                           dev->disk_name);
387                 goto err;
388         }
389
390         linkbuf = pathseg(tmpbuf, -1);
391         if (!linkbuf) {
392                 efi_error("could not get segment -1 of \"%s\"", tmpbuf);
393                 goto err;
394         }
395
396         dev->driver = strdup(linkbuf);
397         if (!dev->driver) {
398                 efi_error("strdup(\"%s\") failed", linkbuf);
399                 goto err;
400         }
401
402         const char *current = dev->link;
403         bool needs_root = true;
404
405         debug(DEBUG, "searching for device nodes in %s", dev->link);
406         for (i = 0; dev_probes[i] && dev_probes[i]->parse; i++) {
407                 struct dev_probe *probe = dev_probes[i];
408                 ssize_t pos;
409
410                 if (!needs_root && (probe->flags & DEV_PROVIDES_ROOT)) {
411                         debug(DEBUG, "not testing %s because flags is 0x%x", probe->name, probe->flags);
412                         continue;
413                 }
414
415                 debug(DEBUG, "trying %s", probe->name);
416                 pos = probe->parse(dev, current);
417                 if (pos < 0) {
418                         efi_error("parsing %s failed", probe->name);
419                         goto err;
420                 } else if (pos == 0) {
421                         continue;
422                 }
423                 debug(DEBUG, "%s matched %s", probe->name, current);
424
425                 if (probe->flags & DEV_PROVIDES_HD)
426                         needs_root = false;
427                 dev->probes[n++] = dev_probes[i];
428                 current += pos;
429                 debug(DEBUG, "current:%s", current);
430
431                 if (!*current || !strncmp(current, "block/", 6))
432                         break;
433         }
434
435         if (dev->interface_type == unknown) {
436                 efi_error("unknown storage interface");
437                 errno = ENOSYS;
438                 goto err;
439         }
440
441         return dev;
442 err:
443         device_free(dev);
444         return NULL;
445 }
446
447 int HIDDEN
448 make_blockdev_path(uint8_t *buf, ssize_t size, struct device *dev)
449 {
450         ssize_t off = 0;
451
452         debug(DEBUG, "entry buf:%p size:%zd", buf, size);
453
454         for (unsigned int i = 0; dev->probes[i] &&
455                                  dev->probes[i]->parse; i++) {
456                 struct dev_probe *probe = dev->probes[i];
457                 ssize_t sz;
458
459                 if (!probe->create)
460                         continue;
461
462                 sz = probe->create(dev, buf + off, size ? size - off : 0, 0);
463                 if (sz < 0) {
464                         efi_error("could not create %s device path",
465                                   probe->name);
466                         return sz;
467                 }
468                 off += sz;
469         }
470
471         debug(DEBUG, "= %zd", off);
472
473         return off;
474 }
475
476 ssize_t HIDDEN
477 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
478 {
479         struct ifreq ifr;
480         struct ethtool_drvinfo drvinfo = { 0, };
481         int fd, rc;
482         ssize_t ret = -1, sz, off = 0;
483         char busname[PATH_MAX+1] = "";
484         struct device dev;
485
486         memset(&dev, 0, sizeof (dev));
487         dev.interface_type = network;
488         dev.ifname = strdup(ifname);
489         if (!dev.ifname)
490                 return -1;
491
492         /*
493          * find the device link, which looks like:
494          * ../../devices/$PCI_STUFF/net/$IFACE
495          */
496         rc = sysfs_readlink(&dev.link, "class/net/%s", ifname);
497         if (rc < 0 || !dev.link)
498                 return -1;
499
500         memset(&ifr, 0, sizeof (ifr));
501         strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
502         ifr.ifr_name[IF_NAMESIZE-1] = '\0';
503         drvinfo.cmd = ETHTOOL_GDRVINFO;
504         ifr.ifr_data = (caddr_t)&drvinfo;
505
506         fd = socket(AF_INET, SOCK_DGRAM, 0);
507         if (fd < 0)
508                 return -1;
509
510         rc = ioctl(fd, SIOCETHTOOL, &ifr);
511         if (rc < 0)
512                 goto err;
513
514         strncpy(busname, drvinfo.bus_info, PATH_MAX);
515
516         rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
517         if (rc < 0)
518                 goto err;
519
520         sz = pci_parser.create(&dev, buf, size, off);
521         if (sz < 0)
522                 goto err;
523         off += sz;
524
525         sz = efidp_make_mac_addr(buf+off, size?size-off:0,
526                                  ifr.ifr_ifru.ifru_hwaddr.sa_family,
527                                  (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
528                                  sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));
529         if (sz < 0)
530                 goto err;
531
532         off += sz;
533         ret = off;
534 err:
535         if (fd >= 0)
536                 close(fd);
537         return ret;
538 }
539
540 /************************************************************
541  * get_sector_size
542  * Requires:
543  *  - filedes is an open file descriptor, suitable for reading
544  * Modifies: nothing
545  * Returns:
546  *  sector size, or 512.
547  ************************************************************/
548 int UNUSED
549 get_sector_size(int filedes)
550 {
551         int rc, sector_size = 512;
552
553         rc = ioctl(filedes, BLKSSZGET, &sector_size);
554         if (rc)
555                 sector_size = 512;
556         return sector_size;
557 }