3c28f1c870a302a7a09f20ff14fd961d13da04ed
[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
36
37
38 void
39 dump_raw_data(void *data, uint64_t length)
40 {
41         char buffer1[80], buffer2[80], *b1, *b2, c;
42         unsigned char *p = data;
43         unsigned long column=0;
44         uint64_t length_printed = 0;
45         const char maxcolumn = 16;
46         while (length_printed < length) {
47                 b1 = buffer1;
48                 b2 = buffer2;
49                 for (column = 0;
50                      column < maxcolumn && length_printed < length; 
51                      column ++) {
52                         b1 += sprintf(b1, "%02x ",(unsigned int) *p);
53                         if (*p < 32 || *p > 126) c = '.';
54                         else c = *p;
55                         b2 += sprintf(b2, "%c", c);
56                         p++;
57                         length_printed++;
58                 }
59                 /* pad out the line */
60                 for (; column < maxcolumn; column++)
61                 {
62                         b1 += sprintf(b1, "   ");
63                         b2 += sprintf(b2, " ");
64                 }
65
66                 printf("%s\t%s\n", buffer1, buffer2);
67         }
68 }
69
70
71
72 unsigned long
73 unparse_raw(char *buffer, uint8_t *p, uint64_t length)
74 {
75         uint64_t i; unsigned char c;
76         char *q = buffer;
77         for (i=0; i<length; i++) {
78                 c = p[i];
79                 //if (c < 32 || c > 127) c = '.';
80                 q += sprintf(q, "%02x", c);
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
116         switch (path->subtype) {
117         case 1:
118                 return sprintf(buffer, "ACPI(%x,%x)", acpi->_HID, acpi->_UID);
119                 break;
120         default:
121                 return unparse_raw(buffer, (uint8_t *)path, path->length);
122                 break;
123         }
124         return 0;
125 }
126
127 static int
128 unparse_vendor_path(char *buffer, VENDOR_DEVICE_PATH *path)
129 {
130         char text_guid[40], *p = buffer, *q = (uint8_t *)path + 20;
131         efi_guid_unparse(&path->vendor_guid, text_guid);
132         p += sprintf(p, "Vendor(%s,", text_guid);
133         p += unparse_raw(p, q, path->length - 20);
134         p += sprintf(p, ")");
135         return p - buffer;
136 }
137
138 static int
139 unparse_hardware_path(char *buffer, EFI_DEVICE_PATH *path)
140 {
141         PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)path;
142         PCCARD_DEVICE_PATH *pccard = (PCCARD_DEVICE_PATH *)path;
143         MEMORY_MAPPED_DEVICE_PATH *mm = (MEMORY_MAPPED_DEVICE_PATH *)path;
144         CONTROLLER_DEVICE_PATH *ctlr = (CONTROLLER_DEVICE_PATH *)path;
145
146         switch (path->subtype) {
147         case 1:
148                 return sprintf(buffer, "PCI(%x,%x)",
149                                pci->device, pci->function);
150                 break;
151         case 2:
152                 return sprintf(buffer, "PCCARD(%x)", pccard->socket);
153                 break;
154         case 3:
155                 return sprintf(buffer, "MM(%x,%" PRIx64 ",%" PRIx64 ")",
156                                mm->memory_type,
157                                mm->start, mm->end);
158                 break;
159         case 4:
160                 return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
161                 break;
162
163         case 5:
164                 return sprintf(buffer, "Controller(%x)", ctlr->controller);
165                 break;
166
167         default:
168                 return unparse_raw(buffer, (uint8_t *)path, path->length);
169         }
170         return 0;
171 }
172
173
174 static int
175 unparse_messaging_path(char *buffer, EFI_DEVICE_PATH *path)
176 {
177         ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)path;
178         SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)path;
179         FIBRE_CHANNEL_DEVICE_PATH *fc = (FIBRE_CHANNEL_DEVICE_PATH *)path;
180         I1394_DEVICE_PATH *i1394 = (I1394_DEVICE_PATH *)path;
181         USB_DEVICE_PATH *usb = (USB_DEVICE_PATH *)path;
182         MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)path;
183         USB_CLASS_DEVICE_PATH *usbclass = (USB_CLASS_DEVICE_PATH *)path;
184         I2O_DEVICE_PATH *i2o = (I2O_DEVICE_PATH *)path; 
185         IPv4_DEVICE_PATH *ipv4 = (IPv4_DEVICE_PATH *)path;
186 /*      IPv6_DEVICE_PATH *ipv6 = (IPv6_DEVICE_PATH *)path; */
187         char *p = buffer;
188
189         switch (path->subtype) {
190         case 1:
191                 return sprintf(buffer, "ATAPI(%x,%x,%x)",
192                                atapi->primary_secondary,
193                                atapi->slave_master, atapi->lun);
194                 break;
195         case 2:
196                 return sprintf(buffer, "SCSI(%x,%x)", scsi->id, scsi->lun);
197                 break;
198
199         case 3:
200                 return sprintf(buffer, "FC(%" PRIx64 ",%" PRIx64 ")", fc->wwn, fc->lun);
201                 break;
202         case 4:
203                 return sprintf(buffer, "1394(%" PRIx64 ")", i1394->guid);
204                 break;
205         case 5:
206                 return sprintf(buffer, "USB(%x,%x)", usb->port, usb->endpoint);
207                 break;
208         case 6:
209                 return sprintf(buffer, "I2O(%x)", i2o->tid);
210                 break;
211         case 11:
212                 p += sprintf(p, "MAC(");
213                 p += unparse_raw(p, mac->macaddr, 6);
214                 p += sprintf(p, ",%hhx)", mac->iftype);
215                 return (int) (p - buffer);
216                 break;
217         case 12:
218                 p += sprintf(p, "IPv4(");
219                 p += unparse_ipv4_port(p, ipv4->local_ip, ipv4->local_port);
220                 p += sprintf(p, "<->");
221                 p += unparse_ipv4_port(p, ipv4->remote_ip, ipv4->remote_port);
222                 p += sprintf(p, ",%hx, %hhx", ipv4->protocol, ipv4->static_addr);
223                 return (int) (p - buffer);
224                 break;
225
226         case 15:
227                 return sprintf(buffer, "USBClass(%hx,%hx,%hhx,%hhx,%hhx)",
228                                usbclass->vendor, usbclass->product,
229                                usbclass->class, usbclass->subclass,
230                                usbclass->protocol);
231                 break;
232         default:
233                 return unparse_raw(buffer, (uint8_t *)path, path->length);
234                 break;
235         }
236         return 0;
237 }
238
239 static int
240 unparse_media_hard_drive_path(char *buffer, EFI_DEVICE_PATH *path)
241 {
242         HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *)path;
243         char text_uuid[40], *sig=text_uuid;
244         
245         switch (hd->signature_type) {
246         case 0x00:
247                 sprintf(sig, "None");
248                 break;
249         case 0x01:
250                 sprintf(sig, "%08x", *(uint32_t *)hd->signature);
251                 break;
252         case 0x02: /* GPT */
253                 efi_guid_unparse((efi_guid_t *)hd->signature, sig);
254                 break;
255         default:
256                 break;
257         }
258
259         return sprintf(buffer, "HD(%x,%" PRIx64 ",%" PRIx64 ",%s)",
260                        hd->part_num, hd->start, hd->size, sig);
261 }
262
263
264
265 static int
266 unparse_media_path(char *buffer, EFI_DEVICE_PATH *path)
267 {
268
269         CDROM_DEVICE_PATH *cdrom = (CDROM_DEVICE_PATH *)path;
270         MEDIA_PROTOCOL_DEVICE_PATH *media = (MEDIA_PROTOCOL_DEVICE_PATH *)path;
271         FILE_PATH_DEVICE_PATH *file = (FILE_PATH_DEVICE_PATH *)path;
272         char text_guid[40], *p = buffer;
273         char file_name[80];
274         memset(file_name, 0, sizeof(file_name));
275
276         switch (path->subtype) {
277         case 1:
278                 return unparse_media_hard_drive_path(buffer, path);
279                 break;
280         case 2:
281                 return sprintf(buffer, "CD-ROM(%x,%" PRIx64 ",%" PRIx64 ")",
282                                cdrom->boot_entry, cdrom->start, cdrom->size);
283                 break;
284         case 3:
285                 return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
286                 break;
287         case 4:
288                 efichar_to_char(file_name, file->path_name, 80);
289                 return sprintf(p, "File(%s)", file_name);
290                 break;
291         case 5:
292                 efi_guid_unparse(&media->guid, text_guid);
293                 return sprintf(buffer, "Media(%s)", text_guid);
294                 break;
295         default:
296                 break;
297         }
298         return 0;
299 }
300
301 static int
302 unparse_bios_path(char *buffer, EFI_DEVICE_PATH *path)
303 {
304         BIOS_BOOT_SPEC_DEVICE_PATH *bios = (BIOS_BOOT_SPEC_DEVICE_PATH *)path;
305         char *p = buffer, *q = (uint8_t *)path + 8;
306         p += sprintf(p, "BIOS(%x,%x,",
307                      bios->device_type, bios->status_flag);
308         p += unparse_raw(p, q, path->length - 8);
309         p += sprintf(p, ")");
310         return p - buffer;
311 }
312
313
314 uint64_t
315 unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize)
316 {
317         uint16_t parsed_length = 0;
318         char *p = buffer;
319         int exit_now = 0;
320
321         while (parsed_length < pathsize && !exit_now) {
322                 switch (path->type) {
323                 case 0x01:
324                         p += unparse_hardware_path(p, path);
325                         break;
326                 case 0x02:
327                         p += unparse_acpi_path(p, path);
328                         break;
329                 case 0x03:
330                         p += unparse_messaging_path(p, path);
331                         break;
332                 case 0x04:
333                         p += unparse_media_path(p, path);
334                         break;
335                 case 0x05:
336                         p += unparse_bios_path(p, path);
337                         break;
338                 case 0x7F:
339                         exit_now = 1;
340                         break;
341                 case 0xFF:
342                         exit_now = 1;
343                         break;
344                 default:
345                         printf("\nwierd path");
346                         dump_raw_data(path, 4);
347                         break;
348                 }
349 //              p += sprintf(p, "\\");
350                 parsed_length += path->length;
351                 path = (EFI_DEVICE_PATH *) ((uint8_t *)path + path->length);
352         }
353
354         return p - buffer;
355 }
356
357
358 #if 0
359 static void
360 unparse_var(efi_variable_t *var)
361 {
362         char buffer[1024];
363         memset(buffer, 0, sizeof(buffer));
364
365         unparse_path(buffer, (EFI_DEVICE_PATH *)var->Data, var->DataSize);
366         printf("%s\n", buffer);
367 }
368
369 static int
370 compare_hardware_path_pci(EFI_DEVICE_PATH *path,
371                           int device, int func)
372 {
373         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
374         uint8_t path_device, path_func;
375
376         switch (path->subtype) {
377         case 1:
378                 /* PCI */
379                 path_func   = *(uint8_t *)p;
380                 path_device = *(uint8_t *)(p+1);
381                 
382                 return !(path_func == func && path_device == device);
383                 
384                 break;
385         default:
386                 break;
387         }
388         return 1;
389 }
390
391 static int
392 compare_hardware_path_scsi(EFI_DEVICE_PATH *path, int id, int lun)
393 {
394         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
395         uint16_t path_id, path_lun;
396
397         switch (path->subtype) {
398         case 2:
399                 /* SCSI */
400                 path_id   = *(uint16_t *)p;
401                 path_lun = *(uint16_t *)(p+2);
402                 
403                 return !(path_id == id && path_lun == lun);
404                 break;
405         default:
406                 break;
407         }
408         return 1;
409 }
410
411 static int
412 compare_hardware_path_acpi(EFI_DEVICE_PATH *path, int bus)
413 {
414         uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
415         uint32_t _HID, _UID;
416
417         switch (path->subtype) {
418         case 1:
419                 /* ACPI */
420                 _HID = *(uint32_t *)p;
421                 _UID = *(uint32_t *)(p+4);
422                 
423                 /* FIXME: Need to convert _HID and _UID to bus number */
424
425                 return 0;
426                 break;
427         default:
428                 break;
429         }
430         return 1;
431 }
432
433 static int
434 compare_media_path_harddrive(EFI_DEVICE_PATH *path, uint32_t num,
435                              uint64_t start, uint64_t size)
436 {
437         HARDDRIVE_DEVICE_PATH *p = (HARDDRIVE_DEVICE_PATH *)path;
438         
439
440         switch (path->subtype) {
441         case 1:
442                 /* Hard Drive */
443                 return !(p->part_num == num
444                          && p->start == start
445                          && p->size == size);
446                 break;
447         default:
448                 break;
449         }
450         return 1;
451 }
452
453
454
455 int
456 compare_pci_scsi_disk_blk(efi_variable_t *var,
457                           int bus, int device, int func,
458                           int host, int channel, int id, int lun,
459                           uint64_t start, uint64_t size)
460 {
461
462         EFI_DEVICE_PATH *path = (EFI_DEVICE_PATH *) var->Data;
463         uint64_t parsed_length = 0;
464         int exit_now = 0;
465         int rc = 0;
466
467         while (parsed_length < var->DataSize && !exit_now && !rc) {
468                 switch (path->type) {
469                 case 0x01:
470                         /* Hardware (PCI) */
471                         rc = compare_hardware_path_pci(path, device, func);
472                         break;
473                 case 0x02:
474                         /* ACPI */
475                         rc = compare_hardware_path_acpi(path, bus);
476                         break;
477                 case 0x03:
478                         /* Messaging (SCSI) */
479                         rc = compare_messaging_path_scsi(path, id, lun);
480                         break;
481                 case 0x04:
482                         /* Media (Hard Drive) */
483                         rc = compare_media_path_harddrive(path, 0,
484                                                           start, size);
485                         break;
486                 case 0x7F:
487                 case 0xFF:
488                         exit_now = 1;
489                         break;
490                 case 0x05: /* BIOS */
491                 default:
492                         break;
493                 }
494                 parsed_length += path->length;
495                 path = var->Data + parsed_length;
496         }
497         return rc;
498 }
499
500 #endif  
501
502
503
504
505
506
507
508
509
510
511
512
513 #ifdef UNPARSE_PATH
514 static void
515 usage(void)
516 {
517         printf("Usage: dumppath filename\n");
518         printf("\t where filename is a blkXXXX EFI variable from /proc/efi/vars\n");
519 }
520
521 int
522 main(int argc, char **argv)
523 {
524         int fd = 0;
525         ssize_t size;
526         efi_variable_t var;
527
528         if (argc == 1) {
529                 usage();
530                 exit(-1);
531         }
532
533         
534         fd = open(argv[1], O_RDONLY);
535         if (fd == -1) {
536                 perror("Failed to open file.");
537                 exit(-1);
538         }
539         size = read(fd, &var, sizeof(var));
540         if (size == -1 || size < sizeof(var)) {
541                 perror("Failed to read file.");
542                 close(fd);
543                 exit(-1);
544         }
545         unparse_var(&var);
546         
547                 
548         return 0;
549 }
550 #endif