Imported Debian patch 0.5.4-1
[debian/efibootmgr] / src / lib / unparse_path.c
1 /*
2   unparse_path.[ch]
3  
4   Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
5  
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /* For PRIx64 */
22 #define __STDC_FORMAT_MACROS
23
24 #include <stdio.h>
25 #include <inttypes.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <netinet/in.h>
30
31 #include "efi.h"
32 #include "unparse_path.h"
33 #include "efichar.h"
34
35 /* Avoid unaligned access warnings */
36 #define get(buf, obj) *(typeof(obj) *)memcpy(buf, &obj, sizeof(obj))
37
38
39 void
40 dump_raw_data(void *data, uint64_t length)
41 {
42         char buffer1[80], buffer2[80], *b1, *b2, c;
43         unsigned char *p = data;
44         unsigned long column=0;
45         uint64_t length_printed = 0;
46         const char maxcolumn = 16;
47         while (length_printed < length) {
48                 b1 = buffer1;
49                 b2 = buffer2;
50                 for (column = 0;
51                      column < maxcolumn && length_printed < length; 
52                      column ++) {
53                         b1 += sprintf(b1, "%02x ",(unsigned int) *p);
54                         if (*p < 32 || *p > 126) c = '.';
55                         else c = *p;
56                         b2 += sprintf(b2, "%c", c);
57                         p++;
58                         length_printed++;
59                 }
60                 /* pad out the line */
61                 for (; column < maxcolumn; column++)
62                 {
63                         b1 += sprintf(b1, "   ");
64                         b2 += sprintf(b2, " ");
65                 }
66
67                 printf("%s\t%s\n", buffer1, buffer2);
68         }
69 }
70
71
72
73 unsigned long
74 unparse_raw(char *buffer, uint8_t *p, uint64_t length)
75 {
76         uint64_t i;
77         char a[1];
78         char *q = buffer;
79         for (i=0; i<length; i++) {
80                 q += sprintf(q, "%02x", get(a, p[i]));
81         }
82         return q - buffer;
83 }
84
85 unsigned long
86 unparse_raw_text(char *buffer, uint8_t *p, uint64_t length)
87 {
88         uint64_t i; unsigned char c;
89         char *q = buffer;
90         for (i=0; i<length; i++) {
91                 c = p[i];
92                 if (c < 32 || c > 127) c = '.';
93                 q += sprintf(q, "%c", c);
94         }
95         return q - buffer;
96 }
97
98 static int
99 unparse_ipv4_port(char *buffer, uint32_t ipaddr, uint16_t port)
100 {
101         unsigned char *ip;
102 //      ipaddr = nltoh(ipaddr);
103 //      port = nstoh(port);
104         ip = (unsigned char *)&ipaddr;
105         return sprintf(buffer, "%hhu.%hhu.%hhu.%hhu:%hu",
106                        ip[0], ip[1], ip[2], ip[3], 
107                        port);
108 }
109
110
111 static int
112 unparse_acpi_path(char *buffer, EFI_DEVICE_PATH *path)
113 {
114         ACPI_DEVICE_PATH *acpi = (ACPI_DEVICE_PATH *)path;
115         char a[16], b[16];
116
117         switch (path->subtype) {
118         case 1:
119                 return sprintf(buffer, "ACPI(%x,%x)", get(a, acpi->_HID), get(b, acpi->_UID));
120                 break;
121         default:
122                 return unparse_raw(buffer, (uint8_t *)path, path->length);
123                 break;
124         }
125         return 0;
126 }
127
128 static int
129 unparse_vendor_path(char *buffer, VENDOR_DEVICE_PATH *path)
130 {
131         char text_guid[40], *p = buffer;
132         unsigned char *q = (uint8_t *)path + 20;
133         efi_guid_unparse(&path->vendor_guid, text_guid);
134         p += sprintf(p, "Vendor(%s,", text_guid);
135         p += unparse_raw(p, q, path->length - 20);
136         p += sprintf(p, ")");
137         return p - buffer;
138 }
139
140 static int
141 unparse_hardware_path(char *buffer, EFI_DEVICE_PATH *path)
142 {
143         PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)path;
144         PCCARD_DEVICE_PATH *pccard = (PCCARD_DEVICE_PATH *)path;
145         MEMORY_MAPPED_DEVICE_PATH *mm = (MEMORY_MAPPED_DEVICE_PATH *)path;
146         CONTROLLER_DEVICE_PATH *ctlr = (CONTROLLER_DEVICE_PATH *)path;
147         char a[16], b[16], c[16];
148
149         switch (path->subtype) {
150         case 1:
151                 return sprintf(buffer, "PCI(%x,%x)", get(a, pci->device), get(b, pci->function));
152                 break;
153         case 2:
154                 return sprintf(buffer, "PCCARD(%x)", get(a, pccard->socket));
155                 break;
156         case 3:
157                 return sprintf(buffer, "MM(%x,%" PRIx64 ",%" PRIx64 ")",
158                                get(a, mm->memory_type),
159                                get(b, mm->start),
160                                get(c, mm->end));
161                 break;
162         case 4:
163                 return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
164                 break;
165
166         case 5:
167                 return sprintf(buffer, "Controller(%x)", get(a, ctlr->controller));
168                 break;
169
170         default:
171                 return unparse_raw(buffer, (uint8_t *)path, path->length);
172         }
173         return 0;
174 }
175
176
177 static int
178 unparse_messaging_path(char *buffer, EFI_DEVICE_PATH *path)
179 {
180         ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)path;
181         SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)path;
182         FIBRE_CHANNEL_DEVICE_PATH *fc = (FIBRE_CHANNEL_DEVICE_PATH *)path;
183         I1394_DEVICE_PATH *i1394 = (I1394_DEVICE_PATH *)path;
184         USB_DEVICE_PATH *usb = (USB_DEVICE_PATH *)path;
185         MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)path;
186         USB_CLASS_DEVICE_PATH *usbclass = (USB_CLASS_DEVICE_PATH *)path;
187         I2O_DEVICE_PATH *i2o = (I2O_DEVICE_PATH *)path; 
188         IPv4_DEVICE_PATH *ipv4 = (IPv4_DEVICE_PATH *)path;
189 /*      IPv6_DEVICE_PATH *ipv6 = (IPv6_DEVICE_PATH *)path; */
190         char *p = buffer;
191         char a[16], b[16], c[16], d[16], e[16];
192
193         switch (path->subtype) {
194         case 1:
195                 return sprintf(buffer, "ATAPI(%x,%x,%x)",
196                                get(a, atapi->primary_secondary),
197                                get(b, atapi->slave_master),
198                                get(c, atapi->lun));
199                 break;
200         case 2:
201                 return sprintf(buffer, "SCSI(%x,%x)", get(a, scsi->id), get(b, scsi->lun));
202                 break;
203
204         case 3:
205                 return sprintf(buffer, "FC(%" PRIx64 ",%" PRIx64 ")", get(a, fc->wwn), get(b, fc->lun));
206                 break;
207         case 4:
208                 return sprintf(buffer, "1394(%" PRIx64 ")", get(a, i1394->guid));
209                 break;
210         case 5:
211                 return sprintf(buffer, "USB(%x,%x)", get(a, usb->port), get(b, usb->endpoint));
212                 break;
213         case 6:
214                 return sprintf(buffer, "I2O(%x)", get(a, i2o->tid));
215                 break;
216         case 11:
217                 p += sprintf(p, "MAC(");
218                 p += unparse_raw(p, mac->macaddr, 6);
219                 p += sprintf(p, ",%hhx)", get(a, mac->iftype));
220                 return (int) (p - buffer);
221                 break;
222         case 12:
223                 p += sprintf(p, "IPv4(");
224                 p += unparse_ipv4_port(p, ipv4->local_ip, ipv4->local_port);
225                 p += sprintf(p, "<->");
226                 p += unparse_ipv4_port(p, ipv4->remote_ip, ipv4->remote_port);
227                 p += sprintf(p, ",%hx, %hhx", get(a, ipv4->protocol), get(b, ipv4->static_addr));
228                 return (int) (p - buffer);
229                 break;
230
231         case 15:
232                 return sprintf(buffer, "USBClass(%hx,%hx,%hhx,%hhx,%hhx)",
233                                get(a, usbclass->vendor), get(b, usbclass->product),
234                                get(c, usbclass->class), get(d, usbclass->subclass),
235                                get(e, usbclass->protocol));
236                 break;
237         default:
238                 return unparse_raw(buffer, (uint8_t *)path, path->length);
239                 break;
240         }
241         return 0;
242 }
243
244 static int
245 unparse_media_hard_drive_path(char *buffer, EFI_DEVICE_PATH *path)
246 {
247         HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *)path;
248         char text_uuid[40], *sig=text_uuid;
249         char a[16], b[16], c[16];
250         
251         switch (hd->signature_type) {
252         case 0x00:
253                 sprintf(sig, "None");
254                 break;
255         case 0x01:
256                 sprintf(sig, "%08x", *(uint32_t *)memcpy(a, &hd->signature,
257                                                          sizeof(hd->signature)));
258                 break;
259         case 0x02: /* GPT */
260                 efi_guid_unparse((efi_guid_t *)hd->signature, sig);
261                 break;
262         default:
263                 break;
264         }
265
266         return sprintf(buffer, "HD(%x,%" PRIx64 ",%" PRIx64 ",%s)",
267                        get(a, hd->part_num),
268                        get(b, hd->start),
269                        get(c, hd->size),
270                        sig);
271 }
272
273
274
275 static int
276 unparse_media_path(char *buffer, EFI_DEVICE_PATH *path)
277 {
278
279         CDROM_DEVICE_PATH *cdrom = (CDROM_DEVICE_PATH *)path;
280         MEDIA_PROTOCOL_DEVICE_PATH *media = (MEDIA_PROTOCOL_DEVICE_PATH *)path;
281         FILE_PATH_DEVICE_PATH *file = (FILE_PATH_DEVICE_PATH *)path;
282         char text_guid[40], *p = buffer;
283         char file_name[80];
284         memset(file_name, 0, sizeof(file_name));
285         char a[16], b[16], c[16];
286
287         switch (path->subtype) {
288         case 1:
289                 return unparse_media_hard_drive_path(buffer, path);
290                 break;
291         case 2:
292                 return sprintf(buffer, "CD-ROM(%x,%" PRIx64 ",%" PRIx64 ")",
293                                get(a, cdrom->boot_entry), get(b, cdrom->start), get(c, cdrom->size));
294                 break;
295         case 3:
296                 return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
297                 break;
298         case 4:
299                 efichar_to_char(file_name, file->path_name, 80);
300                 return sprintf(p, "File(%s)", file_name);
301                 break;
302         case 5:
303                 efi_guid_unparse(&media->guid, text_guid);
304                 return sprintf(buffer, "Media(%s)", text_guid);
305                 break;
306         default:
307                 break;
308         }
309         return 0;
310 }
311
312 static int
313 unparse_bios_path(char *buffer, EFI_DEVICE_PATH *path)
314 {
315         BIOS_BOOT_SPEC_DEVICE_PATH *bios = (BIOS_BOOT_SPEC_DEVICE_PATH *)path;
316         char *p = buffer;
317         unsigned char *q = (uint8_t *)path + 8;
318         char a[16], b[16];
319         p += sprintf(p, "BIOS(%x,%x,",
320                      get(a, bios->device_type), get(b, bios->status_flag));
321         p += unparse_raw(p, q, path->length - 8);
322         p += sprintf(p, ")");
323         return p - buffer;
324 }
325
326
327 uint64_t
328 unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize)
329 {
330         uint16_t parsed_length = 0;
331         char *p = buffer;
332         int exit_now = 0;
333
334         while (parsed_length < pathsize && !exit_now) {
335                 switch (path->type) {
336                 case 0x01:
337                         p += unparse_hardware_path(p, path);
338                         break;
339                 case 0x02:
340                         p += unparse_acpi_path(p, path);
341                         break;
342                 case 0x03:
343                         p += unparse_messaging_path(p, path);
344                         break;
345                 case 0x04:
346                         p += unparse_media_path(p, path);
347                         break;
348                 case 0x05:
349                         p += unparse_bios_path(p, path);
350                         break;
351                 case 0x7F:
352                         exit_now = 1;
353                         break;
354                 case 0xFF:
355                         exit_now = 1;
356                         break;
357                 default:
358                         printf("\nwierd path");
359                         dump_raw_data(path, 4);
360                         break;
361                 }
362 //              p += sprintf(p, "\\");
363                 parsed_length += path->length;
364                 path = (EFI_DEVICE_PATH *) ((uint8_t *)path + path->length);
365         }
366
367         return p - buffer;
368 }
369
370
371 #if 0
372 static void
373 unparse_var(efi_variable_t *var)
374 {
375         char buffer[1024];
376         memset(buffer, 0, sizeof(buffer));
377
378         unparse_path(buffer, (EFI_DEVICE_PATH *)var->Data, var->DataSize);
379         printf("%s\n", buffer);
380 }
381
382 static int
383 compare_hardware_path_pci(EFI_DEVICE_PATH *path,
384                           int device, int func)
385 {
386         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
387         uint8_t path_device, path_func;
388
389         switch (path->subtype) {
390         case 1:
391                 /* PCI */
392                 path_func   = *(uint8_t *)p;
393                 path_device = *(uint8_t *)(p+1);
394                 
395                 return !(path_func == func && path_device == device);
396                 
397                 break;
398         default:
399                 break;
400         }
401         return 1;
402 }
403
404 static int
405 compare_hardware_path_scsi(EFI_DEVICE_PATH *path, int id, int lun)
406 {
407         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
408         uint16_t path_id, path_lun;
409
410         switch (path->subtype) {
411         case 2:
412                 /* SCSI */
413                 path_id   = *(uint16_t *)p;
414                 path_lun = *(uint16_t *)(p+2);
415                 
416                 return !(path_id == id && path_lun == lun);
417                 break;
418         default:
419                 break;
420         }
421         return 1;
422 }
423
424 static int
425 compare_hardware_path_acpi(EFI_DEVICE_PATH *path, int bus)
426 {
427         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
428         uint32_t _HID, _UID;
429
430         switch (path->subtype) {
431         case 1:
432                 /* ACPI */
433                 _HID = *(uint32_t *)p;
434                 _UID = *(uint32_t *)(p+4);
435                 
436                 /* FIXME: Need to convert _HID and _UID to bus number */
437
438                 return 0;
439                 break;
440         default:
441                 break;
442         }
443         return 1;
444 }
445
446 static int
447 compare_media_path_harddrive(EFI_DEVICE_PATH *path, uint32_t num,
448                              uint64_t start, uint64_t size)
449 {
450         HARDDRIVE_DEVICE_PATH *p = (HARDDRIVE_DEVICE_PATH *)path;
451         
452
453         switch (path->subtype) {
454         case 1:
455                 /* Hard Drive */
456                 return !(p->part_num == num
457                          && p->start == start
458                          && p->size == size);
459                 break;
460         default:
461                 break;
462         }
463         return 1;
464 }
465
466
467
468 int
469 compare_pci_scsi_disk_blk(efi_variable_t *var,
470                           int bus, int device, int func,
471                           int host, int channel, int id, int lun,
472                           uint64_t start, uint64_t size)
473 {
474
475         EFI_DEVICE_PATH *path = (EFI_DEVICE_PATH *) var->Data;
476         uint64_t parsed_length = 0;
477         int exit_now = 0;
478         int rc = 0;
479
480         while (parsed_length < var->DataSize && !exit_now && !rc) {
481                 switch (path->type) {
482                 case 0x01:
483                         /* Hardware (PCI) */
484                         rc = compare_hardware_path_pci(path, device, func);
485                         break;
486                 case 0x02:
487                         /* ACPI */
488                         rc = compare_hardware_path_acpi(path, bus);
489                         break;
490                 case 0x03:
491                         /* Messaging (SCSI) */
492                         rc = compare_messaging_path_scsi(path, id, lun);
493                         break;
494                 case 0x04:
495                         /* Media (Hard Drive) */
496                         rc = compare_media_path_harddrive(path, 0,
497                                                           start, size);
498                         break;
499                 case 0x7F:
500                 case 0xFF:
501                         exit_now = 1;
502                         break;
503                 case 0x05: /* BIOS */
504                 default:
505                         break;
506                 }
507                 parsed_length += path->length;
508                 path = var->Data + parsed_length;
509         }
510         return rc;
511 }
512
513 #endif  
514
515
516
517
518
519
520
521
522
523
524
525
526 #ifdef UNPARSE_PATH
527 static void
528 usage(void)
529 {
530         printf("Usage: dumppath filename\n");
531         printf("\t where filename is a blkXXXX EFI variable from /proc/efi/vars\n");
532 }
533
534 int
535 main(int argc, char **argv)
536 {
537         int fd = 0;
538         ssize_t size;
539         efi_variable_t var;
540
541         if (argc == 1) {
542                 usage();
543                 exit(-1);
544         }
545
546         
547         fd = open(argv[1], O_RDONLY);
548         if (fd == -1) {
549                 perror("Failed to open file.");
550                 exit(-1);
551         }
552         size = read(fd, &var, sizeof(var));
553         if (size == -1 || size < sizeof(var)) {
554                 perror("Failed to read file.");
555                 close(fd);
556                 exit(-1);
557         }
558         unparse_var(&var);
559         
560                 
561         return 0;
562 }
563 #endif