]> git.ipfire.org Git - thirdparty/pciutils.git/blame - lib/names-cache.c
lspci: add VirtIO SharedMemory capability support
[thirdparty/pciutils.git] / lib / names-cache.c
CommitLineData
752d4d9a
MM
1/*
2 * The PCI Library -- ID to Name Cache
3 *
fda7c18d 4 * Copyright (c) 2008--2009 Martin Mares <mj@ucw.cz>
752d4d9a 5 *
61829219
MM
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
752d4d9a
MM
9 */
10
fda7c18d
MM
11#include "internal.h"
12#include "names.h"
13
14#ifdef PCI_USE_DNS
15
752d4d9a
MM
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <errno.h>
20#include <sys/types.h>
f022f467 21#include <sys/stat.h>
752d4d9a
MM
22#include <pwd.h>
23#include <unistd.h>
24
752d4d9a
MM
25static const char cache_version[] = "#PCI-CACHE-1.0";
26
98ccf6d6
MM
27static char *get_cache_name(struct pci_access *a)
28{
f022f467
MM
29 if (!a->id_cache_name)
30 {
31 char *name = pci_get_param(a, "net.cache_name");
32 if (!name || !name[0])
33 return NULL;
34
35 if (strncmp(name, "~/", 2))
36 a->id_cache_name = pci_strdup(a, name);
37 else
38 {
39 uid_t uid = getuid();
40 struct passwd *pw = getpwuid(uid);
41 if (!pw)
42 return name;
43
44 a->id_cache_name = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
45 sprintf(a->id_cache_name, "%s%s", pw->pw_dir, name+1);
46 }
47 }
48
49 return a->id_cache_name;
50}
51
52static void create_parent_dirs(struct pci_access *a, char *name)
53{
54 // Assumes that we have a private copy of the name we can modify
55
56 char *p = name + strlen(name);
57 while (p > name && *p != '/')
58 p--;
59 if (p == name)
60 return;
61
62 while (p > name)
63 {
64 // We stand at a slash. Check if the current prefix exists.
65 *p = 0;
66 struct stat st;
67 int res = stat(name, &st);
68 *p = '/';
69 if (res >= 0)
70 break;
71
72 // Does not exist yet, move up one directory
73 p--;
74 while (p > name && *p != '/')
75 p--;
76 }
77
78 // We now stand at the end of the longest existing prefix.
79 // Create all directories to the right of it.
80 for (;;)
81 {
82 p++;
83 while (*p && *p != '/')
84 p++;
85 if (!*p)
86 break;
87
88 *p = 0;
89 int res = mkdir(name, 0777);
90 if (res < 0)
91 {
92 a->warning("Cannot create directory %s: %s", name, strerror(errno));
93 *p = '/';
94 break;
95 }
96 *p = '/';
97 }
98ccf6d6
MM
98}
99
752d4d9a
MM
100int
101pci_id_cache_load(struct pci_access *a, int flags)
102{
103 char *name;
104 char line[MAX_LINE];
752d4d9a
MM
105 FILE *f;
106 int lino;
107
f022f467
MM
108 if (a->id_cache_status > 0)
109 return 0;
752d4d9a 110 a->id_cache_status = 1;
f022f467 111
98ccf6d6
MM
112 name = get_cache_name(a);
113 if (!name)
114 return 0;
115 a->debug("Using cache %s\n", name);
f022f467 116
752d4d9a
MM
117 if (flags & PCI_LOOKUP_REFRESH_CACHE)
118 {
119 a->debug("Not loading cache, will refresh everything\n");
120 a->id_cache_status = 2;
121 return 0;
122 }
123
98ccf6d6 124 f = fopen(name, "rb");
752d4d9a
MM
125 if (!f)
126 {
127 a->debug("Cache file does not exist\n");
128 return 0;
129 }
130 /* FIXME: Compare timestamp with the pci.ids file? */
131
132 lino = 0;
133 while (fgets(line, sizeof(line), f))
134 {
135 char *p = strchr(line, '\n');
136 lino++;
137 if (p)
138 {
139 *p = 0;
140 if (lino == 1)
141 {
142 if (strcmp(line, cache_version))
143 {
144 a->debug("Unrecognized cache version %s, ignoring\n", line);
145 break;
146 }
147 continue;
148 }
149 else
150 {
151 int cat, id1, id2, id3, id4, cnt;
152 if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5)
153 {
154 p = line + cnt;
155 while (*p && *p == ' ')
156 p++;
157 pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE);
158 continue;
159 }
160 }
161 }
98ccf6d6 162 a->warning("Malformed cache file %s (line %d), ignoring", name, lino);
752d4d9a
MM
163 break;
164 }
165
166 if (ferror(f))
98ccf6d6 167 a->warning("Error while reading %s", name);
752d4d9a
MM
168 fclose(f);
169 return 1;
170}
171
752d4d9a
MM
172void
173pci_id_cache_flush(struct pci_access *a)
174{
175 int orig_status = a->id_cache_status;
176 FILE *f;
177 unsigned int h;
178 struct id_entry *e, *e2;
98ccf6d6 179 char hostname[256], *tmpname, *name;
61bc0b58 180 int this_pid;
752d4d9a
MM
181
182 a->id_cache_status = 0;
183 if (orig_status < 2)
184 return;
98ccf6d6
MM
185 name = get_cache_name(a);
186 if (!name)
752d4d9a 187 return;
61bc0b58 188
f022f467
MM
189 create_parent_dirs(a, name);
190
61bc0b58
MM
191 this_pid = getpid();
192 if (gethostname(hostname, sizeof(hostname)) < 0)
193 hostname[0] = 0;
194 else
195 hostname[sizeof(hostname)-1] = 0;
98ccf6d6
MM
196 tmpname = pci_malloc(a, strlen(name) + strlen(hostname) + 64);
197 sprintf(tmpname, "%s.tmp-%s-%d", name, hostname, this_pid);
61bc0b58
MM
198
199 f = fopen(tmpname, "wb");
752d4d9a
MM
200 if (!f)
201 {
98ccf6d6 202 a->warning("Cannot write to %s: %s", name, strerror(errno));
61bc0b58 203 pci_mfree(tmpname);
752d4d9a
MM
204 return;
205 }
98ccf6d6 206 a->debug("Writing cache to %s\n", name);
752d4d9a
MM
207 fprintf(f, "%s\n", cache_version);
208
209 for (h=0; h<HASH_SIZE; h++)
210 for (e=a->id_hash[h]; e; e=e->next)
211 if (e->src == SRC_CACHE || e->src == SRC_NET)
212 {
61bc0b58
MM
213 /* Negative entries are not written */
214 if (!e->name[0])
215 continue;
216
752d4d9a
MM
217 /* Verify that every entry is written at most once */
218 for (e2=a->id_hash[h]; e2 != e; e2=e2->next)
219 if ((e2->src == SRC_CACHE || e2->src == SRC_NET) &&
220 e2->cat == e->cat &&
221 e2->id12 == e->id12 && e2->id34 == e->id34)
222 break;
223 if (e2 == e)
224 fprintf(f, "%d %x %x %x %x %s\n",
225 e->cat,
226 pair_first(e->id12), pair_second(e->id12),
227 pair_first(e->id34), pair_second(e->id34),
228 e->name);
229 }
230
231 fflush(f);
232 if (ferror(f))
98ccf6d6 233 a->warning("Error writing %s", name);
752d4d9a 234 fclose(f);
61bc0b58 235
98ccf6d6 236 if (rename(tmpname, name) < 0)
61bc0b58 237 {
98ccf6d6 238 a->warning("Cannot rename %s to %s: %s", tmpname, name, strerror(errno));
61bc0b58
MM
239 unlink(tmpname);
240 }
241 pci_mfree(tmpname);
752d4d9a
MM
242}
243
94d1b5e0
MM
244#else
245
246int pci_id_cache_load(struct pci_access *a UNUSED, int flags UNUSED)
247{
248 a->id_cache_status = 1;
249 return 0;
250}
251
252void pci_id_cache_flush(struct pci_access *a)
253{
254 a->id_cache_status = 0;
f022f467
MM
255 pci_mfree(a->id_cache_name);
256 a->id_cache_name = NULL;
94d1b5e0
MM
257}
258
259#endif
260
261void
262pci_id_cache_dirty(struct pci_access *a)
263{
264 if (a->id_cache_status >= 1)
265 a->id_cache_status = 2;
266}