]> mj.ucw.cz Git - pciutils.git/blob - lib/names-cache.c
lspci: Add support for CXL MLD DVSEC
[pciutils.git] / lib / names-cache.c
1 /*
2  *      The PCI Library -- ID to Name Cache
3  *
4  *      Copyright (c) 2008--2009 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include "internal.h"
10 #include "names.h"
11
12 #ifdef PCI_USE_DNS
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <pwd.h>
20 #include <unistd.h>
21
22 static const char cache_version[] = "#PCI-CACHE-1.0";
23
24 static char *get_cache_name(struct pci_access *a)
25 {
26   char *name, *buf;
27
28   name = pci_get_param(a, "net.cache_name");
29   if (!name || !name[0])
30     return NULL;
31   if (strncmp(name, "~/", 2))
32     return name;
33
34   uid_t uid = getuid();
35   struct passwd *pw = getpwuid(uid);
36   if (!pw)
37     return name;
38
39   buf = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
40   sprintf(buf, "%s%s", pw->pw_dir, name+1);
41   pci_set_param_internal(a, "net.cache_name", buf, 1);
42   pci_mfree(buf);
43   return pci_get_param(a, "net.cache_name");
44 }
45
46 int
47 pci_id_cache_load(struct pci_access *a, int flags)
48 {
49   char *name;
50   char line[MAX_LINE];
51   FILE *f;
52   int lino;
53
54   a->id_cache_status = 1;
55   name = get_cache_name(a);
56   if (!name)
57     return 0;
58   a->debug("Using cache %s\n", name);
59   if (flags & PCI_LOOKUP_REFRESH_CACHE)
60     {
61       a->debug("Not loading cache, will refresh everything\n");
62       a->id_cache_status = 2;
63       return 0;
64     }
65
66   f = fopen(name, "rb");
67   if (!f)
68     {
69       a->debug("Cache file does not exist\n");
70       return 0;
71     }
72   /* FIXME: Compare timestamp with the pci.ids file? */
73
74   lino = 0;
75   while (fgets(line, sizeof(line), f))
76     {
77       char *p = strchr(line, '\n');
78       lino++;
79       if (p)
80         {
81           *p = 0;
82           if (lino == 1)
83             {
84               if (strcmp(line, cache_version))
85                 {
86                   a->debug("Unrecognized cache version %s, ignoring\n", line);
87                   break;
88                 }
89               continue;
90             }
91           else
92             {
93               int cat, id1, id2, id3, id4, cnt;
94               if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5)
95                 {
96                   p = line + cnt;
97                   while (*p && *p == ' ')
98                     p++;
99                   pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE);
100                   continue;
101                 }
102             }
103         }
104       a->warning("Malformed cache file %s (line %d), ignoring", name, lino);
105       break;
106     }
107
108   if (ferror(f))
109     a->warning("Error while reading %s", name);
110   fclose(f);
111   return 1;
112 }
113
114 void
115 pci_id_cache_flush(struct pci_access *a)
116 {
117   int orig_status = a->id_cache_status;
118   FILE *f;
119   unsigned int h;
120   struct id_entry *e, *e2;
121   char hostname[256], *tmpname, *name;
122   int this_pid;
123
124   a->id_cache_status = 0;
125   if (orig_status < 2)
126     return;
127   name = get_cache_name(a);
128   if (!name)
129     return;
130
131   this_pid = getpid();
132   if (gethostname(hostname, sizeof(hostname)) < 0)
133     hostname[0] = 0;
134   else
135     hostname[sizeof(hostname)-1] = 0;
136   tmpname = pci_malloc(a, strlen(name) + strlen(hostname) + 64);
137   sprintf(tmpname, "%s.tmp-%s-%d", name, hostname, this_pid);
138
139   f = fopen(tmpname, "wb");
140   if (!f)
141     {
142       a->warning("Cannot write to %s: %s", name, strerror(errno));
143       pci_mfree(tmpname);
144       return;
145     }
146   a->debug("Writing cache to %s\n", name);
147   fprintf(f, "%s\n", cache_version);
148
149   for (h=0; h<HASH_SIZE; h++)
150     for (e=a->id_hash[h]; e; e=e->next)
151       if (e->src == SRC_CACHE || e->src == SRC_NET)
152         {
153           /* Negative entries are not written */
154           if (!e->name[0])
155             continue;
156
157           /* Verify that every entry is written at most once */
158           for (e2=a->id_hash[h]; e2 != e; e2=e2->next)
159             if ((e2->src == SRC_CACHE || e2->src == SRC_NET) &&
160                 e2->cat == e->cat &&
161                 e2->id12 == e->id12 && e2->id34 == e->id34)
162             break;
163           if (e2 == e)
164             fprintf(f, "%d %x %x %x %x %s\n",
165                     e->cat,
166                     pair_first(e->id12), pair_second(e->id12),
167                     pair_first(e->id34), pair_second(e->id34),
168                     e->name);
169         }
170
171   fflush(f);
172   if (ferror(f))
173     a->warning("Error writing %s", name);
174   fclose(f);
175
176   if (rename(tmpname, name) < 0)
177     {
178       a->warning("Cannot rename %s to %s: %s", tmpname, name, strerror(errno));
179       unlink(tmpname);
180     }
181   pci_mfree(tmpname);
182 }
183
184 #else
185
186 int pci_id_cache_load(struct pci_access *a UNUSED, int flags UNUSED)
187 {
188   a->id_cache_status = 1;
189   return 0;
190 }
191
192 void pci_id_cache_flush(struct pci_access *a)
193 {
194   a->id_cache_status = 0;
195 }
196
197 #endif
198
199 void
200 pci_id_cache_dirty(struct pci_access *a)
201 {
202   if (a->id_cache_status >= 1)
203     a->id_cache_status = 2;
204 }