xref: /aosp_15_r20/external/pciutils/lib/names-parse.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1 /*
2  *	The PCI Library -- Parsing of the ID list
3  *
4  *	Copyright (c) 1997--2008 Martin Mares <[email protected]>
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 
pci_open(struct pci_access * a)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 
id_hex(char * p,int cnt)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 
id_white_p(int c)81 static inline int id_white_p(int c)
82 {
83   return (c == ' ') || (c == '\t');
84 }
85 
86 
id_parse_list(struct pci_access * a,pci_file f,int * lino)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
pci_load_name_list(struct pci_access * a)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
pci_free_name_list(struct pci_access * a)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
pci_set_name_list_path(struct pci_access * a,char * name,int to_be_freed)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 }
254