OSDN Git Service

Silence some trivial clang-analyzer/coverity complaints.
[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 <stdio.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <sys/sysmacros.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42
43 #include <efivar/efivar.h>
44 #include <efivar/efiboot.h>
45
46 #include "dp.h"
47 #include "linux.h"
48 #include "util.h"
49
50 int
51 __attribute__((__visibility__ ("hidden")))
52 set_disk_and_part_name(struct disk_info *info)
53 {
54         char *linkbuf;
55         ssize_t rc;
56
57         rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%"PRIu32,
58                       info->major, info->minor);
59         if (rc < 0 || !linkbuf)
60                 return -1;
61
62         char *ultimate;
63         ultimate = strrchr(linkbuf, '/');
64         if (!ultimate) {
65                 errno = EINVAL;
66                 return -1;
67         }
68         *ultimate = '\0';
69         ultimate++;
70
71         char *penultimate;
72         penultimate = strrchr(linkbuf, '/');
73         if (!penultimate) {
74                 errno = EINVAL;
75                 return -1;
76         }
77         penultimate++;
78
79         /*
80          * If there's a better way to figure this out, it'd be good, because
81          * I don't want to have to change this for every new disk type...
82          */
83         if (!strncmp(ultimate, "pmem", 4)) {
84                 if (!info->disk_name) {
85                         info->disk_name = strdup(ultimate);
86                         if (!info->disk_name)
87                                 return -1;
88                 }
89         } else if (!strcmp(penultimate, "block")) {
90                 if (!info->disk_name) {
91                         info->disk_name = strdup(ultimate);
92                         if (!info->disk_name)
93                                 return -1;
94                 }
95                 if (!info->part_name) {
96                         rc = asprintf(&info->part_name, "%s%d", info->disk_name,
97                                       info->part);
98                         if (rc < 0)
99                                 return -1;
100                 }
101         } else if (!strncmp(penultimate, "nvme", 4)) {
102                 if (!info->disk_name) {
103                         info->disk_name = strdup(ultimate);
104                         if (!info->disk_name)
105                                 return -1;
106                 }
107                 if (!info->part_name) {
108                         rc = asprintf(&info->part_name, "%sp%d",
109                                       info->disk_name, info->part);
110                         if (rc < 0)
111                                 return -1;
112                 }
113         } else {
114                 if (!info->disk_name) {
115                         info->disk_name = strdup(penultimate);
116                         if (!info->disk_name)
117                                 return -1;
118                 }
119                 if (!info->part_name) {
120                         info->part_name = strdup(ultimate);
121                         if (!info->part_name)
122                                 return -1;
123                 }
124         }
125
126         return 0;
127 }
128
129 int
130 __attribute__((__visibility__ ("hidden")))
131 get_partition_number(const char *devpath)
132 {
133         struct stat statbuf = { 0, };
134         int rc;
135         unsigned int maj, min;
136         char *linkbuf;
137         uint8_t *partbuf;
138         int ret = -1;
139
140         rc = stat(devpath, &statbuf);
141         if (rc < 0) {
142                 efi_error("couldn't stat %s\n", devpath);
143                 return -1;
144         }
145
146         if (!S_ISBLK(statbuf.st_mode)) {
147                 efi_error("%s is not a block device\n", devpath);
148                 errno = EINVAL;
149                 return -1;
150         }
151
152         maj = major(statbuf.st_rdev);
153         min = minor(statbuf.st_rdev);
154
155         rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%u:%u", maj, min);
156         if (rc < 0 || !linkbuf) {
157                 efi_error("couldn't get partition number for %u:%u", maj, min);
158                 return -1;
159         }
160
161         rc = read_sysfs_file(&partbuf, "/sys/dev/block/%s/partition", linkbuf);
162         if (rc < 0) {
163                 efi_error("couldn't get partition number for %s", linkbuf);
164                 /* This isn't strictly an error for e.g. nvdimm pmem devices */
165                 return 0;
166         }
167
168         rc = sscanf((char *)partbuf, "%d\n", &ret);
169         if (rc != 1) {
170                 efi_error("couldn't get partition number for %s", partbuf);
171                 return -1;
172         }
173         return ret;
174 }
175
176 int
177 __attribute__((__visibility__ ("hidden")))
178 find_parent_devpath(const char * const child, char **parent)
179 {
180         int ret;
181         char *node;
182         char *linkbuf;
183
184         /* strip leading /dev/ */
185         node = strrchr(child, '/');
186         if (!node)
187                 return -1;
188         node++;
189
190         /* look up full path symlink */
191         ret = sysfs_readlink(&linkbuf, "/sys/class/block/%s", node);
192         if (ret < 0 || !linkbuf)
193                 return ret;
194
195         /* strip child */
196         node = strrchr(linkbuf, '/');
197         if (!node)
198                 return -1;
199         *node = '\0';
200
201         /* read parent */
202         node = strrchr(linkbuf, '/');
203         if (!node)
204                 return -1;
205         *node = '\0';
206         node++;
207
208         /* write out new path */
209         ret = asprintf(parent, "/dev/%s", node);
210         if (ret < 0)
211                 return ret;
212
213         return 0;
214 }
215
216 /* NVDIMM-P paths */
217 static int
218 sysfs_test_pmem(const char *buf)
219 {
220         char *driverbuf = NULL;
221         int rc;
222
223         rc = sysfs_readlink(&driverbuf,
224                             "/sys/dev/block/%s/device/driver", buf);
225         if (rc < 0 || !driverbuf)
226                 return 0;
227
228         char *driver = strrchr(driverbuf, '/');
229         if (!driver || !*driver)
230                 return -1;
231         driver+=1;
232         if (!strcmp(driver, "nd_pmem"))
233                 return 1;
234         return 0;
235 }
236
237 static int
238 sysfs_test_nvme(const char *buf, ssize_t size)
239 {
240         if (!strncmp(buf, "nvme/", MIN(size, 5)))
241                 return 1;
242         return 0;
243 }
244
245 static int
246 sysfs_test_sata(const char *buf, ssize_t size)
247 {
248         if (!strncmp(buf, "ata", MIN(size, 3)))
249                 return 1;
250         return 0;
251 }
252
253 static int
254 sysfs_test_sas(const char *buf, ssize_t size)
255 {
256         int rc;
257         char *path;
258         struct stat statbuf = { 0, };
259         char *newbuf;
260
261         int host;
262         int sz;
263
264         newbuf = strndupa(buf, size+1);
265         if (!newbuf)
266                 return -1;
267         newbuf[size] = '\0';
268
269         errno = 0;
270         rc = sscanf(newbuf, "host%d/%n", &host, &sz);
271         if (rc < 1)
272                 return (errno == 0) ? 0 : -1;
273
274         rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address",
275                         host);
276         if (rc < 0)
277                 return -1;
278
279         rc = stat(path, &statbuf);
280         if (rc >= 0)
281                 return 1;
282         return 0;
283 }
284
285 static ssize_t
286 sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info)
287 {
288         DIR *d;
289         struct dirent *de;
290         uint8_t *buf = NULL;
291         int rc;
292
293         d = opendir("/sys/class/ata_device/");
294         if (!d) {
295                 efi_error("opendir failed on /sys/class/ata_device/");
296                 return -1;
297         }
298
299         while ((de = readdir(d)) != NULL) {
300                 uint32_t found_print_id;
301                 uint32_t found_pmp;
302                 uint32_t found_devno = 0;
303
304                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
305                         continue;
306
307                 int rc;
308                 rc = sscanf(de->d_name, "dev%d.%d.%d", &found_print_id,
309                             &found_pmp, &found_devno);
310                 if (rc < 2 || rc > 3) {
311                         closedir(d);
312                         errno = EINVAL;
313                         return -1;
314                 } else if (found_print_id != print_id) {
315                         continue;
316                 } else if (rc == 3) {
317                         /*
318                          * the kernel doesn't't ever tell us the SATA PMPN
319                          * sentinal value, it'll give us devM.N instead of
320                          * devM.N.O in that case instead.
321                          */
322                         if (found_pmp > 0x7fff) {
323                                 closedir(d);
324                                 errno = EINVAL;
325                                 return -1;
326                         }
327                         info->sata_info.ata_devno = 0;
328                         info->sata_info.ata_pmp = found_pmp;
329                         break;
330                 } else if (rc == 2) {
331                         info->sata_info.ata_devno = 0;
332                         info->sata_info.ata_pmp = 0xffff;
333                         break;
334                 }
335         }
336         closedir(d);
337
338         rc = read_sysfs_file(&buf, "/sys/class/ata_port/ata%d/port_no",
339                              print_id);
340         if (rc <= 0 || buf == NULL)
341                 return -1;
342
343         rc = sscanf((char *)buf, "%d", &info->sata_info.ata_port);
344         if (rc != 1)
345                 return -1;
346
347         /*
348          * ata_port numbers are 1-indexed from libata in the kernel, but
349          * they're 0-indexed in the spec.  For maximal confusion.
350          */
351         if (info->sata_info.ata_port == 0) {
352                 errno = EINVAL;
353                 return -1;
354         } else {
355                 info->sata_info.ata_port -= 1;
356         }
357
358         return 0;
359 }
360
361 /* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
362  * dev: 259:0
363  * device -> ../../../btt12.1
364  * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8
365  * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
366  *
367  * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
368  * dev: 259:1
369  * device -> ../../../btt12.2
370  * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940
371  * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
372  *
373  * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
374  * dev: 259:2
375  * device -> ../../../pfn12.1
376  * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622
377  * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
378  */
379 static ssize_t
380 sysfs_parse_pmem(uint8_t *buf,  ssize_t size, ssize_t *off,
381                  const char *pbuf, ssize_t psize __attribute__((__unused__)),
382                  ssize_t *poff __attribute__((__unused__)),
383                  struct disk_info *info)
384 {
385         uint8_t *filebuf = NULL;
386         int rc;
387
388         rc = read_sysfs_file(&filebuf,
389                              "/sys/class/block/%s/device/uuid", pbuf);
390         if ((rc < 0 && errno == ENOENT) || filebuf == NULL)
391                 return -1;
392
393         rc = efi_str_to_guid((char *)filebuf, &info->nvdimm_label);
394         if (rc < 0)
395                 return -1;
396
397         /* UUIDs are stored opposite Endian from GUIDs, so our normal GUID
398          * parser is giving us the wrong thing; swizzle those bytes around.
399          */
400         swizzle_guid_to_uuid(&info->nvdimm_label);
401
402         *off = efidp_make_nvdimm(buf, size, &info->nvdimm_label);
403         return *off;
404 }
405
406 static ssize_t
407 sysfs_parse_nvme(uint8_t *buf, ssize_t size, ssize_t *off,
408                 const char *pbuf, ssize_t psize, ssize_t *poff,
409                 struct disk_info *info)
410 {
411         int rc;
412         int psz = 0;
413         uint8_t *filebuf = NULL;
414
415         *poff = 0;
416         *off = 0;
417
418         char *newpbuf;
419
420         newpbuf = strndupa(pbuf, psize+1);
421         if (!newpbuf)
422                 return -1;
423         newpbuf[psize] = '\0';
424
425         int32_t tosser0;
426         int32_t ctrl_id;
427         int32_t ns_id;
428
429         /* buf is:
430          * nvme/nvme0/nvme0n1
431          */
432         rc = sscanf(newpbuf, "nvme/nvme%d/nvme%dn%d%n", &tosser0,
433                     &ctrl_id, &ns_id, &psz);
434         if (rc != 3)
435                 return -1;
436         *poff += psz;
437
438         info->nvme_info.ctrl_id = ctrl_id;
439         info->nvme_info.ns_id = ns_id;
440         info->nvme_info.has_eui = 0;
441         info->interface_type = nvme;
442
443         /*
444          * now fish the eui out of sysfs is there is one...
445          */
446         rc = read_sysfs_file(&filebuf,
447                              "/sys/class/block/nvme%dn%d/eui",
448                              ctrl_id, ns_id);
449         if ((rc < 0 && errno == ENOENT) || filebuf == NULL) {
450                 rc = read_sysfs_file(&filebuf,
451                              "/sys/class/block/nvme%dn%d/device/eui",
452                              ctrl_id, ns_id);
453         }
454         if (rc >= 0 && filebuf != NULL) {
455                 uint8_t eui[8];
456                 if (rc < 23) {
457                         errno = EINVAL;
458                         return -1;
459                 }
460                 rc = sscanf((char *)filebuf,
461                             "%02hhx %02hhx %02hhx %02hhx "
462                             "%02hhx %02hhx %02hhx %02hhx",
463                             &eui[0], &eui[1], &eui[2], &eui[3],
464                             &eui[4], &eui[5], &eui[6], &eui[7]);
465                 if (rc < 8) {
466                         errno = EINVAL;
467                         return -1;
468                 }
469                 info->nvme_info.has_eui = 1;
470                 memcpy(info->nvme_info.eui, eui, sizeof(eui));
471         }
472
473         *off = efidp_make_nvme(buf, size,
474                                info->nvme_info.ns_id,
475                                info->nvme_info.has_eui ? info->nvme_info.eui
476                                                        : NULL);
477         return *off;
478 }
479
480
481 static ssize_t
482 sysfs_parse_sata(uint8_t *buf, ssize_t size, ssize_t *off,
483                  const char *pbuf, ssize_t psize, ssize_t *poff,
484                  struct disk_info *info)
485 {
486         int psz = 0;
487         int rc;
488
489         *poff = 0;
490         *off = 0;
491
492         uint32_t print_id;
493
494         uint32_t scsi_bus;
495         uint32_t scsi_device;
496         uint32_t scsi_target;
497         uint32_t scsi_lun;
498
499         char *newpbuf;
500
501         newpbuf = strndupa(pbuf, psize+1);
502         if (!newpbuf)
503                 return -1;
504         newpbuf[psize] = '\0';
505
506         /* find the ata info:
507          * ata1/host0/target0:0:0/
508          *    ^dev  ^host   x y z
509          */
510         rc = sscanf(newpbuf, "ata%d/host%d/target%d:%d:%d/%n",
511                     &print_id, &scsi_bus, &scsi_device, &scsi_target, &scsi_lun,
512                     &psz);
513         if (rc != 5)
514                 return -1;
515         *poff += psz;
516
517         /* find the emulated scsi bits (and ignore them)
518          * 0:0:0:0/
519          */
520         uint32_t dummy0, dummy1, dummy2;
521         uint64_t dummy3;
522         rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", &dummy0, &dummy1,
523                     &dummy2, &dummy3, &psz);
524         if (rc != 4)
525                 return -1;
526         *poff += psz;
527
528         /* what's left is:
529          * block/sda/sda4
530          */
531         char *disk_name = NULL;
532         char *part_name = NULL;
533         int psz1 = 0;
534         rc = sscanf(newpbuf+*poff, "block/%m[^/]%n/%m[^/]%n", &disk_name, &psz,
535                     &part_name, &psz1);
536         if (rc == 1) {
537                 rc = asprintf(&part_name, "%s%d", disk_name, info->part);
538                 if (rc < 0) {
539                         free(disk_name);
540                         errno = EINVAL;
541                         return -1;
542                 }
543                 *poff += psz;
544         } else if (rc != 2) {
545                 errno = EINVAL;
546                 return -1;
547         } else {
548                 *poff += psz1;
549         }
550
551         info->sata_info.scsi_bus = scsi_bus;
552         info->sata_info.scsi_device = scsi_device;
553         info->sata_info.scsi_target = scsi_target;
554         info->sata_info.scsi_lun = scsi_lun;
555
556         rc = sysfs_sata_get_port_info(print_id, info);
557         if (rc < 0) {
558                 free(disk_name);
559                 free(part_name);
560                 return -1;
561         }
562
563         /* check the original of this; it's guaranteed in our copy */
564         if (pbuf[*poff] != '\0') {
565                 free(disk_name);
566                 free(part_name);
567                 errno = EINVAL;
568                 return -1;
569         }
570
571         info->disk_name = disk_name;
572         info->part_name = part_name;
573         if (info->interface_type == interface_type_unknown)
574                 info->interface_type = sata;
575
576         if (info->interface_type == ata) {
577                 *off = efidp_make_atapi(buf, size, info->sata_info.ata_port,
578                                         info->sata_info.ata_pmp,
579                                         info->sata_info.ata_devno);
580         } else {
581                 *off = efidp_make_sata(buf, size, info->sata_info.ata_port,
582                                        info->sata_info.ata_pmp,
583                                        info->sata_info.ata_devno);
584         }
585         return *off;
586 }
587
588 static ssize_t
589 sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off,
590                 const char *pbuf, ssize_t psize, ssize_t *poff,
591                 struct disk_info *info)
592 {
593         int rc;
594         int psz = 0;
595         uint8_t *filebuf = NULL;
596         uint64_t sas_address;
597
598         char *newpbuf;
599
600         newpbuf = strndupa(pbuf, psize+1);
601         if (!newpbuf)
602                 return -1;
603         newpbuf[psize] = '\0';
604
605         *poff = 0;
606         *off = 0;
607
608         /* buf is:
609          * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
610          */
611         uint32_t tosser0, tosser1, tosser2;
612
613         /* ignore a bunch of stuff
614          *    host4/port-4:0
615          * or host4/port-4:0:0
616          */
617         rc = sscanf(newpbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1,
618                     &tosser2, &psz);
619         if (rc != 3)
620                 return -1;
621         *poff += psz;
622
623         psz = 0;
624         rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz);
625         if (rc != 0 && rc != 1)
626                 return -1;
627         *poff += psz;
628
629         /* next:
630          *    /end_device-4:0
631          * or /end_device-4:0:0
632          * awesomely these are the exact same fields that go into port-blah,
633          * but we don't care for now about any of them anyway.
634          */
635         rc = sscanf(newpbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1,
636                     &psz);
637         if (rc != 2)
638                 return -1;
639         *poff += psz;
640
641         psz = 0;
642         rc = sscanf(newpbuf+*poff, ":%d%n", &tosser0, &psz);
643         if (rc != 0 && rc != 1)
644                 return -1;
645         *poff += psz;
646
647         /* now:
648          * /target4:0:0/
649          */
650         uint64_t tosser3;
651         rc = sscanf(newpbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0,
652                     &tosser1, &tosser3, &psz);
653         if (rc != 3)
654                 return -1;
655         *poff += psz;
656
657         /* now:
658          * %d:%d:%d:%llu/
659          */
660         rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n",
661                     &info->sas_info.scsi_bus,
662                     &info->sas_info.scsi_device,
663                     &info->sas_info.scsi_target,
664                     &info->sas_info.scsi_lun, &psz);
665         if (rc != 4)
666                 return -1;
667         *poff += psz;
668
669         /* what's left is:
670          * block/sdc/sdc1
671          */
672         char *disk_name = NULL;
673         char *part_name = NULL;
674         rc = sscanf(newpbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name,
675                     &part_name, &psz);
676         if (rc != 2)
677                 return -1;
678         *poff += psz;
679
680         /* check the original of this; it's guaranteed in our copy */
681         if (pbuf[*poff] != '\0') {
682                 free(disk_name);
683                 free(part_name);
684                 errno = EINVAL;
685                 return -1;
686         }
687
688         /*
689          * we also need to get the actual sas_address from someplace...
690          */
691         rc = read_sysfs_file(&filebuf,
692                              "/sys/class/block/%s/device/sas_address",
693                              disk_name);
694         if (rc < 0 || filebuf == NULL)
695                 return -1;
696
697         rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address);
698         if (rc != 1)
699                 return -1;
700
701         info->sas_info.sas_address = sas_address;
702         info->disk_name = disk_name;
703         info->part_name = part_name;
704         info->interface_type = sas;
705
706         *off = efidp_make_sas(buf, size, sas_address);
707         return *off;
708 }
709
710 static ssize_t
711 make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff)
712 {
713         ssize_t off=0, sz=0;
714         ssize_t poff = 0;
715         int psz;
716         int rc;
717
718         if (pathstr == NULL || pathoff == NULL || pathstr[0] == '\0') {
719                 errno = EINVAL;
720                 return -1;
721         }
722
723         *pathoff = 0;
724
725         uint16_t root_domain;
726         uint8_t root_bus;
727         uint32_t acpi_hid = 0;
728         uint64_t acpi_uid_int = 0;
729         /*
730          * find the pci root domain and port; they basically look like:
731          * pci0000:00/
732          *    ^d   ^p
733          */
734         rc = sscanf(pathstr+poff, "pci%hx:%hhx/%n", &root_domain,
735                     &root_bus, &psz);
736         if (rc != 2)
737                 return -1;
738         poff += psz;
739
740         uint8_t *fbuf = NULL;
741         rc = read_sysfs_file(&fbuf,
742                              "/sys/devices/pci%04hx:%02hhx/firmware_node/hid",
743                              root_domain, root_bus);
744         if (rc < 0 || fbuf == NULL)
745                 return -1;
746
747         uint16_t tmp16 = 0;
748         rc = sscanf((char *)fbuf, "PNP%hx", &tmp16);
749         if (rc != 1)
750                 return -1;
751         acpi_hid = EFIDP_EFI_PNP_ID(tmp16);
752
753         /* Apparently basically nothing can look up a PcieRoot() node,
754          * because they just check _CID.  So since _CID for the root pretty
755          * much always has to be PNP0A03 anyway, just use that no matter
756          * what.
757          */
758         if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID)
759                 acpi_hid = EFIDP_ACPI_PCI_ROOT_HID;
760
761         errno = 0;
762         fbuf = NULL;
763         int use_uid_str = 0;
764         rc = read_sysfs_file(&fbuf,
765                              "/sys/devices/pci%04hx:%02hhx/firmware_node/uid",
766                              root_domain, root_bus);
767         if ((rc <= 0 && errno != ENOENT) || fbuf == NULL)
768                 return -1;
769         if (rc > 0) {
770                 rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int);
771                 if (rc != 1) {
772                         /* kernel uses "%s\n" to print it, so there
773                          * should always be some value and a newline... */
774                         int l = strlen((char *)buf);
775                         if (l >= 1) {
776                                 use_uid_str=1;
777                                 fbuf[l-1] = '\0';
778                         }
779                 }
780         }
781         errno = 0;
782
783         if (use_uid_str) {
784                 sz = efidp_make_acpi_hid_ex(buf+off, size?size-off:0,
785                                             acpi_hid, 0, 0, "", (char *)fbuf,
786                                             "");
787         } else {
788                 sz = efidp_make_acpi_hid(buf+off, size?size-off:0,
789                                          acpi_hid, acpi_uid_int);
790         }
791         if (sz < 0)
792                 return -1;
793         off += sz;
794
795         /* find the pci domain/bus/device/function:
796          * 0000:00:01.0/0000:01:00.0/
797          *              ^d   ^b ^d ^f (of the last one in the series)
798          */
799         int found=0;
800         while (1) {
801                 uint16_t domain;
802                 uint8_t bus, device, function;
803                 rc = sscanf(pathstr+poff, "%hx:%hhx:%hhx.%hhx/%n",
804                             &domain, &bus, &device, &function, &psz);
805                 if (rc != 4)
806                         break;
807                 found=1;
808                 poff += psz;
809
810                 sz = efidp_make_pci(buf+off, size?size-off:0, device, function);
811                 if (sz < 0)
812                         return -1;
813                 off += sz;
814         }
815         if (!found)
816                 return -1;
817
818         *pathoff = poff;
819         return off;
820 }
821
822 int
823 __attribute__((__visibility__ ("hidden")))
824 make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info)
825 {
826         char *linkbuf = NULL;
827         char *driverbuf = NULL;
828         ssize_t off=0, sz=0, loff=0;
829         int lsz = 0;
830         int rc;
831         int found = 0;
832
833         rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%u",
834                             info->major, info->minor);
835         if (rc < 0 || !linkbuf) {
836                 efi_error("couldn't read link for /sys/dev/block/%"PRIu64":%u",
837                           info->major, info->minor);
838                 return -1;
839         }
840
841         /*
842          * the sysfs path basically looks like one of:
843          * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
844          * ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
845          */
846         rc = sysfs_test_pmem(linkbuf+loff);
847         if (rc < 0) {
848                 efi_error("sysfs_test_pmem(\"%s\") failed", linkbuf+loff);
849                 return -1;
850         } else if (rc > 0) {
851                 ssize_t linksz=0;
852                 info->interface_type = nd_pmem;
853                 rc = sysfs_parse_pmem(buf+off, size?size-off:0, &sz,
854                                       linkbuf+loff, PATH_MAX-off,
855                                       &linksz, info);
856                 if (rc < 0)
857                         return -1;
858                 loff += linksz;
859                 off += sz;
860                 found = 1;
861         }
862
863         if (!found) {
864                 rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz);
865                 if (rc != 0) {
866                         efi_error("scanf(\"%s\", %s, &lz) failed",
867                                   linkbuf+loff, "../../devices/%n");
868                         return -1;
869                 }
870                 loff += lsz;
871
872                 ssize_t tmplsz=0;
873                 sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
874                 if (sz < 0)
875                         return -1;
876                 loff += tmplsz;
877                 off += sz;
878
879                 char *tmppath;
880                 tmppath = strdupa(linkbuf);
881                 if (!tmppath)
882                         return -1;
883                 tmppath[loff] = '\0';
884                 rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver",
885                                     tmppath);
886                 if (rc < 0 || !driverbuf)
887                         return -1;
888
889                 char *driver = strrchr(driverbuf, '/');
890                 if (!driver || !*driver)
891                         return -1;
892                 driver+=1;
893
894                 if (!strncmp(driver, "pata_", 5) ||
895                     !(strcmp(driver, "ata_piix")))
896                         info->interface_type = ata;
897         }
898
899         if (!found &&
900             (info->interface_type == interface_type_unknown ||
901              info->interface_type == atapi ||
902              info->interface_type == usb ||
903              info->interface_type == i1394 ||
904              info->interface_type == fibre ||
905              info->interface_type == i2o ||
906              info->interface_type == md)) {
907                 uint32_t tosser;
908                 int tmpoff;
909
910                 rc = sscanf(linkbuf+loff, "virtio%x/%n", &tosser, &tmpoff);
911                 if (rc < 0) {
912                         return -1;
913                 } else if (rc == 1) {
914                         info->interface_type = virtblk;
915                         loff += tmpoff;
916                         found = 1;
917                 }
918         }
919
920         /* /dev/nvme0n1 looks like:
921          * /sys/dev/block/259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
922          */
923         if (!found) {
924                 rc = sysfs_test_nvme(linkbuf+loff, PATH_MAX-off);
925                 if (rc < 0)
926                         return -1;
927                 else if (rc > 0) {
928                         ssize_t linksz;
929                         rc = sysfs_parse_nvme(buf+off, size?size-off:0, &sz,
930                                               linkbuf+loff, PATH_MAX-off,
931                                               &linksz, info);
932                         if (rc < 0)
933                                 return -1;
934                         loff += linksz;
935                         off += sz;
936                         found = 1;
937                 }
938         }
939
940         /* /dev/sda as SATA looks like:
941          * /sys/dev/block/8:0 -> ../../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
942          */
943         if (!found) {
944                 rc = sysfs_test_sata(linkbuf+loff, PATH_MAX-off);
945                 if (rc < 0)
946                         return -1;
947                 else if (rc > 0) {
948                         ssize_t linksz=0;
949                         rc = sysfs_parse_sata(buf+off, size?size-off:0, &sz,
950                                               linkbuf+loff, PATH_MAX-off,
951                                               &linksz, info);
952                         if (rc < 0)
953                                 return -1;
954                         loff += linksz;
955                         off += sz;
956                         found = 1;
957                 }
958         }
959
960         /* /dev/sdc as SAS looks like:
961          * /sys/dev/block/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
962          */
963         if (!found) {
964                 rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off);
965                 if (rc < 0)
966                         return -1;
967                 else if (rc > 0) {
968                         ssize_t linksz=0;
969                         rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz,
970                                              linkbuf+loff, PATH_MAX-off,
971                                              &linksz, info);
972                         if (rc < 0)
973                                 return -1;
974                         /*
975                          * clang-analyzer complains about this because they
976                          * don't believe in writing code to avoid introducing
977                          * bugs later.
978                          */
979                         // loff += linksz;
980                         off += sz;
981                         found = 1;
982                 }
983         }
984
985         if (!found && info->interface_type == scsi) {
986                 char *linkbuf;
987
988                 rc = sysfs_readlink(&linkbuf, "/sys/class/block/%s/device",
989                               info->disk_name);
990                 if (rc < 0 || !linkbuf)
991                         return 0;
992
993                 rc = sscanf(linkbuf, "../../../%d:%d:%d:%"PRIu64,
994                             &info->scsi_info.scsi_bus,
995                             &info->scsi_info.scsi_device,
996                             &info->scsi_info.scsi_target,
997                             &info->scsi_info.scsi_lun);
998                 if (rc != 4)
999                         return -1;
1000
1001                 sz = efidp_make_scsi(buf+off, size?size-off:0,
1002                                      info->scsi_info.scsi_target,
1003                                      info->scsi_info.scsi_lun);
1004                 if (sz < 0)
1005                         return -1;
1006                 off += sz;
1007                 found = 1;
1008         }
1009
1010         if (!found) {
1011                 errno = ENOENT;
1012                 return -1;
1013         }
1014
1015         return off;
1016 }
1017
1018 int
1019 __attribute__((__visibility__ ("hidden")))
1020 eb_disk_info_from_fd(int fd, struct disk_info *info)
1021 {
1022         struct stat buf;
1023         char *driver;
1024         int rc;
1025
1026         memset(info, 0, sizeof *info);
1027
1028         info->pci_root.root_pci_domain = 0xffff;
1029         info->pci_root.root_pci_bus = 0xff;
1030
1031         memset(&buf, 0, sizeof(struct stat));
1032         rc = fstat(fd, &buf);
1033         if (rc == -1) {
1034                 efi_error("fstat() failed: %m");
1035                 return 1;
1036         }
1037         if (S_ISBLK(buf.st_mode)) {
1038                 info->major = major(buf.st_rdev);
1039                 info->minor = minor(buf.st_rdev);
1040         } else if (S_ISREG(buf.st_mode)) {
1041                 info->major = major(buf.st_dev);
1042                 info->minor = minor(buf.st_dev);
1043         } else {
1044                 efi_error("Cannot stat non-block or non-regular file");
1045                 return 1;
1046         }
1047
1048         /* IDE disks can have up to 64 partitions, or 6 bits worth,
1049          * and have one bit for the disk number.
1050          * This leaves an extra bit at the top.
1051          */
1052         if (info->major == 3) {
1053                 info->disknum = (info->minor >> 6) & 1;
1054                 info->controllernum = (info->major - 3 + 0) + info->disknum;
1055                 info->interface_type = ata;
1056                 info->part    = info->minor & 0x3F;
1057                 return 0;
1058         } else if (info->major == 22) {
1059                 info->disknum = (info->minor >> 6) & 1;
1060                 info->controllernum = (info->major - 22 + 2) + info->disknum;
1061                 info->interface_type = ata;
1062                 info->part    = info->minor & 0x3F;
1063                 return 0;
1064         } else if (info->major >= 33 && info->major <= 34) {
1065                 info->disknum = (info->minor >> 6) & 1;
1066                 info->controllernum = (info->major - 33 + 4) + info->disknum;
1067                 info->interface_type = ata;
1068                 info->part    = info->minor & 0x3F;
1069                 return 0;
1070         } else if (info->major >= 56 && info->major <= 57) {
1071                 info->disknum = (info->minor >> 6) & 1;
1072                 info->controllernum = (info->major - 56 + 8) + info->disknum;
1073                 info->interface_type = ata;
1074                 info->part    = info->minor & 0x3F;
1075                 return 0;
1076         } else if (info->major >= 88 && info->major <= 91) {
1077                 info->disknum = (info->minor >> 6) & 1;
1078                 info->controllernum = (info->major - 88 + 12) + info->disknum;
1079                 info->interface_type = ata;
1080                 info->part    = info->minor & 0x3F;
1081                 return 0;
1082         }
1083
1084         /* I2O disks can have up to 16 partitions, or 4 bits worth. */
1085         if (info->major >= 80 && info->major <= 87) {
1086                 info->interface_type = i2o;
1087                 info->disknum = 16*(info->major-80) + (info->minor >> 4);
1088                 info->part    = (info->minor & 0xF);
1089                 return 0;
1090         }
1091
1092         /* SCSI disks can have up to 16 partitions, or 4 bits worth
1093          * and have one bit for the disk number.
1094          */
1095         if (info->major == 8) {
1096                 info->interface_type = scsi;
1097                 info->disknum = (info->minor >> 4);
1098                 info->part    = (info->minor & 0xF);
1099                 return 0;
1100         } else  if (info->major >= 65 && info->major <= 71) {
1101                 info->interface_type = scsi;
1102                 info->disknum = 16*(info->major-64) + (info->minor >> 4);
1103                 info->part    = (info->minor & 0xF);
1104                 return 0;
1105         } else  if (info->major >= 128 && info->major <= 135) {
1106                 info->interface_type = scsi;
1107                 info->disknum = 16*(info->major-128) + (info->minor >> 4);
1108                 info->part    = (info->minor & 0xF);
1109                 return 0;
1110         }
1111
1112         rc = sysfs_readlink(&driver, "/sys/dev/block/%"PRIu64":%"PRIu32"/device/driver",
1113                             info->major, info->minor);
1114         if (rc > 0) {
1115                 char *last = strrchr(driver, '/');
1116                 if (last) {
1117                         if (!strcmp(last+1, "nd_pmem")) {
1118                                 info->interface_type = nd_pmem;
1119                                 return 0;
1120 #if 0 /* dunno */
1121                         } else if (!strcmp(last+1, "nd_blk")) {
1122                                 /* dunno */
1123                                 info->inteface_type = scsi;
1124 #endif
1125                         }
1126                 }
1127         }
1128
1129         errno = ENOSYS;
1130         return -1;
1131 }
1132
1133 static ssize_t
1134 make_net_pci_path(uint8_t *buf, ssize_t size, const char * const ifname)
1135 {
1136         char *linkbuf = NULL;
1137         ssize_t off=0, sz=0, loff=0;
1138         int lsz = 0;
1139         int rc;
1140
1141         rc = sysfs_readlink(&linkbuf, "/sys/class/net/%s", ifname);
1142         if (rc < 0 || !linkbuf)
1143                 return -1;
1144
1145         /*
1146          * the sysfs path basically looks like:
1147          * ../../devices/$PCI_STUFF/net/$IFACE
1148          */
1149         rc = sscanf(linkbuf, "../../devices/%n", &lsz);
1150         if (rc != 0)
1151                 return -1;
1152         loff += lsz;
1153
1154         ssize_t tmplsz = 0;
1155         sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
1156         if (sz < 0)
1157                 return -1;
1158         off += sz;
1159         /*
1160          * clang-analyzer complains about this because they don't believe in
1161          * writing code to avoid introducing bugs later.
1162          */
1163         //loff += tmplsz;
1164
1165         return off;
1166 }
1167
1168 ssize_t
1169 __attribute__((__visibility__ ("hidden")))
1170 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
1171 {
1172         struct ifreq ifr;
1173         struct ethtool_drvinfo drvinfo = { 0, };
1174         int fd, rc;
1175         ssize_t ret = -1, sz, off=0;
1176         char busname[PATH_MAX+1] = "";
1177
1178         memset(&ifr, 0, sizeof (ifr));
1179         strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
1180         ifr.ifr_name[IF_NAMESIZE-1] = '\0';
1181         drvinfo.cmd = ETHTOOL_GDRVINFO;
1182         ifr.ifr_data = (caddr_t)&drvinfo;
1183
1184         fd = socket(AF_INET, SOCK_DGRAM, 0);
1185         if (fd < 0)
1186                 return -1;
1187
1188         rc = ioctl(fd, SIOCETHTOOL, &ifr);
1189         if (rc < 0)
1190                 goto err;
1191
1192         strncpy(busname, drvinfo.bus_info, PATH_MAX);
1193
1194         rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
1195         if (rc < 0)
1196                 goto err;
1197
1198         sz = make_net_pci_path(buf, size, ifname);
1199         if (sz < 0)
1200                 goto err;
1201         off += sz;
1202
1203         sz = efidp_make_mac_addr(buf+off, size?size-off:0,
1204                                  ifr.ifr_ifru.ifru_hwaddr.sa_family,
1205                                  (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
1206                                  sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));
1207         if (sz < 0)
1208                 goto err;
1209
1210         off += sz;
1211         ret = off;
1212 err:
1213         if (fd >= 0)
1214                 close(fd);
1215         return ret;
1216 }