xref: /pciutils/lib/dump.c (revision ea4e5f5d)
1 /*
2  *	The PCI Library -- Reading of Bus Dumps
3  *
4  *	Copyright (c) 1997--2004 Martin Mares <[email protected]>
5  *
6  *	Can be freely distributed and used under the terms of the GNU GPL.
7  */
8 
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <errno.h>
13 
14 #include "internal.h"
15 
16 struct dump_data {
17   int len;
18   byte data[1];
19 };
20 
21 static int
22 dump_detect(struct pci_access *a)
23 {
24   return !!a->method_params[PCI_ACCESS_DUMP];
25 }
26 
27 static void
28 dump_alloc_data(struct pci_dev *dev, int len)
29 {
30   struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
31   dd->len = len;
32   memset(dd->data, 0xff, len);
33   dev->aux = dd;
34 }
35 
36 static void
37 dump_init(struct pci_access *a)
38 {
39   char *name = a->method_params[PCI_ACCESS_DUMP];
40   FILE *f;
41   char buf[256];
42   struct pci_dev *dev = NULL;
43   int len, mn, bn, dn, fn, i, j;
44 
45   if (!a)
46     a->error("dump: File name not given.");
47   if (!(f = fopen(name, "r")))
48     a->error("dump: Cannot open %s: %s", name, strerror(errno));
49   while (fgets(buf, sizeof(buf)-1, f))
50     {
51       char *z = strchr(buf, '\n');
52       if (!z)
53 	a->error("dump: line too long or unterminated");
54       *z-- = 0;
55       if (z >= buf && *z == '\r')
56 	*z-- = 0;
57       len = z - buf + 1;
58       mn = 0;
59       if ((len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' &&
60 	   sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) ||
61 	  (len >= 13 && buf[4] == ':' && buf[7] == ':' && buf[10] == '.' && buf[12] == ' ' &&
62 	   sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4))
63 	{
64 	  dev = pci_get_dev(a, mn, bn, dn, fn);
65 	  dump_alloc_data(dev, 256);
66 	  pci_link_dev(a, dev);
67 	}
68       else if (!len)
69 	dev = NULL;
70       else if (dev &&
71 	       (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') &&
72 	       sscanf(buf, "%x: ", &i) == 1)
73 	{
74 	  struct dump_data *dd = dev->aux;
75 	  z = strchr(buf, ' ');
76 	  while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2]))
77 	    {
78 	      z++;
79 	      if (sscanf(z, "%x", &j) != 1 || i >= 256)
80 		a->error("dump: Malformed line");
81 	      if (i >= 4096)
82 		break;
83 	      if (i > dd->len)		/* Need to re-allocate the buffer */
84 		{
85 		  dump_alloc_data(dev, 4096);
86 		  memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256);
87 		  pci_mfree(dd);
88 		  dd = dev->aux;
89 		}
90 	      dd->data[i++] = j;
91 	      z += 2;
92 	    }
93 	}
94     }
95 }
96 
97 static void
98 dump_cleanup(struct pci_access *a UNUSED)
99 {
100 }
101 
102 static void
103 dump_scan(struct pci_access *a UNUSED)
104 {
105 }
106 
107 static int
108 dump_read(struct pci_dev *d, int pos, byte *buf, int len)
109 {
110   struct dump_data *dd;
111   if (!(dd = d->aux))
112     {
113       struct pci_dev *e = d->access->devices;
114       while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func))
115 	e = e->next;
116       if (!e)
117 	return 0;
118       dd = e->aux;
119     }
120   if (pos + len > dd->len)
121     return 0;
122   memcpy(buf, dd->data + pos, len);
123   return 1;
124 }
125 
126 static int
127 dump_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED)
128 {
129   d->access->error("Writing to dump files is not supported.");
130   return 0;
131 }
132 
133 static void
134 dump_cleanup_dev(struct pci_dev *d)
135 {
136   if (d->aux)
137     {
138       pci_mfree(d->aux);
139       d->aux = NULL;
140     }
141 }
142 
143 struct pci_methods pm_dump = {
144   "dump",
145   NULL,					/* config */
146   dump_detect,
147   dump_init,
148   dump_cleanup,
149   dump_scan,
150   pci_generic_fill_info,
151   dump_read,
152   dump_write,
153   NULL,					/* init_dev */
154   dump_cleanup_dev
155 };
156