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