OSDN Git Service

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