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