]> git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/names-parse.c
lspci: Show device name as exported by BIOS (sysfs label attribute) (V2)
[thirdparty/pciutils.git] / lib / names-parse.c
1 /*
2 * The PCI Library -- Parsing of the ID list
3 *
4 * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include "internal.h"
15 #include "names.h"
16
17 #ifdef PCI_COMPRESSED_IDS
18 #include <zlib.h>
19 typedef gzFile pci_file;
20 #define pci_gets(f, l, s) gzgets(f, l, s)
21 #define pci_eof(f) gzeof(f)
22
23 static pci_file pci_open(struct pci_access *a)
24 {
25 pci_file result;
26 size_t len;
27 char *new_name;
28
29 result = gzopen(a->id_file_name, "rb");
30 if (result)
31 return result;
32 len = strlen(a->id_file_name);
33 if (len < 3 || memcmp(a->id_file_name + len - 3, ".gz", 3) != 0)
34 return result;
35 new_name = malloc(len - 2);
36 memcpy(new_name, a->id_file_name, len - 3);
37 new_name[len - 3] = 0;
38 pci_set_name_list_path(a, new_name, 1);
39 return gzopen(a->id_file_name, "rb");
40 }
41
42 #define pci_close(f) gzclose(f)
43 #define PCI_ERROR(f, err) \
44 if (!err) { \
45 int errnum; \
46 gzerror(f, &errnum); \
47 if (errnum >= 0) err = NULL; \
48 else if (errnum == Z_ERRNO) err = "I/O error"; \
49 else err = zError(errnum); \
50 }
51 #else
52 typedef FILE * pci_file;
53 #define pci_gets(f, l, s) fgets(l, s, f)
54 #define pci_eof(f) feof(f)
55 #define pci_open(a) fopen(a->id_file_name, "r")
56 #define pci_close(f) fclose(f)
57 #define PCI_ERROR(f, err) if (!err && ferror(f)) err = "I/O error";
58 #endif
59
60 static int id_hex(char *p, int cnt)
61 {
62 int x = 0;
63 while (cnt--)
64 {
65 x <<= 4;
66 if (*p >= '0' && *p <= '9')
67 x += (*p - '0');
68 else if (*p >= 'a' && *p <= 'f')
69 x += (*p - 'a' + 10);
70 else if (*p >= 'A' && *p <= 'F')
71 x += (*p - 'A' + 10);
72 else
73 return -1;
74 p++;
75 }
76 return x;
77 }
78
79 static inline int id_white_p(int c)
80 {
81 return (c == ' ') || (c == '\t');
82 }
83
84
85 static const char *id_parse_list(struct pci_access *a, pci_file f, int *lino)
86 {
87 char line[MAX_LINE];
88 char *p;
89 int id1=0, id2=0, id3=0, id4=0;
90 int cat = -1;
91 int nest;
92 static const char parse_error[] = "Parse error";
93
94 *lino = 0;
95 while (pci_gets(f, line, sizeof(line)))
96 {
97 (*lino)++;
98 p = line;
99 while (*p && *p != '\n' && *p != '\r')
100 p++;
101 if (!*p && !pci_eof(f))
102 return "Line too long";
103 *p = 0;
104 if (p > line && (p[-1] == ' ' || p[-1] == '\t'))
105 *--p = 0;
106
107 p = line;
108 while (id_white_p(*p))
109 p++;
110 if (!*p || *p == '#')
111 continue;
112
113 p = line;
114 while (*p == '\t')
115 p++;
116 nest = p - line;
117
118 if (!nest) /* Top-level entries */
119 {
120 if (p[0] == 'C' && p[1] == ' ') /* Class block */
121 {
122 if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4]))
123 return parse_error;
124 cat = ID_CLASS;
125 p += 5;
126 }
127 else if (p[0] == 'S' && p[1] == ' ')
128 { /* Generic subsystem block */
129 if ((id1 = id_hex(p+2, 4)) < 0 || p[6])
130 return parse_error;
131 if (!pci_id_lookup(a, 0, ID_VENDOR, id1, 0, 0, 0))
132 return "Vendor does not exist";
133 cat = ID_GEN_SUBSYSTEM;
134 continue;
135 }
136 else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ')
137 { /* Unrecognized block (RFU) */
138 cat = ID_UNKNOWN;
139 continue;
140 }
141 else /* Vendor ID */
142 {
143 if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
144 return parse_error;
145 cat = ID_VENDOR;
146 p += 5;
147 }
148 id2 = id3 = id4 = 0;
149 }
150 else if (cat == ID_UNKNOWN) /* Nested entries in RFU blocks are skipped */
151 continue;
152 else if (nest == 1) /* Nesting level 1 */
153 switch (cat)
154 {
155 case ID_VENDOR:
156 case ID_DEVICE:
157 case ID_SUBSYSTEM:
158 if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
159 return parse_error;
160 p += 5;
161 cat = ID_DEVICE;
162 id3 = id4 = 0;
163 break;
164 case ID_GEN_SUBSYSTEM:
165 if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
166 return parse_error;
167 p += 5;
168 id3 = id4 = 0;
169 break;
170 case ID_CLASS:
171 case ID_SUBCLASS:
172 case ID_PROGIF:
173 if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
174 return parse_error;
175 p += 3;
176 cat = ID_SUBCLASS;
177 id3 = id4 = 0;
178 break;
179 default:
180 return parse_error;
181 }
182 else if (nest == 2) /* Nesting level 2 */
183 switch (cat)
184 {
185 case ID_DEVICE:
186 case ID_SUBSYSTEM:
187 if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9]))
188 return parse_error;
189 p += 10;
190 cat = ID_SUBSYSTEM;
191 break;
192 case ID_CLASS:
193 case ID_SUBCLASS:
194 case ID_PROGIF:
195 if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
196 return parse_error;
197 p += 3;
198 cat = ID_PROGIF;
199 id4 = 0;
200 break;
201 default:
202 return parse_error;
203 }
204 else /* Nesting level 3 or more */
205 return parse_error;
206 while (id_white_p(*p))
207 p++;
208 if (!*p)
209 return parse_error;
210 if (pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_LOCAL))
211 return "Duplicate entry";
212 }
213 return NULL;
214 }
215
216 int
217 pci_load_name_list(struct pci_access *a)
218 {
219 pci_file f;
220 int lino;
221 const char *err;
222
223 pci_free_name_list(a);
224 a->id_load_failed = 1;
225 if (!(f = pci_open(a)))
226 return 0;
227 err = id_parse_list(a, f, &lino);
228 PCI_ERROR(f, err);
229 pci_close(f);
230 if (err)
231 a->error("%s at %s, line %d\n", err, a->id_file_name, lino);
232 a->id_load_failed = 0;
233 return 1;
234 }
235
236 void
237 pci_free_name_list(struct pci_access *a)
238 {
239 pci_id_cache_flush(a);
240 pci_id_hash_free(a);
241 a->id_load_failed = 0;
242 }
243
244 void
245 pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed)
246 {
247 if (a->free_id_name)
248 free(a->id_file_name);
249 a->id_file_name = name;
250 a->free_id_name = to_be_freed;
251 }