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